From ae30b384a706866466f67308fbb72faef5638b3d Mon Sep 17 00:00:00 2001 From: PProvost Date: Thu, 14 May 2020 18:12:37 -0600 Subject: Moved protocol handlers to addons --- CMakeLists.txt | 2 +- README.md | 4 +- addons/BSD/nxd_bsd.c | 14542 +++++++++++++++ addons/BSD/nxd_bsd.h | 883 + addons/CMakeLists.txt | 70 + addons/auto_ip/nx_auto_ip.c | 1223 ++ addons/auto_ip/nx_auto_ip.h | 215 + addons/dhcp/nxd_dhcp_client.c | 10109 +++++++++++ addons/dhcp/nxd_dhcp_client.h | 750 + addons/dhcp/nxd_dhcp_server.c | 5532 ++++++ addons/dhcp/nxd_dhcp_server.h | 592 + addons/dhcp/nxd_dhcpv6_client.c | 12222 +++++++++++++ addons/dhcp/nxd_dhcpv6_client.h | 1060 ++ addons/dhcp/nxd_dhcpv6_server.c | 7281 ++++++++ addons/dhcp/nxd_dhcpv6_server.h | 825 + addons/dns/nxd_dns.c | 9907 +++++++++++ addons/dns/nxd_dns.h | 1013 ++ addons/ftp/nxd_ftp_client.c | 6078 +++++++ addons/ftp/nxd_ftp_client.h | 373 + addons/ftp/nxd_ftp_server.c | 6684 +++++++ addons/ftp/nxd_ftp_server.h | 438 + addons/http/nxd_http_client.c | 3418 ++++ addons/http/nxd_http_client.h | 294 + addons/http/nxd_http_server.c | 9253 ++++++++++ addons/http/nxd_http_server.h | 652 + addons/mdns/nxd_mdns.c | 13867 +++++++++++++++ addons/mdns/nxd_mdns.h | 1316 ++ addons/mqtt/nxd_mqtt_client.c | 5964 +++++++ addons/mqtt/nxd_mqtt_client.h | 510 + addons/nat/nx_nat.c | 4542 +++++ addons/nat/nx_nat.h | 302 + addons/pop3/nxd_pop3_client.c | 3227 ++++ addons/pop3/nxd_pop3_client.h | 277 + addons/ppp/nx_ppp.c | 12044 +++++++++++++ addons/ppp/nx_ppp.h | 824 + addons/pppoe/nx_pppoe_client.c | 3734 ++++ addons/pppoe/nx_pppoe_client.h | 352 + addons/pppoe/nx_pppoe_server.c | 4408 +++++ addons/pppoe/nx_pppoe_server.h | 376 + addons/smtp/nxd_smtp_client.c | 4752 +++++ addons/smtp/nxd_smtp_client.h | 433 + addons/snmp/nx_des.c | 546 + addons/snmp/nx_des.h | 75 + addons/snmp/nx_sha1.c | 494 + addons/snmp/nx_sha1.h | 114 + addons/snmp/nxd_snmp.c | 23756 +++++++++++++++++++++++++ addons/snmp/nxd_snmp.h | 888 + addons/sntp/nxd_sntp_client.c | 6362 +++++++ addons/sntp/nxd_sntp_client.h | 781 + addons/telnet/nxd_telnet_client.c | 961 + addons/telnet/nxd_telnet_client.h | 184 + addons/telnet/nxd_telnet_server.c | 2565 +++ addons/telnet/nxd_telnet_server.h | 354 + addons/tftp/nxd_tftp_client.c | 2396 +++ addons/tftp/nxd_tftp_client.h | 313 + addons/tftp/nxd_tftp_server.c | 2855 +++ addons/tftp/nxd_tftp_server.h | 384 + addons/web/nx_tcpserver.c | 1426 ++ addons/web/nx_tcpserver.h | 191 + addons/web/nx_web_http_client.c | 8505 +++++++++ addons/web/nx_web_http_client.h | 655 + addons/web/nx_web_http_common.h | 245 + addons/web/nx_web_http_server.c | 11103 ++++++++++++ addons/web/nx_web_http_server.h | 674 + protocol_handlers/BSD/nxd_bsd.c | 14542 --------------- protocol_handlers/BSD/nxd_bsd.h | 883 - protocol_handlers/CMakeLists.txt | 70 - protocol_handlers/auto_ip/nx_auto_ip.c | 1223 -- protocol_handlers/auto_ip/nx_auto_ip.h | 215 - protocol_handlers/dhcp/nxd_dhcp_client.c | 10109 ----------- protocol_handlers/dhcp/nxd_dhcp_client.h | 750 - protocol_handlers/dhcp/nxd_dhcp_server.c | 5532 ------ protocol_handlers/dhcp/nxd_dhcp_server.h | 592 - protocol_handlers/dhcp/nxd_dhcpv6_client.c | 12222 ------------- protocol_handlers/dhcp/nxd_dhcpv6_client.h | 1060 -- protocol_handlers/dhcp/nxd_dhcpv6_server.c | 7281 -------- protocol_handlers/dhcp/nxd_dhcpv6_server.h | 825 - protocol_handlers/dns/nxd_dns.c | 9907 ----------- protocol_handlers/dns/nxd_dns.h | 1013 -- protocol_handlers/ftp/nxd_ftp_client.c | 6078 ------- protocol_handlers/ftp/nxd_ftp_client.h | 373 - protocol_handlers/ftp/nxd_ftp_server.c | 6684 ------- protocol_handlers/ftp/nxd_ftp_server.h | 438 - protocol_handlers/http/nxd_http_client.c | 3418 ---- protocol_handlers/http/nxd_http_client.h | 294 - protocol_handlers/http/nxd_http_server.c | 9253 ---------- protocol_handlers/http/nxd_http_server.h | 652 - protocol_handlers/mdns/nxd_mdns.c | 13867 --------------- protocol_handlers/mdns/nxd_mdns.h | 1316 -- protocol_handlers/mqtt/nxd_mqtt_client.c | 5964 ------- protocol_handlers/mqtt/nxd_mqtt_client.h | 510 - protocol_handlers/nat/nx_nat.c | 4542 ----- protocol_handlers/nat/nx_nat.h | 302 - protocol_handlers/pop3/nxd_pop3_client.c | 3227 ---- protocol_handlers/pop3/nxd_pop3_client.h | 277 - protocol_handlers/ppp/nx_ppp.c | 12044 ------------- protocol_handlers/ppp/nx_ppp.h | 824 - protocol_handlers/pppoe/nx_pppoe_client.c | 3734 ---- protocol_handlers/pppoe/nx_pppoe_client.h | 352 - protocol_handlers/pppoe/nx_pppoe_server.c | 4408 ----- protocol_handlers/pppoe/nx_pppoe_server.h | 376 - protocol_handlers/smtp/nxd_smtp_client.c | 4752 ----- protocol_handlers/smtp/nxd_smtp_client.h | 433 - protocol_handlers/snmp/nx_des.c | 546 - protocol_handlers/snmp/nx_des.h | 75 - protocol_handlers/snmp/nx_sha1.c | 494 - protocol_handlers/snmp/nx_sha1.h | 114 - protocol_handlers/snmp/nxd_snmp.c | 23756 ------------------------- protocol_handlers/snmp/nxd_snmp.h | 888 - protocol_handlers/sntp/nxd_sntp_client.c | 6362 ------- protocol_handlers/sntp/nxd_sntp_client.h | 781 - protocol_handlers/telnet/nxd_telnet_client.c | 961 - protocol_handlers/telnet/nxd_telnet_client.h | 184 - protocol_handlers/telnet/nxd_telnet_server.c | 2565 --- protocol_handlers/telnet/nxd_telnet_server.h | 354 - protocol_handlers/tftp/nxd_tftp_client.c | 2396 --- protocol_handlers/tftp/nxd_tftp_client.h | 313 - protocol_handlers/tftp/nxd_tftp_server.c | 2855 --- protocol_handlers/tftp/nxd_tftp_server.h | 384 - protocol_handlers/web/nx_tcpserver.c | 1426 -- protocol_handlers/web/nx_tcpserver.h | 191 - protocol_handlers/web/nx_web_http_client.c | 8505 --------- protocol_handlers/web/nx_web_http_client.h | 655 - protocol_handlers/web/nx_web_http_common.h | 245 - protocol_handlers/web/nx_web_http_server.c | 11103 ------------ protocol_handlers/web/nx_web_http_server.h | 674 - 126 files changed, 216172 insertions(+), 216172 deletions(-) create mode 100644 addons/BSD/nxd_bsd.c create mode 100644 addons/BSD/nxd_bsd.h create mode 100644 addons/CMakeLists.txt create mode 100644 addons/auto_ip/nx_auto_ip.c create mode 100644 addons/auto_ip/nx_auto_ip.h create mode 100644 addons/dhcp/nxd_dhcp_client.c create mode 100644 addons/dhcp/nxd_dhcp_client.h create mode 100644 addons/dhcp/nxd_dhcp_server.c create mode 100644 addons/dhcp/nxd_dhcp_server.h create mode 100644 addons/dhcp/nxd_dhcpv6_client.c create mode 100644 addons/dhcp/nxd_dhcpv6_client.h create mode 100644 addons/dhcp/nxd_dhcpv6_server.c create mode 100644 addons/dhcp/nxd_dhcpv6_server.h create mode 100644 addons/dns/nxd_dns.c create mode 100644 addons/dns/nxd_dns.h create mode 100644 addons/ftp/nxd_ftp_client.c create mode 100644 addons/ftp/nxd_ftp_client.h create mode 100644 addons/ftp/nxd_ftp_server.c create mode 100644 addons/ftp/nxd_ftp_server.h create mode 100644 addons/http/nxd_http_client.c create mode 100644 addons/http/nxd_http_client.h create mode 100644 addons/http/nxd_http_server.c create mode 100644 addons/http/nxd_http_server.h create mode 100644 addons/mdns/nxd_mdns.c create mode 100644 addons/mdns/nxd_mdns.h create mode 100644 addons/mqtt/nxd_mqtt_client.c create mode 100644 addons/mqtt/nxd_mqtt_client.h create mode 100644 addons/nat/nx_nat.c create mode 100644 addons/nat/nx_nat.h create mode 100644 addons/pop3/nxd_pop3_client.c create mode 100644 addons/pop3/nxd_pop3_client.h create mode 100644 addons/ppp/nx_ppp.c create mode 100644 addons/ppp/nx_ppp.h create mode 100644 addons/pppoe/nx_pppoe_client.c create mode 100644 addons/pppoe/nx_pppoe_client.h create mode 100644 addons/pppoe/nx_pppoe_server.c create mode 100644 addons/pppoe/nx_pppoe_server.h create mode 100644 addons/smtp/nxd_smtp_client.c create mode 100644 addons/smtp/nxd_smtp_client.h create mode 100644 addons/snmp/nx_des.c create mode 100644 addons/snmp/nx_des.h create mode 100644 addons/snmp/nx_sha1.c create mode 100644 addons/snmp/nx_sha1.h create mode 100644 addons/snmp/nxd_snmp.c create mode 100644 addons/snmp/nxd_snmp.h create mode 100644 addons/sntp/nxd_sntp_client.c create mode 100644 addons/sntp/nxd_sntp_client.h create mode 100644 addons/telnet/nxd_telnet_client.c create mode 100644 addons/telnet/nxd_telnet_client.h create mode 100644 addons/telnet/nxd_telnet_server.c create mode 100644 addons/telnet/nxd_telnet_server.h create mode 100644 addons/tftp/nxd_tftp_client.c create mode 100644 addons/tftp/nxd_tftp_client.h create mode 100644 addons/tftp/nxd_tftp_server.c create mode 100644 addons/tftp/nxd_tftp_server.h create mode 100644 addons/web/nx_tcpserver.c create mode 100644 addons/web/nx_tcpserver.h create mode 100644 addons/web/nx_web_http_client.c create mode 100644 addons/web/nx_web_http_client.h create mode 100644 addons/web/nx_web_http_common.h create mode 100644 addons/web/nx_web_http_server.c create mode 100644 addons/web/nx_web_http_server.h delete mode 100644 protocol_handlers/BSD/nxd_bsd.c delete mode 100644 protocol_handlers/BSD/nxd_bsd.h delete mode 100644 protocol_handlers/CMakeLists.txt delete mode 100644 protocol_handlers/auto_ip/nx_auto_ip.c delete mode 100644 protocol_handlers/auto_ip/nx_auto_ip.h delete mode 100644 protocol_handlers/dhcp/nxd_dhcp_client.c delete mode 100644 protocol_handlers/dhcp/nxd_dhcp_client.h delete mode 100644 protocol_handlers/dhcp/nxd_dhcp_server.c delete mode 100644 protocol_handlers/dhcp/nxd_dhcp_server.h delete mode 100644 protocol_handlers/dhcp/nxd_dhcpv6_client.c delete mode 100644 protocol_handlers/dhcp/nxd_dhcpv6_client.h delete mode 100644 protocol_handlers/dhcp/nxd_dhcpv6_server.c delete mode 100644 protocol_handlers/dhcp/nxd_dhcpv6_server.h delete mode 100644 protocol_handlers/dns/nxd_dns.c delete mode 100644 protocol_handlers/dns/nxd_dns.h delete mode 100644 protocol_handlers/ftp/nxd_ftp_client.c delete mode 100644 protocol_handlers/ftp/nxd_ftp_client.h delete mode 100644 protocol_handlers/ftp/nxd_ftp_server.c delete mode 100644 protocol_handlers/ftp/nxd_ftp_server.h delete mode 100644 protocol_handlers/http/nxd_http_client.c delete mode 100644 protocol_handlers/http/nxd_http_client.h delete mode 100644 protocol_handlers/http/nxd_http_server.c delete mode 100644 protocol_handlers/http/nxd_http_server.h delete mode 100644 protocol_handlers/mdns/nxd_mdns.c delete mode 100644 protocol_handlers/mdns/nxd_mdns.h delete mode 100644 protocol_handlers/mqtt/nxd_mqtt_client.c delete mode 100644 protocol_handlers/mqtt/nxd_mqtt_client.h delete mode 100644 protocol_handlers/nat/nx_nat.c delete mode 100644 protocol_handlers/nat/nx_nat.h delete mode 100644 protocol_handlers/pop3/nxd_pop3_client.c delete mode 100644 protocol_handlers/pop3/nxd_pop3_client.h delete mode 100644 protocol_handlers/ppp/nx_ppp.c delete mode 100644 protocol_handlers/ppp/nx_ppp.h delete mode 100644 protocol_handlers/pppoe/nx_pppoe_client.c delete mode 100644 protocol_handlers/pppoe/nx_pppoe_client.h delete mode 100644 protocol_handlers/pppoe/nx_pppoe_server.c delete mode 100644 protocol_handlers/pppoe/nx_pppoe_server.h delete mode 100644 protocol_handlers/smtp/nxd_smtp_client.c delete mode 100644 protocol_handlers/smtp/nxd_smtp_client.h delete mode 100644 protocol_handlers/snmp/nx_des.c delete mode 100644 protocol_handlers/snmp/nx_des.h delete mode 100644 protocol_handlers/snmp/nx_sha1.c delete mode 100644 protocol_handlers/snmp/nx_sha1.h delete mode 100644 protocol_handlers/snmp/nxd_snmp.c delete mode 100644 protocol_handlers/snmp/nxd_snmp.h delete mode 100644 protocol_handlers/sntp/nxd_sntp_client.c delete mode 100644 protocol_handlers/sntp/nxd_sntp_client.h delete mode 100644 protocol_handlers/telnet/nxd_telnet_client.c delete mode 100644 protocol_handlers/telnet/nxd_telnet_client.h delete mode 100644 protocol_handlers/telnet/nxd_telnet_server.c delete mode 100644 protocol_handlers/telnet/nxd_telnet_server.h delete mode 100644 protocol_handlers/tftp/nxd_tftp_client.c delete mode 100644 protocol_handlers/tftp/nxd_tftp_client.h delete mode 100644 protocol_handlers/tftp/nxd_tftp_server.c delete mode 100644 protocol_handlers/tftp/nxd_tftp_server.h delete mode 100644 protocol_handlers/web/nx_tcpserver.c delete mode 100644 protocol_handlers/web/nx_tcpserver.h delete mode 100644 protocol_handlers/web/nx_web_http_client.c delete mode 100644 protocol_handlers/web/nx_web_http_client.h delete mode 100644 protocol_handlers/web/nx_web_http_common.h delete mode 100644 protocol_handlers/web/nx_web_http_server.c delete mode 100644 protocol_handlers/web/nx_web_http_server.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f5d0e5d..56f0d183 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLC add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common) # Pick up the apps directory containing the protocol and app-layer components -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/protocol_handlers) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/addons) # Network security and crypto components add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/crypto_libraries) diff --git a/README.md b/README.md index 305f90ef..bf888a0b 100755 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ Each official release (preview or GA) will be tagged to mark the commit and push ## Directory layout ``` +- addons + - auto_ip, BSD, dhcp, dns, ftp, http, mdns, mqtt, nat, pop3, ppp, pppoe, smtp, sntp, telnet, tftp, web - cmake - common - inc @@ -78,8 +80,6 @@ Each official release (preview or GA) will be tagged to mark the commit and push - cortex_m7/gnu - inc - src -- protocol_handlers - - auto_ip, BSD, dhcp, dns, ftp, http, mdns, mqtt, nat, pop3, ppp, pppoe, smtp, sntp, telnet, tftp, web - samples ``` diff --git a/addons/BSD/nxd_bsd.c b/addons/BSD/nxd_bsd.c new file mode 100644 index 00000000..afaa8a8e --- /dev/null +++ b/addons/BSD/nxd_bsd.c @@ -0,0 +1,14542 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** BSD 4.3 Socket API Compatible Interface to NetX Duo */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/* Include necessary files. */ +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_tcp.h" +#include "nx_ip.h" + +#include "nx_ipv6.h" +#include "nx_ipv4.h" +#include "nxd_bsd.h" + +#ifdef NX_BSD_ENABLE_DNS +#include "nxd_dns.h" +#endif + + +#include "nx_udp.h" +#include "nx_igmp.h" +#include "nx_system.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_icmpv6.h" +#endif +#include "tx_timer.h" + +/* Define a NetX packet pool pointer for BSD use. */ + +NX_PACKET_POOL *nx_bsd_default_packet_pool; + + +/* Define the default IP instance for BSD use. */ + +NX_IP *nx_bsd_default_ip; + + +/* Define the single mutex protection for the BSD layer calls. */ + +TX_MUTEX *nx_bsd_protection_ptr; + + +/* Define IP fast periodic timer entry. */ +VOID (*nx_bsd_ip_fast_periodic_timer_entry)(ULONG id); + +/* Define BSD system clock time. The precision depends on _nx_ip_fast_timer_rate. */ +ULONG nx_bsd_system_clock; + +/* Define BSD system clock timer rate. */ +ULONG nx_bsd_timer_rate; + +/* Define the event flag group for notifying threads suspended on BSD sockets to wakeup. */ + +TX_EVENT_FLAGS_GROUP nx_bsd_events; + + +/* Define the array of BSD managed sockets. */ + +NX_BSD_SOCKET nx_bsd_socket_array[NX_BSD_MAX_SOCKETS]; + +/* Define the raw socket protocol hash table. */ + +NX_BSD_SOCKET *nx_bsd_socket_raw_protocol_table[NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE]; + +/* Create some buffer space for number string conversions. */ +#define NX_BSD_URL_BUFSIZE 18 +CHAR nx_bsd_url_buffer[NX_BSD_URL_BUFSIZE]; + +/* Define the search index for the BSD array. */ + +UINT nx_bsd_socket_array_index; + + +/* Define the block pool that will be used to dynamically allocate either NetX UDP or TCP sockets. */ + +TX_BLOCK_POOL nx_bsd_socket_block_pool; + +/* Define the memory area for the socket block pool... use TCP socket size, since it is the larger. */ + +static UCHAR nx_bsd_socket_pool_memory[NX_BSD_MAX_SOCKETS*(sizeof(NX_TCP_SOCKET)+sizeof(VOID *))]; + +/* Define the block pool that will be used to dynamically allocate addrinfo struct. */ + +TX_BLOCK_POOL nx_bsd_addrinfo_block_pool; + +/* Define the memory area for addrinfo pool. sizeof(addrinfo) is the MAX of: + * {sizeof(addrinfo)== 32, sizeof(sockaddr_in) == 16, or sizeof(sockaddr_in6)} = 28. + * Every address may be mapped to 3 socktypes, SOCK_STREAM, SOCK_DGRAM and SOCK_RAW, + * 3 blocks for addrinfo) + 1 block for IP adddress = 4 blocks */ + +static UCHAR nx_bsd_addrinfo_pool_memory[(NX_BSD_IPV4_ADDR_MAX_NUM + NX_BSD_IPV6_ADDR_MAX_NUM)* 4 + *(sizeof(struct addrinfo) + sizeof(VOID *))]; + +#ifdef NX_BSD_ENABLE_DNS + +/* The global DNS client instance. */ +extern NX_DNS *_nx_dns_instance_ptr; + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/* Define the block pool that will be used to dynamically allocate canonical name buffer. */ +TX_BLOCK_POOL nx_bsd_cname_block_pool; + +/* Here we just support a CNAME per IP address. */ +static UCHAR nx_bsd_cname_pool_memory[(NX_BSD_IPV4_ADDR_MAX_NUM + NX_BSD_IPV6_ADDR_MAX_NUM) * + (NX_DNS_NAME_MAX + 1)]; +#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ +#endif /* NX_BSD_ENABLE_DNS */ + +/* Buffer used to store IP address get from DNS. */ +static ULONG nx_bsd_ipv4_addr_buffer[NX_BSD_IPV4_ADDR_PER_HOST]; +static ULONG nx_bsd_ipv6_addr_buffer[NX_BSD_IPV6_ADDR_PER_HOST * 4]; + +/* Utility character type functions*/ +static UINT nx_bsd_isspace(UCHAR c); +static UINT nx_bsd_islower(UCHAR c); +static UINT nx_bsd_isdigit(UCHAR c); +static UINT nx_bsd_isxdigit(UCHAR c); + +/* Standard BSD callback functions to register with NetX Duo. */ + +static VOID nx_bsd_tcp_receive_notify(NX_TCP_SOCKET *socket_ptr); +static VOID nx_bsd_tcp_socket_disconnect_notify(NX_TCP_SOCKET *socket_ptr); +static VOID nx_bsd_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +static UINT nx_bsd_raw_packet_filter(NX_IP *ip_ptr, ULONG protocol, NX_PACKET *packet_ptr); +#ifdef FEATURE_NX_IPV6 +static VOID _nxd_bsd_swap_ipv6_extension_headers(NX_PACKET *packet_ptr, UCHAR header_type); +#endif /* FEATURE_NX_IPV6 */ +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +static VOID nx_bsd_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +static VOID nx_bsd_select_wakeup(UINT sock_id, UINT fdsets); +static VOID nx_bsd_set_error_code(NX_BSD_SOCKET *bsd_socket_ptr, UINT status_code); +static VOID nx_bsd_udp_packet_received(INT sockID, NX_PACKET *packet_ptr); +static UINT nx_bsd_tcp_syn_received_notify(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr); +static INT nx_bsd_tcp_create_listen_socket(INT master_sockid, INT backlog); +static VOID nx_bsd_tcp_pending_connection(UINT local_port, NX_TCP_SOCKET *socket_ptr); +static INT nx_bsd_find_interface_by_source_addr(UINT addr_family, ULONG* ip_addr); +#ifndef NX_DISABLE_IPV4 +static VOID _nxd_bsd_ipv4_packet_send(NX_PACKET *packet_ptr); +#endif /* NX_DISABLE_IPV4 */ +static INT nx_bsd_send_internal(INT sockID, const CHAR *msg, INT msgLength, INT flags, + NXD_ADDRESS *dst_address, USHORT dst_port, UINT local_interface_index); + +#ifdef FEATURE_NX_IPV6 +static VOID _nxd_bsd_ipv6_packet_send(NX_PACKET *packet_ptr, ULONG *src_addr, ULONG *dest_addr); +#endif /* FEATURE_NX_IPV6 */ + +static INT inet_ntoa_internal(const VOID *src, CHAR *dst, ULONG dst_size); +static INT bsd_string_to_number(const CHAR *string, UINT *number); +static ULONG _nx_bsd_string_length(CHAR * string); + +#ifdef NX_BSD_RAW_PPPOE_SUPPORT +static INT nx_bsd_pppoe_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, + INT flags, struct sockaddr* destAddr, INT destAddrLen); +static UINT nx_bsd_socket_create_id = 0; +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + +#ifdef NX_BSD_RAW_SUPPORT +static INT _nx_bsd_hardware_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, + INT flags, struct sockaddr* destAddr, INT destAddrLen); +static VOID _nx_bsd_hardware_packet_received(NX_PACKET *packet_ptr, UCHAR *consumed); +#endif /* NX_BSD_RAW_SUPPORT */ +static VOID _nx_bsd_fast_periodic_timer_entry(ULONG id); + +#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER +TX_THREAD nx_bsd_task_thread; +static VOID nx_bsd_thread_entry(ULONG info); +#else +static TX_TIMER nx_bsd_timer; +static VOID nx_bsd_timer_entry(ULONG info); +#endif +UINT bsd_number_convert(UINT number, CHAR *string, ULONG buffer_len, UINT base); +VOID nx_bsd_socket_timed_wait_callback(NX_TCP_SOCKET *tcp_socket_ptr); + +#define FDSET_READ 1 +#define FDSET_WRITE 2 +#define FDSET_EXCEPTION 4 + +extern TX_THREAD *_tx_thread_current_ptr; + +static ULONG _nx_bsd_serv_list_len; +static struct NX_BSD_SERVICE_LIST *_nx_bsd_serv_list_ptr; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* bsd_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up all data structures and NetX, and ThreadX */ +/* resources needed by the BSD compatibility layer. It is recommended */ +/* to call this routine from tx_application_define. */ +/* */ +/* INPUTS */ +/* */ +/* *default_ip NX_IP created for BSD API */ +/* *default_pool Packet Pool used by BSD API */ +/* *bsd_thread_stack_area Stack memory pointer for the */ +/* BSD thread stack space */ +/* bsd_thread_stack_size Size of thread stack */ +/* bsd_thread_priority BSD thread priority */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_BSD_BLOCK_POOL_ERROR Error creating socket block */ +/* pool */ +/* NX_BSD_EVENT_ERROR Error creating the event flag */ +/* group */ +/* NX_BSD_MUTEX_ERROR Error creating mutex */ +/* NX_BSD_ENVIRONMENT_ERROR Error environment */ +/* */ +/* CALLS */ +/* */ +/* memset Set memory */ +/* tx_block_pool_create Create a block pool */ +/* tx_block_pool_delete Delete a block pool */ +/* tx_event_flags_create Create event flag group */ +/* tx_mutex_create Create protection mutex */ +/* tx_mutex_delete Delete protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Start-up code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT bsd_initialize(NX_IP *default_ip, NX_PACKET_POOL *default_pool, CHAR *bsd_thread_stack_area, + ULONG bsd_thread_stack_size, UINT bsd_thread_priority) +{ + +INT i; +UINT status; +ULONG info; + +#ifndef NX_ENABLE_EXTENDED_NOTIFY_SUPPORT + + /* Error, return the error message. */ + /* BSD doesn't work with out NX_ENABLE_EXTENDED_NOTIFY_SUPPORT option. */ + NX_BSD_ERROR(NX_BSD_ENVIRONMENT_ERROR, __LINE__); + return(NX_BSD_ENVIRONMENT_ERROR); +#endif /* NX_ENABLE_EXTENDED_NOTIFY_SUPPORT */ + + /* Create a block pool for dynamically allocating sockets. */ + status = tx_block_pool_create(&nx_bsd_socket_block_pool, "NetX BSD Socket Block Pool", sizeof(NX_TCP_SOCKET), + nx_bsd_socket_pool_memory, sizeof(nx_bsd_socket_pool_memory)); + + /* Determine if the pool was created. */ + if (status) + { + + /* Error, return the error message. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + return(NX_BSD_BLOCK_POOL_ERROR); + } + + /* Create a block pool for dynamically allocating addrinfo. */ + status = tx_block_pool_create(&nx_bsd_addrinfo_block_pool, "NetX BSD Addrinfo Block Pool", sizeof(struct addrinfo), + nx_bsd_addrinfo_pool_memory, sizeof(nx_bsd_addrinfo_pool_memory)); + + /* Determine if the pool was created. */ + if(status) + { + + /* Error, return the error messafe. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Delete the block pool. */ + tx_block_pool_delete(&nx_bsd_socket_block_pool); + return(NX_BSD_BLOCK_POOL_ERROR); + + } + +#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) + /* Create a block pool for dynamically allocating canonical name buffer. */ + status = tx_block_pool_create(&nx_bsd_cname_block_pool, "NetX BSD CNAME Block Pool", (NX_DNS_NAME_MAX + 1), + nx_bsd_cname_pool_memory, sizeof(nx_bsd_cname_pool_memory)); + + /* Determine if the pool was created. */ + if(status) + { + + /* Error, return the error messafe. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Delete the block pool. */ + tx_block_pool_delete(&nx_bsd_socket_block_pool); + tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); + return(NX_BSD_BLOCK_POOL_ERROR); + + } +#endif + + nx_bsd_protection_ptr = &default_ip -> nx_ip_protection; + + /* Create the BSD event flag group. */ + status = tx_event_flags_create(&nx_bsd_events, "NetX BSD Events"); + + /* Check the return status. */ + if (status) + { + /* Delete the block pool. */ + tx_block_pool_delete(&nx_bsd_socket_block_pool); + tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); +#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) + tx_block_pool_delete(&nx_bsd_cname_block_pool); +#endif + + /* Error present, return error code. */ + NX_BSD_ERROR(NX_BSD_EVENT_ERROR, __LINE__); + return(NX_BSD_EVENT_ERROR); + } + + /* Set the array index to 0. */ + nx_bsd_socket_array_index = 0; + + /* Loop through the BSD socket array and clear it out! */ + for (i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* Clear the BSD socket structure. */ + memset((VOID*) &nx_bsd_socket_array[i], 0, sizeof(NX_BSD_SOCKET)); + } + + /* Save the IP instance and NX_PACKET_POOL for BSD Socket API. */ + nx_bsd_default_ip = default_ip; + nx_bsd_default_packet_pool = default_pool; + + + if ((bsd_thread_stack_area == TX_NULL) || (bsd_thread_stack_size == 0)) + { + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + +#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER + /* Create a thread for BSD socket features requiring periodic tasks. */ + info = 0 ; + status = tx_thread_create(&nx_bsd_task_thread, "BSD thread task", nx_bsd_thread_entry, info, + bsd_thread_stack_area, bsd_thread_stack_size, bsd_thread_priority, + bsd_thread_priority, 1, TX_AUTO_START); + + if (status != TX_SUCCESS) + { + /* Delete the event flag group. */ + tx_event_flags_delete(&nx_bsd_events); + + /* Delete the block pool. */ + tx_block_pool_delete(&nx_bsd_socket_block_pool); + tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); +#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) + tx_block_pool_delete(&nx_bsd_cname_block_pool); +#endif + + /* Error, return the error message. */ + NX_BSD_ERROR(NX_BSD_THREAD_ERROR, __LINE__); + + /* Return an error. */ + return(NX_IP_INTERNAL_ERROR); + } +#else + + info = 0 ; + + /* Create a one shot timer. Do not activate it. We will use it if + a socket being disconnected is NOT enabled for REUSEADDR socket option. */ + status = tx_timer_create(&nx_bsd_timer, "BSD Timer", + nx_bsd_timer_entry, info, + NX_BSD_TIMER_RATE, NX_BSD_TIMER_RATE, TX_AUTO_START); + + if (status != TX_SUCCESS) + { + + /* Delete the event flag group. */ + tx_event_flags_delete(&nx_bsd_events); + + /* Delete the block pool. */ + tx_block_pool_delete(&nx_bsd_socket_block_pool); + tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); +#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) + tx_block_pool_delete(&nx_bsd_cname_block_pool); +#endif + +#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER + /* Delete the thread. */ + tx_thread_delete(&nx_bsd_task_thread); +#endif + /* Error, return the error message. */ + NX_BSD_ERROR(NX_BSD_THREAD_ERROR, __LINE__); + + /* Return an error. */ + return(NX_IP_INTERNAL_ERROR); + } +#endif + +#ifdef NX_BSD_RAW_SUPPORT + _nx_driver_hardware_packet_received_callback = _nx_bsd_hardware_packet_received; +#endif /* NX_BSD_RAW_SUPPORT */ + + /* Calculate BSD system timer rate. */ + nx_bsd_timer_rate = (NX_IP_PERIODIC_RATE + (NX_IP_FAST_TIMER_RATE - 1)) / NX_IP_FAST_TIMER_RATE; + + /* Return success! */ + return(NX_SOC_OK); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_timeout_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for sockets waiting to make a TCP connection. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain exclusive access to */ +/* tx_mutex_put Release exclusive access */ +/* nx_tcp_server_socket_unaccept Remove socket from listen list */ +/* nx_tcp_server_socket_relisten Restore socket to listening */ +/* nx_tcp_server_socket_accept Accept to connection request */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_timeout_process() +{ + +INT i; +ULONG status; +INT master_socket_index; +NX_BSD_SOCKET *bsd_socket_ptr; + + + /* Obtain the BSD lock. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + if(status) + { + /* Mutex operation failed. This should be fatal. */ + return; + } + + for( i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* Skip the unused sockets. */ + if(!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + continue; + } + + /* Skip if it is not TCP server socket. */ + if((nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket == NX_NULL) || + ((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT))) + { + continue; + } + + /* Check for sockets trying to make a TCP connection. + Detect that the socket state is CLOSED, which is an indication + that the attempted connection failed, and we shall signal any pending + select on the socket. */ + if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) + { + + /* Is the NetX socket closed? */ + if(nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket -> nx_tcp_socket_state == NX_TCP_CLOSED) + { + + /* Yes. Set up a local pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[i]; + + /* Is this a secondary socket (passive open)? */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) + { + + /* Yes; Is the socket is connected yet? */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED)) + { + + /* No; Turn off the disconnection_request flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_DISCONNECTION_REQUEST); + + /* Remove the underlying NetX socket from the listen state. */ + nx_tcp_server_socket_unaccept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + + /* Check if a listen request is queued up for this socket. */ + nx_bsd_tcp_pending_connection(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + + /* Relisten on this socket. */ + status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + /* Set the socket to accept the connection. */ + nx_tcp_server_socket_accept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket, NX_NO_WAIT); + + /* Check the result of the relisten call. */ + if(status == NX_CONNECTION_PENDING) + { + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; + } + else if(status != NX_SUCCESS) + { + + + /* Failed the relisten on the secondary socket. Set the error code on the + master socket, and wake it up. */ + + master_socket_index = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id; + + nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + nx_bsd_set_error_code(&nx_bsd_socket_array[master_socket_index], status); + + nx_bsd_select_wakeup((UINT)master_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); + } + } + } + else + { + /* The underlying socket is closed. This indicates an error, and since is a non-blocking + socket, we need to wake up the corresponding thread. */ + + /* Mark this socket as error, and remove the CONNECT and INPROGRESS flags */ + nx_bsd_socket_array[i].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + nx_bsd_socket_array[i].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); + nx_bsd_socket_array[i].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); + nx_bsd_socket_array[i].nx_bsd_socket_error_code = ECONNREFUSED; + + /* Wake up the socket that could be listening on it. */ + /* Notice that on error the both read and write are selectable. */ + nx_bsd_select_wakeup((UINT)i, FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION); + } + } + } + } + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for events indicating BSD TCP socket tasks are */ +/* waiting to be performed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Check for registered events */ +/* nx_bsd_timeout_process Process BSD tasks */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER +VOID nx_bsd_thread_entry(ULONG info) +{ + NX_PARAMETER_NOT_USED(info); + + while(1) + { + + /* Wait for timeout. */ + tx_thread_sleep(NX_BSD_TIMER_RATE); + + /* Timeout process. */ + nx_bsd_timeout_process(); + } +} +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* socket PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Creates a TCP or UDP socket, which may then be used as an end point */ +/* of communication for sending and receiving data using the specified */ +/* protocol. */ +/* */ +/* INPUT */ +/* */ +/* protocolFamily Protocol family e.g AF_INET */ +/* type Type of the socket TCP or UDP */ +/* protocol Socket protocol */ +/* */ +/* OUTPUT */ +/* */ +/* socket descriptor On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* memset Clears memory */ +/* nx_tcp_socket_create Create TCP BSD Socket */ +/* nx_udp_socket_create Create UDP BSD Socket */ +/* nx_tcp_socket_receive_notify TCP receive notify function */ +/* nx_udp_socket_receive_notify UDP receive notify function */ +/* tx_block_allocate Allocate socket memory */ +/* tx_block_release Release socket memory */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT socket(INT protocolFamily, INT type, INT protocol) +{ + +INT i; +UINT status; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +VOID *socket_memory = NX_NULL; +NX_BSD_SOCKET *bsd_socket_ptr; + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +UINT index; +#else + + NX_PARAMETER_NOT_USED(protocol); +#endif + + /* Check for a supported protocol family. */ +#ifndef NX_DISABLE_IPV4 + if (protocolFamily == AF_INET) + { + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (protocolFamily == AF_INET6) + { + } + else +#endif /* FEATURE_NX_IPV6 */ +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) + if (protocolFamily == AF_PACKET) + { + } + else +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + { + + /* Set the socket error. */ + set_errno(EAFNOSUPPORT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check for a supported socket type. */ +#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) + if ((type != SOCK_STREAM) && (type != SOCK_DGRAM) && (type != SOCK_RAW)) +#else + if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) +#endif + { + + /* Set the socket error. */ + set_errno(EPROTOTYPE); + + /* Invalid type. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) + /* An extra check when BSD RAW Packet type is enabled: + Only RAW_SOCKET type is supported in AF_PACKET family. */ + if((protocolFamily == AF_PACKET) && (type != SOCK_RAW)) + { + /* Set the socket error. */ + set_errno(EPROTOTYPE); + + /* Invalid type. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + + + /* Obtain the BSD protection socket. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error. */ + set_errno(EACCES); + + /* Error getting the protection mutex. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check whether IP fast timer is created or not. */ + if ((nx_bsd_ip_fast_periodic_timer_entry == NX_NULL) || + (nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function != _nx_bsd_fast_periodic_timer_entry)) + { + + /* BSD socket requires a fast periodic timer to calculate wait option in recv() function. */ + /* Create IP fast periodic timer. */ + _nx_ip_fast_periodic_timer_create(nx_bsd_default_ip); + + /* Replace timer expiration function entry. */ + nx_bsd_ip_fast_periodic_timer_entry = nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function; + nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function = _nx_bsd_fast_periodic_timer_entry; + } + + /* Now find a free slot in the BSD socket array. */ + for (i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* See if this entry is available. Check the in use flag. */ + if (!(nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Yes, Ok to use this socket. */ + + /* Clear the entire structure. */ + memset((VOID*) &nx_bsd_socket_array[nx_bsd_socket_array_index], 0, sizeof(NX_BSD_SOCKET)); + nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_id = (INT)nx_bsd_socket_array_index; + + /* Mark this socket as in-use. */ + nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_IN_USE; + + /* Get out of the loop. */ + break; + } + else + { + + /* Try the next socket. */ + nx_bsd_socket_array_index++; + + /* Check if we need to wrap around to the start of the socket table. */ + if (nx_bsd_socket_array_index >= NX_BSD_MAX_SOCKETS) + { + + /* Reset the index to 0. */ + nx_bsd_socket_array_index = 0; + } + } + } + + /* Check if a free socket was found. */ + if (i >= NX_BSD_MAX_SOCKETS) + { + + /* No, set the error status and return. */ + + /* Set the socket error. */ + set_errno(ENFILE); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Mark the location of the free socket. */ + i = (INT)nx_bsd_socket_array_index; + + /* Update the socket index to the next entry. */ + nx_bsd_socket_array_index++; + + /* Check if we need to wrap around to the start of the table. */ + if (nx_bsd_socket_array_index >= NX_BSD_MAX_SOCKETS) + { + + /* Reset the index to 0. */ + nx_bsd_socket_array_index = 0; + } + + /* Set up a pointer to the BSD socket to use. */ + bsd_socket_ptr = &nx_bsd_socket_array[i]; + + /* For TCP or UDP sockets we need to allocate memory to create the NetX Duo socket + (not necessary for raw socket). */ + + if ((type == SOCK_STREAM) || (type == SOCK_DGRAM)) + { + + /* Allocate a socket from the block pool. */ + status = tx_block_allocate(&nx_bsd_socket_block_pool, &socket_memory, NX_BSD_TIMEOUT); + + /* Check for error status. */ + if (status != TX_SUCCESS) + { + + /* Set the socket error. */ + set_errno(ENOMEM); + + /* Clear the allocated internal BSD socket. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_IN_USE); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Clear the socket memory. */ + memset((VOID*) socket_memory, 0, sizeof(NX_TCP_SOCKET)); + + } + + /* Is this a stream socket e.g. TCP? */ + if (type == SOCK_STREAM) + { + bsd_socket_ptr -> nx_bsd_socket_protocol = NX_PROTOCOL_TCP; + + /* Mark the master/secondary socket id as invalid. */ + (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; + (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = NX_BSD_MAX_SOCKETS; + + /* Yes, allocate memory for a TCP socket. */ + tcp_socket_ptr = (NX_TCP_SOCKET *) socket_memory; + + /* Create a NetX TCP socket. */ + /* Note that the nx_bsd_tcp_socket_disconnect_notify is invoked when an + established connection is disconnected. + The disconnect_complete_notify is called for all types of disconnect, + including the ones covered by tcp_socket_disconnect_notify. */ + + status = nx_tcp_socket_create(nx_bsd_default_ip, tcp_socket_ptr, "NetX BSD TCP Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, NX_BSD_TCP_WINDOW, NX_NULL, + nx_bsd_tcp_socket_disconnect_notify); + + /* Check for a successful status. */ + if (status == NX_SUCCESS) + { + + /* Register a receive notify callback. */ + status = nx_tcp_socket_receive_notify(tcp_socket_ptr, nx_bsd_tcp_receive_notify); + + /* Check for invalid input. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Release the allocated socket memory block. */ + tx_block_release(socket_memory); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* Set the SYN received notify function */ + tcp_socket_ptr -> nx_tcp_socket_syn_received_notify = nx_bsd_tcp_syn_received_notify; +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Set the keep alive feature to disabled. */ + tcp_socket_ptr -> nx_tcp_socket_keepalive_enabled = NX_FALSE; +#endif /* NX_ENABLE_TCP_KEEPALIVE */ + + /* Set the socket reuse feature to enabled. This is the default NetX socket behavior. */ + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + /* Register an establish notify callback for the specified server socket with NetX. */ + nx_tcp_socket_establish_notify(tcp_socket_ptr, nx_bsd_tcp_establish_notify); + + /* Register a disconnect complete notify callback for the specified server socket with NetX. */ + /* The callback function is the same as the one used for TCP disconnect callback. */ + status += nx_tcp_socket_disconnect_complete_notify(tcp_socket_ptr, nx_bsd_tcp_socket_disconnect_notify); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + + /* Return successful completion. */ + + /* Save the TCP pointer in the appropriate place. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket = tcp_socket_ptr; + + /* Set up pointer in the NetX socket back to the BSD socket. */ + tcp_socket_ptr -> nx_tcp_socket_reserved_ptr = (VOID *) i; + + + } + } + else if (type == SOCK_DGRAM) + { + + bsd_socket_ptr -> nx_bsd_socket_protocol = NX_PROTOCOL_UDP; + + /* Make a double circular list. */ + bsd_socket_ptr -> nx_bsd_socket_next = bsd_socket_ptr; + bsd_socket_ptr -> nx_bsd_socket_previous = bsd_socket_ptr; + + /* Allocate memory for a UDP socket. */ + udp_socket_ptr = (NX_UDP_SOCKET *) socket_memory; + + /* Create a NetX UDP socket */ + status = nx_udp_socket_create(nx_bsd_default_ip, udp_socket_ptr, "NetX BSD UDP Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, + (nx_bsd_default_packet_pool -> nx_packet_pool_total)/8+1); + + /* Check for successful result. */ + if (status == NX_SUCCESS) + { + + /* Register a receive notify callback. */ + status = nx_udp_socket_receive_notify(udp_socket_ptr, nx_bsd_udp_receive_notify); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Release the allocated socket memory block. */ + tx_block_release(socket_memory); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Save the UDP pointer in the BSD socket. */ + bsd_socket_ptr -> nx_bsd_socket_udp_socket = udp_socket_ptr; + + /* Set the reserved UDP socket pointer back to the BSD socket. */ + udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID *) (i + 0x00010000); + } + } +#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) + else if (type == SOCK_RAW) + { + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + /* Check if raw sockets are enabled in NetX Duo. */ + if (((protocolFamily == AF_INET) || + (protocolFamily == AF_INET6)) && + (nx_bsd_default_ip -> nx_ip_raw_ip_processing == NX_NULL)) + { + /* No, Enable raw socket handling in NetX Duo. */ + status = nx_ip_raw_packet_enable(nx_bsd_default_ip); + + if (status != NX_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + set_errno(EPROTONOSUPPORT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + + /* Check if we set the packet filter already. */ + if (((protocolFamily == AF_INET) || + (protocolFamily == AF_INET6)) && + (nx_bsd_default_ip -> nx_ip_raw_packet_filter == NX_NULL)) + { + + /* We have not. Do so now. Set the raw packet filter to the IP instance. */ + status = nx_ip_raw_packet_filter_set(nx_bsd_default_ip, nx_bsd_raw_packet_filter); + + /* Has a raw packet filter been successfully set? */ + if (status != NX_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + set_errno(EPROTONOSUPPORT); + + /* No, return error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + + /* For IPv6 raw socket, by default the header is not included in the received packet. */ + if(protocolFamily == AF_INET6) + { + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_RX_NO_HDR; + } + + /* Set the raw socket protocol to the BSD raw socket. */ + bsd_socket_ptr -> nx_bsd_socket_protocol = (USHORT)protocol; + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_RAW_SOCKET; + + /* Calculate the hash index in the raw socket protocol table. */ + index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); + + /* Determine if the list is NULL. */ + if(nx_bsd_socket_raw_protocol_table[index]) + { + /* There are already sockets on the list... just add this one to the end. */ + bsd_socket_ptr -> nx_bsd_socket_next = nx_bsd_socket_raw_protocol_table[index]; + bsd_socket_ptr -> nx_bsd_socket_previous = (nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous; + ((nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr; + (nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous = bsd_socket_ptr; + } + else + { + /* Nothing is on the list. Add this one to an empty list. */ + bsd_socket_ptr -> nx_bsd_socket_next = bsd_socket_ptr; + bsd_socket_ptr -> nx_bsd_socket_previous = bsd_socket_ptr; + nx_bsd_socket_raw_protocol_table[index] = bsd_socket_ptr; + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + if(protocolFamily == AF_PACKET) + { +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + bsd_socket_ptr -> nx_bsd_socket_create_id = nx_bsd_socket_create_id; + nx_bsd_socket_create_id++; +#elif defined(NX_BSD_RAW_SUPPORT) + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + } + + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER || NX_BSD_RAW_PPPOE_SUPPORT || NX_BSD_RAW_SUPPORT */ + + else + { + /* Not a supported socket type. */ + set_errno(EOPNOTSUPP); + + /* Invalid type. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set the protocol family: AF_INET or AF_INET6. */ + bsd_socket_ptr -> nx_bsd_socket_family = (ULONG)protocolFamily; + + /* For UDP and RAW sockets, set the maximum receive queue depth. */ + if(bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + + bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max = NX_BSD_SOCKET_QUEUE_MAX; + } + + /* Check for error creating the NetX Duo socket. */ + if (status != NX_SUCCESS) + { + + /* Release the BSD protection. */ + + /* Clear the BSD socket in use flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_IN_USE); + + if ((type == SOCK_DGRAM) || (type == SOCK_STREAM)) + { + /* Release the socket memory block allocated for TCP or UDP socket. */ + tx_block_release(socket_memory); + } + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Error present, return error code. */ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return success! */ + return(i + NX_BSD_SOCKFD_START); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Establishes a connection between a client socket and a remote server*/ +/* socket associated with the remote address, if any. Upon returning */ +/* successfully, the given socket's local and remote IP address and */ +/* port information are filled in. If the socket was not previously */ +/* bound to a local port, one is assigned randomly. */ +/* */ +/* For TCP sockets, connect() completes with a connection handshake is */ +/* complete, or if an error occurs. A TCP negotiation is performed */ +/* to open a connection and success implies the existence of a reliable*/ +/* channel to that socket. */ +/* */ +/* For UDP sockets, the connection is established simply by setting the*/ +/* supplied destination (remote) IP address and port for the remote */ +/* host. */ +/* */ +/* For non blocking sockets, the function returns immediately if a */ +/* connection is not possible. The socket thread error is set to */ +/* EINPROGRESS to distinguish from blocking sockets. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket descriptor */ +/* *remoteAddress Remote address structure */ +/* addressLength Address structure length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) If success */ +/* NX_SOC_ERROR (-1) If failure or if called with */ +/* an UDP socket */ +/* */ +/* CALLS */ +/* */ +/* nx_ip_status_check Check to make sure link is up */ +/* nx_tcp_client_socket_bind Bind a TCP socket to a port */ +/* nxd_tcp_client_socket_connect Connect to a TCP server */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT connect(INT sockID, struct sockaddr *remoteAddress, INT addressLength) +{ +UINT status; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +NX_BSD_SOCKET *bsd_socket_ptr; +ULONG timeout; +ULONG actual_status; + + /* Check for a valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Adjust the sockID to index into the BSD socket table. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Ensure the IP instance has been initialized. */ + status = nx_ip_status_check(nx_bsd_default_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error. */ + set_errno(EFAULT); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Make sure the socket is valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Socket is no longer in use. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Obtain the BSD protection. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check whether supplied address structure and length is valid */ + if (remoteAddress == NX_NULL ) + { + + /* For UDP socket or RAW socket, a NULL remoteAddress dis-associate + a remote address bound to the socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + memset(&bsd_socket_ptr -> nx_bsd_socket_peer_ip, 0, sizeof(NXD_ADDRESS)); + bsd_socket_ptr -> nx_bsd_socket_peer_port = 0; + + /* Clear the connect flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); + + /* All done. Return. */ + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + + } + else + { + /* For TCP socket, each socket can only be connected once, and + the remote address must be set correctly. */ + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + /* Set the socket error if extended socket options enabled. */ + set_errno(EAFNOSUPPORT); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + + + /* Check if the remote address family matches the local BSD socket address family. */ + if((remoteAddress -> sa_family != bsd_socket_ptr -> nx_bsd_socket_family) || + ((remoteAddress -> sa_family == AF_INET) && (addressLength != sizeof(struct sockaddr_in))) || + ((remoteAddress -> sa_family == AF_INET6) && (addressLength != sizeof(struct sockaddr_in6)))) + { + + /* Mismatch! */ + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EAFNOSUPPORT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(ERROR); + } + +#ifndef NX_DISABLE_IPV4 + /* Check the socket family type. */ + if(remoteAddress -> sa_family == AF_INET) + { + + /* This is an IPv4 socket type. */ + + /* Set the UDP remote host IP address and port for the UDP 'connection'; for NetX Duo + set the IP version. */ + /* NetX API expects multi byte values to be in host byte order. + Therefore ntohl/s are used to make the conversion. */ + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_version = NX_IP_VERSION_V4; + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4 = htonl(((struct sockaddr_in *) remoteAddress ) -> sin_addr.s_addr); + bsd_socket_ptr -> nx_bsd_socket_peer_port = htons(((struct sockaddr_in *) remoteAddress ) -> sin_port); + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 + if(remoteAddress -> sa_family == AF_INET6) + { + + /* This is an IPv6 enabled socket family type). */ + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_version = NX_IP_VERSION_V6; + /* NetX API expects multi byte values to be in host byte order. + Therefore ntohl/s are used to make the conversion. */ + /* Get remote address and port. */ + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[0]); + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[1]); + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[2]); + bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[3]); + + bsd_socket_ptr -> nx_bsd_socket_peer_port = htons(((struct sockaddr_in6 *) remoteAddress ) -> sin6_port); + + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Address family not supported. */ + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EAFNOSUPPORT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(ERROR); + } + + + /* Handle the UDP 'connection' request. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; + + /* Check to see if the UDP socket is already bound. */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) + { + + /* Not yet, bind to a randomly selected available free port. */ + status = nx_udp_socket_bind(udp_socket_ptr, NX_ANY_PORT, NX_BSD_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error based on NetX error status return. */ + nx_bsd_set_error_code(bsd_socket_ptr, status); + + /* Return an error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + /* Bind is successful. Obtain the port number. */ + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)udp_socket_ptr -> nx_udp_socket_port; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + } + + /* Mark the socket as connected. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return successful status. */ + return(NX_SOC_OK); + } + else if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + + /* This is not UDP or TCP socket. So it must be raw socket. */ + /* We treat raw socket the same as UDP socket. For connec, raw socket + associates the remote address as its default destination address when + transmit, and also limit the reception of data from that remote address. */ + + /* Mark the socket as connected. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return successful status. */ + return(NX_SOC_OK); + } + + /* This is a TCP BSD socket. */ + + /* If the socket is already connected. */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) + { + + /* If INPROGRESS is set, clear the INPROGRESS flag and return OK. + The INPROGRESS flag needs to be cleared so the next connect call would return EISCONN */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) + { + + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + + /* Already connected. */ + set_errno(EISCONN); + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + + } + + /* If the socket is marked as EINPROGRESS, return EALREADY. */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) + { + + + set_errno(EALREADY); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + + } + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & ((ULONG)(~NX_BSD_SOCKET_ERROR)); + + set_errno(errcode); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Set a NetX tcp pointer. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + + /* Mark this as a client TCP socket. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CLIENT; + + /* Is the TCP socket already bound? */ + if (tcp_socket_ptr -> nx_tcp_socket_port == 0) + { + + /* Not yet; bind to a randomly selected available free port. */ + + /* Call NetX TCP bind service with NX_NO_WAIT. */ + status = nx_tcp_client_socket_bind(tcp_socket_ptr, NX_ANY_PORT, NX_NO_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Clear the client socket flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CLIENT); + + /* Set the socket error depending on NetX error status return. */ + nx_bsd_set_error_code(bsd_socket_ptr, status); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_ERROR); + } + + /* Mark the socket as bound. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)tcp_socket_ptr -> nx_tcp_socket_port; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; + + } + + /* Mark this BSD socket as busy. */ + bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); + + /* Attempt to make the connection. If the socket is non-blocking, + set the timeout to 0. Otherwise, use wait-forever */ + if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) + { + + /* Yes, the socket is enabled for non blocking. Do not wait. */ + timeout = 0; + } + else + { + /* This call may be blocked internally. Release the mutex + so the nx_tcp_client_socket_connect can suspend waiting + for a connection. */ + timeout = NX_WAIT_FOREVER; + tx_mutex_put(nx_bsd_protection_ptr); + } + + /* Make the connection. */ + status = nxd_tcp_client_socket_connect(tcp_socket_ptr, &(bsd_socket_ptr -> nx_bsd_socket_peer_ip), bsd_socket_ptr -> nx_bsd_socket_peer_port, timeout); + if(timeout != 0) + { + /* The mutex was released prior to the call. Accquire the mutex + again. */ + tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Verify that the socket is still valid. */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* The socket is no longer in use. */ + + /* Set the socket error code. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if (status == NX_NOT_CONNECTED) + { + + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) || + (tcp_socket_ptr -> nx_tcp_socket_timeout_retries >= tcp_socket_ptr -> nx_tcp_socket_timeout_max_retries)) + { + + /* Connect timeouts since NX_BSD_SOCKET_ERROR is not set or + * number of timeout retry has been exceeded. */ + status = NX_WAIT_ABORTED; + } + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + bsd_socket_ptr -> nx_bsd_socket_error_code = ENOTCONN; + } + } + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error depending on NetX error status return. */ + nx_bsd_set_error_code(bsd_socket_ptr, status); + + + /* Make sure this thread is still the owner. */ + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + + /* Clear the busy flag. */ + bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* At this point NX TCP connect service returns success, so the connection is established. */ + + /* Mark the socket as connected. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; + + /* Clear the CONNECTION_INPROGRESS flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); + + /* Mark the connection_request flag */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; + + /* Make sure thread making the bind call is the current thread. */ + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + + /* OK to clear the busy flag. */ + bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; + + /* Check if the connect call was successful. */ + if (status == NX_SUCCESS) + { + + /* It was. Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Successful connection. Return the success status. */ + return(NX_SOC_OK); + } + } + + /* Error condition: the thread that was executing connect is not the current thread. */ + + /* Clear the connected flags and peer infomration .*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_REQUEST); + memset(&bsd_socket_ptr -> nx_bsd_socket_source_ip_address, 0, sizeof(NXD_ADDRESS)); + bsd_socket_ptr -> nx_bsd_socket_source_port = 0; + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error. */ + set_errno(EINTR); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* bind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function binds a socket to a local port. The port in the struct*/ +/* in the struct sockaddr structure may be wildcarded, in which case */ +/* NetX will select a port number. */ +/* */ +/* To wildcard the port, set the sin_port field of the address to 0. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket descriptor */ +/* *localAddress Populated socket address */ +/* addressLength Socket address length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) If success */ +/* NX_SOC_ERROR (-1) If failure */ +/* */ +/* CALLS */ +/* */ +/* nx_ip_status_check Check for link up */ +/* nx_tcp_client_socket_bind Binds a TCP socket to a port */ +/* nx_udp_client_socket_bind Binds a UDP socket to a port */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Gets the current thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT bind(INT sockID, struct sockaddr *localAddress, INT addressLength) +{ + +INT local_port = 0; +UINT status; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +NX_BSD_SOCKET *bsd_socket_ptr; +INT i; +INT address_conflict; + + + /* Check for invalid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error. */ + set_errno(EBADF); + + /* Error, invalid socket ID. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check for a valid input local address and address length input buffer. */ + if ((localAddress == NX_NULL ) || (addressLength == 0)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EFAULT); + + /* Error, invalid local address. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if (((localAddress -> sa_family == AF_INET) && (addressLength != sizeof(struct sockaddr_in))) || + ((localAddress -> sa_family == AF_INET6) && (addressLength != sizeof(struct sockaddr_in6)))) + { + set_errno(EAFNOSUPPORT); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set up a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* See if the socket is still in use. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Socket is no longer in use. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(bsd_socket_ptr -> nx_bsd_socket_error_code); + + /* Clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Check the address family. */ + if (bsd_socket_ptr -> nx_bsd_socket_family != localAddress -> sa_family) + { + set_errno(EAFNOSUPPORT); + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check to see if the socket is already bound. */ + if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND) + { + + /* It is. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Zero out the local bind info */ + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = 0; + +#ifndef NX_DISABLE_IPV4 + if(localAddress -> sa_family == AF_INET) + { + + ULONG local_addr; + INT if_index; + + /* Pickup the local port. */ + local_port = ntohs(((struct sockaddr_in *) localAddress) -> sin_port); + + /* Pick up the local IP address */ + local_addr = ntohl(((struct sockaddr_in*)localAddress) -> sin_addr.s_addr); + + if(local_addr == INADDR_ANY) + { + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; + } + else + { + + for(if_index = 0; if_index < NX_MAX_IP_INTERFACES; if_index++) + { + + if((nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid) && + (nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_address == local_addr)) + { + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ip_interface[if_index]); + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = (UINT)if_index; + break; + } + } + } + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(localAddress -> sa_family == AF_INET6) + { + + ULONG ipv6_addr[4]; + INT if_index; + + /* Pickup the local port. */ + local_port = ntohs(((struct sockaddr_in6 *) localAddress) -> sin6_port); + + ipv6_addr[0] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[0]); + ipv6_addr[1] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[1]); + ipv6_addr[2] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[2]); + ipv6_addr[3] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[3]); + + if((ipv6_addr[0] | ipv6_addr[1] | ipv6_addr[2] | ipv6_addr[3]) == 0) + { + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; + } + else + { + + for(if_index = 0; if_index < NX_MAX_IPV6_ADDRESSES; if_index++) + { + + if((nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[0] == ipv6_addr[0]) && + (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[1] == ipv6_addr[1]) && + (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[2] == ipv6_addr[2]) && + (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[3] == ipv6_addr[3])) + { + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ipv6_address[if_index]); + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = (UINT)if_index; + break; + } + } + } + } +#endif +#ifdef NX_BSD_RAW_SUPPORT + if ((localAddress -> sa_family == AF_PACKET) && (addressLength == sizeof(struct sockaddr_ll))) + { + UINT if_index; + + if_index = (UINT)(((struct sockaddr_ll *)localAddress) -> sll_ifindex); + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ip_interface[if_index]); + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = if_index; + } +#endif /* NX_BSD_RAW_SUPPORT */ + + /* Check if the bind information is correctly set. */ + if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EADDRNOTAVAIL); + + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* At this point the local bind interface and port are known. + If port number is specified, we need to go through the existing sockets + and make sure there is no conflict. */ + address_conflict = 0; + + if(local_port) + { + + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* Skip its own entry. */ + if((i == sockID) || + /* Skip invalid entries. */ + (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) || + /* Skip the entries with different protocol ID */ + (nx_bsd_socket_array[i].nx_bsd_socket_protocol != bsd_socket_ptr -> nx_bsd_socket_protocol) || + /* Skip the unbound entries */ + (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND))) + { + + continue; + } + + /* Check for port number and interface ID */ + if(nx_bsd_socket_array[i].nx_bsd_socket_local_port == (USHORT)local_port) + { + + address_conflict = 1; + + if((nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface) && + (nx_bsd_socket_array[i].nx_bsd_socket_family == bsd_socket_ptr -> nx_bsd_socket_family)) + { + + /* This is completely duplicate binding. */ + + /* If it is a TCP non-listen socket (in other words a TCP server socket that is + already in connection, and the REUSEADDR is set, it is OK. */ + if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) && + (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT)) && + (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR)) + { + + address_conflict = 0; + } + } + else + { + + /* If the REUSEADDR option is set, the socket can be bound to its specififed local address. */ + if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR) + { + + address_conflict = 0; + + if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + UINT counter; + + /* For UDP socket, it needs to share the underlying NetX UDP socket. */ + nx_udp_socket_delete(bsd_socket_ptr -> nx_bsd_socket_udp_socket); + + /* Free the memory. */ + memset((VOID*)bsd_socket_ptr -> nx_bsd_socket_udp_socket, 0, sizeof(NX_UDP_SOCKET)); + + tx_block_release((VOID*)bsd_socket_ptr -> nx_bsd_socket_udp_socket); + + /* Add this bsd udp socket to the list that map to the same NetX udp socket. */ + + /* See if this is the only bsd udp socket on the list. */ + if ((&nx_bsd_socket_array[i]) == nx_bsd_socket_array[i].nx_bsd_socket_next) + { + + /* Yes, the only bsd udp socket on the list. */ + /* Update the list. */ + bsd_socket_ptr -> nx_bsd_socket_next = &nx_bsd_socket_array[i]; + bsd_socket_ptr -> nx_bsd_socket_previous = &nx_bsd_socket_array[i]; + nx_bsd_socket_array[i].nx_bsd_socket_next = bsd_socket_ptr; + nx_bsd_socket_array[i].nx_bsd_socket_previous = bsd_socket_ptr; + + } + else + { + + /* At least one more bsd udp socket on this list. */ + /* Update the list. */ + bsd_socket_ptr -> nx_bsd_socket_next = nx_bsd_socket_array[i].nx_bsd_socket_next; + bsd_socket_ptr -> nx_bsd_socket_previous = &nx_bsd_socket_array[i]; + (nx_bsd_socket_array[i].nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr; + nx_bsd_socket_array[i].nx_bsd_socket_next = bsd_socket_ptr; + } + + + bsd_socket_ptr -> nx_bsd_socket_udp_socket = nx_bsd_socket_array[i].nx_bsd_socket_udp_socket; + + /* Increase the counter. */ + counter = (UINT)bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_reserved_ptr; + counter = ((counter & 0xFFFF0000) + 0x00010000 + (counter & 0x0000FFFF)) & 0xFFFFFFFF; + + bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_reserved_ptr = (VOID*)counter; + + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + + /* Just point this BSD TCP socket to the same secondary socket. */ + (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id; + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; +#if defined(__PRODUCT_NETXDUO__) && !defined(NX_DISABLE_IPV4) + /* Handle client sockets differently. Share the port here for sockets with different IP/IPv6 addresses. */ + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type == NX_TRUE) + { + + /* Handle client sockets differently. Share the port here for sockets with different IP/IPv6 addresses. */ + if (((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) && (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_INET)) || + ((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) && (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_INET6))) + + { + + NX_IP *ip_ptr = nx_bsd_default_ip; + NX_TCP_SOCKET *socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + UINT index = (UINT) ((local_port + (local_port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* This non server socket needs to share a port with the other client socket. */ + socket_ptr -> nx_tcp_socket_port = (UINT)local_port; + + + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Add this socket to the list of bound sockets. */ + socket_ptr -> nx_tcp_socket_bound_next = ip_ptr -> nx_ip_tcp_port_table[index]; + socket_ptr -> nx_tcp_socket_bound_previous = (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous; + ((ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next = socket_ptr; + (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous = socket_ptr; + + + tx_mutex_put(&ip_ptr -> nx_ip_protection); + } + } +#endif + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + } + } + + if(address_conflict) + { + + break; /* Break out of the for loop */ + } + } + } + } + +#ifdef NX_BSD_RAW_SUPPORT + if (localAddress -> sa_family == AF_PACKET) + { + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* Skip its own entry. */ + if((i == sockID) || + /* Skip invalid entries. */ + (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) || + /* Skip the entries with different protocol ID */ + (nx_bsd_socket_array[i].nx_bsd_socket_protocol != bsd_socket_ptr -> nx_bsd_socket_protocol) || + /* Skip the entries with different address family. */ + (nx_bsd_socket_array[i].nx_bsd_socket_family != bsd_socket_ptr -> nx_bsd_socket_family) || + /* Skip the unbound entries */ + (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND))) + { + + continue; + } + + if (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface_index == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index) + { + + /* Bind to same interface. */ + address_conflict = 1; + break; + } + + if (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) + { + + /* A socket is bound to any interface. */ + address_conflict = 1; + break; + } + } + } +#endif /* NX_BSD_RAW_SUPPORT */ + + if(address_conflict) + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EADDRINUSE); + + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Mark this BSD socket as busy. */ + bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); + + /* Determine what type of bind is required. */ + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + + /* Setup TCP socket pointer. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + + /* Call NetX to bind the client socket. */ + status = nx_tcp_client_socket_bind(tcp_socket_ptr, (UINT)local_port, NX_NO_WAIT); + + /* Update the port. */ + if((status == NX_SUCCESS) && (local_port == 0)) + local_port = (INT)(tcp_socket_ptr -> nx_tcp_socket_port); + + } + else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) + { + + /* Set up a pointer to the UDP socket. */ + udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; + + /* Bind the UDP socket to the specified port in NetX. */ + status = nx_udp_socket_bind(udp_socket_ptr, (UINT)local_port, NX_BSD_TIMEOUT); + + /* Update the port. */ + if((status == NX_SUCCESS) && (local_port == 0)) + local_port = (INT)(udp_socket_ptr -> nx_udp_socket_port); + } + else + { + + /* Raw socket. All done. Just need to set status = NX_SUCCESS and continue. */ + status = NX_SUCCESS; + } + + + /* Check if we were able to bind the port. */ + if (status == NX_SUCCESS) + { + + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + + + /* Make sure this thread is still the owner. */ + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + + /* Clear the busy flag. */ + bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return successful status. */ + return(NX_SOC_OK); + + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if extended socket options enabled, depending on the status returned by NetX. */ + nx_bsd_set_error_code(bsd_socket_ptr, status); + + /* Return an error, unsuccessful socket bind call. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* listen PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the given socket ready to accept incoming client */ +/* connections. The socket must already be associated with a local port*/ +/* which means the bind() must have been called previously. */ +/* After this call, incoming TCP connections requests addressed to the */ +/* local port (and IP address, if specified previously) will be */ +/* completed & queued until they are passed to the program via accept()*/ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* backlog Maximum number of new */ +/* connections queued */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) If success */ +/* NX_SOC_ERROR (-1) If failure. */ +/* */ +/* CALLS */ +/* */ +/* socket Create a server socket */ +/* nx_tcp_server_socket_listen Enable a server socket listen */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT listen(INT sockID, INT backlog) +{ + +UINT status; +NX_BSD_SOCKET *bsd_socket_ptr; +NX_BSD_SOCKET *bsd_secondary_socket; +INT secondary_sockID; +INT ret; + + + /* Check whether supplied socket ID is valid. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set up a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Determine if the socket is a UDP socket or raw */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + + /* The underlying protocol is not TCP, therefore it does not support the listen operation. */ + set_errno(EOPNOTSUPP); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check if the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Have we already started listening? */ + if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) + { + + /* Error, socket is already listening. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check if this is a secondary server socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) + { + + /* Error, socket is a secondary server socket. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EOPNOTSUPP); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check if bound to a port. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error code. */ + set_errno(EDESTADDRREQ); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check if this master (listening) socket's secondary socket is not marked invalid. If not, it means this socket will + share the secondary socket with another master socket. */ + if((bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id != NX_BSD_MAX_SOCKETS) + { + + /* It is set. */ + + secondary_sockID = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; + + bsd_secondary_socket = &nx_bsd_socket_array[secondary_sockID]; + + /* Now check if the other master socket is in listen mode. */ + if(bsd_secondary_socket -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) + { + + /* It is ready.. we are ready to listen on this socket. */ + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + } + + if(backlog < NX_BSD_TCP_LISTEN_MIN_BACKLOG) + { + backlog = NX_BSD_TCP_LISTEN_MIN_BACKLOG; + } + + /* We need to set up this socket as a listen socket. */ + ret = nx_bsd_tcp_create_listen_socket(sockID, backlog); + + /* Release the mutex protection. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return success. */ + return(ret); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* accept PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function blocks while waiting for connections addressed to the */ +/* IP address and port to which this socket is bound. A listen() must */ +/* previously have been called on this given socket. */ +/* */ +/* When a connection arrives and the TCP handshake is successfully */ +/* completed, this function returns with a new socket with local and */ +/* remote address and port numbers filled in. */ +/* */ +/* For non blocking sockets, this function returns immediately. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* clientAddress Originating socket IP address */ +/* and port. */ +/* addressLength Length of sockaddr buffer (in)*/ +/* returned address (out) */ +/* */ +/* OUTPUT */ +/* */ +/* socket id Socket ID for new connection */ +/* NX_SOC_ERROR (-1) If failure */ +/* */ +/* CALLS */ +/* */ +/* memset Clears memory */ +/* socket Create a server socket */ +/* nx_tcp_server_socket_relisten Relisten with a new TCP soc */ +/* nx_tcp_server_socket_accept Accept a client connection */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Gets the current thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT accept(INT sockID, struct sockaddr *ClientAddress, INT *addressLength) +{ +/* Define the accept function if NetX BSD accept() is not set to asynchronous (on automatic callback). */ + +UINT status; +NX_BSD_SOCKET *bsd_socket_ptr; +NX_BSD_SOCKET *bsd_secondary_socket; +INT sec_sock_id; +INT ret = 0; +INT connected = 0; +ULONG requested_events; +INT secondary_socket_id = 0; +#ifndef NX_DISABLE_IPV4 +struct sockaddr_in peer4_address; +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 +struct sockaddr_in6 peer6_address; +#endif + + + /* Check for valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return an error.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Setup pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error.*/ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Determine if the socket is a UDP socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + + /* Error, UDP or raw sockets do not perform listen. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EOPNOTSUPP); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Has listening been enabled on this socket? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN)) + { + + /* No, this socket is not ready to accept TCP connections. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Make sure the accept call operates on the master socket. */ + if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) == 0) + { + /* This is not a master socket. + BSD accept is only allowed on the master socket. + Return. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Validate the secondary server socket. */ + if ((bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id >= NX_BSD_MAX_SOCKETS) + { + + /* This secondary socket is not available yet. This could happen if the + previous accept call fails to allocate a new secondary socket. */ + ret = nx_bsd_tcp_create_listen_socket(sockID, 0); + + if(ret < 0) + { + + /* Failed to allocate a secondary socket, release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Errno is already set inside nx_bsd_tcp_create_listen_socket. Therefore + there is no need to set errno here. */ + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + + /* At this point, we have found and marked a secondary server socket for the connection request. */ + + /* Set up a pointer to the secondary server socket. */ + sec_sock_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; + bsd_secondary_socket = &nx_bsd_socket_array[sec_sock_id]; + + /* Mark this BSD socket as busy. */ + bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); + + /* If the master socket is marked as non-blocking, we just need to check if the + secondary socket has a connection already. */ + while(!connected) + { + + secondary_socket_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; + + if((secondary_socket_id < NX_BSD_MAX_SOCKETS) && + (nx_bsd_socket_array[secondary_socket_id].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id == sockID) && + (nx_bsd_socket_array[secondary_socket_id].nx_bsd_socket_status_flags & (NX_BSD_SOCKET_CONNECTED | NX_BSD_SOCKET_ERROR))) + { + + connected = 1; + bsd_secondary_socket = &nx_bsd_socket_array[secondary_socket_id]; + bsd_secondary_socket -> nx_bsd_socket_family = bsd_socket_ptr -> nx_bsd_socket_family; + bsd_secondary_socket -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); + + } + else + { + + if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) + { + + /* No connection yet. Return EWOULDBLOCK */ + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EWOULDBLOCK); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + bsd_socket_ptr -> nx_bsd_socket_busy = NX_NULL; + } + return(NX_SOC_ERROR); + } + + tx_mutex_put(nx_bsd_protection_ptr); + tx_event_flags_get(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR_CLEAR, &requested_events, TX_WAIT_FOREVER); + tx_mutex_get(nx_bsd_protection_ptr, TX_WAIT_FOREVER); + + /* Verify the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* The socket is no longer in use. */ + + /* Set the socket error code. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + } + + /* If we get here, we should have a valid connection, or an error occured. */ + if(bsd_secondary_socket -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + INT errcode = bsd_secondary_socket -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_secondary_socket -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_secondary_socket -> nx_bsd_socket_status_flags = + bsd_secondary_socket -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Update the BSD socket source port and sender IP address. */ + status = nxd_tcp_socket_peer_info_get(bsd_secondary_socket -> nx_bsd_socket_tcp_socket, + &bsd_secondary_socket -> nx_bsd_socket_source_ip_address, + (ULONG *)(&bsd_secondary_socket -> nx_bsd_socket_source_port)); + + memcpy(&bsd_secondary_socket -> nx_bsd_socket_peer_ip, &bsd_secondary_socket -> nx_bsd_socket_source_ip_address, sizeof(NXD_ADDRESS)); + + bsd_secondary_socket -> nx_bsd_socket_peer_port = (USHORT)(bsd_secondary_socket -> nx_bsd_socket_source_port); + + /* Record the peer information. */ +#ifndef NX_DISABLE_IPV4 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4 = + bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4; + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]; + bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]; + bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]; + bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]; + } +#endif + + /* Attempt to obtain peer address if ClientAddress is not NULL. */ + if(ClientAddress && addressLength != 0) + { + +#ifndef NX_DISABLE_IPV4 + /* Handle the IPv4 socket type. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* Update the Client address with socket family, remote host IPv4 address and port. */ + peer4_address.sin_family = AF_INET; + peer4_address.sin_addr.s_addr = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4); + peer4_address.sin_port = ntohs((USHORT)bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); + + /* Copy the peer address/port info to the ClientAddress. Truncate if + addressLength is smaller than the size of struct sockaddr_in */ + if(*addressLength > (INT)sizeof(struct sockaddr_in)) + { + + memcpy(ClientAddress, &peer4_address, sizeof(struct sockaddr_in)); + *addressLength = sizeof(struct sockaddr_in); + } + else + { + memcpy(ClientAddress, &peer4_address, (UINT)(*addressLength)); + } + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + /* Update the Client address with socket family, remote host IPv6 address and port. */ + peer6_address.sin6_family = AF_INET6; + + peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]); + peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]); + peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]); + peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]); + + peer6_address.sin6_port = ntohs((USHORT)bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); + + if((*addressLength) > (INT)sizeof(peer6_address)) + { + + memcpy(ClientAddress, &peer6_address, sizeof(peer6_address)); + *addressLength = sizeof(peer6_address); + } + else + { + memcpy(ClientAddress, &peer6_address, (UINT)(*addressLength)); + } + } + else +#endif /* !FEATURE_NX_IPV6 */ + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Make sure this thread is still the owner. */ + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + + /* Clear the busy flag. */ + bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; + } + + /* Error, IPv6 support is not enabled. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + } + + /* Mark the sock_id field in both the master and secondary socket invalid. */ + (bsd_secondary_socket -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; + + /* Clear the master socket connect flags. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_REQUEST); + + /* Reset the master_socket_id */ + ret = nx_bsd_tcp_create_listen_socket(sockID, 0); + + if(ret < 0) + { + (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = NX_BSD_MAX_SOCKETS; + } + + /* Make sure this thread is still the owner. */ + if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) + { + + /* Clear the busy flag. */ + bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(secondary_socket_id + NX_BSD_SOCKFD_START); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_send_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is sends a message to a given destination address/port */ +/* */ +/* INPUT */ +/* */ +/* sockID BSD Socket ID */ +/* msg Pointer to the outgoing */ +/* message */ +/* msgLength The Size of the message */ +/* flags Control flags, support */ +/* MSG_DONTWAIT */ +/* dst_address The Destination Address */ +/* dst_port The Destination Port */ +/* local_inteterface_index The local outgoing interface */ +/* to use */ +/* */ +/* OUTPUT */ +/* */ +/* data_sent */ +/* */ +/* CALLS */ +/* */ +/* set_errno Sets the BSD errno */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_append Append data to the packet */ +/* tx_mutex_get Get Mutex protction */ +/* tx_mutex_put Release Mutex protection */ +/* nx_packet_release Release the packet on error */ +/* nx_udp_socket_send UDP packet send */ +/* nx_udp_socket_interface_send UDP packet send via a */ +/* specific interface */ +/* nx_tcp_socket_send TCP packet send */ +/* _nxd_bsd_ipv4_packet_send Raw IPv4 packet with header */ +/* included */ +/* _nxd_bsd_ipv6_packet_send Raw IPv6 packet with header */ +/* included */ +/* nxd_ip_raw_packet_interface_send Raw packet send via a */ +/* specific interface */ +/* CALLED BY */ +/* */ +/* send */ +/* sendto */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT nx_bsd_send_internal(INT sockID, const CHAR *msg, INT msgLength, INT flags, + NXD_ADDRESS *dst_address, USHORT dst_port, UINT local_interface_index) +{ +UINT status; +NX_PACKET *packet_ptr; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +NX_BSD_SOCKET *bsd_socket_ptr; +UINT packet_type = 0; +UINT wait_option; +ULONG data_sent = (ULONG)msgLength; + + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + +#ifndef NX_DISABLE_IPV4 + /* Determine the socket family for allocating a packet. */ + if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* This is for an IPv4 socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + /* Allocate an IPv4 UDP packet. */ + packet_type = NX_IPv4_UDP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + + /* Allocate an IPv4 TCP packet. */ + packet_type = NX_IPv4_TCP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) + { + + packet_type = NX_PHYSICAL_HEADER; + } + else + { + + /* Raw socket. */ + packet_type = NX_IPv4_PACKET; + } + } +#endif /* NX_DISABLE_IPV4 */ + if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + /* This is for an IPv6 socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + /* Allocate an IPv4 UDP packet. */ + packet_type = NX_IPv6_UDP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + /* Allocate an IPv4 TCP packet. */ + packet_type = NX_IPv6_TCP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) + { + packet_type = NX_PHYSICAL_HEADER; + } + else + { + /* Raw socket. */ + packet_type = NX_IPv6_PACKET; + } + } + + /* Allocate the packet for sending. */ + if(packet_type == 0) + { + /* Set the socket error. */ + set_errno(EINVAL); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Is this a non blocking socket? */ + if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || + (flags & MSG_DONTWAIT)) + { + + /* Yes, set to wait to zero on the NetX call. */ + wait_option = 0 ; + } + /* Does this socket have a send timeout option set? */ + else if (bsd_socket_ptr -> nx_bsd_option_send_timeout) + { + + /* Yes, this is our wait option. */ + wait_option = bsd_socket_ptr -> nx_bsd_option_send_timeout; + } + else + wait_option = TX_WAIT_FOREVER; + + status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, packet_type, wait_option); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + /* Now copy the data into the NetX packet. */ + status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, wait_option); + + /* Was the data copy successful? */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + + /* Determine if the socket is a UDP socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + /* Pickup the NetX UDP socket. */ + udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; + + /* Send the UDP packet. */ + if(local_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) + status = nxd_udp_socket_send(udp_socket_ptr, packet_ptr, dst_address, dst_port); + else + status = nxd_udp_socket_interface_send(udp_socket_ptr, packet_ptr, dst_address, dst_port, local_interface_index); + } + else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + + /* We have a TCP socket and a packet ready to send. */ + + /* Set a pointer to the TCP BSD socket. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + + if(wait_option != TX_NO_WAIT) + { + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + } + + /* Send the TCP packet. */ + status = nx_tcp_socket_send(tcp_socket_ptr, packet_ptr, wait_option); + + /* Check partial data sent. */ + if (status) + { + + /* Get length of data sent. */ + data_sent -= packet_ptr -> nx_packet_length; + + if (data_sent) + { + + /* Partial data sent. Mark as success. */ + status = NX_SUCCESS; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + } + + if(wait_option != TX_NO_WAIT) + { + /* Obtain the protection mutex. */ + tx_mutex_get(nx_bsd_protection_ptr, TX_WAIT_FOREVER); + } + } + else + { + /* Is this BSD socket configured to append the IP header? */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) + { + + /* Yes it is. Make sure the packet source and destination interface are set. */ + ULONG *ip_addr_ptr; + UINT src_interface; + +#ifndef NX_DISABLE_IPV4 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + ip_addr_ptr = (ULONG*)(packet_ptr -> nx_packet_prepend_ptr + 12); + + src_interface = (UINT)nx_bsd_find_interface_by_source_addr(AF_INET, ip_addr_ptr); + + if(src_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + src_interface = 0; + + packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &(nx_bsd_default_ip -> nx_ip_interface[src_interface]); + + /* If the IP ID field is non-zero, the current nx_ip_packet_id + value is modified */ + if((*(packet_ptr -> nx_packet_prepend_ptr + 4) == 0) && + (*(packet_ptr -> nx_packet_prepend_ptr + 5) == 0)) + { + + *(packet_ptr -> nx_packet_prepend_ptr + 4) = (UCHAR)(((nx_bsd_default_ip -> nx_ip_packet_id) & 0xFFFF) >> 8); + *(packet_ptr -> nx_packet_prepend_ptr + 5) = (UCHAR)((nx_bsd_default_ip -> nx_ip_packet_id) & 0xFF); + } + + /* Clear the checksum field. */ + *(packet_ptr -> nx_packet_prepend_ptr + 10) = 0; + *(packet_ptr -> nx_packet_prepend_ptr + 11) = 0; + + _nxd_bsd_ipv4_packet_send(packet_ptr); + + status = NX_SUCCESS; + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + ip_addr_ptr = (ULONG*)(packet_ptr -> nx_packet_prepend_ptr + 8); + src_interface = (UINT)nx_bsd_find_interface_by_source_addr(AF_INET6, ip_addr_ptr); + + if(src_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + { + status = NX_NOT_SUCCESSFUL; + } + + else + { + + NX_IPV6_HEADER *ipv6_header; + ULONG src_addr[4], dest_addr[4]; + + packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr; + + packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = &nx_bsd_default_ip -> nx_ipv6_address[src_interface]; + + ipv6_header = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_ip_header; + + /* Set up source / Destination IP */ + COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_destination_ip, dest_addr); + COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_source_ip, src_addr); + NX_IPV6_ADDRESS_CHANGE_ENDIAN(dest_addr); + NX_IPV6_ADDRESS_CHANGE_ENDIAN(src_addr); + + + _nxd_bsd_ipv6_packet_send(packet_ptr, src_addr, dest_addr); + + status = NX_SUCCESS; + } + } +#endif + } + else + { + + /* Raw socket without any IP header appended yet. We can send this directly to the NetX Duo IP packet handler. */ + if(local_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) + local_interface_index = 0; + + status = nxd_ip_raw_packet_interface_send(nx_bsd_default_ip, packet_ptr, dst_address, + local_interface_index, bsd_socket_ptr -> nx_bsd_socket_protocol, + NX_IP_TIME_TO_LIVE, NX_IP_NORMAL); + } + } + + /* Was the packet send successful? */ + if (status != NX_SUCCESS) + { + + /* No, release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the socket error. */ + + /* Set the socket error according to the NetX error status returned. */ + switch (status) + { + + case NX_IP_ADDRESS_ERROR: + set_errno(EDESTADDRREQ); + break; + + case NX_NOT_ENABLED: + set_errno(EPROTONOSUPPORT); + break; + + case NX_NOT_CONNECTED: + set_errno(ENOTCONN); + break; + + case NX_NO_PACKET: + case NX_UNDERFLOW: + set_errno(ENOBUFS); + break; + + case NX_WINDOW_OVERFLOW: + case NX_WAIT_ABORTED: + case NX_TX_QUEUE_DEPTH: + if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || + (flags & MSG_DONTWAIT)) + set_errno( EWOULDBLOCK); + else + set_errno(ETIMEDOUT); + break; + + default: + /* NX_NOT_BOUND */ + /* NX_PTR_ERROR */ + /* NX_INVALID_PACKET */ + set_errno(EINVAL); + break; + } + + /* Return an error status. */ + NX_BSD_ERROR(status, __LINE__); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_ERROR); + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return((INT)data_sent); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a packet out the given socket. */ +/* When the call returns, the data has been queued for transmission */ +/* over the connection. The return value indicates the number of byes */ +/* actually transmitted. */ +/* */ +/* The flags argument is provided for consistency with the BSD send */ +/* service. It allows various protocol features, such as out-of-bound */ +/* out-of-bound data, to be accessed. However, none of these features */ +/* are implemented. */ +/* */ +/* If packets are being sent out a UDP socket which is not bound to a */ +/* local port, this function find an available free port to bind to the*/ +/* socket. For TCP sockets, the socket must already by connected (so */ +/* also bound to port) */ +/* */ +/* Note: send() does not support raw sockets. Use the sendto() service */ +/* to transmit raw packets. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket */ +/* msg Data to be transmitted */ +/* msgLength Number of bytes to be sent */ +/* flags Control flags, support */ +/* MSG_DONTWAIT */ +/* */ +/* OUTPUT */ +/* */ +/* number of bytes sent If successful */ +/* NX_SOC_ERROR (-1) If failure */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_send Send a packet */ +/* nx_packet_allocate Get a free packet */ +/* nx_packet_data_append Copy data into packet */ +/* nx_packet_release Free a packet used to send */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT send(INT sockID, const CHAR *msg, INT msgLength, INT flags) +{ + +NX_BSD_SOCKET *bsd_socket_ptr; + + + /* Check for invalid socket IDd. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Set up a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Send() requires the socket be connected. A connected socket implies the socket is bound.*/ + if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) + { + + /* For AF_PACKET family, user shall use the sendto call. */ +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + /* Set the socket error */ + set_errno(ENOTCONN); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + + /* However if the socket is raw socket and HDR_INCLUDE is set, it is OK. */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE)) + { + /* Set the socket error */ + set_errno(ENOTCONN); + + /* Return an error status.*/ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + + return nx_bsd_send_internal(sockID, msg, msgLength, flags, + &bsd_socket_ptr -> nx_bsd_socket_peer_ip, + bsd_socket_ptr -> nx_bsd_socket_peer_port, + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* sendto PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a packet out the given socket. */ +/* When the call returns, the data has been queued for transmission */ +/* over the connection. To use sendto on a TCP BSD socket, the */ +/* socket must already be in connected state. */ +/* */ +/* The flags argument is provided for consistency with the BSD send */ +/* service. It allows various protocol features, such as out-of-bound */ +/* out-of-bound data, to be accessed. However, none of these features */ +/* are implemented. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket (must be connected). */ +/* msg Data to transmit. */ +/* msgLength Number of bytes to send */ +/* flags Control flags, support */ +/* MSG_DONTWAIT */ +/* sockaddr Destination address */ +/* destAddrLen Length of destination address */ +/* */ +/* OUTPUT */ +/* */ +/* Number of bytes sent If no error occurs */ +/* NX_SOC_ERROR (-1) In case of socket error */ +/* */ +/* CALLS */ +/* */ +/* bind Bind NetX UDP sockets */ +/* nx_packet_allocate Get a free packet */ +/* nx_packet_data_append Copy data into packet */ +/* nx_packet_release Free the nx_packet used */ +/* nx_tcp_socket_send Send packet over a TCP Socket */ +/* nx_udp_socket_send Send packet over a UDP Socket */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT sendto(INT sockID, CHAR *msg, INT msgLength, INT flags, struct sockaddr *destAddr, INT destAddrLen) +{ +UINT status; +NX_BSD_SOCKET *bsd_socket_ptr; +NXD_ADDRESS peer_ip_address; +USHORT peer_port = 0; + + /* Check for a valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set up a socket pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID - NX_BSD_SOCKFD_START]; + + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. Application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + /* For TCP, make sure the socket is already connected. */ + if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) + { + set_errno(ENOTCONN); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + return nx_bsd_send_internal((sockID - NX_BSD_SOCKFD_START), msg, msgLength, flags, NX_NULL, 0, + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); + } + else + { + + /* This is a UDP or raw socket. */ + + /* Check whther or not the socket is AF_PACKET family. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + /* nx_bsd_pppoe_internal_sendto shall returns */ + status = (UINT)nx_bsd_pppoe_internal_sendto(bsd_socket_ptr, msg, msgLength, flags, destAddr, destAddrLen); +#elif defined(NX_BSD_RAW_SUPPORT) + /* _nx_bsd_hardware_internal_sendto shall returns */ + status = (UINT)_nx_bsd_hardware_internal_sendto(bsd_socket_ptr, msg, msgLength, flags, destAddr, destAddrLen); +#else + NX_PARAMETER_NOT_USED(destAddrLen); + status = (UINT)NX_SOC_ERROR; +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + return((INT)status); + + } + + /* Perform error checkings on the remote address if the socket is + not raw socket, or HDRINCL is not set for the raw socket. */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE)) + { + + /* Check for an invalid destination. */ + if (destAddr == NX_NULL) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Validate the destination address. */ + if(bsd_socket_ptr -> nx_bsd_socket_family != destAddr -> sa_family) + { + set_errno(EAFNOSUPPORT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + } + + /* For UDP socket, make sure the socket is bound. */ + if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) + { + status = nx_udp_socket_bind(bsd_socket_ptr -> nx_bsd_socket_udp_socket, NX_ANY_PORT, NX_NO_WAIT); + if((status != NX_SUCCESS) && (status != NX_ALREADY_BOUND)) + { + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; + bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)(bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_port); + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + } + + } + + + + if(destAddr) + { + /* Get the destination IP and port for this UDP socket. */ +#ifndef NX_DISABLE_IPV4 + if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* This is for an IPv4 packet. */ + peer_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + peer_ip_address.nxd_ip_address.v4 = htonl(((struct sockaddr_in *) destAddr) -> sin_addr.s_addr); + peer_port = htons(((struct sockaddr_in *) destAddr) -> sin_port); + + /* Local interface ID is set to invalid value, so the send routine needs to + find the best interface to send the packet based on destination IP address. */ + + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + /* This is for an IPv6 packet. Set the NetX Duo IP address version. */ + peer_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + peer_ip_address.nxd_ip_address.v6[0] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[0]); + peer_ip_address.nxd_ip_address.v6[1] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[1]); + peer_ip_address.nxd_ip_address.v6[2] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[2]); + peer_ip_address.nxd_ip_address.v6[3] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[3]); + + peer_port = htons(((struct sockaddr_in6 *) destAddr) -> sin6_port); + + } +#endif + } + + /* Call the internal send routine to finish the send process. */ + /* Local interface ID is set to a special marker, so the send routine needs to + find the best interface to send the packet based on destination IP address. */ + return nx_bsd_send_internal((sockID - NX_BSD_SOCKFD_START), msg, msgLength, flags, + &peer_ip_address, peer_port, + bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); + + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* recv PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies up to a specified number of bytes received on */ +/* the socket into specified location. The given socket must be in the */ +/* connected state. Normally, the call blocks until either at least one*/ +/* byte is returned or the connection closes.The return value indicates*/ +/* the number of bytes actually copied into the buffer starting at the */ +/* specified location. */ +/* */ +/* For a stream socket, the bytes are delivered in the same order as */ +/* they were transmitted, without omissions. For a datagram socket, */ +/* each recv() returns the data from at most one send(), and order is */ +/* not necessarily preserved. */ +/* */ +/* For non blocking sockets, a receive status of NX_NO_PACKET from NetX*/ +/* results in an error status returned from BSD, and the socket error */ +/* set to EWOULDBLOCK (if BSD extended socket features are enabled. */ +/* */ +/* Likewise, an event flag status of TX_NO_EVENTS returned from ThreadX*/ +/* on a non blocking socket sets the socket error to EWOULDBLOCK. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket (must be connected). */ +/* rcvBuffer Pointer to put data received. */ +/* bufferLength Maximum bytes in buffer */ +/* flags Control flags, support */ +/* MSG_PEEK and MSG_DONTWAIT */ +/* */ +/* OUTPUT */ +/* */ +/* Number of bytes received If success */ +/* NX_SOC_ERROR (-1) If failure */ +/* 0 socket disconnected */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive a Packet */ +/* nx_packet_allocate Allocate packet for receive */ +/* nx_packet_release Free the nx_packet after use */ +/* nx_packet_data_extract_offset Retrieve packet data */ +/* tx_event_flags_get Wait for data to arrive */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT recv(INT sockID, VOID *rcvBuffer, INT bufferLength, INT flags) +{ + +UINT status; +NX_PACKET *packet_ptr; +NX_BSD_SOCKET *bsd_socket_ptr; +NX_TCP_SOCKET *tcp_socket_ptr; +ULONG requested_events; +ULONG bytes_received; +UINT wait_option; +UINT remaining_wait_option; +ULONG offset; +INT header_size = 0; +ULONG start_time = nx_bsd_system_clock; + + + /* Check for a valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Set up a pointer to the socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Set the receive wait time to FOREVER for blocking sockets. */ + wait_option = NX_WAIT_FOREVER; + + /* Is this a nonblocking socket?: */ + if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || + (flags & MSG_DONTWAIT)) + { + + /* Yes, set to receive wait option to no wait (zero). */ + wait_option = 0; + } + /* Does this socket have a receive timeout option set? */ + else if (bsd_socket_ptr -> nx_bsd_option_receive_timeout) + { + + /* Yes, this is our wait option. */ + wait_option = bsd_socket_ptr -> nx_bsd_option_receive_timeout; + } + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* If the socket has an error */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + + INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = + bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + + set_errno(errcode); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* At this point the error flag is cleared. The application should + detect and handle the error codition. This socket is still bound + to the port (either the application called bind(), or a bind + operation was executed as part of the connect call) and is able to + handle another "connect" call, or be closed. */ + return(NX_SOC_ERROR); + } + + /* Set pointers to the BSD NetX Duo sockets. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + + /* Loop to check for a received packet. */ + do + { + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check if the BSD socket already has received a packet. */ + packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; + + if (packet_ptr) + { + + /* Got one. Break out of the loop. */ + break; + } + + /* Check if there is an incoming packet on this socket. */ + else + { + + /* Determine if this is a TCP BSD socket. */ + if (tcp_socket_ptr) + { + + /* It is, check the socket TCP receive queue with a zero wait option (no suspension). */ + status = nx_tcp_socket_receive(tcp_socket_ptr, &packet_ptr, TX_NO_WAIT); + + /* Check for no packet on the queue. */ + if (status == NX_NOT_CONNECTED) + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Is peer shutdown orderly? */ + if ((tcp_socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSE_WAIT) || + (tcp_socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSING)) + { + + /* Yes. Return 0. */ + return(NX_SUCCESS); + } + + /* Set the socket status (not really an error). */ + set_errno(ENOTCONN); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if (status == NX_SUCCESS) + { + + /* Increase the received count. */ + bsd_socket_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count++; + } + } + + /* Have we found a new packet? */ + if ((status == NX_SUCCESS) && (packet_ptr)) + { + + /* Setup the bsd socket with the packet information. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr; + bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; + + /* Get out of the loop. */ + break; + } + } + + /* No packet is available. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Calculate remaining wait option. */ + remaining_wait_option = (UINT)(wait_option - (nx_bsd_system_clock - start_time)); + if (remaining_wait_option > wait_option) + { + + /* Wait option expired. */ + status = TX_NO_EVENTS; + } + else + { + + /* Suspend this socket on a RECEIVE event (incoming packet) for the specified wait time. */ + status = tx_event_flags_get(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR_CLEAR, &requested_events, remaining_wait_option); + } + + /* Check for any events. */ + if (status == TX_NO_EVENTS) + { + + /* No packets received. */ + + /* Set the socket error depending if this is a non blocking socket. */ + if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || + (wait_option == NX_WAIT_FOREVER) || + (flags & MSG_DONTWAIT)) + set_errno(EWOULDBLOCK); + else + set_errno (EAGAIN); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + else if (status != TX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Re-obtain the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* The socket is no longer in use. */ + + /* Set the socket error code. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + } while (1); + + /* At this point, the socket has received a packet. */ + + + /* Obtain sender information for UDP socket. */ + if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) + { + + /* Get the sender and port from the UDP packet. */ + nxd_udp_source_extract(packet_ptr, &bsd_socket_ptr -> nx_bsd_socket_source_ip_address, (UINT *)&bsd_socket_ptr -> nx_bsd_socket_source_port); + } + +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) + else if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + + /* Validate the packet length. */ + if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 14) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return an error. */ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + /* Pick up the sender's MAC address. */ + bsd_socket_ptr -> nx_bsd_socket_sll_addr[0] = packet_ptr -> nx_packet_prepend_ptr[6]; + bsd_socket_ptr -> nx_bsd_socket_sll_addr[1] = packet_ptr -> nx_packet_prepend_ptr[7]; + bsd_socket_ptr -> nx_bsd_socket_sll_addr[2] = packet_ptr -> nx_packet_prepend_ptr[8]; + bsd_socket_ptr -> nx_bsd_socket_sll_addr[3] = packet_ptr -> nx_packet_prepend_ptr[9]; + bsd_socket_ptr -> nx_bsd_socket_sll_addr[4] = packet_ptr -> nx_packet_prepend_ptr[10]; + bsd_socket_ptr -> nx_bsd_socket_sll_addr[5] = packet_ptr -> nx_packet_prepend_ptr[11]; + + /* Pick up the sender's protocol */ + bsd_socket_ptr -> nx_bsd_socket_sll_protocol = (USHORT)((packet_ptr -> nx_packet_prepend_ptr[12] << 8) | + (packet_ptr -> nx_packet_prepend_ptr[13])); + if (bsd_socket_ptr -> nx_bsd_socket_sll_protocol == 0x8100) + { + + /* Skip VLAN tag. */ + bsd_socket_ptr -> nx_bsd_socket_sll_protocol = (USHORT)((packet_ptr -> nx_packet_prepend_ptr[16] << 8) | + (packet_ptr -> nx_packet_prepend_ptr[17])); + } + + /* Find the IF Index */ + bsd_socket_ptr -> nx_bsd_socket_sll_ifindex = packet_ptr -> nx_packet_ip_interface -> nx_interface_index; + + } +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + /* For raw socket, make sure the source address is extracted. */ + else if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) + { + + /* Get the sender IP address from the raw packet. */ + status = nx_bsd_raw_packet_info_extract(packet_ptr, &(bsd_socket_ptr -> nx_bsd_socket_source_ip_address), NX_NULL); + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + /* Pickup the current offset. */ + offset = bsd_socket_ptr -> nx_bsd_socket_received_packet_offset; + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + /* Perform extra processing on this packet if it processed as a raw packet. */ + if((bsd_socket_ptr -> nx_bsd_socket_family != AF_PACKET) && + (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) + { + + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & (NX_BSD_SOCKET_RX_NO_HDR)) + { + header_size = 0; + } + else + { +#ifndef NX_DISABLE_IPV4 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + + header_size = packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header; + + /* Byte-Swap the basic IPv4 header. The NetX Duo IP receive process does not + examine the extension header. Therefore it does not perform byte swap + on extension headers. */ + NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_0)); + NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_1)); + NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_2)); + NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_source_ip)); + NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_destination_ip)); + + if(bufferLength < header_size) + { + header_size = bufferLength; + } + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + NX_IPV6_HEADER *ipv6_header_ptr; + UCHAR next_header_type; + + header_size = (INT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header); + + if(bufferLength < header_size) + { + + header_size = bufferLength; + } + + ipv6_header_ptr = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_ip_header; + + /* Pick up the next header. */ + next_header_type = (ipv6_header_ptr -> nx_ip_header_word_1 >> 8) & 0xFF; + + NX_CHANGE_ULONG_ENDIAN(ipv6_header_ptr -> nx_ip_header_word_0); + NX_CHANGE_ULONG_ENDIAN(ipv6_header_ptr -> nx_ip_header_word_1); + NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_header_ptr -> nx_ip_header_destination_ip); + NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_header_ptr -> nx_ip_header_source_ip); + + /* Go through the rest of the IPv6 extension headers. */ + _nxd_bsd_swap_ipv6_extension_headers(packet_ptr, next_header_type); + } +#endif + + memcpy(rcvBuffer, packet_ptr -> nx_packet_ip_header, (UINT)header_size); + } + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + + /* Copy the packet data into the supplied buffer. */ + status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID*)((INT)rcvBuffer + header_size), (ULONG) (bufferLength - header_size), &bytes_received); + + /* Check for an error. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return an error. */ + NX_BSD_ERROR( status, __LINE__); + return(NX_SOC_ERROR); + } + + if((flags & MSG_PEEK) == 0) + { + + /* Calculate the new offset. */ + offset = offset + bytes_received; + + /* Determine if all the packet data was consumed. */ + if(packet_ptr -> nx_packet_length <= offset) + { + + bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr -> nx_packet_queue_next; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Clear the offset. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; + } + else if((bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + || (bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + ) + { + + /* For UDP or raw socket, We extracted as much as can fit in the caller's buffer. + We will discard the remaining bytes. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr -> nx_packet_queue_next; + + bytes_received = packet_ptr -> nx_packet_length; + + /* No need to retain the packet. */ + nx_packet_release(packet_ptr); + + /* Clear the offset. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; + } + else + { + + /* For TCP, the remaining data is saved for the next recv call. + Just update the offset. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = offset; + } + bsd_socket_ptr -> nx_bsd_socket_received_byte_count -= bytes_received; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count--; + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Successful received a packet. Return the number of bytes copied to buffer. */ + return((INT)bytes_received + (INT)header_size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* recvfrom PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies up to a specified number of bytes, received on */ +/* the socket into a specified location. To use recvfrom() on a TCP */ +/* socket requires the socket to be in the connected state. */ +/* */ +/* This function is identical to recv() except for returning the sender*/ +/* address and length if non null arguments are supplied. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket(must be connected) */ +/* buffer Pointer to hold data received */ +/* bufferSize Maximum number of bytes */ +/* flags Control flags, support */ +/* MSG_PEEK and MSG_DONTWAIT */ +/* fromAddr Address data of sender */ +/* fromAddrLen Length of address structure */ +/* */ +/* OUTPUT */ +/* */ +/* number of bytes received If no error occurs */ +/* NX_SOC_ERROR (-1) In case of any error */ +/* */ +/* CALLS */ +/* */ +/* memset Clear memory */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_extract_offset Extract packet data */ +/* nx_packet_release Free the packet used */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_event_flags_get Wait for data to arrive */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT recvfrom(INT sockID, CHAR *rcvBuffer, INT bufferLength, INT flags, struct sockaddr *fromAddr, INT *fromAddrLen) +{ + +INT bytes_received; +NX_BSD_SOCKET *bsd_socket_ptr; +#ifndef NX_DISABLE_IPV4 +struct sockaddr_in peer4_address; +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 +struct sockaddr_in6 peer6_address; +#endif + + /* Check for a valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set up a pointer to the socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID - NX_BSD_SOCKFD_START]; + + /* Socket error checking is done inside recv() call. */ + + /* Call the equivalent recv() function. */ + bytes_received = recv(sockID, rcvBuffer, bufferLength, flags); + + /* Check for error. */ + if (bytes_received < 0) + { + + /* Return an error status. */ + return NX_SOC_ERROR; + } + /* If no bytes are received do not handle as an error. */ + else if (bytes_received == 0) + { + return NX_SOC_OK; + } + + /* At this point we did receive a packet. */ + /* Supply the sender address if valid pointer is supplied. */ + if(fromAddr && (*fromAddrLen != 0)) + { + +#ifndef NX_DISABLE_IPV4 + /* Handle the IPv4 socket type. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + /* Update the Client address with socket family, remote host IPv4 address and port. */ + peer4_address.sin_family = AF_INET; + if(bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + peer4_address.sin_addr.s_addr = htonl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4); + peer4_address.sin_port = htons(bsd_socket_ptr -> nx_bsd_socket_peer_port); + } + else + { + peer4_address.sin_addr.s_addr = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4); + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + if(!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + peer4_address.sin_port = ntohs((USHORT)bsd_socket_ptr -> nx_bsd_socket_source_port); + } + /* Copy the peer address/port info to the ClientAddress. Truncate if + addressLength is smaller than the size of struct sockaddr_in */ + if(*fromAddrLen > (INT)sizeof(struct sockaddr_in)) + { + *fromAddrLen = sizeof(struct sockaddr_in); + } + memcpy(fromAddr, &peer4_address, (UINT)(*fromAddrLen)); + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + /* Update the Client address with socket family, remote host IPv6 address and port. */ + peer6_address.sin6_family = AF_INET6; + + if(bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0]); + peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1]); + peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2]); + peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3]); + peer6_address.sin6_port = ntohs(bsd_socket_ptr -> nx_bsd_socket_peer_port); + } + else + { + peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0]); + peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1]); + peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2]); + peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3]); + + /* Skip the port data for raw sockets. They do not use them. */ +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + if(!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + peer6_address.sin6_port = ntohs((USHORT)bsd_socket_ptr -> nx_bsd_socket_source_port); + } + + if((*fromAddrLen) > (INT)sizeof(peer6_address)) + { + *fromAddrLen = sizeof(peer6_address); + } + memcpy(fromAddr, &peer6_address, (UINT)(*fromAddrLen)); + + } + else +#endif /* !FEATURE_NX_IPV6 */ +#if defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + if(*fromAddrLen >= (INT)sizeof(struct sockaddr_ll)) + { + struct sockaddr_ll *sockaddr = (struct sockaddr_ll*)fromAddr; + INT i; + sockaddr -> sll_family = AF_PACKET; + sockaddr -> sll_protocol = bsd_socket_ptr -> nx_bsd_socket_sll_protocol; + sockaddr -> sll_ifindex = bsd_socket_ptr -> nx_bsd_socket_sll_ifindex; + sockaddr -> sll_hatype = 0; + sockaddr -> sll_pkttype = 0; + sockaddr -> sll_halen = 6; + for(i = 0; i < 6; i++) + sockaddr -> sll_addr[i] = bsd_socket_ptr -> nx_bsd_socket_sll_addr[i]; + *fromAddrLen = sizeof(struct sockaddr_ll); + } + + } + else +#endif + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Error, IPv6 support is not enabled. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + } + + /* Successfully received a packet. Return bytes received. */ + return (INT)(bytes_received); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* soc_close PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function terminates communications on the supplied BSD socket. */ +/* The socket is disallowed for further sends and receives. Socket */ +/* resources such as socket memory are returned to the system. */ +/* */ +/* If a socket is enabled with the linger option, that will be used in */ +/* place of the default NX_BSD TIMEOUT for blocking sockets. Sockets */ +/* enabled for non blocking have their timeout set for zero. Note that */ +/* a zero wait option results in an immediate shutdown (e.g. send RST) */ +/* unless the NX_DISABLE_RESET_DISCONNECT is not enabled. */ +/* */ +/* For BSD applications enabled for disconnect complete notification */ +/* for TCP sockets, the socket will remain open until NetX notifies us */ +/* that the disconnect is complete. This allows the host BSD */ +/* application to perform asynchronous disconnects without having to */ +/* wait for the disconnect to complete. */ +/* */ +/* INPUT */ +/* */ +/* socketID */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* memset Clear memory */ +/* nx_tcp_socket_disconnect Disconnect a TCP Socket */ +/* nx_tcp_client_socket_unbind Unbind the socket */ +/* nx_tcp_server_socket_unaccept Unaccept the socket */ +/* nx_tcp_server_socket_unlisten Unlisten on a port */ +/* nx_tcp_socket_delete Deletes a TCP Socket */ +/* nx_udp_socket_unbind Unbind a UDP Socket */ +/* nx_udp_socket_delete Deletes a UDP Socket */ +/* tx_block_release Release block for socket */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT soc_close(INT sockID) +{ + +NX_BSD_SOCKET *bsd_socket_ptr; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; +ULONG timeout; +INT i; +UINT counter; +INT delete_socket; +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +INT protocol; +UINT index; +#endif + + /* Check for a valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error. */ + set_errno(EBADF); + + /* Error, invalid socket ID. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Set up a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Get the protection mutex. */ + tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Is the socket already in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* No; If the NetX socket associated with this BSD socket been deleted, this is ok. */ + if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket && !bsd_socket_ptr -> nx_bsd_socket_udp_socket) + { + + /* Yes, no further action possible. Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return NX_SOC_OK; + } + + /* Otherwise, it is an error if socket not in use anymore. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set NetX socket pointers. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; + + /* There is. Flush the queue of all packets. */ + packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; + /* Setup packet pointer to the beginning of the queue. */ + while(packet_ptr) + { + next_packet_ptr = packet_ptr -> nx_packet_queue_next; + + /* Mark it as allocated so it will be released. */ + packet_ptr -> nx_packet_queue_next = (NX_PACKET *) NX_PACKET_ALLOCATED; + + nx_packet_release(packet_ptr); + + /* Move to the next packet */ + packet_ptr = next_packet_ptr; + } + + bsd_socket_ptr -> nx_bsd_socket_received_packet = NX_NULL; + bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = NX_NULL; + bsd_socket_ptr -> nx_bsd_socket_received_byte_count = 0; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 0; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max = 0; + + /* Now delete the underlying TCP or UDP socket. */ + + /* Is this a TCP socket? */ + if (tcp_socket_ptr) + { + + /* If the socket has not been closed, disconnect it. This would be the case + if NetX already closed the socket e.g. a RST packet received before the + host application called this function. */ + if (tcp_socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Disconnect the socket. */ + + /* If the disconnect takes more than the timeout option, NetX marks the socket as "closed" + or puts it back to "listen" state. The default value is 1 to emulate an immediate + socket closure without sending a RST packet. */ + timeout = NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT; + + /* Release the mutex while disconnecting. */ + tx_mutex_put(nx_bsd_protection_ptr); + + nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); + + tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Verify that the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* The socket is no longer in use. */ + + /* Set the socket error code. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + /* Make sure the socket is unbound, not accepting connections and not bound to a listening port. */ + if(tcp_socket_ptr -> nx_tcp_socket_port) + { + + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT) + { + nx_tcp_client_socket_unbind(tcp_socket_ptr); + } + else + { + nx_tcp_server_socket_unaccept(tcp_socket_ptr); + } + + } + + /* Now we can delete the NetX TCP socket. */ + nx_tcp_socket_delete(tcp_socket_ptr); + + /* Clear the TCP socket structure. */ + memset((VOID *) tcp_socket_ptr, 0, sizeof(NX_TCP_SOCKET)); + + /* Release the NetX TCP socket. */ + tx_block_release((VOID *) tcp_socket_ptr); + + /* If this is the master server socket, we need to unaccept the + associated secondary socket. */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) + { + + INT sec_soc_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; + + if(sec_soc_id < NX_BSD_MAX_SOCKETS) + { + + /* Find whether or not this is the only master socket that is connected to this + secondary socket. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + if(i == sockID) + continue; + + if((nx_bsd_socket_array[i].nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && + (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && + (nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id == sec_soc_id)) + { + break; + } + } + + if(i == NX_BSD_MAX_SOCKETS) + { + + /* Unaccept and unlisten on the socket/port */ + /* nx_tcp_server_socket_unaccept(tcp_socket_ptr); */ + /* nx_tcp_server_socket_unlisten(nx_bsd_default_ip, tcp_socket_ptr -> nx_tcp_socket_port); */ + + /* Release the secondary socket if there are no more master sockets associated + with this secondary socket. */ + + tcp_socket_ptr = nx_bsd_socket_array[sec_soc_id].nx_bsd_socket_tcp_socket; + + /* If the secondary socket has not been closed, disconnect it. This would be the case + if NetX already closed the master socket. */ + if (tcp_socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Disconnect the socket. */ + + /* If the disconnect takes more than the timeout option, NetX marks the socket as "closed" + or puts it back to "listen" state. The default value is 1 to emulate an immediate + socket closure without sending a RST packet. */ + timeout = NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT; + + /* Release the mutex while disconnecting. */ + tx_mutex_put(nx_bsd_protection_ptr); + + nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); + + tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Verify that the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* The socket is no longer in use. */ + + /* Set the socket error code. */ + set_errno(EBADF); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + + /* Unaccept on the secondary socket. */ + nx_tcp_server_socket_unaccept(tcp_socket_ptr); + nx_tcp_server_socket_unlisten(nx_bsd_default_ip, tcp_socket_ptr -> nx_tcp_socket_port); + nx_tcp_socket_delete(tcp_socket_ptr); + + memset((VOID*)tcp_socket_ptr, 0, sizeof(NX_TCP_SOCKET)); + tx_block_release((VOID*)tcp_socket_ptr); + memset((VOID*)&(nx_bsd_socket_array[sec_soc_id]), 0, sizeof(NX_BSD_SOCKET)); + } + } + } + + /* Finally Clear the BSD socket structure. */ + memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return */ + return(NX_SOC_OK); + + } + else if (udp_socket_ptr) + { + + /* A UDP socket needs to be closed. */ + + /* Check whether this is the last BSD socket attached to the NX_UDP_SOCKET */ + counter = (UINT)udp_socket_ptr -> nx_udp_socket_reserved_ptr; + + delete_socket = NX_TRUE; + /* Decrease the counter value. */ + if(counter & 0xFFFF0000) + { + + counter = ((counter & 0xFFFF0000) - 0x00010000 + (counter & 0x0000FFFF)) & 0xFFFFFFFF; + + udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID*)counter; + + if(counter & 0xFFFF0000) + { + + /* Do not delete this socket. */ + delete_socket = NX_FALSE; + + /* If the underlying NX_UDP_SOCKET points to this UDP socket, we need to + reassign a BSD socket to the NX UDP socket. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + if((nx_bsd_socket_array[i].nx_bsd_socket_udp_socket == udp_socket_ptr) && + (i != sockID)) + { + + counter = (counter & 0xFFFF0000) + (UINT)i; + udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID*)counter; + break; + } + } + + if(i == NX_BSD_MAX_SOCKETS) + { + delete_socket = NX_TRUE; + } + } + } + + if(delete_socket == NX_TRUE) + { + + if(udp_socket_ptr -> nx_udp_socket_bound_next) + { + nx_udp_socket_unbind(udp_socket_ptr); + } + + /* Socket successfully unbound. Now delete the UDP socket. */ + nx_udp_socket_delete(udp_socket_ptr); + + /* Clear the UDP socket block. */ + memset((VOID *) udp_socket_ptr, 0, sizeof(NX_UDP_SOCKET)); + + /* Release the NetX UDP socket memory. */ + tx_block_release((VOID *) udp_socket_ptr); + } + else + { + /* Remove this bsd udp socket from the list. */ + (bsd_socket_ptr -> nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr -> nx_bsd_socket_previous; + (bsd_socket_ptr -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr -> nx_bsd_socket_next; + } + + /* Clear the BSD socket block. */ + memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + else if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) + { + + /* There is no native NetX Duo raw socket to delete or + port to unbind. So just release the BSD socket memory. */ + + /* Remove this socket from the list. */ + protocol = bsd_socket_ptr -> nx_bsd_socket_protocol; + + /* Calculate the hash index in the raw socket protocol table. */ + index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); + + /* Determine if this is the only socket on this list. */ + if(bsd_socket_ptr -> nx_bsd_socket_next == bsd_socket_ptr) + { + /* Yes, this is the only socket on the list. */ + + /* Clear the list head pointer. */ + nx_bsd_socket_raw_protocol_table[index] = NX_NULL; + } + else + { + /* Remove this bsd udp socket from the list. */ + (bsd_socket_ptr -> nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr -> nx_bsd_socket_previous; + (bsd_socket_ptr -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr -> nx_bsd_socket_next; + + /* Determine if the head of the list points to the socket being removed. + If so, we need to move the head pointer. */ + if(nx_bsd_socket_raw_protocol_table[index] == bsd_socket_ptr) + { + /* Yes, we need to move the list head pointer. */ + nx_bsd_socket_raw_protocol_table[index] = bsd_socket_ptr -> nx_bsd_socket_next; + } + } + + /* Clear the BSD socket block. */ + memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ +#if defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) + else if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + /* There is no native NetX Duo raw socket to delete or + port to unbind. So just release the BSD socket memory. */ + + /* Clear the BSD socket block. */ + memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_OK); + } + +#endif /* defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) */ + + + + + /* Unknown socket type or invalid socket. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + + + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* fcntl PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs the requested operation on the file (e.g. */ +/* socket) descriptor set. This implementation supports only the set */ +/* or get flag, and only sets (or clears) the non blocking option. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* flag_type File description request */ +/* f_options Option(s) to set on the */ +/* specified file (socket) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_ERROR Errors with request */ +/* (file descriptor flags) File descriptor flags */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT fcntl(INT sockID, UINT flag_type, UINT f_options) +{ + +NX_BSD_SOCKET *bsd_socket_ptr; + + /* Check for invalid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* Return error status. */ + return NX_SOC_ERROR; + } + + /* Normalize the socket ID to our array. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Build pointer to BSD socket structure. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + if(flag_type == F_SETFL) + { + /* Set the FD flag. */ + bsd_socket_ptr -> nx_bsd_file_descriptor_flags = (INT)f_options; + + + /* Are there flags to clear? */ + if ((f_options & O_NONBLOCK) == 0) + { + /* Disable the socket for non blocking. */ + bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); + } + else + { + /* Enable the socket for non blocking. */ + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; + } + + /* All done. Return 0 */ + return(0); + } + else if(flag_type == F_GETFL) + { + return(bsd_socket_ptr -> nx_bsd_file_descriptor_flags); + } + /* Flag_type is not the one we support */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* Return error status. */ + return NX_SOC_ERROR; + + + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* ioctl PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function carries out a socket IO service specified by the */ +/* command. */ +/* */ +/* INPUT */ +/* */ +/* sockID Socket (must be connected). */ +/* command IO command for ioctl function */ +/* result data returned (value) */ +/* */ +/* OUTPUT */ +/* */ +/* Number of bytes received If success */ +/* NX_SOC_ERROR (-1) Error during socket opration */ +/* NX_SOC_OK (0) Successful completion */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_bytes_available Retreive number of bytes on */ +/* the specified TCP socket */ +/* nx_udp_socket_bytes_available Retreive number of bytes on */ +/* the specified UDP socket */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT ioctl(INT sockID, INT command, INT *result) +{ + +NX_BSD_SOCKET *bsd_socket_ptr; +NX_TCP_SOCKET *tcp_socket_ptr; +NX_UDP_SOCKET *udp_socket_ptr; +UINT status; + + + /* Check that the supplied socket ID is valid. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Error, invalid socket ID. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Error getting the protection mutex. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set a pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Pick up the associated NetX socket pointers. */ + tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; + udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; + + /* Handle the command. */ + switch (command) + { + + case FIONREAD: + { + + /* Check NULL pointer. */ + if(result == NX_NULL) + { + tx_mutex_put(nx_bsd_protection_ptr); + + set_errno(EFAULT); + + /* Error, invalid address. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + + /* Determine which socket pointer to use. */ + if (tcp_socket_ptr) + { + + /* Extract the number of bytes on the TCP receive queue. */ + status = nx_tcp_socket_bytes_available(tcp_socket_ptr, (ULONG *)result); + + if (status != NX_SUCCESS) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Error in the native NetX call. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + else if (udp_socket_ptr) + { + + /* Extract the number of bytes on the UDP receive queue. */ + *result = (INT)(bsd_socket_ptr -> nx_bsd_socket_received_byte_count); + } + + break; + } + + case FIONBIO: + { + + /* Check NULL pointer. */ + if(result == NX_NULL) + { + tx_mutex_put(nx_bsd_protection_ptr); + + set_errno(EFAULT); + + /* Error, invalid address. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return(NX_SOC_ERROR); + } + + if(*result == NX_FALSE) + { + + /* Disable the socket for non blocking. */ + bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); + + /* Update the file descriptor with the non blocking bit. */ + bsd_socket_ptr -> nx_bsd_file_descriptor_flags &= ~O_NONBLOCK; + } + else + { + + /* Enable the socket for non blocking. */ + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; + + /* Update the file descriptor with the non blocking bit. */ + bsd_socket_ptr -> nx_bsd_file_descriptor_flags |= O_NONBLOCK; + } + + break; + } + + default: + + /* Unhandled command; ignore */ + break; + } + + tx_mutex_put(nx_bsd_protection_ptr); + + return NX_SOC_OK; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_ntoa PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IP address to a string and returns a */ +/* pointer to the string. The caller is recommended to copy the */ +/* contents of the buffer to local memory since this function and */ +/* internal buffer can be reused. */ +/* */ +/* INPUT */ +/* */ +/* address_to_convert Struct holding IP address. */ +/* */ +/* OUTPUT */ +/* */ +/* char * Pointer to converted string */ +/* 0x0 Error during conversion */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get mutex protection */ +/* bsd_number_convert Convert integer to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +CHAR *inet_ntoa(struct in_addr address_to_convert) +{ +UINT status; + + /* Because we are using global buffer space to write out the string, get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + if (status != NX_SUCCESS) + { + return NX_NULL; + } + + inet_ntoa_internal(&address_to_convert, nx_bsd_url_buffer, NX_BSD_URL_BUFSIZE); + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return the start of the string buffer. */ + return nx_bsd_url_buffer; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* bsd_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an integer to a string. */ +/* */ +/* INPUT */ +/* */ +/* number Number to convert */ +/* string Pointer to string buffer */ +/* buffer_len Size of the string buffer */ +/* base the base of the number, */ +/* 2,8,10,16 */ +/* */ +/* OUTPUT */ +/* */ +/* size Size of string buffer */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT bsd_number_convert(UINT number, CHAR *string, ULONG buffer_len, UINT base) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < buffer_len) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string[j] = string[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % base; + + /* Update the input number. */ + number = number / base; + + /* Store the new digit in ASCII form. */ + if(digit < 10) + string[0] = (CHAR) (digit + 0x30); + else + string[0] = (CHAR) (digit + 0x57); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Make the string NULL terminated. */ + string[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_aton PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts hexadecimal characters into an ASCII IP */ +/* address representation. */ +/* */ +/* INPUT */ +/* */ +/* address_buffer_ptr String holding the IP address */ +/* addr Struct to store the IP address*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful conversion */ +/* NX_SOC_ERROR Error during conversion */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_isdigit Indicate char is a number */ +/* isspace Indicate char is a space */ +/* islower Indicate char is lowercase */ +/* htonl Convert to network byte order */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT inet_aton(const CHAR *address_buffer_ptr, struct in_addr *addr) +{ +ULONG value; +INT base = 10, ip_address_index; +UCHAR tempchar; +const UCHAR *buffer_ptr; +UINT ip_address_number[4]; /* Four discreet numbers in IP address representation. */ +UINT *ip_number_ptr; /* IP address as equivalent ULONG value. */ +UINT dot_flag; + + /* Set local variables. */ + buffer_ptr = (const UCHAR *) address_buffer_ptr; + ip_number_ptr = ip_address_number; + + tempchar = *buffer_ptr; + + /* Check for an invalid first character. */ + if (nx_bsd_isdigit(tempchar)== NX_FALSE) + { + return (0); + } + + dot_flag = 1; + + /* Parse the rest of the characters from the input number. */ + do + { + + /* Initialize the (next) extracted IP address number to zero. */ + value = 0; + + if(dot_flag== 1) + { + /* Initialize the numeric base to decimal unless we determine hex or octal. */ + base = 10; + + /* Determine which number base the input number buffer is. */ + if (*buffer_ptr == '0') + { + /* Get the next character. */ + buffer_ptr++; + + /* A leading 0 followed by an 'x' indicates this is hexidecimal. */ + if ((*buffer_ptr== 'x') || (*buffer_ptr == 'X')) + { + base = 16; + + /* Move ahead one character past the leading '0x' */ + buffer_ptr++; + } + else + { + /* This is octal. */ + base = 8; + buffer_ptr--; + } + } + } + + tempchar = *buffer_ptr; + + /* Parse characters making up the next word. */ + while (*buffer_ptr != '\0') + { + /* Check if the next character is a decimal or octal digit. */ + if (nx_bsd_isdigit(tempchar)) + { + + dot_flag = 0; + + /* Convert the tempchar character to a number. Multiply the existing + number by the base (8 or 10) and this digit to the sum. */ + value = (value * (ULONG)base) + (ULONG)(tempchar - '0'); + + /* Advance the IP address pointer to the next character. */ + buffer_ptr++; + + /* Get the next character. */ + tempchar = *buffer_ptr; + } + /* Else check if we are expecting a hexidecimal number. */ + else if (nx_bsd_isxdigit(tempchar)) + { + /* We are; Verify the base is 16. */ + if(base == 16) + { + + /* It is. handle upper or lower case hex digit. */ + CHAR c = (CHAR)(nx_bsd_islower(tempchar) ? 'a' : 'A'); + + dot_flag = 0; + + /* Convert the hex character to a hex digit, multiply the existing word by shifting the bits, + and add this hex digit to the sum. */ + value = (value << 4) + (ULONG)(tempchar + 10 - c); + + buffer_ptr++; + + /* Get the next character. */ + tempchar = *buffer_ptr; + } + else + { + /* Not a valid hex character. */ + return (0); + } + } + else + { + /* We have reached a number separator or possibly end of the string. */ + break; + } + } + + /* At the end of the current word. Is this a separator character? */ + if (*buffer_ptr == '.') + { + + dot_flag = 1; + + /* Yes, check for an invalid number (cannot exceed 255 or 0xFF. */ + if (value > 0xff) + { + return (0); + } + + /* Check that the pointer to the last extracted number does not exceed the array holding the IP address numbers. */ + if (ip_number_ptr >= (ip_address_number + 3)) + { + return (0); + } + + /* Copy the computed value into the IP address number buffer. */ + *ip_number_ptr = value; + + /* Move the pointer to where we will store the next number extracted. */ + ip_number_ptr++; + + /* Move to the next character in the IP address string. */ + buffer_ptr++; + } + /* Check for non digit or seperator character indicating (maybe) end of the buffer. */ + else + break; + + } while (1); + + /* If this is not a null terminating character, check for invalid trailing characters. */ + if (*buffer_ptr) + { + + if((*buffer_ptr != '\0') && (!nx_bsd_isspace(*buffer_ptr))) + { + + return (0); + } + } + + /* IP addresses are grouped as A, B, C, or D types. Determine which + type address we have by comparing the IP address value against...*/ + + /* Determine this by substracting the pointer to beginning of the whole + IP address number ip_number_ptr[4] against the pointer to the last extracted word, ip_address_number. */ + ip_address_index = ip_number_ptr - ip_address_number + 1; + + /* Check for an invalid array index (assume 'the array' is indexed 1-4). */ + if ((ip_address_index == 0) || (ip_address_index > 4)) + { + return (0); + } + + /* Sum each of the individual IP address numbers depending how many there were extracted. */ + + /* Most common input... */ + if (ip_address_index == 4) + { + INT i; + + /* Three separators parsed, so the format is a.b.c.d where c is 8 bits */ + + /* Check for a computed sum greater than can be contained in 8 bits. */ + if (value > 0xff) + return (0); + + /* 'Add' the last extracted number by prepending the three other bytes onto the total value. */ + for (i = 0; i<=2; i++) + { + value |= ip_address_number[i] << (24 - (i*8)); + } + } + /* Most common input... */ + else if (ip_address_index == 1) + { + + /* We are done, this address contained one 32 bit word (no separators). */ + } + /* Less common input... */ + else if (ip_address_index == 2) + { + /* One separator, so the format is a.b where b is 24 bits */ + + /* Check for a computed sum greater than can be contained in 24 bits. */ + if (value > 0xffffff) + return (0); + + /* 'Add' the last extracted number by prepending the most significant byte onto the total value. */ + value |= (ip_address_number[0] << 24); + } + else if (ip_address_index == 3) + { + /* Two separators parsed, so the format is a.b.c where c is 16 bits */ + INT i; + + /* Check for a computed sum greater than can be contained in 16 bits. */ + if (value > 0xffff) + return (0); + + /* 'Add' the last extracted number by prepending the two most significant bytes onto the total value. */ + for (i = 0; i<=1; i++) + { + value |= ip_address_number[i] << (24 - (i*8)); + } + } + + /* Check if a return pointer for the address data is supplied. */ + if (addr) + { + + /* Convert the IP address data to network byte order and return the data. */ + addr->s_addr = htonl(value); + } + + return (1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_addr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IP address string to a number. If it */ +/* detects an error in the conversion it returns a zero address. */ +/* */ +/* INPUT */ +/* */ +/* buffer IP address text buffer */ +/* address Converted address number */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful conversion */ +/* NX_SOC_ERROR Error during conversion */ +/* */ +/* CALLS */ +/* */ +/* inet_aton Indicate char is a space */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +in_addr_t inet_addr(const CHAR *buffer) +{ + +struct in_addr ip_address; +UINT status; + + status = (UINT)inet_aton(buffer, &ip_address); + + if (status == 0) + { + return (0xFFFFFFFF); + } + + return(ip_address.s_addr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* getsockopt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the status of the specified socket option in */ +/* the current BSD socket session. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* option_level Category of option (SOCKET) */ +/* option_name Socket option ID */ +/* option_value Pointer to option value */ +/* option_value Pointer to size of value */ +/* */ +/* OUTPUT */ +/* */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLS */ +/* */ +/* NX_SOC_OK Request processed successfully*/ +/* NX_SOC_ERROR Errors with request */ +/* (option data) Pointer to requested data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT getsockopt(INT sockID, INT option_level, INT option_name, VOID *option_value, INT *option_length) +{ + +TX_INTERRUPT_SAVE_AREA + +INT status; +NX_BSD_SOCKET *bsd_socket_ptr; +struct sock_errno *so_errno; +struct sock_keepalive *so_keepalive; +struct sock_reuseaddr *so_reuseaddr; +struct timeval *so_rcvtimeval; +struct sock_winsize *soc_window_size; +ULONG ticks; + + + /* Check for valid socket ID/descriptor. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check for invalid input. */ + if((option_value == NX_NULL) || (option_length == NX_NULL)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if (option_level == IPPROTO_IP) + { + + if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + else if(option_level == SOL_SOCKET) + { + + if((option_name > SO_MAX) || (option_name < SO_MIN)) + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + else + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Get the protection mutex. */ + status = (INT)tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Setup pointer to socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + status = NX_SOC_OK; + switch (option_name) + { + + case SO_ERROR: + { + + /* If a valid option pointer was supplied, verify it points to a valid data size. */ + if (*option_length < (INT)sizeof(so_errno -> error)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + so_errno = (struct sock_errno *)option_value; + + TX_DISABLE + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + so_errno -> error = bsd_socket_ptr -> nx_bsd_socket_error_code; + + /* Now clear the error code. */ + bsd_socket_ptr -> nx_bsd_socket_error_code = 0; + + /* Clear the error flag. The application is expected to close the socket at this point.*/ + bsd_socket_ptr -> nx_bsd_socket_status_flags = bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); + } + else + so_errno -> error = 0; + TX_RESTORE + + /* Set the actual size of the data returned. */ + *option_length = sizeof(struct sock_errno); + + } + + break; + + case SO_KEEPALIVE: + + /* Determine if NetX Duo supports keepalive. */ + + /* Check to make sure the size arguement is sufficient if supplied. */ + if (*option_length < (INT)sizeof(so_keepalive -> keepalive_enabled)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + so_keepalive = (struct sock_keepalive *)option_value; +#ifndef NX_ENABLE_TCP_KEEPALIVE + so_keepalive -> keepalive_enabled = NX_FALSE; +#else + so_keepalive -> keepalive_enabled = (INT)(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled); +#endif /* NX_ENABLE_TCP_KEEPALIVE */ + *option_length = sizeof(struct sock_keepalive); + + break; + + case SO_RCVTIMEO: + + /* Check if the receive time out is set. */ + if (bsd_socket_ptr -> nx_bsd_option_receive_timeout == 0) + { + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + + } + + so_rcvtimeval = (struct timeval *)option_value; + + ticks = bsd_socket_ptr -> nx_bsd_option_receive_timeout; + + + so_rcvtimeval -> tv_usec = (suseconds_t)(ticks * NX_MICROSECOND_PER_CPU_TICK) % 1000000; + so_rcvtimeval -> tv_sec = (time_t)((ticks * NX_MICROSECOND_PER_CPU_TICK) / 1000000); + *option_length = sizeof(so_rcvtimeval); + + break; + + case SO_RCVBUF: + + soc_window_size = (struct 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); + + break; + + case SO_REUSEADDR: + + /* Check to make sure the size arguement is sufficient if supplied. */ + if (*option_length < (INT)sizeof(so_reuseaddr -> reuseaddr_enabled)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + so_reuseaddr= (struct sock_reuseaddr *)option_value; + so_reuseaddr -> reuseaddr_enabled = bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; + *option_length = sizeof(struct sock_reuseaddr); + + break; + + case IP_MULTICAST_TTL: + + /* Validate the option length. */ + if(*option_length != sizeof(UCHAR)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Verify that the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Make sure socket is UDP type. */ + if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) + { + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + 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); + break; + + default: + + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + /* Unsupported or unknown option. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* setsockopt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the specified socket option in the current BSD*/ +/* socket session to the specified setting. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* option_level Category of option (SOCKET) */ +/* option_name Socket option ID */ +/* option_value Pointer to option value */ +/* option_length Size of option value data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK Request processed successfully*/ +/* NX_SOC_ERROR Errors with request */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT setsockopt(INT sockID, INT option_level, INT option_name, const VOID *option_value, INT option_length) +{ +UINT reuse_enabled; +NX_BSD_SOCKET *bsd_socket_ptr; +ULONG window_size; +ULONG timer_ticks; +struct timeval *time_val; +#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || !defined(NX_DISABLE_IPV4) +INT i; +#endif /* defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || !defined(NX_DISABLE_IPV4) */ +#ifndef NX_DISABLE_IPV4 +struct ip_mreq *mreq; +UINT mcast_interface; +UINT status; +#endif /* NX_DISABLE_IPV4 */ + + + /* Check for valid socket ID. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Error, invalid socket ID. */ + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check for invalid paremters. */ + if((option_value == NX_NULL) || (option_length == 0)) + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if (option_level == IPPROTO_IP) + { + + if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) + { + + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + else if(option_level == SOL_SOCKET) + { + + if((option_name > SO_MAX) || + (option_name < SO_MIN)) + { + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + } + else + { + /* Error, one or more invalid arguments. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Set up pointer to the BSD socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Set the socket option status. */ + switch (option_name) + { + + case SO_BROADCAST: + + /* This is the default behavior of NetX. All sockets have this capability. */ + break; + + case SO_KEEPALIVE: + + /* Only available to TCP BSD sockets. */ + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + + /* Verify TCP keep alive is built into the NetX library or return an error. */ +#ifndef NX_ENABLE_TCP_KEEPALIVE + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; +#else + /* Determine if NetX Duo supports keepalive. */ + + /* Update the BSD socket with this attribute. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled = + (UINT)(((struct sock_keepalive *)option_value) -> keepalive_enabled); + + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled == NX_TRUE) + { + + /* Set the keep alive timeout for this socket with the NetX configurable keep alive timeout. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL; + } + else + { + + /* Clear the socket keep alive timeout. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_timeout = 0; + } +#endif /* NX_ENABLE_TCP_KEEPALIVE */ + } + else + { + /* Not a TCP socket. */ + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + break; + + case SO_LINGER: + + /* The Linger socket option is not supported in NetX Duo BSD. */ + + return NX_NOT_ENABLED; + + case SO_SNDTIMEO: + + time_val = (struct timeval *)option_value; + + /* Calculate ticks for the ThreadX Timer. */ + timer_ticks = (ULONG)(time_val -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(time_val -> tv_sec) * NX_IP_PERIODIC_RATE; + + bsd_socket_ptr -> nx_bsd_option_send_timeout = timer_ticks; + + break; + + case SO_RCVTIMEO: + + time_val = (struct timeval *)option_value; + + /* Calculate ticks for the ThreadX Timer. */ + timer_ticks = (ULONG)(time_val -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(time_val -> tv_sec) * NX_IP_PERIODIC_RATE; + + bsd_socket_ptr -> nx_bsd_option_receive_timeout = timer_ticks; + + break; + + case SO_RCVBUF: + + /* Only available to TCP sockets. */ + if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + + window_size = (ULONG)(((struct sock_winsize *)option_value) -> winsize); + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + + + /* If Window scaling feature is enabled, record this user-specified window size. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum = window_size; +#else + /* Otherwise the windows size limit is applied. */ + if(window_size > 65535) + window_size = 65535; + +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Setup the sliding window information. */ + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_default = window_size; + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_current = window_size; + + break; + + case SO_REUSEADDR: + + reuse_enabled = (UINT)(((struct sock_reuseaddr *)option_value) -> reuseaddr_enabled); + + if(reuse_enabled) + bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; + else + bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR); + + break; + + + case TCP_NODELAY: + + /* This is the default behavior of NetX. All sockets have this attribute. */ + + break; + + case IP_MULTICAST_TTL: + + /* Validate the option length. */ + if(option_length != sizeof(UCHAR)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Verify that the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Make sure socket is UDP type. */ + if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + /* Set the TTL value. */ + bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = *(UCHAR*)option_value; + break; + + + case IP_RAW_RX_NO_HEADER: + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + i = *(INT*)option_value; + + if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && + ((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) || (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6))) + { + + if(i) + { + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_RX_NO_HDR; + } + else + { + + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_RX_NO_HDR); + } + } + else +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + { + + set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return NX_SOC_ERROR; + } +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + break; +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + case IP_RAW_IPV6_HDRINCL: + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + i = *(INT*)option_value; + + /* Is this an IPv6 socket? */ + if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && + (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6)) + { + + /* Should the No Header feature be enabled (NX_TRUE)? */ + if(i) + { + + /* Yes, set the flag for no header. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_TX_HDR_INCLUDE; + } + else + { + + /* No, clear the flag for no header. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_TX_HDR_INCLUDE); + } + } + else +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + { + + set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return NX_SOC_ERROR; + } +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + break; +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + +#ifndef NX_DISABLE_IPV4 + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + + /* Validate the option length */ + if(option_length != sizeof(struct ip_mreq)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + mreq = (struct ip_mreq*)option_value; + + /* Make sure the multicast group address is valid. */ + if((mreq -> imr_multiaddr.s_addr & ntohl(NX_IP_CLASS_D_TYPE)) != ntohl(NX_IP_CLASS_D_TYPE)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Verify that the socket is still valid. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Make sure socket is UDP type. */ + if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOPROTOOPT); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Validate that the interface is one of the local IPv4 interfaces. */ + /* We allow imr_interface being zero to indicate the primary interface. */ + mcast_interface = NX_MAX_IP_INTERFACES; + + if(mreq -> imr_interface.s_addr == INADDR_ANY) + { + mcast_interface = 0; + } + else + { + + /* Set the socket error if extended socket options enabled. */ + UINT addr; + + /* Convert the local interface value to host byte order. */ + addr = ntohl(mreq -> imr_interface.s_addr); + + /* Search through the interface table for a matching one. */ + for(i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + if(addr == nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_ip_address) + { + + mcast_interface = (UINT)i; + break; + } + } + } + + if(mcast_interface == NX_MAX_IP_INTERFACES) + { + + /* Did not find a matching interface. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + if(option_name == IP_ADD_MEMBERSHIP) + { + + /* Make sure the IGMP feature is enabled. */ + if(nx_bsd_default_ip -> nx_ip_igmp_packet_receive == NX_NULL) + { + nx_igmp_enable(nx_bsd_default_ip); + } + + /* Join the group. */ + status = nx_igmp_multicast_interface_join(nx_bsd_default_ip, ntohl(mreq -> imr_multiaddr.s_addr), mcast_interface); + } + else + { + + /* Leave group */ + status = nx_igmp_multicast_leave(nx_bsd_default_ip, ntohl(mreq -> imr_multiaddr.s_addr)); + } + + if(status != NX_SUCCESS) + { + + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + break; +#endif /* NX_DISABLE_IPV4 */ + + case IP_HDRINCL: + +#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) && !defined(NX_DISABLE_IPV4) + i = *(INT*)option_value; + /* First verify that raw socket processing is enabled on the IP instance and that this is + an IPv4 thread. */ + if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && + (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET)) + { + + /* Is the option being enabled (NX_TRUE)? */ + if(i) + { + + /* Yes, set the flag bit indicating BSD will append the IP header. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_TX_HDR_INCLUDE; + } + else + { + + /* No, clear the flag bit indicating IP task will append the IP header. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_TX_HDR_INCLUDE); + } + } + else +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + { + + set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + return NX_SOC_ERROR; + } + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + break; +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + default: + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return an error status. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return NX_SOC_ERROR; + } + + /* Socket option successfully updated. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* getsockname PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the socket's primary interface address and */ +/* port. For NetX Duo environments, it returns the address at address */ +/* index 1 into the IP address table; this is where the primary */ +/* interface global IP address is normally located. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* localAddress sockaddr struct to return */ +/* the local address */ +/* addressLength Number of bytes in sockAddr */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT getsockname(INT sockID, struct sockaddr *localAddress, INT *addressLength) +{ + +#ifndef NX_DISABLE_IPV4 +struct sockaddr_in soc_struct; +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 +struct sockaddr_in6 soc6_struct; +#endif +UINT status; +NX_BSD_SOCKET *bsd_socket_ptr; + + + /* Check whether supplied socket ID is valid. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if((localAddress == NX_NULL) || (addressLength == NX_NULL) || (*addressLength == 0)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Setup pointer to socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) + { + /* This socket is not bound yet. Just return. + According to the spec, if the socket is not bound, the value stored in + localAddress is unspecified. */ + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Success! */ + return(NX_SOC_OK); + } + +#ifndef NX_DISABLE_IPV4 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + { + soc_struct.sin_addr.s_addr = INADDR_ANY; + } + else if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) + { + + set_errno(EINVAL); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + else + { + NX_INTERFACE* local_if = (NX_INTERFACE*)(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface); + soc_struct.sin_addr.s_addr = htonl(local_if -> nx_interface_ip_address); + } + soc_struct.sin_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_local_port); + + soc_struct.sin_family = AF_INET; + + if((*addressLength) > (INT)sizeof(struct sockaddr_in)) + { + *addressLength = sizeof(struct sockaddr_in); + } + memcpy(localAddress, &soc_struct, (UINT)(*addressLength)); + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + + if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + { + soc6_struct.sin6_addr._S6_un._S6_u32[0] = 0; + soc6_struct.sin6_addr._S6_un._S6_u32[1] = 0; + soc6_struct.sin6_addr._S6_un._S6_u32[2] = 0; + soc6_struct.sin6_addr._S6_un._S6_u32[3] = 0; + } + else if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) + { + + set_errno(EINVAL); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + else + { + NXD_IPV6_ADDRESS* local_v6if = (NXD_IPV6_ADDRESS*)(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface); + + soc6_struct.sin6_addr._S6_un._S6_u32[0] = htonl(local_v6if -> nxd_ipv6_address[0]); + soc6_struct.sin6_addr._S6_un._S6_u32[1] = htonl(local_v6if -> nxd_ipv6_address[1]); + soc6_struct.sin6_addr._S6_un._S6_u32[2] = htonl(local_v6if -> nxd_ipv6_address[2]); + soc6_struct.sin6_addr._S6_un._S6_u32[3] = htonl(local_v6if -> nxd_ipv6_address[3]); + } + + soc6_struct.sin6_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_local_port); + + soc6_struct.sin6_family = AF_INET6; + + if((*addressLength) > (INT)sizeof(struct sockaddr_in6)) + { + *addressLength = sizeof(struct sockaddr_in6); + } + memcpy(localAddress, &soc6_struct, (UINT)(*addressLength)); + + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + set_errno(EPROTONOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Success! */ + return(NX_SOC_OK); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* getpeername PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the socket's remote address and port. */ +/* */ +/* INPUT */ +/* */ +/* sockID socket descriptor */ +/* localAddress sockaddr struct to return */ +/* the remote address */ +/* addressLength Number of bytes in sockAddr */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK (0) On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT getpeername(INT sockID, struct sockaddr *remoteAddress, INT *addressLength) +{ + +UINT status; +NX_BSD_SOCKET *bsd_socket_ptr; +#ifndef NX_DISABLE_IPV4 +struct sockaddr_in *soc_struct_ptr = NX_NULL; +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 +struct sockaddr_in6 *soc6_struct_ptr = NX_NULL; +#endif + + + /* Check whether supplied socket ID is valid. */ + if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Error, invalid socket ID. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + /* Normalize the socket ID. */ + sockID = sockID - NX_BSD_SOCKFD_START; + + /* Check the remote address and length pointers. */ + if((remoteAddress == NX_NULL) ||(addressLength == NX_NULL)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Error getting the protection mutex. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(ERROR); + } + + /* Setup pointer to socket. */ + bsd_socket_ptr = &nx_bsd_socket_array[sockID]; + +#ifndef NX_DISABLE_IPV4 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* This is an IPv4 only socket. */ + + /* Now validate the size of remoteAddress structure. */ + if(*addressLength < (INT)sizeof(struct sockaddr_in)) + { + + /* User supplied buffer is too small .*/ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if socket enabled with extended BSD features. */ + set_errno(ESOCKTNOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + soc_struct_ptr = (struct sockaddr_in*)remoteAddress; + *addressLength = sizeof(struct sockaddr_in); + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + /* IPv6 socket */ + + /* Now validate the size of remoteAddress structure. */ + if(*addressLength < (INT)sizeof(struct sockaddr_in6)) + { + + /* User supplied buffer is too small .*/ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if socket enabled with extended BSD features. */ + set_errno(ESOCKTNOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + soc6_struct_ptr = (struct sockaddr_in6*)remoteAddress; + *addressLength = sizeof(struct sockaddr_in6); + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Not a valid address family. */ + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if socket enabled with extended BSD features. */ + set_errno(ESOCKTNOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + /* Is the socket still in use? */ + if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Error, socket not in use anymore. */ + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + /* Check whether TCP or UDP */ + if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) + { + +#ifndef NX_DISABLE_IPV4 + /* TCP Socket. Determine socket family type. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + soc_struct_ptr -> sin_family = AF_INET; + soc_struct_ptr -> sin_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); + soc_struct_ptr -> sin_addr.s_addr = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4); + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + + soc6_struct_ptr -> sin6_family = AF_INET6; + soc6_struct_ptr -> sin6_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); + soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[0] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]); + soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[1] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]); + soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[2] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]); + soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[3] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]); + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error if extended options enabled. */ + set_errno(EBADF); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + + } + } + else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) + { + +#ifndef NX_DISABLE_IPV4 + /* UDP Socket. Get Peer Name doesn't apply to UDP sockets. Only fill in AF family information.*/ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + soc_struct_ptr -> sin_family = AF_INET; + soc_struct_ptr -> sin_port = 0; + soc_struct_ptr -> sin_addr.s_addr = 0; + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) + { + soc6_struct_ptr -> sin6_family = AF_INET6; + soc6_struct_ptr -> sin6_port = 0; + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if socket enabled with extended BSD features. */ + set_errno(ESOCKTNOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + + } + } + else + { + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Set the socket error, if socket enabled with extended BSD features. */ + set_errno(ESOCKTNOSUPPORT); + + /* Return error. */ + NX_BSD_ERROR(ERROR, __LINE__); + return(ERROR); + } + + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Success! */ + return(NX_SOC_OK); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* select PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows for sockets to be checked for incoming packets.*/ +/* nfds should be one greater than value of the largest valued socket */ +/* descriptor in any of the lists. If you don't wish to calculate this,*/ +/* use FD_SETSIZE instead.For small numbers of sockets,select() will be*/ +/* less efficient if FD_SETSIZE is passed.If the bit corresponding to */ +/* a socket in an fd_set is set,that socket will be checked for the */ +/* condition the fd_set corresponds to.If the condition they are */ +/* checked for is true, they will still be set to true when select() */ +/* returns (otherwise they will be set to false). */ +/* Note that the sets are modified by select():thus they must be reset */ +/* between each call to the function. */ +/* */ +/* fd_sets can be manipulated using the following macros or functions: */ +/* */ +/* FD_SET(fd, fdset) Sets socket fd in fdset to true. */ +/* FD_CLR(fd, fdset) Sets socket fd in fdset to false. */ +/* FD_ISSET(fd, fdset)Returns true if socket fd is set to true in fdset*/ +/* FD_ZERO(fdset) Sets all the sockets in fdset to false. */ +/* */ +/* If the input timeout is NULL, select() blocks until one of the */ +/* sockets receives a packet. If the timeout is non-NULL, select waits */ +/* for the specified time and returns regardless if any socket has */ +/* received a packet. Otherwise as soon as a socket receives a packet */ +/* this function will return immediately. */ +/* */ +/* To use select() in non-blocking mode call it with a non-null timeout*/ +/* input but set tv_sec and tv_usec to zero, in Unix fashion. */ +/* */ +/* select() returns the number of sockets for which the specified */ +/* conditions are true. If it encounters an error, it will return -1. */ +/* */ +/* NOTE: ****** When select returns NX_SOC_ERROR it won't update */ +/* the readfds descriptor. */ +/* */ +/* INPUT */ +/* */ +/* nfds Maximum socket descriptor # */ +/* fd_set *readFDs List of read ready sockets */ +/* fd_set *writeFDs List of write ready sockets */ +/* fd_set *exceptFDs List of exceptions */ +/* struct timeval *timeOut */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS No descriptors read */ +/* (successful completion) */ +/* status Number of descriptors read */ +/* (< 0 if error occurred) */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* nx_tcp_socket_receive Receive TCP packet */ +/* nx_udp_source_extract Extract source IP and port */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* tx_thread_preemption_change Disable/restore preemption */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT select(INT nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + +INT i; +UINT status; +NX_BSD_SOCKET_SUSPEND suspend_request; +NX_PACKET *packet_ptr; +fd_set readfds_found; +fd_set writefds_found; +fd_set exceptfds_found; +INT readfds_left; +INT writefds_left; +INT exceptfds_left; +ULONG ticks; +UINT original_threshold; +TX_THREAD *current_thread_ptr; +INT ret; + + + /* Check for valid input parameters. */ + if ((readfds == NX_NULL) && (writefds == NX_NULL) && (exceptfds == NX_NULL) && (timeout == NX_NULL)) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Check the maximum number of file descriptors. */ + if((nfds < (NX_BSD_SOCKFD_START + 1)) || (nfds >= (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START + 1))) + { + + /* Set the socket error */ + set_errno(EBADF); + + /* Return an error. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Clear the read and the write selector set. */ + FD_ZERO(&readfds_found); + FD_ZERO(&writefds_found); + FD_ZERO(&exceptfds_found); + + if(readfds) + readfds_left = readfds -> fd_count; + else + readfds_left = 0; + + if(writefds) + { + + writefds_left = writefds -> fd_count; + } + else + { + + writefds_left = 0; + } + + if(exceptfds) + { + + exceptfds_left = exceptfds -> fd_count; + } + else + { + + exceptfds_left = 0; + } + + /* Compute the timeout for the suspension if a timeout value was supplied. */ + if (timeout != NX_NULL) + { + + /* Calculate ticks for the ThreadX Timer. */ + ticks = (ULONG)(timeout -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(timeout -> tv_sec) * NX_IP_PERIODIC_RATE; + } + else + { + + /* If no timeout input, set the wait to 'forever.' */ + ticks = TX_WAIT_FOREVER; + } + + /* Get the protection mutex. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Set the socket error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Loop through the BSD sockets to see if the read ready request can be satisfied. */ + for (i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) + { + + if((readfds == NX_NULL) || (readfds_left == 0)) + break; + + /* Is this socket selected for read? */ + if (FD_ISSET((i + NX_BSD_SOCKFD_START), readfds)) + { + + /* Yes, decrement the number of read selectors left to search for. */ + readfds_left--; + + /* Is this BSD socket in use? */ + if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* There is; add this socket to the read ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + + /* Check to see if there is a disconnection request pending. */ + else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_DISCONNECTION_REQUEST) + { + + /* There is; add this socket to the read ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + + /* Check to see if there is a receive packet pending. */ + else if (nx_bsd_socket_array[i].nx_bsd_socket_received_packet) + { + + /* Therer is; add this socket to the read ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + /* Is this a TCP socket? */ + else if (nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket) + { + /* Check if this is a master socket and if its associated secondary socket + is connected. If it is, the master socket should be considered readable. */ + if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) + { + + if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) + { + + /* If the secondary socket does not exist, try to allocate one. */ + if(nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id >= NX_BSD_MAX_SOCKETS) + { + + /* This secondary socket is not avaialble yet. This could happen if the + previous accept call fails to allocate a new secondary socket. */ + ret = nx_bsd_tcp_create_listen_socket(i, 0); + + if(ret < 0) + { + + /* Mark the FD set so the application could be notified. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + } + + if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) + { + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + } + } + else if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) + { + + /* Yes; attempt to perform a non-blocking read. */ + status = nx_tcp_socket_receive(nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket, &packet_ptr, TX_NO_WAIT); + + /* Check for success. */ + if (status == NX_SUCCESS) + { + + /* Save the received packet in the TCP BSD socket packet pointer. */ + nx_bsd_socket_array[i].nx_bsd_socket_received_packet = packet_ptr; + + /* Reset the packet offset. */ + nx_bsd_socket_array[i].nx_bsd_socket_received_packet_offset = 0; + + /* Increase the received count. */ + nx_bsd_socket_array[i].nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + nx_bsd_socket_array[i].nx_bsd_socket_received_packet_count++; + + /* Add this socket to the read ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + } + } +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + /* Is this a raw socket? */ + else if (nx_bsd_socket_array[i].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) + { + + /* Check the raw receive queue (by definition has a zero wait option (no suspension)). */ + status = nx_bsd_raw_packet_receive(&nx_bsd_socket_array[i], &packet_ptr); + + /* Determine if we have a packet. */ + if ((status == NX_SUCCESS) && (packet_ptr)) + { + + /* Get the sender IP address from the raw packet. */ + status = nx_bsd_raw_packet_info_extract(packet_ptr, &(nx_bsd_socket_array[i].nx_bsd_socket_source_ip_address), NX_NULL); + + /* Save the received packet in the BSD socket packet pointer. */ + nx_bsd_socket_array[i].nx_bsd_socket_received_packet = packet_ptr; + + /* Reset the packet offset. */ + nx_bsd_socket_array[i].nx_bsd_socket_received_packet_offset = 0; + + /* Add this socket to the read ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); + } + } +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + } + } + /* Loop through the BSD sockets to see if the write ready request can be satisfied. */ + for(i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) + { + + if((writefds == NX_NULL) || (writefds_left == 0)) + break; + + /* Is this socket selected for write? */ + if (FD_ISSET(i + NX_BSD_SOCKFD_START, writefds)) + { + + /* Yes, decrement the number of read selectors left to search for. */ + writefds_left--; + + /* Is this BSD socket in use? */ + if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + /* Yes, add this socket to the write ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); + } + + /* Check to see if there is a connection request pending. */ + else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_REQUEST) + { + + /* Yes, add this socket to the write ready list. */ + FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); + } + + /* Check to see if there is an error.*/ + else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + + FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); + } + } + } + + /* Loop through the BSD sockets to see if the exception request can be satisfied. */ + for(i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) + { + + if((exceptfds == NX_NULL) || (exceptfds_left == 0)) + break; + + /* Is this socket selected for exceptions? */ + if (FD_ISSET(i + NX_BSD_SOCKFD_START, exceptfds)) + { + + /* Yes, decrement the number of read selectors left to search for. */ + exceptfds_left--; + + /* Is this BSD socket in use? */ + if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + FD_SET(i + NX_BSD_SOCKFD_START, &exceptfds_found); + } + + /* Check to see if there is an error.*/ + else if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) + { + + FD_SET(i + NX_BSD_SOCKFD_START, &exceptfds_found); + } + } + } + + /* Now determine if we have found anything that satisfies the select request. */ + if (readfds_found.fd_count || writefds_found.fd_count || exceptfds_found.fd_count) + { + + /* Yes, return what we have and we're done. */ + + /* Copy over the requested read ready fds. */ + if(readfds) + *readfds = readfds_found; + + if(writefds) + *writefds = writefds_found; + + if(exceptfds) + *exceptfds = exceptfds_found; + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + /* Return the number of fds found. */ + return(readfds_found.fd_count + writefds_found.fd_count + exceptfds_found.fd_count); + } + + /* Otherwise, nothing is ready to be read at this point. */ + + /* Pickup the current thread. */ + current_thread_ptr = tx_thread_identify(); + + /* Save the fd requests in the local suspension structure. This will be used by the receive notify routines to + wakeup threads on the select. */ + suspend_request.nx_bsd_socket_suspend_actual_flags = 0; + + if(readfds) + suspend_request.nx_bsd_socket_suspend_read_fd_set = *readfds; + else + FD_ZERO(&suspend_request.nx_bsd_socket_suspend_read_fd_set); + + if(writefds) + suspend_request.nx_bsd_socket_suspend_write_fd_set = *writefds; + else + FD_ZERO(&suspend_request.nx_bsd_socket_suspend_write_fd_set); + + if(exceptfds) + suspend_request.nx_bsd_socket_suspend_exception_fd_set = *exceptfds; + else + FD_ZERO(&suspend_request.nx_bsd_socket_suspend_exception_fd_set); + + /* Temporarily disable preemption. */ + tx_thread_preemption_change(current_thread_ptr, 0, &original_threshold); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + status = tx_event_flags_get(&nx_bsd_events, NX_BSD_SELECT_EVENT, TX_OR_CLEAR, (ULONG *) &suspend_request, ticks); + + /* Restore original preemption threshold. */ + tx_thread_preemption_change(current_thread_ptr, original_threshold, &original_threshold); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* If we got here, we received no packets. */ + + /* TX_NO_EVENT implies an immediate return from the flag get call. + This happens if the wait option is set to zero. */ + if (status == TX_NO_EVENTS) + { + + /* Determine if the effected sockets are non blocking (zero ticks for the wait option). */ + if (ticks == 0) + set_errno(EWOULDBLOCK); + else + set_errno(ETIMEDOUT); + + /* Do not handle as an error; just a timeout so return 0. */ + return(0); + } + else + { + + /* Actual error. */ + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + /* Error getting the protection mutex. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + else + { + + /* Otherwise, a receive event has been found. Simply copy the receive events. */ + if(readfds) + *readfds = suspend_request.nx_bsd_socket_suspend_read_fd_set; + if(writefds) + *writefds = suspend_request.nx_bsd_socket_suspend_write_fd_set; + if(exceptfds) + *exceptfds = suspend_request.nx_bsd_socket_suspend_exception_fd_set; + + /* Return the number of fds. */ + return(suspend_request.nx_bsd_socket_suspend_read_fd_set.fd_count + + suspend_request.nx_bsd_socket_suspend_write_fd_set.fd_count + + suspend_request.nx_bsd_socket_suspend_exception_fd_set.fd_count); + } + + +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the NetX callback function for TCP Socket receive operation */ +/* This function resumes all the threads suspended on the socket. */ +/* */ +/* INPUT */ +/* */ +/* *socket_ptr Pointer to the socket which */ +/* received the data packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_tcp_receive_notify(NX_TCP_SOCKET *socket_ptr) +{ +UINT bsd_socket_index; + + /* Figure out what BSD socket this is. */ + bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Determine if this is a good index into the BSD socket array. */ + if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) + { + + /* Bad socket index... simply return! */ + return; + } + + /* Now check if the socket may have been released (e.g. socket closed) while + waiting for the mutex. */ + if( socket_ptr -> nx_tcp_socket_id == 0 ) + { + + return; + } + + /* Check the suspended socket list for one ready to receive or send packets. */ + nx_bsd_select_wakeup(bsd_socket_index, FDSET_READ); + + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_establish_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the NetX callback function for TCP Server Socket listen. */ +/* This function resumes all the threads suspended on the socket. */ +/* */ +/* INPUT */ +/* */ +/* *socket_ptr Pointer to the socket which */ +/* Received the data packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +static VOID nx_bsd_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr) +{ +UINT bsd_socket_index; +UINT master_socket_index; + + /* Figure out what BSD socket this is. */ + bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Determine if this is a good index into the BSD socket array. */ + if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) + { + + /* Bad socket index... simply return! */ + return; + } + + /* Initialize the master socket index to an invalid value so we can check if it was actually used + later. */ + master_socket_index = NX_BSD_MAX_SOCKETS; + + /* Mark the socket as connected, and also clear the EINPROGRESS flag */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; + + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; + + /* Reset the listen-enabled flag. */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_LISTEN); + + /* Mark the socket is bound. */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; + +#ifndef NX_DISABLE_IPV4 + /* Find out the local address this socket is connected on. */ + if(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_family == AF_INET) + { + /* IPv4 case */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_local_bind_interface = (ULONG)socket_ptr -> nx_tcp_socket_connect_interface; + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_family == AF_INET6) + { + /* IPv6 */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_local_bind_interface = (ULONG)socket_ptr -> nx_tcp_socket_ipv6_addr; + } +#endif + /* Determine if the BSD socket is server socket. */ + + + /* Is this a secondary socket? */ + if (nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) + { + + /* Yes, get the master socket. */ + master_socket_index = (UINT)(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id); + + /* Mark the server socket as also connected. */ + nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; + + nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; + + /* Check on connect requests for all server sockets for this master socket. */ + nx_bsd_select_wakeup(master_socket_index, FDSET_READ); + } + else + { + /* This is a client socket. */ + nx_bsd_select_wakeup(bsd_socket_index, FDSET_WRITE); + } +} +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_socket_disconnect_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the NetX callback function for TCP Socket disconnect. */ +/* This function resumes all the BSD threads suspended on the socket. */ +/* */ +/* INPUT */ +/* */ +/* *socket_ptr Pointer to the socket which */ +/* received the data packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_tcp_socket_disconnect_notify(NX_TCP_SOCKET *socket_ptr) +{ + +UINT bsd_socket_index; +UINT master_socket_index; +NX_BSD_SOCKET *bsd_socket_ptr; +UINT status; + + + /* Figure out what BSD socket this is. */ + bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Determine if this is a good index into the BSD socket array. */ + if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) + { + /* No good! */ + return; + } + + bsd_socket_ptr = &nx_bsd_socket_array[bsd_socket_index]; + + /* If the socket already received a disconnect request, no need to do anything here. */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_DISCONNECTION_REQUEST) + { + return; + } + + /* Mark this socket as having a disconnect request pending. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_DISCONNECTION_REQUEST; + + /* Is the socket trying to make a connection? */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) + { + + /* Yes, clear the INPROGRESS flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); + + /* If this is secondary server socket, there is no need to wake up the select call. */ + if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) + { + + + /* Instead the socket needs to be cleaned up and to perform a relisten. */ + if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED)) + { + + /* Turn off the disconnection_request flag. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_DISCONNECTION_REQUEST); + + nx_tcp_server_socket_unaccept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + + /* Check if a listen request is queued up for this socket. */ + nx_bsd_tcp_pending_connection(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + + status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, + bsd_socket_ptr -> nx_bsd_socket_tcp_socket); + + /* Force the socket into SYN_RECEIVED state */ + nx_tcp_server_socket_accept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket, NX_NO_WAIT); + + if(status == NX_CONNECTION_PENDING) + { + + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; + } + else if(status != NX_SUCCESS) + { + + /* Failed the relisten on the secondary socket. Set the error code on the + master socket, and wake it up. */ + + master_socket_index = (UINT)(bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id; + + nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + nx_bsd_set_error_code(&nx_bsd_socket_array[master_socket_index], status); + + nx_bsd_select_wakeup(master_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); + } + } + + } + else + { + + /* Set error code. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + bsd_socket_ptr -> nx_bsd_socket_error_code = ECONNREFUSED; + + /* Wake up the select on both read and write FDsets. */ + nx_bsd_select_wakeup(bsd_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); + } + } + else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) + { + + /* Wake up the select on both read and write FDsets. */ + nx_bsd_select_wakeup(bsd_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); + } + else + { + + /* In this case, connection reaches maximum retries or is refused by peer. */ + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; + bsd_socket_ptr -> nx_bsd_socket_error_code = ENOTCONN; + } + +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_udp_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the NetX callback function for UDP Socket receive */ +/* operation. */ +/* */ +/* INPUT */ +/* */ +/* *socket_ptr Pointer to the socket which */ +/* Received the data packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* nx_udp_socket_receive Receive UDP packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + +UINT bsd_socket_index; +NX_PACKET *packet_ptr; +NX_UDP_SOCKET *udp_socket_ptr; + + + /* Figure out what BSD socket this is. */ + bsd_socket_index = ((UINT) socket_ptr -> nx_udp_socket_reserved_ptr) & 0x0000FFFF; + + /* Determine if this is a good index into the BSD socket array. */ + if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) + { + return; + } + + udp_socket_ptr = nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_udp_socket; + + if (nx_udp_socket_receive(udp_socket_ptr, &packet_ptr, NX_NO_WAIT)) + { + return; + } + + nx_bsd_udp_packet_received((INT)bsd_socket_index, packet_ptr); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* FD_SET PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a fd to the set. */ +/* */ +/* INPUT */ +/* */ +/* fd fd to add. */ +/* fd_set *fdset fd set. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID FD_SET(INT fd, fd_set *fdset) +{ + +UINT index; + + + /* Check the FD size. */ + if (fd >= NX_BSD_SOCKFD_START) + { + + /* Normalize the fd. */ + fd = fd - NX_BSD_SOCKFD_START; + + /* Now make sure it isn't too big. */ + if (fd < NX_BSD_MAX_SOCKETS) + { + + /* Calculate the index into the bit map. */ + index = (UINT)fd/32; + + /* Now calculate the bit position. */ + fd = fd % 32; + + /* Is the bit already set? */ + if ((fdset -> fd_array[index] & (((ULONG) 1) << fd)) == 0) + { + + /* No, set the bit. */ + fdset -> fd_array[index] = fdset -> fd_array[index] | (((ULONG) 1) << fd); + + /* Increment the counter. */ + fdset -> fd_count++; + } + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* FD_CLR PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes a fd from a fd set. */ +/* */ +/* INPUT */ +/* */ +/* fd fd to remove. */ +/* fd_set *fdset fd set. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID FD_CLR(INT fd, fd_set *fdset) +{ + +UINT index; + + + /* Check the FD size. */ + if (fd >= NX_BSD_SOCKFD_START) + { + + /* Normalize the fd. */ + fd = fd - NX_BSD_SOCKFD_START; + + /* Now make sure it isn't too big. */ + if ((fd < NX_BSD_MAX_SOCKETS) && (fdset -> fd_count)) + { + + /* Calculate the index into the bit map. */ + index = (UINT)fd/32; + + /* Now calculate the bit position. */ + fd = fd % 32; + + /* Determine if the bit is set. */ + if (fdset -> fd_array[index] & (((ULONG) 1) << fd)) + { + + /* Yes, clear the bit. */ + fdset -> fd_array[index] = fdset -> fd_array[index] & ~(((ULONG) 1) << fd); + + /* Decrement the counter. */ + fdset -> fd_count--; + } + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* FD_ISSET PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function tests to see if a fd is in the set. */ +/* */ +/* INPUT */ +/* */ +/* fd fd to add. */ +/* fd_set *fdset fd set. */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE If fd is found in the set. */ +/* NX_FALSE If fd is not there in the set.*/ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT FD_ISSET(INT fd, fd_set *fdset) +{ + +UINT index; + + + /* Check the FD size. */ + if (fd >= NX_BSD_SOCKFD_START) + { + + /* Normalize the fd. */ + fd = fd - NX_BSD_SOCKFD_START; + + /* Now make sure it isn't too big. */ + if (fd < NX_BSD_MAX_SOCKETS) + { + + /* Calculate the index into the bit map. */ + index = (UINT)fd/32; + + /* Now calculate the bit position. */ + fd = fd % 32; + + /* Finally, see if the bit is set. */ + if (fdset -> fd_array[index] & (((ULONG) 1) << fd)) + { + + /* Yes, return true! */ + return(NX_TRUE); + } + } + } + + /* Otherwise, return false. */ + return(NX_FALSE); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* FD_ZERO PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears a fd set. */ +/* */ +/* INPUT */ +/* */ +/* fd_set *fdset fd set to clear. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID FD_ZERO(fd_set *fdset) +{ + +INT i; + + + /* Clear the count. */ + fdset -> fd_count = 0; + + /* Loop to clear the fd set. */ + for (i = 0; i < (NX_BSD_MAX_SOCKETS+31)/32; i++) + { + /* Clear an entry in the array. */ + fdset -> fd_array[i] = 0; + } +} + + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_raw_packet_filter PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives raw packets from NetX Duo and determines if */ +/* BSD will consume the packet (store on the BSD socket raw receive */ +/* queue) or if the packet is available to NetX Duo (not consumed). */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr NetX Duo IP instance */ +/* protocol Received packet protocol */ +/* packet_ptr Pointer to the received packet */ +/* */ +/* OUTPUT */ +/* */ +/* 0 Raw filter consumed the packet*/ +/* 1 Raw filter did not consume */ +/* packet. Allow the caller to*/ +/* process this packet */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_raw_receive_notify Notify threads waiting to */ +/* receive a raw packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_raw_packet_filter(NX_IP *ip_ptr, ULONG protocol, NX_PACKET *packet_ptr) +{ + +UINT index; +NX_BSD_SOCKET * bsd_socket_ptr; + + /* Calculate the hash index in the raw socket protocol table. */ + index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); + + /* Search the bound sockets in this index for particular protocol. */ + bsd_socket_ptr = nx_bsd_socket_raw_protocol_table[index]; + + do + { + /* Determine if the protocol is matched. */ + if ((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && + (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET ) && + (bsd_socket_ptr -> nx_bsd_socket_protocol == protocol)) + { + + /* This packet protocol matches the BSD socket. */ + /* Make sure the queue_next is zero'ed out. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Add the packet to the BSD socket raw packet receive queue. + Are there any packets on this queue yet? */ + if (bsd_socket_ptr -> nx_bsd_socket_received_packet == NX_NULL) + { + + /* No, this will be the only one. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr; + bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; + + + /* Set the packet count. */ + bsd_socket_ptr -> nx_bsd_socket_received_byte_count = packet_ptr -> nx_packet_length; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 1; + } + else + { + /* Yes; add this packet to the end of the queue. */ + + /* Check if the queue is currently full. */ + if (bsd_socket_ptr -> nx_bsd_socket_received_byte_count_max && + (bsd_socket_ptr -> nx_bsd_socket_received_byte_count >= + bsd_socket_ptr -> nx_bsd_socket_received_byte_count_max)) + { + + /* Release the packet here, and tell NetX Duo the packet is 'consumed'. */ + nx_packet_release(packet_ptr); + + return 0; + } + + /* Drop the packet if the receive queue exceeds max depth.*/ + if(bsd_socket_ptr -> nx_bsd_socket_received_packet_count >= + bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max) + { + /* Release the packet here, and tell NetX Duo the packet is 'consumed'. */ + nx_packet_release(packet_ptr); + + return 0; + } + + /* Add this packet to the end of the BSD raw receive queue. */ + (bsd_socket_ptr -> nx_bsd_socket_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; + + + /* Update our packet count. */ + bsd_socket_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count++; + } + + /* Notify any suspended threads waiting on this receive event. */ + nx_bsd_raw_receive_notify(ip_ptr, (UINT)(bsd_socket_ptr -> nx_bsd_socket_id)); + + return 0; + } + + }while(bsd_socket_ptr != nx_bsd_socket_raw_protocol_table[index]); + + /* Was a BSD socket with this protocol found? */ + if (bsd_socket_ptr == nx_bsd_socket_raw_protocol_table[index]) + { + /* No, let NetX Duo know it can discard the packet. */ + return 1; + } + + return(NX_SUCCESS); +} + +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_raw_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the NetX Duo callback function for raw socket receive */ +/* operation. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr NetX Duo IP instance */ +/* bsd_socket_index Index of the raw socket which */ +/* received the data packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Clear a socket ready list */ +/* FD_ISSET Check a socket is ready */ +/* FD_SET Set a socket to check */ +/* tx_event_flags_get Get events */ +/* tx_mutex_get Get protection */ +/* tx_mutex_put Release protection */ +/* tx_thread_identify Get current thread pointer */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID nx_bsd_raw_receive_notify(NX_IP *ip_ptr, UINT bsd_socket_index) +{ + NX_PARAMETER_NOT_USED(ip_ptr); + + nx_bsd_select_wakeup(bsd_socket_index, FDSET_READ); + +} + +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_raw_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves a packet from the BSD raw socket receive */ +/* queue. */ +/* */ +/* INPUT */ +/* */ +/* bsd_socket_ptr BSD raw socket */ +/* packet_ptr Pointer to retrieved packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Packet successfully retrieved */ +/* NX_NO_PACKET No packet on receive queue */ +/* NX_NOT_ENABLED Not enabled for raw packets */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* select Checks for receive packets */ +/* recv Checks the specified socket for */ +/* received packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT nx_bsd_raw_packet_receive(NX_BSD_SOCKET *bsd_socket_ptr, NX_PACKET **packet_ptr) +{ + + + /* Sanity check. Check this is indeed a raw socket. */ + if (!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) + { + /* Set the socket error. */ + set_errno(EPROTOTYPE); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_NOT_ENABLED); + } + + /* Verify this socket is enabled for raw packet processing. */ + if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) + { + + /* Are there any packets on the socket raw receive queue? */ + if (bsd_socket_ptr -> nx_bsd_socket_received_packet != NX_NULL) + { + + /* Yes, return a pointer to the packet at the top of the queue. */ + *packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; + + /* Update the packet count. */ + bsd_socket_ptr -> nx_bsd_socket_received_byte_count -= (*packet_ptr) -> nx_packet_length; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count--; + + + /* Remove this packet from the receive queue and update queue packet pointers. */ + bsd_socket_ptr -> nx_bsd_socket_received_packet = (*packet_ptr) -> nx_packet_queue_next; + + /* If this was the last packet, set the tail pointer to NULL. */ + if (bsd_socket_ptr -> nx_bsd_socket_received_packet == NX_NULL) + { + bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = NX_NULL; + bsd_socket_ptr -> nx_bsd_socket_received_byte_count = 0; + bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 0; + } + } + else + { + + /* No packets on the queue. Return the NetX Duo status. This is an internal call, so no BSD socket error to report. */ + return NX_NO_PACKET; + } + } + else + { + return NX_NOT_ENABLED; + } + + return NX_SUCCESS; +} + +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_raw_packet_info_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the source IP address and interface index */ +/* from the received packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to received raw packet*/ +/* address Pointer to sender IP address */ +/* interface_index Pointer to network index */ +/* packet received on */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* COPY_IPV6_ADDRESS Copy IPv6 address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT nx_bsd_raw_packet_info_extract(NX_PACKET *packet_ptr, NXD_ADDRESS *address, UINT *interface_index) +{ + +NX_INTERFACE *if_ptr = NX_NULL; + + +#ifndef NX_DISABLE_IPV4 + /* Determine what IP version the packet is. */ + if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) + { + + NX_IPV4_HEADER *ip_header_ptr; + + /* Set a pointer to the IPv4 header. */ + ip_header_ptr = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER)); + + /* Fill in the IP address information. */ + address -> nxd_ip_version = NX_IP_VERSION_V4; + address -> nxd_ip_address.v4 = ip_header_ptr -> nx_ip_header_source_ip; + + /* Pick up the packet interface. */ + if_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) + { + + NX_IPV6_HEADER *ipv6_header_ptr; + + ipv6_header_ptr = (NX_IPV6_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV6_HEADER)); + + /* Fill in the IPv6 address information. */ + address -> nxd_ip_version = NX_IP_VERSION_V6; + + /* Copy the IPv6 address. */ + address -> nxd_ip_address.v6[0] = ipv6_header_ptr -> nx_ip_header_source_ip[0]; + address -> nxd_ip_address.v6[1] = ipv6_header_ptr -> nx_ip_header_source_ip[1]; + address -> nxd_ip_address.v6[2] = ipv6_header_ptr -> nx_ip_header_source_ip[2]; + address -> nxd_ip_address.v6[3] = ipv6_header_ptr -> nx_ip_header_source_ip[3]; + + /* Pick up the packet interface. */ + if_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; + } +#endif + + /* The last piece of information is the packet interface. If the return pointer is NULL we are done! */ + if(interface_index == NX_NULL) + return(NX_SUCCESS); + + /* Search for interface index number. Initialize interface value as + invalid (0xFFFFFFFF). Once we find valid interface, we will update + the returned value. */ + *interface_index = 0xFFFFFFFF; + + if(if_ptr == NX_NULL) + { + /* No interface attached. Done here, and return success. */ + return(NX_SUCCESS); + } + + /* Compute the index by difference of the packet's interface from the primary interface, and dividing by the size. */ + *interface_index = if_ptr -> nx_interface_index; + + return(NX_SUCCESS); +} + +#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_set_socket_timed_wait_callback PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when a BSD TCP socket has closed. If the */ +/* BSD socket associated with the TCP socket is not enabled for */ +/* REUSEADDR, this function will put the BSD socket in the TIMED WAIT */ +/* state. */ +/* */ +/* When this time out expires, the BSD socket is removed from the TIME */ +/* WAIT State and available to the host application. */ +/* */ +/* Note: only sockets not enabled with REUSEADDR are placed in the WAIT*/ +/* STATE. All other BSD sockets are immediately available upon closing.*/ +/* */ +/* INPUT */ +/* */ +/* tcp_socket_ptr TCP socket state being closed */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_identify Identify socket owning thread */ +/* tx_mutex_get Obtain BSD mutex protection */ +/* tx_mutex_put Release BSD mutex protection */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID nx_bsd_socket_timed_wait_callback(NX_TCP_SOCKET *tcp_socket_ptr) +{ + NX_PARAMETER_NOT_USED(tcp_socket_ptr); + + /* Logic has been removed elsewhere but for compatibility with + NetX we leave this function stub. */ + + return; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_packet_data_extract_offset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies data from a NetX packet (or packet chain) into */ +/* the supplied user buffer. */ +/* */ +/* This basically defines the data extract service in the BSD source */ +/* code if it is not provided in the NetX or NetX Duo library already. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to the source packet */ +/* buffer_start Pointer to destination data area */ +/* buffer_length Size in bytes */ +/* bytes_copied Number of bytes copied */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifdef NX_BSD_INCLUDE_DATA_EXTRACT_OFFSET +UINT nx_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, ULONG buffer_length, ULONG *bytes_copied) +{ + +ULONG remaining_bytes; +UCHAR *source_ptr; +UCHAR *destination_ptr; +ULONG offset_bytes; +#ifndef NX_DISABLE_PACKET_CHAIN +ULONG packet_fragment_length; +#endif +ULONG bytes_to_copy; +NX_PACKET *working_packet_ptr; + + working_packet_ptr = packet_ptr; + + /* Check for an invalid offset or packet length. */ + if(offset >= working_packet_ptr -> nx_packet_length) + { + /* Note: A zero offset with a packet of zero length is ok. */ + if ((offset == 0) && (working_packet_ptr -> nx_packet_length == 0)) + { + *bytes_copied = 0; + return(NX_SUCCESS); + } + + /* Otherwise, this is an invalid offset or packet length. */ + return(NX_PACKET_OFFSET_ERROR); + } + + /* Initialize the source pointer to NULL. */ + source_ptr = NX_NULL; + + /* Traverse packet chain to offset. */ + offset_bytes = offset; +#ifndef NX_DISABLE_PACKET_CHAIN + while (working_packet_ptr) + { + packet_fragment_length = (working_packet_ptr -> nx_packet_append_ptr - working_packet_ptr -> nx_packet_prepend_ptr) ; + + /* Determine if we are at the offset location fragment in the packet chain */ + if (packet_fragment_length > offset_bytes) + { + /* Setup loop to copy from this packet. */ + source_ptr = working_packet_ptr -> nx_packet_prepend_ptr + offset_bytes; + + /* Yes, get out of this loop. */ + break; + } + + /* Decrement the remaining offset bytes*/ + offset_bytes = offset_bytes - packet_fragment_length ; + + /* Move to next packet. */ + working_packet_ptr = working_packet_ptr -> nx_packet_next; + } +#else /* NX_DISABLE_PACKET_CHAIN */ + + /* Setup loop to copy from this packet. */ + source_ptr = working_packet_ptr -> nx_packet_prepend_ptr + offset_bytes; + +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Check for a valid source pointer. */ + if (source_ptr == NX_NULL) + return(NX_PACKET_OFFSET_ERROR); + + /* Setup the destination pointer. */ + destination_ptr = buffer_start; + bytes_to_copy = (packet_ptr->nx_packet_length - offset); + + /* Pickup the amount of bytes to copy. */ + if( bytes_to_copy < buffer_length) + { + *bytes_copied = bytes_to_copy; /* the amount of bytes returned to the caller */ + remaining_bytes = bytes_to_copy; /* for use in the copy loop */ + } + else + { + *bytes_copied = buffer_length; + remaining_bytes = buffer_length; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Loop to copy bytes from packet(s). */ + while (working_packet_ptr && remaining_bytes) + { +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Calculate bytes to copy. */ + bytes_to_copy = working_packet_ptr -> nx_packet_append_ptr - source_ptr; + if(remaining_bytes < bytes_to_copy) + bytes_to_copy = remaining_bytes; + + /* Copy data from this packet. */ + memcpy(destination_ptr, source_ptr, bytes_to_copy); + + /* Update the pointers. */ + destination_ptr += bytes_to_copy; + remaining_bytes -= bytes_to_copy; + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Move to next packet. */ + working_packet_ptr = working_packet_ptr -> nx_packet_next; + + /* Check for a next packet. */ + if (working_packet_ptr) + { + + /* Setup new source pointer. */ + source_ptr = working_packet_ptr -> nx_packet_prepend_ptr; + } + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Return successful completion. */ + return(NX_SUCCESS); + +} +#endif /* NX_BSD_INCLUDE_DATA_EXTRACT_OFFSET */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the nx_bsd_socket_wait_timer expires. */ +/* It signals the BSD thread task to check and decrement the time */ +/* remaining on all sockets suspended in the wait state. */ +/* */ +/* INPUT */ +/* */ +/* info Timer thread data (not used) */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Sets the WAIT event in the BSD */ +/* event group */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifdef NX_BSD_TIMEOUT_PROCESS_IN_TIMER +VOID nx_bsd_timer_entry(ULONG info) +{ + nx_bsd_timeout_process(); +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_socket_set_inherited_settings PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function applies the socket options of the specified parent */ +/* (master) socket to the specified child (secondary) socket, if BSD */ +/* extended socket options are enabled. If they are not, this function */ +/* has no effect. */ +/* */ +/* INPUT */ +/* */ +/* master_sock_id Source of socket options */ +/* secondary_sock_id Socket inheriting options */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT nx_bsd_socket_set_inherited_settings(UINT master_sock_id, UINT secondary_sock_id) +{ + + /* Update the secondary socket options from the master socket. */ + if(nx_bsd_socket_array[master_sock_id].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; + else + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); + + if(nx_bsd_socket_array[master_sock_id].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR) + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; + else + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR); + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum = + nx_bsd_socket_array[master_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum; +#endif + + + /* Does this version of NetX Duo support TCP keep alive? */ + /* Is NetX Duo currently enabled for TCP keep alive? */ +#ifdef NX_ENABLE_TCP_KEEPALIVE + + nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled = + nx_bsd_socket_array[master_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled; + +#endif /* NX_ENABLE_TCP_KEEPALIVE */ + + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_isspace PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the input character is white space */ +/* (ascii characters 0x09 - 0x0D or space (0x20). */ +/* */ +/* INPUT */ +/* */ +/* c Input character to examine */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Input character is white space */ +/* NX_FALSE Input character not white space*/ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_isspace(UCHAR c) +{ + + /* Check for horizontal, vertical tabs, carriage return or formfeed characters. */ + if ((c >= 0x09) && (c <= 0x0D)) + { + return NX_TRUE; + } + /* Check for a single space character*/ + else if (c == 20) + { + return NX_TRUE; + } + else + /* Not a white space character. */ + return NX_FALSE; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_islower PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the input character is lower case */ +/* alphabetic character. */ +/* */ +/* INPUT */ +/* */ +/* c Input character to examine */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Input character is lower case */ +/* NX_FALSE Input character not lower case */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_islower(UCHAR c) +{ + + /* Check if characters is any character 'a' through 'z'. */ + if ((c >= 0x61) && (c <= 0x7A)) + { + + return NX_TRUE; + } + else + return NX_FALSE; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_isdigit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the input character is a digit (0-9) */ +/* Does not include hex digits, (see nx_bsd_isxdigit). */ +/* */ +/* INPUT */ +/* */ +/* c Input character to examine */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Input character is a digit */ +/* NX_FALSE Input character not a digit */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_isdigit(UCHAR c) +{ + + /* Is the character any digit between 0 and 9? */ + if ((c >= 0x30) && (c <= 0x39)) + { + return NX_TRUE; + } + else + return NX_FALSE; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_isxdigit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the input character is a digit (0-9) */ +/* or hex digit (A - F, or a-f). For decimal digits, see */ +/* nx_bsd_isdigit. */ +/* */ +/* INPUT */ +/* */ +/* c Input character to examine */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Input character is hex digit */ +/* NX_FALSE Input character not hex digit */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_isxdigit(UCHAR c) +{ + + /* Is the character any digit between 0 - 9? */ + if ((c >= 0x30) && (c <= 0x39)) + { + return NX_TRUE; + } + + /* Or is the character any base 16 digit A-F? */ + if ((c >= 0x41) && (c <= 0x46)) + { + return NX_TRUE; + } + + /* Lastly, check if character is any base 16 digit a-f? */ + if ((c >= 0x61) && (c <= 0x66)) + { + return NX_TRUE; + } + else + return NX_FALSE; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* set_errno PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the error on the current socket (thread) for */ +/* sockets enabled with BSD extended socket options. For sockets not */ +/* enabled with extended features, this function has no effect. */ +/* */ +/* INPUT */ +/* */ +/* tx_errno Socket error status code */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID set_errno(INT tx_errno) +{ + +TX_INTERRUPT_SAVE_AREA +TX_THREAD *current_thread_ptr; + + + TX_DISABLE + + current_thread_ptr = tx_thread_identify(); + current_thread_ptr -> bsd_errno = tx_errno; + + TX_RESTORE + + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* get_errno PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the error on the current socket (thread) for*/ +/* sockets enabled with BSD extended socket options. For sockets not */ +/* enabled with extended features, this function has no effect. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* Socket error status code */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT _nxd_get_errno() +{ + +TX_INTERRUPT_SAVE_AREA +INT val; +TX_THREAD *current_thread_ptr; + + + TX_DISABLE + + current_thread_ptr = tx_thread_identify(); + val = current_thread_ptr -> bsd_errno; + + TX_RESTORE + + return (val); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_select_wakeup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks the suspend list for a given socket being */ +/* readable or writeable. */ +/* */ +/* INPUT */ +/* */ +/* sock_id BSD socket ID */ +/* fd_sets The FD set to check */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* FD_ZERO Zeros out an FD Set */ +/* FD_SET Set a socket in the FDSET */ +/* TX_DISABLE Disable Interrupt */ +/* TX_RESTORE Enable Interrupt */ +/* tx_event_flags_set Set an event flag */ +/* */ +/* CALLED BY */ +/* */ +/* nx_bsd_timeout_process */ +/* nx_bsd_tcp_receive_notify */ +/* nx_bsd_tcp_establish_notify */ +/* nx_bsd_tcp_socket_disconnect_notify */ +/* nx_bsd_raw_receive_notify */ +/* nx_bsd_udp_packet_received */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_select_wakeup(UINT sock_id, UINT fd_sets) +{ +TX_INTERRUPT_SAVE_AREA +fd_set local_fd; +TX_THREAD *suspended_thread; +ULONG suspended_count; +ULONG original_suspended_count; +NX_BSD_SOCKET_SUSPEND *suspend_info; + + + /* At this point the thread should NOT own the IP mutex, and it must own the + BSD mutex. */ + + + FD_ZERO(&local_fd); + FD_SET((INT)sock_id + NX_BSD_SOCKFD_START, &local_fd); + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Setup the head pointer and the count. */ + suspended_thread = nx_bsd_events.tx_event_flags_group_suspension_list; + suspended_count = nx_bsd_events.tx_event_flags_group_suspended_count; + + /* Save the original suspended count. */ + original_suspended_count = suspended_count; + + /* Loop to examine all threads suspended on select via the BSD event flag group. */ + while (suspended_count--) + { + + /* Determine if this thread is suspended on select. */ + if (suspended_thread -> tx_thread_suspend_info == NX_BSD_SELECT_EVENT) + { + + /* Yes, this thread is suspended on select. */ + + /* Pickup a pointer to its select suspend structure. */ + suspend_info = (NX_BSD_SOCKET_SUSPEND *) suspended_thread -> tx_thread_additional_suspend_info; + + /* Now determine if this thread was waiting for this socket. */ + if ((fd_sets & FDSET_READ) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set))) + { + + /* Copy the local fd over so that the return shows the receive socket. */ + suspend_info -> nx_bsd_socket_suspend_read_fd_set = local_fd; + + /* Adjust the suspension type so that the event flag set below will wakeup the thread + selecting. */ + suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; + } + + /* Now determine if this thread was waiting for this socket. */ + if ((fd_sets & FDSET_WRITE) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set))) + { + + /* Copy the local fd over so that the return shows the receive socket. */ + suspend_info -> nx_bsd_socket_suspend_write_fd_set = local_fd; + + /* Adjust the suspension type so that the event flag set below will wakeup the thread + selecting. */ + suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; + } + + /* Now determine if this thread was waiting for this socket. */ + if ((fd_sets & FDSET_EXCEPTION) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set))) + { + + /* Copy the local fd over so that the return shows the receive socket. */ + suspend_info -> nx_bsd_socket_suspend_exception_fd_set = local_fd; + + /* Adjust the suspension type so that the event flag set below will wakeup the thread + selecting. */ + suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; + } + + /* Clear FD that is not set. */ + if (suspended_thread -> tx_thread_suspend_info == NX_BSD_RECEIVE_EVENT) + { + if (!(fd_sets & FDSET_READ) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set))) + { + + /* Clear read FD. */ + FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set); + } + + if (!(fd_sets & FDSET_WRITE) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set))) + { + + /* Clear write FD. */ + FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set); + } + + if (!(fd_sets & FDSET_EXCEPTION) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set))) + { + + /* Clear exception FD. */ + FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set); + } + } + } + + /* Now move to the next event. */ + suspended_thread = suspended_thread -> tx_thread_suspended_next; + + /* Restore interrupts. */ + TX_RESTORE + + /* Disable interrupts again. */ + TX_DISABLE + + /* Determine if something changes on the suspension list... this could have happened if there + was a timeout or a wait abort on the thread. */ + if (original_suspended_count != nx_bsd_events.tx_event_flags_group_suspended_count) + { + + /* Something changed, so simply restart the search. */ + + /* Setup the head pointer and the count. */ + suspended_thread = nx_bsd_events.tx_event_flags_group_suspension_list; + suspended_count = nx_bsd_events.tx_event_flags_group_suspended_count; + + /* Save the original suspended count. */ + original_suspended_count = suspended_count; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */ + tx_event_flags_set(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR); + + return; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_set_error_code PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is sets the BSD error code based on NetX Duo API return code */ +/* */ +/* INPUT */ +/* */ +/* bsd_socket_ptr Pointer to the BSD socket */ +/* status_code NetX Duo API return code */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* set_errno Sets the BSD errno */ +/* */ +/* CALLED BY */ +/* */ +/* connect */ +/* bind */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_set_error_code(NX_BSD_SOCKET *bsd_socket_ptr, UINT status_code) +{ + switch(status_code) + { + case NX_NOT_CLOSED: + /* TCP connection is not closed state. */ + set_errno(EISCONN); + break; + + case NX_PTR_ERROR: + case NX_INVALID_PORT: + /* Invalid arguement. */ + set_errno(EINVAL); + break; + + case NX_MAX_LISTEN: + set_errno(ENOBUFS); + break; + + case NX_PORT_UNAVAILABLE: + case NX_NO_FREE_PORTS: + set_errno(EADDRNOTAVAIL); + break; + + case NX_ALREADY_BOUND: + set_errno(EINVAL); + break; + + case NX_WAIT_ABORTED: + set_errno(ETIMEDOUT); + break; + + case NX_NOT_CONNECTED: + /* NX TCP connect service may return NX_NOT_CONNECTED if the timeout is WAIT_FOREVER. */ + set_errno(ECONNREFUSED); + break; + + case NX_IN_PROGRESS: + /* The NetX "in progress" status is the equivalent of the non blocking BSD socket waiting + to connect. This can only happen if timeout is NX_NO_WAIT.*/ + if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) + { + bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; + set_errno(EINPROGRESS); + } + else + set_errno(EINTR); + break; + + case NX_INVALID_INTERFACE: + case NX_IP_ADDRESS_ERROR: + set_errno(ENETUNREACH); + break; + + case NX_NOT_ENABLED: + set_errno(EPROTONOSUPPORT); + break; + + case NX_NOT_BOUND: + case NX_DUPLICATE_LISTEN: + default: + set_errno(EINVAL); + break; + } + + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_udp_packet_received PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is executed as part of the UDP packet receive callback */ +/* function. */ +/* */ +/* This routine puts an incoming UDP packet into the appropriate */ +/* UDP BSD socket, taking into consideration that multiple BSD sockets */ +/* may be mapped to the same NetX Duo UDP socket. */ +/* */ +/* INPUT */ +/* */ +/* sockID The BSD socket descriptor */ +/* packet_ptr The incoming UDP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release a packet that is not */ +/* received by any sockets. */ +/* nx_bsd_select_wakeup Wake up any asychronous */ +/* receive call */ +/* */ +/* CALLED BY */ +/* */ +/* nx_bsd_udp_receive_notify */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_udp_packet_received(INT sockID, NX_PACKET *packet_ptr) +{ + +NX_BSD_SOCKET *bsd_ptr; +ULONG addr_family; +NX_BSD_SOCKET *exact_match = NX_NULL; +NX_BSD_SOCKET *receiver_match = NX_NULL; +NX_BSD_SOCKET *wildcard_match = NX_NULL; +NX_INTERFACE *interface_ptr; + + + bsd_ptr = &nx_bsd_socket_array[sockID]; + +#ifndef NX_DISABLE_IPV4 + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) + { + addr_family = AF_INET; + interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) + { + addr_family = AF_INET6; + interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; + } + else +#endif /* FEATURE_NX_IPV6 */ + { + + /* Invalid version. Release the packet and return. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Start the search for the BSD socket we received this packet on from current input socket ID. */ + bsd_ptr = &nx_bsd_socket_array[sockID]; + + do + { + /* Skip the sockets with different address family. */ + if(bsd_ptr -> nx_bsd_socket_family == addr_family) + { + /* bsd_ptr points to a related UDP socket. */ + if(bsd_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + { + wildcard_match = bsd_ptr; + } + else if(((ULONG)(interface_ptr) == bsd_ptr -> nx_bsd_socket_local_bind_interface) || + ((ULONG)(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr) == bsd_ptr -> nx_bsd_socket_local_bind_interface)) + { + + receiver_match = bsd_ptr; + } + else + { + + /* Does not match the local interface. Move to the next entry. */ + bsd_ptr = bsd_ptr -> nx_bsd_socket_next; + continue; + } + + /* At this point this socket is either a wildcard match or a receiver match. */ + + /* If the socket is connected, we check for sender's address match. */ + if(bsd_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) + { + + nxd_udp_source_extract(packet_ptr, + &bsd_ptr -> nx_bsd_socket_source_ip_address, + (UINT *)&bsd_ptr -> nx_bsd_socket_source_port); + +#ifndef NX_DISABLE_IPV4 + if(bsd_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* Now we can check for an exact match based on sender IP address and port. */ + if((bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4 == + bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4) && + (bsd_ptr -> nx_bsd_socket_source_port == + bsd_ptr -> nx_bsd_socket_peer_port)) + { + exact_match = bsd_ptr; + } + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(bsd_ptr -> nx_bsd_socket_family == AF_INET6) + { + + /* Now we can check for an exact match based on sender IP address and port. */ + if((bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0] == + bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0]) && + (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1] == + bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1]) && + (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2] == + bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2]) && + (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3] == + bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3]) && + (bsd_ptr -> nx_bsd_socket_source_port == + bsd_ptr -> nx_bsd_socket_peer_port)) + { + + exact_match = bsd_ptr; + } + } +#endif + + if(exact_match != NX_NULL) + break; + + if(receiver_match != NX_NULL) + receiver_match = NX_NULL; + + if(wildcard_match != NX_NULL) + wildcard_match = NX_NULL; + } + } + + /* Move to the next entry. */ + bsd_ptr = bsd_ptr -> nx_bsd_socket_next; + + }while(bsd_ptr != &nx_bsd_socket_array[sockID]); + + /* Let bsd_ptr point to the matched socket. */ + if(exact_match != NX_NULL) + bsd_ptr = exact_match; + else if(receiver_match != NX_NULL) + bsd_ptr = receiver_match; + else if(wildcard_match != NX_NULL) + bsd_ptr = wildcard_match; + else + { + /* This packet is not for any of the BSD sockets. Release the packet and we are done. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Move the packet to the socket internal receive queue. */ + + if(bsd_ptr -> nx_bsd_socket_received_byte_count_max && + (bsd_ptr -> nx_bsd_socket_received_byte_count >= bsd_ptr -> nx_bsd_socket_received_byte_count_max)) + { + + /* Receive buffer is full. Release the packet and return. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Drop the packet if the receive queue exceeds max depth.*/ + if(bsd_ptr -> nx_bsd_socket_received_packet_count >= + bsd_ptr -> nx_bsd_socket_received_packet_count_max) + { + + /* Receive buffer is full. Release the packet and return. */ + nx_packet_release(packet_ptr); + + return; + } + if(bsd_ptr -> nx_bsd_socket_received_packet) + { + bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; + } + else + { + + bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; + } + + bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + bsd_ptr -> nx_bsd_socket_received_packet_count++; + + nx_bsd_select_wakeup((UINT)(bsd_ptr -> nx_bsd_socket_id), FDSET_READ); + + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_syn_received_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if the socket has a connection request. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Socket receiving the packet */ +/* packet_ptr Pointer to the received packet */ +/* */ +/* OUTPUT */ +/* */ +/* 0 Not a valid match */ +/* 1 Valid match found */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT nx_bsd_tcp_syn_received_notify(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr) +{ + +UINT bsd_socket_index; +INT i; +INT sockID_find; +ULONG addr_family; +INT search_index; +INT receiver_match = NX_BSD_MAX_SOCKETS; +INT wildcard_match = NX_BSD_MAX_SOCKETS; +NX_BSD_SOCKET *bsd_socket_ptr; +NX_INTERFACE *interface_ptr; + + + bsd_socket_index = (UINT)socket_ptr -> nx_tcp_socket_reserved_ptr; + + if(bsd_socket_index >= NX_BSD_MAX_SOCKETS) + { + + /* Bad socket index... simply return! */ + return(NX_FALSE); + } + + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; + +#ifndef NX_DISABLE_IPV4 + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) + { + addr_family = AF_INET; + } + else +#endif /* NX_DISABLE_IPV4 */ + { + addr_family = AF_INET6; + } + + /* Start the search at the position of the input socket. */ + search_index = (INT)bsd_socket_index; + + /* Get the packet interface. */ +#ifdef FEATURE_NX_IPV6 + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) +#endif /* FEATURE_NX_IPV6 */ + interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; +#ifdef FEATURE_NX_IPV6 + else if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) + interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; + else + return (NX_FALSE); +#endif /* FEATURE_NX_IPV6 */ + + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + bsd_socket_ptr = &nx_bsd_socket_array[search_index]; + + /* Skip the unrelated sockets. */ + if((bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && + (bsd_socket_ptr -> nx_bsd_socket_family == addr_family) && + ((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) && + (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && + (bsd_socket_ptr -> nx_bsd_socket_local_port == socket_ptr -> nx_tcp_socket_port) && + (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) + { + + if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) + { + + wildcard_match = search_index; + } + else if(((ULONG)(interface_ptr) == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface) || + ((ULONG)(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr) == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface)) + { + + receiver_match = search_index; + + /* Found a receiver match, which is a tighter match than the wildcard match. + So we can get out of the loop. */ + break; + } + } + + /* Move to the next entry. */ + search_index++; + + if(search_index >= NX_BSD_MAX_SOCKETS) + search_index = 0; + } + + if(receiver_match != NX_BSD_MAX_SOCKETS) + sockID_find = receiver_match; + else if(wildcard_match != NX_BSD_MAX_SOCKETS) + sockID_find = wildcard_match; + else + { + + /* No match found. Simply return .*/ + return(NX_FALSE); + } + + /* Found the listening master socket. Update the master socket ID of the input socket. */ + nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id = sockID_find; + + return(NX_TRUE); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_create_listen_socket PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine sets up the input socket as a listen socket. */ +/* */ +/* INPUT */ +/* */ +/* master_sockid Index to the master socket */ +/* backlog Size of the socket listen queue*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SOC_OK Successfully set up socket */ +/* NX_SOC_ERROR Error setting up the socket */ +/* */ +/* CALLS */ +/* */ +/* socket Allocate a BSD socket */ +/* nx_bsd_socket_set_inherited_settings Apply master socket options */ +/* nx_tcp_server_socket_listen Enable the socket to listen **/ +/* nx_tcp_server_socket_accept Wait for connection request */ +/* nx_tcp_server_socket_relisten Reset the socket to listen */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT nx_bsd_tcp_create_listen_socket(INT master_sockid, INT backlog) +{ + +INT i; +UINT status; +UINT local_port; +NX_BSD_SOCKET *master_socket_ptr = &nx_bsd_socket_array[master_sockid]; +NX_BSD_SOCKET *bsd_secondary_socket; +NX_BSD_SOCKET *bsd_socket_ptr; +NX_TCP_SOCKET *sec_socket_ptr; +INT secondary_sockID = NX_BSD_MAX_SOCKETS; + + + /* This is called from BSD internal code so the BSD mutex is obtained. */ + + /* Search through the sockets to find a master socket that is listening on the same port. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + /* Skip the entry if it is not master socket */ + if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) == 0) + continue; + + /* Skip the current master socket. */ + if(i == master_sockid) + continue; + + /* Skip the entry if it is not TCP */ + if(nx_bsd_socket_array[i].nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + continue; + + /* Skip the entry if the the secondary socket id field is not valid. */ + if(nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id == NX_BSD_MAX_SOCKETS) + continue; + + /* Check if another master socket is listening on the same port. */ + if((nx_bsd_socket_array[i].nx_bsd_socket_local_port == master_socket_ptr -> nx_bsd_socket_local_port) && + (nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id + != (master_socket_ptr -> nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id)) && + (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN)) + { + + /* This one is. Point to the same secondary socket. */ + (master_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = + nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id; + master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; + master_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); + master_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; + master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; + + return(NX_SOC_OK); + } + } + + /* Did not find an existing master socket for listening. */ + + /* Check for a valid backlog. */ + if(backlog) + { + + /* Check backlog argument is within limits. */ + if (backlog > NX_BSD_MAX_LISTEN_BACKLOG) + { + + /* Error, invalid backlog. */ + /* Set the socket error if extended socket options enabled. */ + set_errno(ENOBUFS); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + } + + /* Now create a dedicated secondary socket to listen for next client connection. */ + secondary_sockID = socket((INT)(master_socket_ptr -> nx_bsd_socket_family), SOCK_STREAM, IPPROTO_TCP); + + /* Determine if there was an error. */ + if (secondary_sockID == NX_SOC_ERROR) + { + + /* Secondary socket create failed. Note: The socket thread error is set in socket(). */ + set_errno(ENOMEM); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Adjust the secondary socket ID. */ + secondary_sockID = secondary_sockID - NX_BSD_SOCKFD_START; + + /* The master server socket will never connect to a client! For each successful + client connection there will be a new secondary server socket and + each such socket is associated with this master server socket. This is + the difference between NetX and BSD sockets. The NetX listen() service is used + with this secondary server socket. */ + + /* Set a pointer to the secondary socket. */ + bsd_secondary_socket = &nx_bsd_socket_array[secondary_sockID]; + + /* Apply the master socket options to the secondary socket. */ + nx_bsd_socket_set_inherited_settings((UINT)master_sockid, (UINT)secondary_sockID); + + local_port = master_socket_ptr -> nx_bsd_socket_local_port; + + /* Invalidate the secondary master socket ID. */ + (bsd_secondary_socket -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; + + /* Now call listen for the secondary server socket. */ + if(backlog) + status = nx_tcp_server_socket_listen(nx_bsd_default_ip, local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket, (UINT)backlog, NX_NULL); + else + { + + /* Since a zero backlog is specified, this secondary socket needs to share with another master socket. */ + bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port = local_port; + + /* Check if a listen request is queued up for this socket. */ + nx_bsd_tcp_pending_connection(local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket); + + status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket); + } + + /* Check for an error. */ + if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + + /* Error, listen or relisten failed. */ + + /* Set the socket error depending on the NetX error status returned. */ + nx_bsd_set_error_code(master_socket_ptr, status); + + /* Return error code. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Now mark this as a master server socket listening to client connections. */ + master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; + master_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); + master_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; + master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; + + /* This is a master socket. So we use the nx_bsd_socket_master_socket_id field to + record the secondary socket that is doing the real listen/accept work. */ + (master_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = secondary_sockID; + + /* Mark the secondary server socket as assigned to this master server socket. */ + bsd_secondary_socket -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_ACCEPTING); + bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET; + bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; + bsd_secondary_socket -> nx_bsd_socket_local_port = (USHORT)local_port; + + /* If the master server socket is marked as non-blocking, we need to + start the NetX accept process here. */ + + sec_socket_ptr = bsd_secondary_socket -> nx_bsd_socket_tcp_socket; + + /* Allow accept from remote. */ + nx_tcp_server_socket_accept(sec_socket_ptr, 0); + + /* Set the master socket of other BSD TCP sockets that bind to the same port to the same secondary socket. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + + bsd_socket_ptr = &nx_bsd_socket_array[i]; + + if((bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && + (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT)) && + (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && + (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) && + (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND) && + (bsd_socket_ptr -> nx_bsd_socket_local_port == local_port)) + { + + (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = secondary_sockID; + } + } + + /* Check the relisten/listen status. */ + if(status == NX_CONNECTION_PENDING) + { + + /* Set the connection pending flag. */ + bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; + + } + + return(NX_SOC_OK); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_tcp_pending_connection PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine checks if the BSD TCP socket has a listen request */ +/* queued up on in the specified port. */ +/* */ +/* INPUT */ +/* */ +/* local_port Listening port */ +/* socket_ptr Socket to check */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_tcp_syn_received_notify Match connection request */ +/* (packet) to input socket */ +/* nx_packet_receive Release packet to packet pool */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID nx_bsd_tcp_pending_connection(UINT local_port, NX_TCP_SOCKET *socket_ptr) +{ + +struct NX_TCP_LISTEN_STRUCT *listen_ptr; +NX_PACKET *packet_ptr; +NX_TCP_HEADER *tcp_header_ptr; +UINT ret; + + + listen_ptr = nx_bsd_default_ip -> nx_ip_tcp_active_listen_requests; + + if(listen_ptr) + { + + do + { + + if((listen_ptr -> nx_tcp_listen_port == local_port) && + (listen_ptr -> nx_tcp_listen_queue_current)) + { + + do + { + + packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + + tcp_header_ptr = (NX_TCP_HEADER*)packet_ptr -> nx_packet_prepend_ptr; + + if(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + + ret = nx_bsd_tcp_syn_received_notify(socket_ptr, packet_ptr); + + /* Yes. We are done. */ + if(ret == NX_TRUE) + { + + return; + } + + listen_ptr -> nx_tcp_listen_queue_head = packet_ptr -> nx_packet_queue_next; + + if(packet_ptr == listen_ptr -> nx_tcp_listen_queue_tail) + { + listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; + } + + listen_ptr -> nx_tcp_listen_queue_current--; + + nx_packet_release(packet_ptr); + + } + } while(listen_ptr -> nx_tcp_listen_queue_head); + } + + listen_ptr = listen_ptr -> nx_tcp_listen_next; + + }while(listen_ptr != nx_bsd_default_ip -> nx_ip_tcp_active_listen_requests); + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_find_interface_by_source_addr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the interface index value of a given IPv4 or */ +/* IPv6 source address. */ +/* */ +/* INPUT */ +/* */ +/* addr_family Address Family */ +/* ip_addr Pointer to an array of IPv4 */ +/* or IPv6 address */ +/* */ +/* OUTPUT */ +/* */ +/* Index value */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* nx_bsd_send_internal */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT nx_bsd_find_interface_by_source_addr(UINT addr_family, ULONG* ip_addr) +{ +INT i; +#ifndef NX_DISABLE_IPV4 +ULONG ipv4_addr; +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 +ULONG ipv6_addr[4]; +#endif + +#ifndef NX_DISABLE_IPV4 + if(addr_family == AF_INET) + { + ipv4_addr = *ip_addr; + NX_CHANGE_ULONG_ENDIAN(ipv4_addr); + + for(i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + if((nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_valid) && + (nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_ip_address == ipv4_addr)) + return i; + } + } +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if(addr_family == AF_INET6) + { + ipv6_addr[0] = *(ip_addr); + ipv6_addr[1] = *(ip_addr + 1); + ipv6_addr[2] = *(ip_addr + 2); + ipv6_addr[3] = *(ip_addr + 3); + NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_addr); + + for(i = 0; i < NX_MAX_IPV6_ADDRESSES; i++) + { + + if((nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address_valid) && + (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address_attached -> nx_interface_valid) && + (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[0] == ipv6_addr[0]) && + (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[1] == ipv6_addr[1]) && + (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[2] == ipv6_addr[2]) && + (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[3] == ipv6_addr[3])) + return i; + } + } +#endif + + return((INT)(NX_BSD_LOCAL_IF_INADDR_ANY)); + +} + + +#ifndef NX_DISABLE_IPV4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_bsd_ipv4_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the IP header checksum and updates that into */ +/* the ip header ,which is assumed to be already prepended in the */ +/* input packet buffer, and forwards it to the driver directly. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_checksum_compute Compute IP checksum */ +/* (_nx_arp_entry_allocate) ARP entry allocate service */ +/* (_nx_arp_packet_send) Send an ARP packet */ +/* _nx_ip_packet_deferred_receive Receive loopback packet */ +/* _nx_packet_copy Copy packet to input packet */ +/* _nx_packet_transmit_release Release transmit packet */ +/* (nx_ip_fragment_processing) Fragment processing */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* nx_bsd_send_internal */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_bsd_ipv4_packet_send(NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +NX_IP_DRIVER driver_request; +NX_IPV4_HEADER *ip_header_ptr; +#ifndef NX_DISABLE_IP_TX_CHECKSUM +ULONG checksum; +ULONG val; +#endif +UINT index; +NX_ARP *arp_ptr; +NX_PACKET *last_packet; +NX_PACKET *remove_packet; +UINT queued_count; +NX_PACKET *packet_copy; +ULONG network_mask; +ULONG network; +NX_IP * ip_ptr; +ULONG destination_ip; + + ip_ptr = nx_bsd_default_ip; +#ifndef NX_DISABLE_IP_INFO + + /* Increment the total send requests counter. */ + ip_ptr -> nx_ip_total_packet_send_requests++; +#endif + + + /* Setup the IP header pointer. */ + ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; + + destination_ip = ip_header_ptr -> nx_ip_header_destination_ip; + + /* Swap the destination address to host byte order.*/ + NX_CHANGE_ULONG_ENDIAN(destination_ip); + +#ifndef NX_DISABLE_IP_TX_CHECKSUM + checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4, + /* Length is the size of IP header, including options */ + (UINT)((*(UCHAR*)ip_header_ptr & 0xf) << 2), + /* IPv4 header checksum does not use src/dest addresses */ + NULL, NULL); + + val = (ULONG)(~checksum); + val = val & NX_LOWER_16_MASK; + + /* Convert to network byte order. */ + NX_CHANGE_ULONG_ENDIAN(val); + + /* Now store the checksum in the IP header. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val; + +#endif + + /* Determine if physical mapping is needed by the link driver. */ + if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_address_mapping_needed ) + { + + + network_mask = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network_mask; + network = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network; + + /* Determine whether or not the destination address is out of this local network. */ + if (((destination_ip & network_mask) != network) || + ((destination_ip & ~network_mask) == ~network_mask) || + (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)) + { + + /* We have an out-of-network destination IP address, check for a variety + of out-of-network destinations. */ + + /* Determine if an IP limited or directed broadcast is requested. */ + if ((destination_ip == NX_IP_LIMITED_BROADCAST) || + (((destination_ip & network_mask) == network) && + ((destination_ip & ~network_mask) == ~network_mask))) + { + + /* Build the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_BROADCAST; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_physical_address_msw = 0xFFFFUL; + driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFFUL; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) + { + + /* Fragmentation is needed, call the fragment routine if available. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#endif + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Broadcast packet. */ + (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); + + return; + } + + /* Determine if we have a loopback address. */ + else if ((((destination_ip >= NX_IP_LOOPBACK_FIRST) && + (destination_ip <= NX_IP_LOOPBACK_LAST))) || + (destination_ip == ip_ptr -> nx_ip_interface[0].nx_interface_ip_address)) + { + + /* Yes, we have an internal loopback address. */ + + /* Copy the packet so it can be enqueued properly by the receive + processing. */ + if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Send the packet to this IP's receive processing like it came in from the + driver. */ + _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); + } +#ifndef NX_DISABLE_IP_INFO + else + { + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + } +#endif + + /* Release the transmit packet. */ + _nx_packet_transmit_release(packet_ptr); + return; + } + + /* Determine if we have a class D multicast address. */ + else if ((destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) + { + + /* Yes, we have a class D multicast address. Derive the physical mapping from + the class D address. */ + driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER; + driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (destination_ip & NX_IP_MULTICAST_MASK); + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + + /* Determine if the group address has been joined in this IP instance. */ + index = 0; + while (index < NX_MAX_MULTICAST_GROUPS) + { + + /* Determine if the destination address matches the requested address. */ + if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_join_list == destination_ip) + { + + /* Yes, break the loop! */ + break; + } + + /* Increment the join list index. */ + index++; + } + + /* Determine if the group was joined by this IP instance. */ + if (index < NX_MAX_MULTICAST_GROUPS) + { + + /* Determine if the group has loopback enabled. */ + if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_loopback_enable) + { + + /* Yes, loopback is enabled! */ + + /* Copy the packet so we can send it via loopback. */ + if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Packet copy was successful. Send the packet to this IP's receive processing like it came in from the + driver. */ + _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); + } +#ifndef NX_DISABLE_IP_INFO + else + { + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + } +#endif + } + } + + /* Build the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) + { + + /* Fragmentation is needed, call the fragment routine if available. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#endif + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); + + /* Return to caller. */ + return; + } + + /* Use default gateway. */ + else + { + + /* We have an out-of-network destination IP address, check to see if a + Gateway IP address has been specified. */ + if (ip_ptr -> nx_ip_gateway_address) + { + + /* Remap the destination IP address to the Gateway IP address. The ARP + processing below will handle getting the physical address for the + Gateway. */ + destination_ip = ip_ptr -> nx_ip_gateway_address; + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the number of no route errors. */ + ip_ptr -> nx_ip_transmit_no_route_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + + /* In either case, this packet send is complete, just return. */ + return; + } + } + } + + /* Yes, look into the ARP Routing Table to derive the physical address. */ + + /* Calculate the hash index for the destination IP address. */ + index = (UINT) ((destination_ip + (destination_ip >> 8)) & NX_ARP_TABLE_MASK); + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Determine if there is an entry for this IP address. */ + arp_ptr = ip_ptr -> nx_ip_arp_table[index]; + + /* Determine if this arp entry matches the destination IP address. */ + if ((arp_ptr) && (arp_ptr -> nx_arp_ip_address == destination_ip)) + { + + /* Yes, we have an existing ARP mapping entry. */ + + /* Determine if there is a physical address. */ + if (arp_ptr -> nx_arp_physical_address_msw | arp_ptr -> nx_arp_physical_address_lsw) + { + + /* Yes, we have a physical mapping. Copy the physical address into the driver + request structure. */ + driver_request.nx_ip_driver_physical_address_msw = arp_ptr -> nx_arp_physical_address_msw; + driver_request.nx_ip_driver_physical_address_lsw = arp_ptr -> nx_arp_physical_address_lsw; + + /* Restore interrupts. */ + TX_RESTORE + + /* Build the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) + { + + /* Fragmentation is needed, call the fragment routine if available. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#endif + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); + + /* Return to caller. */ + return; + } + else + { + + /* Ensure the current packet's queue next pointer to NULL. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Determine if the queue is empty. */ + if (arp_ptr -> nx_arp_packets_waiting == NX_NULL) + { + + /* Yes, we have an empty ARP packet queue. Simply place the + packet at the head of the list. */ + arp_ptr -> nx_arp_packets_waiting = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Determine how many packets are on the ARP entry's packet + queue and remember the last packet in the queue. We know + there is at least one on the queue and another that is + going to be queued. */ + last_packet = arp_ptr -> nx_arp_packets_waiting; + queued_count = 0; + while (last_packet -> nx_packet_queue_next) + { + + /* Increment the queued count. */ + queued_count++; + + /* Move to the next packet in the queue. */ + last_packet = last_packet -> nx_packet_queue_next; + } + + /* Place the packet at the end of the list. */ + last_packet -> nx_packet_queue_next = packet_ptr; + + /* Default the remove packet pointer to NULL. */ + remove_packet = NX_NULL; + + /* Determine if the packets queued has exceeded the queue + depth. */ + if (queued_count >= NX_ARP_MAX_QUEUE_DEPTH) + { + + /* Save the packet pointer at the head of the list. */ + remove_packet = arp_ptr -> nx_arp_packets_waiting; + + /* Remove the packet from the ARP queue. */ + arp_ptr -> nx_arp_packets_waiting = remove_packet -> nx_packet_queue_next; + + /* Clear the remove packet queue next pointer. */ + remove_packet -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if there is a packet to remove. */ + if (remove_packet) + { + + /* Yes, the packet queue depth for this ARP entry was exceeded + so release the packet that was removed from the queue. */ + _nx_packet_transmit_release(remove_packet); + } + } + + /* Return to caller. */ + return; + } + } + else + { + + /* At this point, we need to search the ARP list for a match for the + destination IP. */ + + /* First, restore interrupts. */ + TX_RESTORE + + /* Pickup the first ARP entry. */ + arp_ptr = ip_ptr -> nx_ip_arp_table[index]; + + /* Loop to look for an ARP match. */ + while (arp_ptr) + { + + /* Check for an IP match. */ + if (arp_ptr -> nx_arp_ip_address == destination_ip) + { + + /* Yes, we found a match. Get out of the loop! */ + break; + } + + /* Move to the next active ARP entry. */ + arp_ptr = arp_ptr -> nx_arp_active_next; + + /* Determine if we are at the end of the ARP list. */ + if (arp_ptr == ip_ptr -> nx_ip_arp_table[index]) + { + /* Clear the ARP pointer. */ + arp_ptr = NX_NULL; + break; + } + } + + /* Determine if we actually found a matching ARP entry. */ + if (arp_ptr) + { + + /* Yes, we found an ARP entry. Now check and see if + it has an actual physical address. */ + if (arp_ptr -> nx_arp_physical_address_msw | arp_ptr -> nx_arp_physical_address_lsw) + { + + /* Yes, we have a physical mapping. Copy the physical address into the driver + request structure. */ + driver_request.nx_ip_driver_physical_address_msw = arp_ptr -> nx_arp_physical_address_msw; + driver_request.nx_ip_driver_physical_address_lsw = arp_ptr -> nx_arp_physical_address_lsw; + + /* Disable interrupts. */ + TX_DISABLE + + /* Move this ARP entry to the head of the list. */ + ip_ptr -> nx_ip_arp_table[index] = arp_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Build the driver request message. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) + { + + /* Fragmentation is needed, call the fragment routine if available. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#endif + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); + + /* Return to caller. */ + return; + } + else + { + + /* We don't have physical mapping. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Ensure the current packet's queue next pointer to NULL. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Determine if the queue is empty. */ + if (arp_ptr -> nx_arp_packets_waiting == NX_NULL) + { + + /* Yes, we have an empty ARP packet queue. Simply place the + packet at the head of the list. */ + arp_ptr -> nx_arp_packets_waiting = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + + /* Determine how many packets are on the ARP entry's packet + queue and remember the last packet in the queue. We know + there is at least one on the queue and another that is + going to be queued. */ + last_packet = arp_ptr -> nx_arp_packets_waiting; + queued_count = 0; + while (last_packet -> nx_packet_queue_next) + { + + /* Increment the queued count. */ + queued_count++; + + /* Move to the next packet in the queue. */ + last_packet = last_packet -> nx_packet_queue_next; + } + + /* Place the packet at the end of the list. */ + last_packet -> nx_packet_queue_next = packet_ptr; + + /* Default the remove packet pointer to NULL. */ + remove_packet = NX_NULL; + + /* Determine if the packets queued has exceeded the queue + depth. */ + if (queued_count >= NX_ARP_MAX_QUEUE_DEPTH) + { + + /* Save the packet pointer at the head of the list. */ + remove_packet = arp_ptr -> nx_arp_packets_waiting; + + /* Remove the packet from the ARP queue. */ + arp_ptr -> nx_arp_packets_waiting = remove_packet -> nx_packet_queue_next; + + /* Clear the remove packet queue next pointer. */ + remove_packet -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if there is a packet to remove. */ + if (remove_packet) + { + + /* Yes, the packet queue depth for this ARP entry was exceeded + so release the packet that was removed from the queue. */ + _nx_packet_transmit_release(remove_packet); + } + } + + /* Return to caller. */ + return; + } + } + else + { + + /* No ARP entry was found. We need to allocate a new ARP entry, populate it, and + initiate an ARP request to get the specific physical mapping. */ + + /* Allocate a new ARP entry. */ + if ((!ip_ptr -> nx_ip_arp_allocate) || + ((ip_ptr -> nx_ip_arp_allocate)(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_FALSE))) + { + + /* Error, release the protection and the packet. */ + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release the packet. */ + _nx_packet_transmit_release(packet_ptr); + + /* Just return! */ + return; + } + + /* Otherwise, setup a pointer to the new ARP entry. */ + arp_ptr = (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous; + + /* Setup the IP address and clear the physical mapping. */ + arp_ptr -> nx_arp_ip_address = destination_ip; + arp_ptr -> nx_arp_physical_address_msw = 0; + arp_ptr -> nx_arp_physical_address_lsw = 0; + arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE; + arp_ptr -> nx_arp_retries = 0; + arp_ptr -> nx_arp_ip_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + + /* Ensure the queue next pointer is NULL for the packet before it + is placed on the ARP waiting queue. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Queue the packet for output. */ + arp_ptr -> nx_arp_packets_waiting = packet_ptr; + + /* Call ARP send to send an ARP request. */ + (ip_ptr -> nx_ip_arp_packet_send)(ip_ptr, destination_ip, packet_ptr -> nx_packet_address.nx_packet_interface_ptr); + return; + } + } + } + else + { + + /* This IP instance does not require any IP-to-physical mapping. */ + + /* Determine if we have a loopback address. */ + if ((((destination_ip >= NX_IP_LOOPBACK_FIRST) && + (destination_ip <= NX_IP_LOOPBACK_LAST))) || + (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)) + { + + /* Yes, we have an internal loopback address. */ + + /* Copy the packet so it can be enqueued properly by the receive + processing. */ + if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); +#endif + + /* Send the packet to this IP's receive processing like it came in from the + driver. */ + _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); + } +#ifndef NX_DISABLE_IP_INFO + else + { + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; + } +#endif + + /* Release the transmit packet. */ + _nx_packet_transmit_release(packet_ptr); + return; + } + + /* Build the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) + { + + /* Fragmentation is needed, call the fragment routine if available. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#endif + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); + +#endif + + /* No mapping driver. Just send the packet out! */ + (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); + } +} +#endif /*NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_bsd_ipv6_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function forwards the input packet directly to the appropriate */ +/* link driver. The caller needs to fill in the correct */ +/* source and destination addresses into the packet source and */ +/* destination address. The caller also makes sure that the packet */ +/* interface address is valid (not in tentative state), and source */ +/* address is not unspecified e.g. NULL. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to send */ +/* src_addr Pointer to source address */ +/* dest_addr Pointer to dest address */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_transmit_release Release transmit packet */ +/* _nx_nd_cache_add_entry Add new entry to ND Cache */ +/* IPv6_Address_Type Find IPv6 address type */ +/* _nx_packet_copy Packet copy */ +/* _nx_ip_packet_deferred_receive Places received packets in */ +/* deferred packet queue */ +/* _nx_icmpv6_send_ns Send neighbor solicitation */ +/* _nxd_ipv6_search_onlink Find onlink match */ +/* _nx_ipv6_fragment_processing Fragment processing */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* nx_bsd_send_internal */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_bsd_ipv6_packet_send(NX_PACKET *packet_ptr, ULONG *src_addr, ULONG *dest_addr) +{ + +UINT status; +ULONG address_type; +NX_IP_DRIVER driver_request; +NX_PACKET *remove_packet; +NX_PACKET *packet_copy; +UINT same_address; +NX_INTERFACE *if_ptr; +#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY +NX_IPV6_HEADER *ip_header_ptr; +#endif +NX_IPV6_DESTINATION_ENTRY *dest_entry_ptr; +#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY +UINT next_hop_path_mtu; +NX_IPV6_DESTINATION_ENTRY *next_hop_dest_entry_ptr; +#endif +NX_IP *ip_ptr; + + ip_ptr = nx_bsd_default_ip; +#ifndef NX_DISABLE_IP_INFO + + /* Increment the total send requests counter. */ + ip_ptr -> nx_ip_total_packet_send_requests++; +#endif + + if_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; + + + /* If the interface IP address is not valid (in DAD state), only ICMP is allowed */ + if(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid packet error. */ + ip_ptr -> nx_ip_invalid_transmit_packets++; +#endif + + /* Release the packet. */ + _nx_packet_transmit_release(packet_ptr); + + /* Return... nothing more can be done! */ + return; + } + +#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY + /* Build the IP header. */ + ip_header_ptr = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_prepend_ptr; +#endif + + /* Check if the host is sending itself a packet. */ + same_address = (UINT)CHECK_IPV6_ADDRESSES_SAME(dest_addr, src_addr); + + /* If it is, consider this a loopback address. */ + if (same_address == 1) + { + + address_type = IPV6_ADDRESS_LOOPBACK; + } + else + { + + /* Otherwise check if this packet sending to a known loopback address. */ + address_type = IPv6_Address_Type(dest_addr); + } + + /* Handle the internal loopback case. */ + if(address_type == IPV6_ADDRESS_LOOPBACK) + { + + if(_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) + { +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); +#endif + + /* Send the packet to this IP's receive processing like it came in from the driver. */ + _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); + } +#ifndef NX_DISABLE_IP_INFO + else + { + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + } +#endif + /* Release the transmit packet. */ + _nx_packet_transmit_release(packet_ptr); + return; + + } + + /* Is this packet a multicast ? */ + if((dest_addr[0] & 0xFF000000) == 0xFF000000) + { + + + /* Set up the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_physical_address_msw = 0x00003333; + driver_request.nx_ip_driver_physical_address_lsw = dest_addr[3]; + driver_request.nx_ip_driver_interface = if_ptr; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); +#endif + + /* Check if fragmentation is enabled. */ +#ifndef NX_DISABLE_FRAGMENTATION + + /* It is; is path MTU enabled? */ +#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY + + /* It is. We will check the path MTU for the packet destination to + determine if we need to fragment the packet. */ + + /* Get a pointer to the packet IP header. */ + ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Lookup the multicast destination in the destination table. */ + status = _nx_icmpv6_dest_table_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &dest_entry_ptr, 0, 0); + + /* Did we find it in the table? */ + if ((status == NX_SUCCESS) && (dest_entry_ptr != NX_NULL)) + { + + /* Yes; Check the destination path MTU if fragmentation is needed. */ + if ((dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu > 0) && (packet_ptr -> nx_packet_length > + dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu)) + { + + /* Yes we must fragment the payload. */ + _nx_ipv6_fragment_process(&driver_request, dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu); + + /* This packet send is complete, just return. */ + return; + } + + /* Packet should drop through and be checked against the IP mtu. */ + } + +#endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */ + + + /* Does the packet payload exceed our IP instance MTU? */ + if (packet_ptr -> nx_packet_length > if_ptr -> nx_interface_ip_mtu_size) + { + /* Yes; ok to fragment the packet payload. */ + _nx_ipv6_fragment_process(&driver_request, if_ptr -> nx_interface_ip_mtu_size); + + /* This packet send is complete, just return. */ + return; + } + + /* Packet will go out unfragmented. */ + +#endif /* NX_DISABLE_FRAGMENTATION */ + + + /* Send the IP packet out on the network via the attached driver. */ + (if_ptr -> nx_interface_link_driver_entry) (&driver_request); + + /* Return to caller. */ + return; + } + + /* Determine if physical mapping is needed by this link driver. */ + if( if_ptr && if_ptr -> nx_interface_address_mapping_needed ) + { + + /* Obtain MAC address */ + ND_CACHE_ENTRY *NDCacheEntry = NX_NULL; + ULONG next_hop_address[4]; + + SET_UNSPECIFIED_ADDRESS(next_hop_address); + + /* Lookup the packet destination in the destination table. */ + status = _nx_icmpv6_dest_table_find(ip_ptr, dest_addr, &dest_entry_ptr, 0, 0); + + /* Was a matching entry found? */ + if(status != NX_SUCCESS) + { + + /* No; If the packet is either onlink or there is no default router, + just copy the packet destination address to the 'next hop' address. */ + + if(_nxd_ipv6_search_onlink(ip_ptr, dest_addr)) + { + COPY_IPV6_ADDRESS(dest_addr, next_hop_address); + + /* Add the next_hop in destination table. */ + status = _nx_icmpv6_dest_table_add(ip_ptr, dest_addr, &dest_entry_ptr, + next_hop_address, if_ptr -> nx_interface_ip_mtu_size, + NX_WAIT_FOREVER, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr); + + /* Get the NDCacheEntry. */ + if(status == NX_SUCCESS) + NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; + } + + /* Check whether or not we have a default router. */ + else if(_nxd_ipv6_router_lookup(ip_ptr, if_ptr, next_hop_address, (VOID**)&NDCacheEntry) == NX_SUCCESS) + { + /* Add the next_hop in destination table. */ + status = _nx_icmpv6_dest_table_add(ip_ptr, dest_addr, &dest_entry_ptr, + next_hop_address, if_ptr -> nx_interface_ip_mtu_size, + NX_WAIT_FOREVER, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr); + + /* If the default router did not has a reachable ND_CACHE_ENTRY. Get the NDCacheEntry. */ + if(!NDCacheEntry) + NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; + } + + /* Can not find next_hop or the destination table add failed. */ + if(status || ((next_hop_address[0] == 0) && (next_hop_address[1] == 0) && (next_hop_address[2] == 0) && (next_hop_address[3] == 0))) + { + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Can't send it. */ + return; + } + + } + + /* Find a valid destination cache, set the nd cache and next hop address. */ + else + { + + /* Check the NDCacheEntry is valid. */ + if(dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry -> nx_nd_cache_nd_status == ND_CACHE_STATE_INVALID) + { + if(_nx_nd_cache_add_entry(ip_ptr, dest_addr, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr, &dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry)) + { + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Can't send it. */ + return; + } + + } + + /* Get the destination and next hop address. */ + NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; + COPY_IPV6_ADDRESS(dest_entry_ptr -> nx_ipv6_destination_entry_next_hop, next_hop_address); + } + + /* According RFC2461 ch 7.3.3, as long as the entry is valid and not in INCOMPLETE state, + the IP layer should use the cached link layer address. */ + if((NDCacheEntry -> nx_nd_cache_nd_status >= ND_CACHE_STATE_REACHABLE) && + (NDCacheEntry -> nx_nd_cache_nd_status <= ND_CACHE_STATE_PROBE)) + { + + UCHAR *mac_addr; + + mac_addr = NDCacheEntry -> nx_nd_cache_mac_addr; + + /* Assume we find the mac */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_physical_address_msw = (ULONG)((mac_addr[0] << 8) | mac_addr[1]); + driver_request.nx_ip_driver_physical_address_lsw = + (ULONG)((mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) | mac_addr[5]); + driver_request.nx_ip_driver_interface = if_ptr; + +#ifndef NX_DISABLE_FRAGMENTATION + + /* If the packet size is bigger than MTU, NetX Duo is enabled to fragment + the packet payload. */ + + /* Check if path MTU Discovery is enabled first. */ + +#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY + + /* It is. To know if we need to fragment this packet we need the path MTU for the packet + destination. */ + + /* If this destination has a non null next hop, we need to ascertain the next hop MTU. */ + + /* Get the path MTU for the actual destination. */ + next_hop_path_mtu = dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu; + + + /* Find the next hop in the destination table. */ + status = _nx_icmpv6_dest_table_find(ip_ptr, next_hop_address, &next_hop_dest_entry_ptr, 0, 0); + + if (status == NX_SUCCESS) + { + + /* Now compare the destination path MTU with the next hop path MTU*/ + if ((next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu > 0) && + (next_hop_path_mtu > next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu)) + { + + /* Update the path mtu to reflect the next hop route. */ + next_hop_path_mtu = next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu; + } + } + + /* Yes; Check the destination path MTU if fragmentation is needed. */ + if ((next_hop_path_mtu > 0) && + (packet_ptr -> nx_packet_length > next_hop_path_mtu)) + { + + /* Yes we must fragment the payload. */ + _nx_ipv6_fragment_process(&driver_request, next_hop_path_mtu); + + /* This packet send is complete, just return. */ + return; + } +#endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */ + + /* Send packet unfragmented. */ + + /* If we didn't find anything in the destination table, let the packet drop through. NetX Duo + will check our IP instance MTU if fragmentation is needed before sending. */ + + + /* Does the packet payload exceed our IP instance MTU? */ + if (packet_ptr -> nx_packet_length > if_ptr -> nx_interface_ip_mtu_size) + { + /* Yes; ok to fragment the packet payload. */ + _nx_ipv6_fragment_process(&driver_request, if_ptr -> nx_interface_ip_mtu_size); + + /* This packet send is complete, just return. */ + return; + } + + /* The packet requires no fragmentation. Proceed with sending the packet. */ + +#endif /* NX_DISABLE_FRAGMENTATION */ + + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); +#endif + + /* Send the IP packet out on the network via the attached driver. */ + (if_ptr -> nx_interface_link_driver_entry) (&driver_request); + + /* If the entry is in STALE state, move it to DELAY state. */ + if(NDCacheEntry -> nx_nd_cache_nd_status == ND_CACHE_STATE_STALE) + { + NDCacheEntry -> nx_nd_cache_nd_status = ND_CACHE_STATE_DELAY; + + /* Start the Delay first probe timer */ + NDCacheEntry -> nx_nd_cache_timer_tick = NX_DELAY_FIRST_PROBE_TIME; + + } + + /* Return to caller. */ + return; + } + + /* No MAC address was found in our cache table. Start the Neighbor Discovery (ND) + process to get it. */ + + /* Ensure the current packet's queue next pointer to NULL */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Determine if the queue is empty. */ + if(NDCacheEntry -> nx_nd_cache_packet_waiting_head == NX_NULL) + { + /* ICMPv6 is enabled */ + if(ip_ptr -> nx_ip_icmpv6_packet_process) + { + + /* Queue up this packet */ + NDCacheEntry -> nx_nd_cache_packet_waiting_head = packet_ptr; + NDCacheEntry -> nx_nd_cache_packet_waiting_tail = packet_ptr; + NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length = 1; + + /* Set the outgoing address and interface to the cache entry. */ + NDCacheEntry -> nx_nd_cache_outgoing_address = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr; + NDCacheEntry -> nx_nd_cache_interface_ptr = if_ptr; + + /* Is this a new entry? */ + if(NDCacheEntry -> nx_nd_cache_nd_status == ND_CACHE_STATE_CREATED) + { + + /* Start Neighbor discovery process by advancing to the incomplete state. */ + NDCacheEntry -> nx_nd_cache_nd_status = ND_CACHE_STATE_INCOMPLETE; + } + + _nx_icmpv6_send_ns(ip_ptr, next_hop_address, + 1, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr, 0, NX_NULL); + + NDCacheEntry -> nx_nd_cache_num_solicit = NX_MAX_MULTICAST_SOLICIT - 1; + NDCacheEntry -> nx_nd_cache_timer_tick = ip_ptr -> nx_ipv6_retrans_timer_ticks; + + } + else + { + + _nx_packet_transmit_release(packet_ptr); +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + } + return; + } + + /* The ND process already started. Simply queue up this packet */ + NDCacheEntry -> nx_nd_cache_packet_waiting_tail -> nx_packet_queue_next = packet_ptr; + NDCacheEntry -> nx_nd_cache_packet_waiting_tail = packet_ptr; + NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length++; + + /* Check if the number of packets enqueued exceeds the allowed number. */ + if(NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length > NX_ND_MAX_QUEUE_DEPTH) + { + + /* Yes, so delete the first packet. */ + remove_packet = NDCacheEntry -> nx_nd_cache_packet_waiting_head; + + NDCacheEntry -> nx_nd_cache_packet_waiting_head = remove_packet -> nx_packet_queue_next; + + /* Update the queued packet count for this cache entry. */ + NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length--; + + _nx_packet_transmit_release(remove_packet); +#ifndef NX_DISABLE_IP_INFO + /* Increment the IP transmit resource error count. */ + ip_ptr -> nx_ip_transmit_resource_errors++; + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + } + + return; + } + + /* For now do nothing. Just release the packet */ + _nx_packet_release(packet_ptr); +} + +#endif /* FEATURE_NX_IPV6 */ + +#if defined(FEATURE_NX_IPV6) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_bsd_swap_ipv6_extension_headers PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs endian swap operations on the IPv6 */ +/* extension headers. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet */ +/* header_type Type of the first extension */ +/* header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* NX_CHANGE_USHORT_ENDIAN Swap endian-ness on 16-bit */ +/* integer. */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo BSD Layer Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_bsd_swap_ipv6_extension_headers(NX_PACKET *packet_ptr, UCHAR header_type) +{ +UCHAR *scan_ptr; +ULONG remaining_bytes; +ULONG header_length = 40; +NX_IPV6_HEADER_OPTION *option; + + + remaining_bytes = (ULONG)packet_ptr -> nx_packet_prepend_ptr - (ULONG)packet_ptr -> nx_packet_ip_header; + + scan_ptr = packet_ptr -> nx_packet_ip_header; + + remaining_bytes -= header_length; + scan_ptr += header_length; + + while(remaining_bytes) + { + option = (NX_IPV6_HEADER_OPTION*)scan_ptr; + switch(header_type) + { + case NX_PROTOCOL_NEXT_HEADER_HOP_BY_HOP: + + break; + + case NX_PROTOCOL_NEXT_HEADER_DESTINATION: + + break; + + case NX_PROTOCOL_NEXT_HEADER_ROUTING: + break; + + + case NX_PROTOCOL_NEXT_HEADER_FRAGMENT: + NX_CHANGE_USHORT_ENDIAN(((NX_IPV6_HEADER_FRAGMENT_OPTION *)scan_ptr) -> nx_ipv6_header_fragment_option_offset_flag); + break; + + default: + + break; + } + + header_type = option -> nx_ipv6_header_option_next_header; + + if(header_type == NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION) + header_length = (ULONG)((option -> nx_ipv6_header_option_ext_length << 2) + 2); + else + header_length = (ULONG)((option -> nx_ipv6_header_option_ext_length + 1) << 3); + + + remaining_bytes -= header_length; + scan_ptr += header_length; + } +} +#endif /* defined(FEATURE_NX_IPV6) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) */ +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_pppoe_internal_sendto PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends raw PPPOE packet to driver directly. */ +/* */ +/* INPUT */ +/* */ +/* bsd_socket_ptr Pointer to bsd socket */ +/* msg Message to send */ +/* msgLength Length of message */ +/* flags Flags */ +/* destAddr Pointer to destination address*/ +/* destAddrLen Length of destination address */ +/* */ +/* OUTPUT */ +/* */ +/* msgLength On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_append Append data to the packet */ +/* nx_packet_release Release the packet on error */ +/* tx_mutex_get Obtain exclusive access to */ +/* tx_mutex_put Release exclusive access */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT nx_bsd_pppoe_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, INT flags, struct sockaddr* destAddr, INT destAddrLen) +{ +UINT if_index; +struct sockaddr_ll *destAddr_ll; +#if 0 +ULONG src_mac_msw; +ULONG src_mac_lsw; +#endif +NX_IP_DRIVER driver_request; +UINT status; +NX_PACKET *packet_ptr = NX_NULL; + + NX_PARAMETER_NOT_USED(bsd_socket_ptr); + NX_PARAMETER_NOT_USED(flags); + + /* Validate the parameters. */ + if(destAddr == NX_NULL) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(destAddr -> sa_family != AF_PACKET) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(destAddrLen != sizeof(struct sockaddr_ll)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + destAddr_ll = (struct sockaddr_ll*)destAddr; + + if((destAddr_ll -> sll_protocol != ETHERTYPE_PPPOE_SESS) && (destAddr_ll -> sll_protocol != ETHERTYPE_PPPOE_DISC)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Validate the interface ID */ + if_index = (UINT)(destAddr_ll -> sll_ifindex); + if(if_index >= NX_MAX_IP_INTERFACES) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid == 0) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + +#if 0 + /* Pickup the source MAC address */ + src_mac_msw = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_physical_address_msw; + src_mac_lsw = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_physical_address_lsw; +#endif + + + + /* Validate the packet length */ + if(msgLength > (INT)(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_mtu_size + 14)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* FIXME: If the socket is non-blocking, Timeout value should be set to 0 */ + status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + + + /* Now copy the data into the NetX packet. */ + status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, NX_NO_WAIT); + + /* Was the data copy successful? */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + /* Now ready to transmit this packet. */ + driver_request.nx_ip_driver_ptr = nx_bsd_default_ip; + if(destAddr_ll -> sll_protocol == ETHERTYPE_PPPOE_SESS) + driver_request.nx_ip_driver_command = NX_LINK_PACKET_PPPOE_SESS_SEND; + else + driver_request.nx_ip_driver_command = NX_LINK_PACKET_PPPOE_DISC_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = &nx_bsd_default_ip -> nx_ip_interface[if_index]; + + /* Obtain the BSD lock. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + (driver_request.nx_ip_driver_interface -> nx_interface_link_driver_entry)(&driver_request); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(msgLength); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_bsd_pppoe_packet_received PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives raw PPPOE packet from driver directly. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to received packet */ +/* frame_type Type of frame */ +/* interface_id Interface ID */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_select_wakeup Wake up any asychronous */ +/* receive call */ +/* nx_packet_release Release the packet on error */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_bsd_pppoe_packet_received(NX_PACKET *packet_ptr, UINT frame_type, UINT interface_id) +{ + +UINT i; +UINT sockid = NX_BSD_MAX_SOCKETS; +UINT create_id = 0xFFFFFFFF; +NX_BSD_SOCKET *bsd_ptr; + + NX_PARAMETER_NOT_USED(interface_id); + + /* Find the socket with the lowest create-ID. Put the packet into the socket's recevie queue. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && + /* + (nx_bsd_socket_array[i].nx_bsd_raw_socket_enabled == NX_TRUE) && + */ + (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_PACKET) && + (nx_bsd_socket_array[i].nx_bsd_socket_protocol == frame_type)) + { + if(nx_bsd_socket_array[i].nx_bsd_socket_create_id < create_id) + { + sockid = i; + create_id = nx_bsd_socket_array[i].nx_bsd_socket_create_id; + } + } + } + if(sockid == NX_BSD_MAX_SOCKETS) + { + /* No BSD sockets are avaialble for this frame type. */ + nx_packet_release(packet_ptr); + return(NX_SUCCESS); + } + /* Now we need to put the packet into the socket. */ + bsd_ptr = &nx_bsd_socket_array[sockid]; + + /* Drop the packet if the receive queue exceeds max depth. */ + if(bsd_ptr -> nx_bsd_socket_received_packet_count >= + bsd_ptr -> nx_bsd_socket_received_packet_count_max) + { + nx_packet_release(packet_ptr); + return(NX_SUCCESS); + } + + if(bsd_ptr -> nx_bsd_socket_received_packet) + { + bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; + } + else + { + bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; + } + + bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + bsd_ptr -> nx_bsd_socket_received_packet_count ++; + + nx_bsd_select_wakeup(sockid, FDSET_READ); + + return 0; +} +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + +#ifdef NX_BSD_RAW_SUPPORT + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_bsd_hardware_internal_sendto PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends raw packet to driver directly. */ +/* */ +/* INPUT */ +/* */ +/* bsd_socket_ptr Pointer to bsd socket */ +/* msg Message to send */ +/* msgLength Length of message */ +/* flags Flags */ +/* destAddr Pointer to destination address*/ +/* destAddrLen Length of destination address */ +/* */ +/* OUTPUT */ +/* */ +/* msgLength On success */ +/* NX_SOC_ERROR (-1) On failure */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_append Append data to the packet */ +/* nx_packet_release Release the packet on error */ +/* tx_mutex_get Obtain exclusive access to */ +/* tx_mutex_put Release exclusive access */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT _nx_bsd_hardware_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, INT flags, struct sockaddr* destAddr, INT destAddrLen) +{ +UINT if_index; +struct sockaddr_ll *destAddr_ll; +UINT status; +NX_PACKET *packet_ptr = NX_NULL; + + NX_PARAMETER_NOT_USED(bsd_socket_ptr); + NX_PARAMETER_NOT_USED(flags); + + /* Validate the parameters. */ + if(destAddr == NX_NULL) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(destAddr -> sa_family != AF_PACKET) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(destAddrLen != sizeof(struct sockaddr_ll)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + destAddr_ll = (struct sockaddr_ll*)destAddr; + + /* Validate the interface ID */ + if_index = (UINT)(destAddr_ll -> sll_ifindex); + if(if_index >= NX_MAX_IP_INTERFACES) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + if(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid == 0) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + /* Validate the packet length */ + if(msgLength > (INT)(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_mtu_size + 18)) + { + /* Set the socket error if extended socket options enabled. */ + set_errno(EINVAL); + + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + + /* Set IP interface. */ + packet_ptr -> nx_packet_ip_interface = &nx_bsd_default_ip -> nx_ip_interface[if_index]; + + /* Now copy the data into the NetX packet. */ + status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, NX_NO_WAIT); + + /* Was the data copy successful? */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error. */ + set_errno(ENOBUFS); + + /* Return an error status.*/ + NX_BSD_ERROR(status, __LINE__); + return(NX_SOC_ERROR); + } + +#if defined(__PRODUCT_NETXDUO__) && defined(NX_ENABLE_INTERFACE_CAPABILITY) + packet_ptr -> nx_packet_interface_capability_flag = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_capability_flag; +#endif /* defined(__PRODUCT_NETXDUO__) && defined(NX_ENABLE_INTERFACE_CAPABILITY) */ + + /* Obtain the BSD lock. */ + status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Set the socket error if extended socket options enabled. */ + set_errno(EACCES); + + /* Return an error. */ + NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); + return(NX_SOC_ERROR); + } + + _nx_driver_hardware_packet_send(packet_ptr); + + /* Release the mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(msgLength); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_bsd_hardware_packet_received PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives raw packet from driver directly. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to received packet */ +/* consumed Return packet consumed or not */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_select_wakeup Wake up any asychronous */ +/* receive call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_bsd_hardware_packet_received(NX_PACKET *packet_ptr, UCHAR *consumed) +{ + +UINT i; +UINT sockid = NX_BSD_MAX_SOCKETS; +NX_BSD_SOCKET *bsd_ptr; + + /* Initialize the consumed to be false. */ + *consumed = NX_FALSE; + + /* Find the socket with the matching interface. Put the packet into the socket's recevie queue. */ + for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) + { + if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && + (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_PACKET) && + ((nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) || + (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == (ULONG)(packet_ptr -> nx_packet_ip_interface)))) + { + sockid = i; + } + } + if(sockid == NX_BSD_MAX_SOCKETS) + { + /* No BSD sockets are avaialble for this frame type. */ + return; + } + /* Now we need to put the packet into the socket. */ + bsd_ptr = &nx_bsd_socket_array[sockid]; + + /* Drop the packet if the receive queue exceeds max depth. */ + if(bsd_ptr -> nx_bsd_socket_received_packet_count >= + bsd_ptr -> nx_bsd_socket_received_packet_count_max) + { + return; + } + +#ifndef NX_DISABLE_BSD_RAW_PACKET_DUPLICATE + /* Duplicate the packet. */ + if (nx_packet_copy(packet_ptr, &packet_ptr, nx_bsd_default_packet_pool, NX_NO_WAIT) != NX_SUCCESS) + { + return; + } +#else + /* Consume the packet. IP layer will not see it. */ + *consumed = NX_TRUE; +#endif /* NX_DISABLE_BSD_RAW_PACKET_DUPLICATE */ + + if(bsd_ptr -> nx_bsd_socket_received_packet) + { + bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; + } + else + { + bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; + } + + bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; + bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; + bsd_ptr -> nx_bsd_socket_received_packet_count ++; + + nx_bsd_select_wakeup(sockid, FDSET_READ); + + return; +} +#endif /* NX_BSD_RAW_SUPPORT */ + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_pton PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IP address from presentation to numeric. */ +/* */ +/* INPUT */ +/* */ +/* af Either AF_INET or AF_INET6 */ +/* src A pointer pointing to the */ +/* presentation of IP address */ +/* dst A pointer pointing to the */ +/* destination memory */ +/* */ +/* OUTPUT */ +/* */ +/* status 1 OK */ +/* 0 invalid presentation */ +/* -1 error */ +/* */ +/* CALLS */ +/* */ +/* inet_aton Convert IPv4 address from */ +/* presentation to numeric */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT inet_pton(INT af, const CHAR *src, VOID *dst) +{ +CHAR ch; +USHORT value; +/* A number used to convert a character in '0123456789abcdefABCDEF' to a number. */ +UINT minuend; +/* A counter used to recoder the number of digits between 2 colons. */ +UINT digit_counter; + +UCHAR *colon_location; +/* A pointer used to traverse the destination memory. */ +UCHAR *dst_cur_ptr; +/* A pointer to the end of the destination memory. */ +UCHAR *dst_end_ptr; +ULONG *dst_long_ptr; + +const CHAR *ipv4_addr_start = src; +UINT n, i; + +struct in_addr ipv4_addr; + + if(af == AF_INET) + { + /* Convert IPv4 address from presentation to numeric. */ + if(inet_aton(src, &ipv4_addr)) + { + /* Copy the IPv4 address to the destination. */ + *((ULONG *)dst) = ipv4_addr.s_addr; + return 1; + } + return 0; + } + else if(af == AF_INET6) + { + /* If : is at the beginning, the next value must be : .*/ + if(*src == ':') + if(*src++ != ':') + return 0; + + /* Initialization. */ + value = 0; + digit_counter = 0; + colon_location = NX_NULL; + dst_cur_ptr = dst; + /* Calculate the end of the destination memory. */ + dst_end_ptr = (UCHAR*)dst + 15; + /* Clear the destination memory. */ + memset(dst_cur_ptr, 0, 16); + + while(*src != 0) + { + /* Get the current character. */ + ch = *src++; + + /* Judge which minuend to use. + * '0' - 48 == 0 + * 'a' - 87 == 10 + * 'A' - 55 == 10 + */ + minuend = 0; + if(ch >= '0' && ch <= '9') + minuend = 48; + else if(ch >= 'a' && ch <= 'f') + minuend = 87; + else if(ch >= 'A' && ch <= 'F') + minuend = 55; + + /* if minuend is not 0, then ch is character in "0123456789abcdefABCDEF" */ + if(minuend) + { + /* Convert the character to number. */ + value = (USHORT)(value << 4); + value = (USHORT)(value | ((UINT)ch - minuend)); + + /* The max number of digits between 2 colons is 4. */ + if(++digit_counter > 4) + return 0; + + continue; + } + + if(ch == ':') + { + ipv4_addr_start = src; + + /* Is there a digit before the colon? */ + if(!digit_counter) + { + /* There is no digit before the colon. */ + + /* If there are 2 "::", Invalid Presentation Format. + * IF there is a ":::", Invalid Presention Format. */ + if(colon_location) + return 0; + + /* Record the colon location. */ + colon_location = dst_cur_ptr; + continue; + } + else if(*src == '\0') + { + /* The colon is at the end of src, Invalid Presention Format. */ + return 0; + } + + if(dst_cur_ptr + 1 > dst_end_ptr) + { + /* Invalid Presentation Format. */ + return 0; + } + + /* Store the value to the dst memory. */ + *(dst_cur_ptr++) = (UCHAR) (value >> 8) & 0xff; + *(dst_cur_ptr++) = (UCHAR) (value) & 0xff; + + /* Reset the value and digit counter. */ + digit_counter = 0; + value = 0; + + continue; + + } + else if(ch == '.') + { + /* Process the dotted-decimal string in IPv4-mapped IPv6 address and IPv4-compatible IPv6 address. */ + + if(dst_cur_ptr + 3 > dst_end_ptr) + { + /* Invalid Presentation Format. */ + return 0; + } + + /* Convert the ipv4 address from presentation to numeric. */ + if(inet_aton(ipv4_addr_start, &ipv4_addr)) + { + + /* Make sure the result is in network byte order. */ + ipv4_addr.s_addr = ntohl(ipv4_addr.s_addr); + NX_CHANGE_ULONG_ENDIAN(ipv4_addr.s_addr); + + /* Store the value to the dst memory. */ + *(ULONG *)dst_cur_ptr = ipv4_addr.s_addr; + + dst_cur_ptr += 4; + digit_counter = 0; + + break; + } + else + return 0; + + + } + else + { + return 0; + } + } + + if(digit_counter) + { + + /* Invalid Presentation Format. */ + if(dst_cur_ptr + 1 > dst_end_ptr) + return 0; + + /* Store the value to the dst memory. */ + *(dst_cur_ptr++) = (UCHAR) (value >> 8) & 0xff; + *(dst_cur_ptr++) = (UCHAR) (value) & 0xff; + + } + + if(colon_location) + { + /* There is a :: in the IPv6 address presentation. */ + + /* Calculate how many octets should be moved to the end of the dst memory. */ + n = (UINT)(dst_cur_ptr - colon_location); + + if(dst_cur_ptr == dst_end_ptr) + return 0; + + /* Move the data to the end of dst memory. + * ----------- ----------- + * |aabb0000000| ----> |aa0000000bb| + * ----------- ----------- + */ + for(i = 1; i <=n; i++) + { + *(dst_end_ptr--) = colon_location[n - i]; + colon_location[n-i] = 0; + } + + dst_cur_ptr = dst_end_ptr + 1; + } + + if(dst_cur_ptr != (dst_end_ptr + 1)) + return 0; + + dst_long_ptr = (ULONG *)dst; + + /* First convert it to host byte order. */ + NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[0]); + NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[1]); + NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[2]); + NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[3]); + + /* Convert it to network byte order by BSD macros. */ + dst_long_ptr[0] = htonl(dst_long_ptr[0]); + dst_long_ptr[1] = htonl(dst_long_ptr[1]); + dst_long_ptr[2] = htonl(dst_long_ptr[2]); + dst_long_ptr[3] = htonl(dst_long_ptr[3]); + return 1; + } + else + { + /* Error. */ + return -1; + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_ntop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IP address from numeric to presentation. */ +/* */ +/* INPUT */ +/* */ +/* af Either AF_INET or AF_INET6 */ +/* src A void pointer pointing to */ +/* network byte order IP address*/ +/* dst A char pointer pointing to */ +/* the destination buffer */ +/* size The size of the destination */ +/* buffer */ +/* */ +/* OUTPUT */ +/* */ +/* dst The destination buffer */ +/* */ +/* CALLS */ +/* */ +/* inet_ntoa_internal Convert IPv4 address from */ +/* numeric to presentation */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +const CHAR *inet_ntop(INT af, const VOID *src, CHAR *dst, socklen_t size) +{ + +INT shorthand_index; +INT shorthand_len; +INT current_index; +INT current_len; + +INT i; +INT index; +UINT rt_size; + + + if(af == AF_INET) + { + /* Convert IPv4 address from numeric to presentation. */ + if(inet_ntoa_internal(src, dst, size)) + return dst; + else + return NX_NULL; + } + else if(af == AF_INET6) + { + USHORT temp[8]; + temp[0] = (USHORT)(ntohl(*((ULONG *)src)) >> 16); + temp[1] = (USHORT)(ntohl(*((ULONG *)src)) & 0xFFFF); + temp[2] = (USHORT)(ntohl(*(((ULONG *)src) + 1)) >> 16); + temp[3] = (USHORT)(ntohl(*(((ULONG *)src) + 1)) & 0xFFFF); + temp[4] = (USHORT)(ntohl(*(((ULONG *)src) + 2)) >> 16); + temp[5] = (USHORT)(ntohl(*(((ULONG *)src) + 2)) & 0xFFFF); + temp[6] = (USHORT)(ntohl(*(((ULONG *)src) + 3)) >> 16); + temp[7] = (USHORT)(ntohl(*(((ULONG *)src) + 3)) & 0xFFFF); + + /* Initialization. */ + shorthand_index = -1; + shorthand_len = 0; + current_index = -1; + current_len = 0; + + /* Find the longest 0x00 in src for :: + * 16 * 8 == 128 */ + for(i = 0; i < 8; i++) + { + if(temp[i] == 0) + { + if(current_index == -1) + { + /* Record the index of 0x00, Initialize the length to 1. */ + current_index = i; + current_len = 1; + } + else + { + current_len++; + } + } + else + { + /* Not 0x00 . */ + + if(current_index != -1) + { + /* Not equal -1, means there is record of 0x00s . */ + + if(shorthand_index == -1 || current_len > shorthand_len) + { + /* Record the longest 0x00s. */ + shorthand_index = current_index; + shorthand_len = current_len; + } + + /* Reset the index. */ + current_index = -1; + } + + } + } + + + if(current_len > shorthand_len) + { + /* Record the longest 0x00s. */ + shorthand_index = current_index; + shorthand_len = current_len; + } + + /* If length is less than 2, no need for shorthand. */ + if(shorthand_len < 2) + { + shorthand_index = -1; + } + + index = 0; + /* Format the result. */ + for(i = 0; i < 8; i++) + { + /* Is i in the range of :: */ + if((shorthand_index != -1) && + (i >= shorthand_index) && + (i < (shorthand_index + shorthand_len))) + { + if(i == shorthand_index) + { + /* Check if there is enough memory to store a character. */ + if((size - (ULONG)index) < 1) + return NX_NULL; + + dst[index++] = ':'; + } + continue; + } + + if(i != 0) + { + /* Check if there is enough memory to store a character. */ + if((size - (ULONG)index) < 1) + return NX_NULL; + + dst[index++] = ':'; + } + + /* Does this address contain IPv4 address. */ + if(i == 6 && shorthand_index == 0 && + (shorthand_len == 6 || /* IPv4-mapped IPv6 address -----> ::1.2.3.4 */ + (shorthand_len == 5 && temp[5] == 0xffff))) /* IPv4-compatible IPv6 address -----> ::ffff:1.2.3.4 */ + { + /* Convert ipv4 address to string. 12 == 16 - 4*/ + rt_size = (UINT)inet_ntoa_internal((UCHAR*)src + 12, &dst[index], size - (ULONG)index); + + /* Check the return size, 0 means error. */ + if(rt_size) + index += (INT)rt_size; + else + return NX_NULL; + } + + /* Convert hex number to string */ + rt_size = bsd_number_convert(temp[i], &dst[index], size - (ULONG)index, 16); + if(!rt_size) + return NX_NULL; + + /* Increment the index. */ + index += (INT)rt_size; + + } + + /* Is there a trailing : */ + if((shorthand_index != -1) && (shorthand_index + shorthand_len == 8)) + { + /* Check if there is enough memory to store a character. */ + if((size - (ULONG)index) < 1) + return NX_NULL; + + dst[index++] = ':'; + + } + + /* Check if there is enough memory to store a character. */ + if((size - (ULONG)index) < 1) + return NX_NULL; + + dst[index] = '\0'; + + return dst; + } + else + { + return NX_NULL; + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* inet_ntoa_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IPv4 address to a string and returns the */ +/* size of the string. */ +/* */ +/* INPUT */ +/* */ +/* src A void pointer pointing to */ +/* IPv4 address */ +/* dst A char pointer pointing to */ +/* the destination buffer */ +/* dst_size The size of the destination */ +/* buffer */ +/* */ +/* OUTPUT */ +/* */ +/* index The size of the IPv4 address */ +/* string */ +/* */ +/* CALLS */ +/* */ +/* memset Set the memory to 0 */ +/* bsd_number_convert Convert a number to string */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo BSD Layer Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +static INT inet_ntoa_internal(const VOID *src, CHAR *dst, ULONG dst_size) +{ +ULONG temp; +UINT size; +UINT index = 0; + + + /* Set a local pointer to move up the buffer. */ + temp = ntohl(*((ULONG *)src)); + + memset(dst, 0, dst_size); + + /* Convert the first number to a string. */ + size = bsd_number_convert((temp >> 24), &dst[0], dst_size - index, 10); + + if(!size) + return 0; + + /* Move up the index and buffer pointer. */ + index += size; + + /* Check the rest of the dst buffer. */ + if((dst_size - index) < 1) + return 0; + + /* Add the decimal. */ + dst[index++] = '.'; + + /* And repeat three more times...*/ + size = bsd_number_convert((temp >> 16) & 0xff, &dst[index], dst_size - index, 10); + + if(!size) + return 0; + + index += size; + + if((dst_size - index) < 1) + return 0; + + dst[index++] = '.'; + + size = bsd_number_convert((temp >> 8) & 0xff, &dst[index], dst_size - index, 10); + + if(!size) + return 0; + + index += size; + + if((dst_size - index) < 1) + return 0; + + dst[index++] = '.'; + + size = bsd_number_convert(temp & 0xff, &dst[index], dst_size - index, 10); + + if(!size) + return 0; + + index += size; + + if((dst_size - index) < 1) + return 0; + + dst[index++] = '\0'; + + /* Return the size of the dst string. */ + return((INT)(index)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* getaddrinfo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns one or more addrinfo structures according to */ +/* the specified node and service. */ +/* */ +/* INPUT */ +/* */ +/* node Node is either a hostname or */ +/* an address string(dotted- */ +/* decimal for IPv4 or a hex */ +/* string for IPv6). */ +/* service Service is either a service */ +/* name or a decimal port number*/ +/* string. */ +/* hints Hints is either a null pointer*/ +/* or a pointer to an addrinfo */ +/* structure that the caller */ +/* fills in with hints about the*/ +/* types of information the */ +/* caller wants returned. */ +/* res Pointer to the returned */ +/* addrinfo list. */ +/* */ +/* OUTPUT */ +/* */ +/* status 0 if OK, nonzero on errors */ +/* */ +/* CALLS */ +/* */ +/* bsd_string_to_number Convert a string to a number */ +/* htons Host byte order to network */ +/* byte order */ +/* memcmp Memory compare */ +/* inet_pton Convert IP address from */ +/* presentation to numeric */ +/* tx_block_allocate Allocate memory for address or*/ +/* addrinfo */ +/* memset Set the memory to 0 */ +/* freeaddrinfo Release addrinfo memory */ +/* nx_dns_ipv4_address_by_name_get Get ipv4 addr by name via dns */ +/* nxd_dns_ipv6_address_by_name_get Get ipv6 addr by name via dns */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT getaddrinfo(const CHAR *node, const CHAR *service, const struct addrinfo *hints, struct addrinfo **res) +{ + +UINT status; +#ifdef NX_BSD_ENABLE_DNS +UINT status2; +#endif +UINT pton_flag; +UINT port; +UINT i, j; +INT addr_family; +UINT ipv4_addr_count = 0; +UINT ipv6_addr_count = 0; +UINT match_service_count; +UINT match_service_socktype[3]; +UINT match_service_protocol[3]; +struct addrinfo *addrinfo_cur_ptr = NX_NULL; +struct addrinfo *addrinfo_head_ptr = NX_NULL; +struct addrinfo *addrinfo_tail_ptr = NX_NULL; +struct sockaddr *sockaddr_ptr = NX_NULL; +UCHAR *cname_buffer = NX_NULL; + +/* When hints is a null pointer, use the default value below. */ +static struct addrinfo default_hints = {0, AF_UNSPEC, 0, 0, 0, NX_NULL, NX_NULL, NX_NULL}; + + + + /* if node and service are null return an error, invalid input. */ + if((node == NX_NULL) && (service == NX_NULL)) + return EAI_NONAME; + + if(hints) + { + + /* Check if the address family is valid. */ + if((hints -> ai_family != AF_INET) && + (hints -> ai_family != AF_INET6) && + (hints -> ai_family != AF_UNSPEC)) + return EAI_FAMILY; + + /* Check if the socket type is valid. */ + if((hints -> ai_socktype != SOCK_DGRAM) && + (hints -> ai_socktype != SOCK_STREAM) && + (hints -> ai_socktype != 0)) + return EAI_SOCKTYPE; + + /* If socktype and protocol are both specified, check if they are meaningful. */ + if((hints -> ai_socktype != 0) && (hints -> ai_protocol != 0)) + { + if(((hints -> ai_socktype == SOCK_STREAM) && (hints -> ai_protocol != IPPROTO_TCP)) || + ((hints -> ai_socktype == SOCK_DGRAM) && (hints -> ai_protocol != IPPROTO_UDP)) || + ((hints -> ai_socktype == SOCK_RAW) && (hints -> ai_protocol != IPPROTO_RAW))) + return EAI_SOCKTYPE; + } + + } + else + { + hints = &default_hints; + } + + /* Sock type specified? */ + if(hints -> ai_socktype == 0) + { + + /* No; is protocol specified? */ + if(hints -> ai_protocol == 0) + { + + /* No, protocol is not specified. */ + + /* Set default socktype and protocol. */ + match_service_count = 3; + match_service_socktype[0] = SOCK_STREAM; + match_service_protocol[0] = IPPROTO_TCP; + match_service_socktype[1] = SOCK_DGRAM; + match_service_protocol[1] = IPPROTO_UDP; + match_service_socktype[2] = SOCK_RAW; + match_service_protocol[2] = 0; + } + else + { + + /* protocol is specified. */ + match_service_count = 1; + match_service_protocol[0] = (UINT)(hints -> ai_protocol); + + /* Set default socktype according to protocol. */ + if(hints -> ai_protocol == IPPROTO_TCP) + match_service_socktype[0] = SOCK_STREAM; + else if(hints -> ai_protocol == IPPROTO_UDP) + match_service_socktype[0] = SOCK_DGRAM; + } + } + else + { + + /* Socktype is specified. */ + match_service_count = 1; + match_service_socktype[0] = (UINT)(hints -> ai_socktype); + + if(hints -> ai_protocol == 0) + { + + /* Protocol is not specified. */ + + /* Set default protocol according to socktype. */ + if(hints -> ai_socktype == SOCK_STREAM) + match_service_protocol[0] = IPPROTO_TCP; + else if(hints -> ai_socktype == SOCK_DGRAM) + match_service_protocol[0] = IPPROTO_UDP; + else if(hints -> ai_socktype == SOCK_RAW) + match_service_protocol[0] = 0; + } + else + { + + /* Protocol is specififed. */ + match_service_protocol[0] = (UINT)(hints -> ai_protocol); + } + } + + if(service) + { + + /* Service is not null. */ + if(bsd_string_to_number(service, &port) != NX_SOC_ERROR) + { + + /* Service is a decimal port number string, and has been converted to a numeric port successfully. */ + + /* Convert port from host byte order to network byte order. */ + port = htons(port); + } + else + { + + /* Service is an address name, not a decimal port number string. */ + + /* Check if numeric service flag is set. If so this is an invalid string. */ + if(hints -> ai_flags & AI_NUMERICSERV) + return EAI_NONAME; + + match_service_count = 0; + + /* Look for a match of name, protocol and socket type for a match in the service list. */ + for(i = 0; i < _nx_bsd_serv_list_len; i++) + { + + /* Check if there is a match. */ + if(!memcmp(_nx_bsd_serv_list_ptr[i].service_name, service, _nx_bsd_string_length((CHAR *)service)) && + ((_nx_bsd_serv_list_ptr[i].service_socktype == hints -> ai_socktype) ||(hints -> ai_socktype == 0)) && + ((_nx_bsd_serv_list_ptr[i].service_protocol == hints -> ai_protocol) ||(hints -> ai_protocol == 0))) + { + match_service_socktype[match_service_count] = (UINT)(_nx_bsd_serv_list_ptr[i].service_socktype); + match_service_protocol[match_service_count++] = (UINT)(_nx_bsd_serv_list_ptr[i].service_protocol); + + /* Convert host byte order to network byte order. */ + port = htons(_nx_bsd_serv_list_ptr[i].service_port); + } + } + + /* Service is not available. */ + if(match_service_count == 0) + return EAI_SERVICE; + } + } + else + { + + /* Convert host byte order to network byte order. */ + port = htons(0); + } + + if(node) + { + + /* Node is not null. */ + + /* Determine the address family. */ + addr_family = AF_INET; + + for(i = 0; i < _nx_bsd_string_length((CHAR *)node); i++) + { + if(node[i] == ':') + { + /* There is a colon, so it is an IPv6 address. */ + addr_family = AF_INET6; + break; + } + } + + /* Initialize to 0, default to pton failing. */ + pton_flag = 0; + + if(addr_family == AF_INET) + { + + /* Convert node from a string presentation to a numeric address. */ + if(inet_pton(addr_family, node, &(nx_bsd_ipv4_addr_buffer[0])) == 1) + { + /* pton has successful completion. */ + pton_flag = 1; + + /* Check if the address and the specified family match. */ + if((hints -> ai_family != AF_INET) && (hints -> ai_family != AF_UNSPEC)) + return EAI_ADDRFAMILY; + + NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv4_addr_buffer[0]); + ipv4_addr_count = 1; + } + } + else + { + + /* Convert node from a string presentation to a numeric address. */ + if(inet_pton(addr_family, node, &(nx_bsd_ipv6_addr_buffer[0])) == 1) + { + /* pton completed successfully. */ + pton_flag = 1; + + /* Check is the address and the specified family matches. */ + if((hints -> ai_family != AF_INET6) && (hints -> ai_family != AF_UNSPEC)) + return EAI_ADDRFAMILY; + + NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[0]); + NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[1]); + NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[2]); + NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[3]); + ipv6_addr_count = 1; + } + } + + if(pton_flag == 1) + { + + /* pton completed successfull. Host (node) is an address string. */ + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + /* DNS supports extended services including Canonical name queries. */ + if((hints -> ai_flags & AI_CANONNAME) && !(hints -> ai_flags & AI_NUMERICHOST)) + { + + /* Allocate a block for canonical name. */ + status = tx_block_allocate(&nx_bsd_cname_block_pool, (VOID *) &cname_buffer, NX_BSD_TIMEOUT); + + /* Check for error status. */ + if (status != TX_SUCCESS) + { + /* Set the error. */ + set_errno(ENOMEM); + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Return memory allocation error. */ + return(EAI_MEMORY); + } + + memcpy(cname_buffer, node, _nx_bsd_string_length((CHAR *)node)); + + } +#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ + + } + else + { + + /* Presentation to numeric format fails, node may be a hostname, not a numeric IP address. */ + + /* Check if numeric host flag is set. */ + if(hints -> ai_flags & AI_NUMERICHOST) + return EAI_NONAME; + +#ifdef NX_BSD_ENABLE_DNS + if(hints -> ai_family == AF_INET) + { + + /* Get IPv4 address by hostname. */ + status = nx_dns_ipv4_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv4_addr_buffer[0], + NX_BSD_IPV4_ADDR_PER_HOST * 4, &ipv4_addr_count, NX_BSD_TIMEOUT); + + if(status != NX_SUCCESS) + { + + /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation where the specified + network host exists but does not have any network addresses defined. It would be better to return EAI_FAIL + for DNS FAIL, and EAI_NODATA for the latter situation. */ + return EAI_FAIL; + } + } + else if(hints -> ai_family == AF_INET6) + { + + /* Get IPv6 address by hostname. */ + status = nxd_dns_ipv6_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv6_addr_buffer[0], + NX_BSD_IPV6_ADDR_PER_HOST * 16, &ipv6_addr_count, NX_BSD_TIMEOUT); + + if(status != NX_SUCCESS) + { + /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation where the specified + network host exists but does not have any network addresses defined. It would be better to return EAI_FAIL + for DNS FAIL, and EAI_NODATA for the latter situation. */ + return EAI_FAIL; + } + } + else + { + + /* Address family is not specified. Query for both IPv4 and IPv6 address. */ + + /* Get IPv4 address by hostname. */ + status = nx_dns_ipv4_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv4_addr_buffer[0], + NX_BSD_IPV4_ADDR_PER_HOST * 4, &ipv4_addr_count, NX_BSD_TIMEOUT); + + /* Get IPv6 address by hostname. */ + status2 = nxd_dns_ipv6_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv6_addr_buffer[0], + NX_BSD_IPV6_ADDR_PER_HOST * 16, &ipv6_addr_count, NX_BSD_TIMEOUT); + + if((status != NX_SUCCESS) && status2 != NX_SUCCESS) + { + /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation that the specified + network host exists, but does not have any network addresses defined. It would be better to return EAI_FAIL + for DNS FAIL, and EAI_NODATA for the latter situation. */ + return EAI_FAIL; + } + } + + if(hints -> ai_flags & AI_CANONNAME) + { + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + /* Allocate a block for canonical name. */ + status = tx_block_allocate(&nx_bsd_cname_block_pool, (VOID *) &cname_buffer, NX_BSD_TIMEOUT); + + /* Check for error status. */ + if (status != TX_SUCCESS) + { + /* Set the error. */ + set_errno(ENOMEM); + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Return memory allocation error. */ + return(EAI_MEMORY); + } + + status = nx_dns_cname_get(_nx_dns_instance_ptr, (UCHAR *)node, cname_buffer, + nx_bsd_cname_block_pool.tx_block_pool_block_size, NX_BSD_TIMEOUT); + if(status != NX_SUCCESS) + { + memcpy(cname_buffer, node, _nx_bsd_string_length((CHAR *)node)); + } + +#else + cname_buffer = (UCHAR *)node; +#endif + } +#else + return EAI_FAIL; +#endif + + } + } + else + { + + /* Node is null. */ + if(hints -> ai_flags & AI_PASSIVE) + { + /* The caller wiil use the socket for a passive open. */ + + nx_bsd_ipv4_addr_buffer[0] = INADDR_ANY; + + nx_bsd_ipv6_addr_buffer[0] = 0; + nx_bsd_ipv6_addr_buffer[1] = 0; + nx_bsd_ipv6_addr_buffer[2] = 0; + nx_bsd_ipv6_addr_buffer[3] = 0; + } + else + { + + /* Localhost address. */ + nx_bsd_ipv4_addr_buffer[0] = 0x7F000001; + + nx_bsd_ipv6_addr_buffer[0] = 0; + nx_bsd_ipv6_addr_buffer[1] = 0; + nx_bsd_ipv6_addr_buffer[2] = 0; + nx_bsd_ipv6_addr_buffer[3] = 1; + } + + if (hints -> ai_family != AF_INET6) + { + ipv4_addr_count = 1; + } + ipv6_addr_count = 1; + } + + + for(i = 0; i < ipv4_addr_count + ipv6_addr_count; i++) + { + + /* Allocate a block for ipv4 address. */ + status = tx_block_allocate(&nx_bsd_addrinfo_block_pool, (VOID *) &sockaddr_ptr, NX_BSD_TIMEOUT); + + /* Check for error status. */ + if (status != TX_SUCCESS) + { + + /* Set the error. */ + set_errno(ENOMEM); + + /* If head is not null, free the memory. */ + if(addrinfo_head_ptr) + freeaddrinfo(addrinfo_head_ptr); + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + if(hints -> ai_flags & AI_CANONNAME) + tx_block_release((VOID *)cname_buffer); +#endif + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Return memory allocation error. */ + return(EAI_MEMORY); + } + + /* Clear the memory. */ + memset((VOID*)sockaddr_ptr, 0, sizeof(struct addrinfo)); + + if(i < ipv4_addr_count) + { + + /* Process IPv4 address. */ + ((struct sockaddr_in*)sockaddr_ptr) -> sin_family = AF_INET; + ((struct sockaddr_in*)sockaddr_ptr) -> sin_port = (USHORT)port; + ((struct sockaddr_in*)sockaddr_ptr) -> sin_addr.s_addr = nx_bsd_ipv4_addr_buffer[i]; + + NX_CHANGE_ULONG_ENDIAN(((struct sockaddr_in*)sockaddr_ptr) -> sin_addr.s_addr); + } + else + { + + /* Process IPv6 address. */ + ((struct sockaddr_in6*)sockaddr_ptr) -> sin6_family = AF_INET6; + ((struct sockaddr_in6*)sockaddr_ptr) -> sin6_port = (USHORT)port; + memcpy(&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr), &nx_bsd_ipv6_addr_buffer[(i - ipv4_addr_count)*4], 16); + + NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[0])); + NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[1])); + NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[2])); + NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[3])); + + } + + for(j = 0; j < match_service_count; j++) + { + + /* Allocate a block from the addrinfo block pool. */ + status = tx_block_allocate(&nx_bsd_addrinfo_block_pool, (VOID *) &addrinfo_cur_ptr, NX_BSD_TIMEOUT); + + /* Check for error status. */ + if (status != TX_SUCCESS) + { + + /* Set the error. */ + set_errno(ENOMEM); + + /* If head is not null, free the memory. */ + if(addrinfo_head_ptr) + freeaddrinfo(addrinfo_head_ptr); + + tx_block_release((VOID *)sockaddr_ptr); + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + if(hints -> ai_flags & AI_CANONNAME) + tx_block_release((VOID *)cname_buffer); +#endif + + /* Error getting NetX socket memory. */ + NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); + + /* Return memory allocation error. */ + return(EAI_MEMORY); + } + + /* Clear the socket memory. */ + memset((VOID*)addrinfo_cur_ptr, 0, sizeof(struct addrinfo)); + + if(i < ipv4_addr_count) + { + + /* IPv4 */ + addrinfo_cur_ptr -> ai_family = AF_INET; + addrinfo_cur_ptr -> ai_addrlen = sizeof(struct sockaddr_in); + } + else + { + + /* IPv6 */ + addrinfo_cur_ptr -> ai_family = AF_INET6; + addrinfo_cur_ptr -> ai_addrlen = sizeof(struct sockaddr_in6); + } + + addrinfo_cur_ptr -> ai_socktype = (INT)(match_service_socktype[j]); + addrinfo_cur_ptr -> ai_protocol = (INT)(match_service_protocol[j]); + addrinfo_cur_ptr -> ai_addr = sockaddr_ptr; + if((i == 0) && (j == 0) && (hints -> ai_flags & AI_CANONNAME)) + addrinfo_cur_ptr -> ai_canonname = (CHAR *)cname_buffer; + else + addrinfo_cur_ptr -> ai_canonname = NX_NULL; + addrinfo_cur_ptr -> ai_next = NX_NULL; + + /* Make a list. */ + if(addrinfo_head_ptr == NX_NULL) + addrinfo_head_ptr = addrinfo_cur_ptr; + else + addrinfo_tail_ptr -> ai_next = addrinfo_cur_ptr; + + addrinfo_tail_ptr = addrinfo_cur_ptr; + + } + } + + *res = addrinfo_head_ptr; + + return 0; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* freeaddrinfo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases the memory allocated by getaddrinfo. */ +/* */ +/* INPUT */ +/* */ +/* res Pointer to a addrinfo struct */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_block_release Release socket memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID freeaddrinfo(struct addrinfo *res) +{ + +struct addrinfo *next_addrinfo; +struct sockaddr *ai_addr_ptr = NX_NULL; +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +CHAR *ai_canonname_ptr = NX_NULL; +#endif + + while(res) + { +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + if((res -> ai_canonname) && + (res -> ai_canonname != ai_canonname_ptr)) + { + + /* Release the CNAME memory. */ + tx_block_release((VOID *)res -> ai_canonname); + + ai_canonname_ptr = res -> ai_canonname; + } +#endif + if((res -> ai_addr) && + (res -> ai_addr != ai_addr_ptr)) + { + + /* Release the address memory. */ + tx_block_release((VOID *)res -> ai_addr); + + ai_addr_ptr = res -> ai_addr; + } + + /* Move next. */ + next_addrinfo = res -> ai_next; + + /* Release the addrinfo memory. */ + tx_block_release((VOID *)res); + + res = next_addrinfo; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* bsd_string_to_number PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts string to number. */ +/* */ +/* INPUT */ +/* */ +/* string Pointer to a string */ +/* number Pointer to a number */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* nx_bsd_isdigit Indicate char is a number */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static INT bsd_string_to_number(const CHAR *string, UINT *number) +{ + + /* Initialize the numbet to zero. */ + *number = 0; + + while(*string != '\0') + { + + /* Check if the current character is a digit character. */ + if(!nx_bsd_isdigit((UCHAR)(*string))) + return NX_SOC_ERROR; + + *number = (*number * 10) + (UINT)(*string - 0x30); + + string++; + } + + return NX_SOC_OK; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* getnameinfo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a socket address to a corresponding host and */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* sa Pointer to a generic socket */ +/* address structure */ +/* salen Length of sa structure */ +/* host Pointer to caller-allocated */ +/* buffer for hostname */ +/* hostlen Host buffer size */ +/* serv Pointer to caller-allocated */ +/* buffer for service name */ +/* servlen Service buffer size */ +/* */ +/* OUTPUT */ +/* */ +/* status 0 if OK, nonzero on errors */ +/* */ +/* CALLS */ +/* */ +/* nx_dns_host_by_address_get Get hostname by IPv4 address */ +/* nxd_dns_host_by_address_get Get hostname by IPv6 address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) +{ + +UINT i = 0; +/* Flag used to identify whether host/service is numeric, 0 no, 1 yes. */ +UINT numeric_flag; +USHORT *temp; +#ifdef NX_BSD_ENABLE_DNS +UINT status; +#ifdef FEATURE_NX_IPV6 +NXD_ADDRESS nxd_ipv6_addr; +#endif +#endif +const CHAR *rt_ptr; + + if(!sa) + { + + /* sa is NULL. */ + return EAI_FAMILY; + } + else + { + if((sa -> sa_family != AF_INET) && + (sa -> sa_family != AF_INET6)) + { + + /* sa isn't NULL, but family type is invalid. */ + return EAI_FAMILY; + } + else if((sa -> sa_family == AF_INET && salen != sizeof(struct sockaddr_in)) || + (sa -> sa_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))) + { + + /* Address length is invalid. */ + return EAI_FAMILY; + } + } + + /* Both host and service null are invalid */ + if((host == NX_NULL) && (serv == NX_NULL) && ((flags & NI_NAMEREQD) == 0)) + return EAI_NONAME; + + if(serv && servlen > 0) + { + numeric_flag = 1; + + /* If NUMERICSERV bit is set, set to 1. */ + if(flags & NI_NUMERICSERV) + { + numeric_flag = 1; + } + else if(flags & NI_DGRAM) + { + /* Socket type must be SOCK_DGRAM. */ + + for(i = 0; i < _nx_bsd_serv_list_len; i++) + { + temp = (USHORT *)(sa -> sa_data); + if((_nx_bsd_serv_list_ptr[i].service_port == *temp) && + (_nx_bsd_serv_list_ptr[i].service_socktype == SOCK_DGRAM)) + { + + /* Found a matched service, set numeric flag to 0. */ + numeric_flag = 0; + break; + } + } + } + else + { + + /* Socket type is SOCK_STREAM. */ + for(i = 0; i < _nx_bsd_serv_list_len; i++) + { + temp = (USHORT *)(sa -> sa_data); + if((_nx_bsd_serv_list_ptr[i].service_port == *temp) && + (_nx_bsd_serv_list_ptr[i].service_socktype == SOCK_STREAM)) + { + + /* Found a matched service, set numeric flag to 0. */ + numeric_flag = 0; + break; + } + } + } + + if(numeric_flag) + { + + /* Service is numeric, copy the service port. Then convert host byte order to network byte order. */ + temp = (USHORT *)(sa -> sa_data); + if(bsd_number_convert(htons(*temp), (CHAR *)serv, servlen, 10) == 0) + return EAI_OVERFLOW; + } + else + { + + /* Service isn't numeric, copy the service name. */ + if(_nx_bsd_string_length(_nx_bsd_serv_list_ptr[i].service_name) > servlen) + return EAI_OVERFLOW; + + memcpy(serv, _nx_bsd_serv_list_ptr[i].service_name, + _nx_bsd_string_length(_nx_bsd_serv_list_ptr[i].service_name)); + } + } + + if(host && hostlen > 0) + { + numeric_flag = 1; + + /* If NUMERIC bit is set, set flag to 1. */ + if(flags & NI_NUMERICHOST) + numeric_flag = 1; + else + { + +#ifdef NX_BSD_ENABLE_DNS + if(sa -> sa_family == AF_INET) + { + +#ifndef NX_DISABLE_IPV4 + /* Get host name by IPv4 address via DNS. */ + status = nx_dns_host_by_address_get(_nx_dns_instance_ptr, ntohl(((struct sockaddr_in *)sa) -> sin_addr.s_addr), + (UCHAR *)host, hostlen, NX_BSD_TIMEOUT); +#else + status = NX_DNS_NO_SERVER; +#endif /* NX_DISABLE_IPV4 */ + } + else + { +#ifdef FEATURE_NX_IPV6 + /* copy data from sockaddr structure to NXD_ADDRESS structure. */ + nxd_ipv6_addr.nxd_ip_version = NX_IP_VERSION_V6; + nxd_ipv6_addr.nxd_ip_address.v6[0] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[0]); + nxd_ipv6_addr.nxd_ip_address.v6[1] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[1]); + nxd_ipv6_addr.nxd_ip_address.v6[2] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[2]); + nxd_ipv6_addr.nxd_ip_address.v6[3] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[3]); + + /* Get host name by IPv6 address via DNS. */ + status = nxd_dns_host_by_address_get(_nx_dns_instance_ptr, &nxd_ipv6_addr, + (UCHAR *) host, hostlen, NX_BSD_TIMEOUT); +#else + status = NX_DNS_NO_SERVER; +#endif + } + + + if(status == NX_DNS_SIZE_ERROR) + return EAI_OVERFLOW; + else if(status != NX_SUCCESS) + { + + /* DNS query fails. */ + if(flags & NI_NAMEREQD) + return EAI_NONAME; + } + else + { + + /* DNS query succeeds. */ + numeric_flag = 0; + } +#else + if(flags & NI_NAMEREQD) + return EAI_NONAME; +#endif + } + + if(numeric_flag) + { + + /* Host must be numeric string. Convert IP address from numeric to presentation. */ + if(sa -> sa_family == AF_INET) + rt_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)sa) -> sin_addr, (CHAR *)host, hostlen); + else + rt_ptr = inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa) -> sin6_addr, (CHAR *)host, hostlen); + + if(!rt_ptr) + return EAI_OVERFLOW; + } + + } + + return 0; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_bsd_set_service_list PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function lets user set the service list used by getaddrinfo */ +/* */ +/* INPUT */ +/* */ +/* serv_list_ptr Pointer to a service list */ +/* serv_list_len Service list length */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID nx_bsd_set_service_list(struct NX_BSD_SERVICE_LIST *serv_list_ptr, ULONG serv_list_len) +{ + _nx_bsd_serv_list_ptr = serv_list_ptr; + _nx_bsd_serv_list_len = serv_list_len; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_bsd_string_length PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the length of string. */ +/* */ +/* INPUT */ +/* */ +/* string Pointer to a string */ +/* */ +/* OUTPUT */ +/* */ +/* ULONG String length */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo BSD Layer Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_bsd_string_length(CHAR * string) +{ +int length = 0; + + while(*string != '\0') + { + length++; + string++; + } + + return((ULONG)length); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_bsd_fast_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles BSD system clock. When the timer expires, the */ +/* BSD system clock is updated and then default IP fast periodic entry */ +/* routine is invoked. */ +/* */ +/* INPUT */ +/* */ +/* id Argument of default timer entry*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_bsd_fast_periodic_timer_entry(ULONG id) +{ + + /* Update the BSD system clock. */ + nx_bsd_system_clock += nx_bsd_timer_rate; + + /* Call default IP fast periodic timer entry. */ + nx_bsd_ip_fast_periodic_timer_entry(id); +} diff --git a/addons/BSD/nxd_bsd.h b/addons/BSD/nxd_bsd.h new file mode 100644 index 00000000..0495cdde --- /dev/null +++ b/addons/BSD/nxd_bsd.h @@ -0,0 +1,883 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** BSD 4.3 Socket API Compatible Interface to NetX Duo */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* BSD DEFINITIONS RELEASE */ +/* */ +/* nxd_bsd.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the constants, structures, etc... needed to */ +/* implement the BSD 4.3 Socket API Compatible Interface to NetX Duo. */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_BSD_H +#define NXD_BSD_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "time.h" + +/* Bring in the necessary NetX include file. */ +#include "nx_api.h" + + +/* Define the print error macro for reporting source line number. + +#define NX_BSD_PRINT_ERRORS +*/ + +/* Defined, raw pppoe feature is enabled. */ +/* +#define NX_BSD_RAW_PPPOE_SUPPORT +*/ + +/* Defined, raw feature is enabled. */ +/* +#define NX_BSD_RAW_SUPPORT +*/ + +/* Defined, raw packet is not duplicated. Then NetX will not handle packets such as ARP. */ +/* +#define NX_DISABLE_BSD_RAW_PACKET_DUPLICATE +*/ + +#if defined(NX_BSD_RAW_SUPPORT) && defined(NX_BSD_RAW_PPPOE_SUPPORT) +#error "Raw feature conflicts with raw PPPoE feature" +#endif /* defined(NX_BSD_RAW_SUPPORT) && defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + +/* Defined, getaddrinfo is able to get address by name/cname. getnameinfo is able to get name by address. */ +/* +#define NX_BSD_ENABLE_DNS +*/ + + +/* + Define the BSD socket timeout process to execute in the timer context. + If this option is not defined, application needs to create stack space for the BSD timeout process + thread, and passes the stack to the BSD layer through the bsd_initialize() call. In this configuration, + the BSD timeout process is all done in the BSD timeout process thread context. + + User may choose to define NX_BSD_TIMEOUT_PROCESS_IN_TIMER, so the BSD timeout process is executed in the + ThreadX timer object context. This configuration could eliminate an extra thread (and associated stack + space.) The following parameters passed into bsd_initialize are ignored: + * bsd_thread_stack_area + * bsd_thread_stack_size + * bsd_thread_priority + However system designer needs to be aware of the following if the BSD timeout process is + executed in ThreadX timer context: + * The amount of BSD socket processing may slow down the ThreadX timer; + * If the timer is executed in ISR context (ThreadX library is built with TX_TIMER_PROCESS_IN_ISR), + the BSD timeout process is now executing in the ISR context; + + By default NX_BSD_TIMEOUT_PROCESS_IN_TIMER is NOT defined. +*/ +/* #define NX_BSD_TIMEOUT_PROCESS_IN_TIMER */ + +/* Define configuration constants for the BSD compatibility layer. Note that these can be overridden via -D or a #define somewhere else. */ + +#ifndef NX_BSD_TCP_WINDOW +#define NX_BSD_TCP_WINDOW 65535 /* 64k is typical window size for 100Mb ethernet. */ +#endif + +#ifndef NX_BSD_SOCKFD_START +#define NX_BSD_SOCKFD_START 32 /* Logical FD starting value. */ +#endif + +#ifndef NX_BSD_MAX_SOCKETS +#define NX_BSD_MAX_SOCKETS 32 /* Maximum number of total sockets available in the BSD layer. Note */ +#endif /* NOTE: Must be multiple of 32! */ + +#ifndef NX_BSD_MAX_LISTEN_BACKLOG +#define NX_BSD_MAX_LISTEN_BACKLOG 5 /* Maximum listen backlog. */ +#endif + +#ifndef NX_MICROSECOND_PER_CPU_TICK +#define NX_MICROSECOND_PER_CPU_TICK (1000000/NX_IP_PERIODIC_RATE) /* Number of microseconds per timer interrupt, default 10ms. */ +#endif +#ifndef NX_BSD_TIMEOUT +#define NX_BSD_TIMEOUT (20*NX_IP_PERIODIC_RATE) + /* By default all internal NetX calls wait and block for 20 seconds. */ +#endif + + +#ifndef NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT +#define NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT 1 /* Timeout in timer ticks for internal NetX to disconnect the socket. + The default value of 1 tick is so NetX BSD emulates native BSD + socket and performs an immediate socket close without sending an RST + packet. */ +#endif + +/* Define configurable options for BSD extended options. */ + + +#ifndef NX_BSD_TIMER_RATE +#define NX_BSD_TIMER_RATE (1 * NX_IP_PERIODIC_RATE) /* Rate at which BSD timer runs. */ +#endif + + +/* Define BSD events */ + +#define NX_BSD_RECEIVE_EVENT ((ULONG) 0x00000001) /* Event flag to signal a receive packet event */ +#define NX_BSD_SELECT_EVENT ((ULONG) 0x00008000) /* Event flag to signal a thread is waiting in select */ +#define NX_BSD_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flag */ +#define NX_BSD_CONNECT_EVENT ((ULONG) 0x00000002) +#define NX_BSD_LINGER_EVENT ((ULONG) 0x00000004) /* Event flag to signal a timed linger state has expired on a socket */ +#define NX_BSD_TIMED_WAIT_EVENT ((ULONG) 0x00000008) /* Event flag to signal a timed wait state has expired on a socket */ +#define NX_BSD_TIMER_EVENT ((ULONG) 0x00000010) /* Event flag to singal a BSD 1 sec timer */ + +/* For compatibility undefine the fd_set. Then define the FD set size. */ + +#ifdef fd_set +#undef fd_set +#endif + +#ifdef FD_SETSIZE +#undef FD_SETSIZE /* May be different in other header files e.g 64 in GNU types.h file */ +#define FD_SETSIZE (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START) /* Number of sockets to select on - same is max sockets! */ +#else +#define FD_SETSIZE (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START) /* Number of sockets to select on - same is max sockets! */ +#endif + + +/* Define some BSD protocol constants. */ + +#define SOCK_STREAM 1 /* TCP Socket */ +#define SOCK_DGRAM 2 /* UDP Socket */ +#define SOCK_RAW 3 /* Raw socket */ +#define IPPROTO_TCP 6 /* TCP Socket */ +#define IPPROTO_UDP 17 /* TCP Socket */ +#define IPPROTO_RAW 255 /* Raw Socket */ + +/* Define supported flags for 'send' and 'recv'. */ +#define MSG_PEEK 0x02 /* Peek incoming message */ +#define MSG_DONTWAIT 0x40 /* Nonblocking IO */ + +/* Address families. */ + +#define AF_UNSPEC 0 /* Unspecified. */ +#define AF_NS 1 /* Local to host (pipes, portals). */ +#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) */ + +/* Protocol families, same as address families. */ +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 +#define PF_PACKET AF_PACKET +#define ETH_P_ALL 3 + +#define INADDR_ANY 0 +#define NX_BSD_LOCAL_IF_INADDR_ANY 0xFFFFFFFF +/* Define API error codes. */ + +#define NX_SOC_ERROR -1 /* Failure. */ +#ifndef ERROR +#define ERROR NX_SOC_ERROR +#endif +#define NX_SOC_OK 0 /* Success. */ +#ifndef OK +#define OK NX_SOC_OK +#endif +#define NX_BSD_BLOCK_POOL_ERROR 1 +#define NX_BSD_MUTEX_ERROR 2 +#define NX_BSD_THREAD_ERROR 4 +#define NX_BSD_EVENT_ERROR 7 +#define NX_BSD_ENVIRONMENT_ERROR 8 + +#ifndef NX_PACKET_OFFSET_ERROR +#define NX_PACKET_OFFSET_ERROR 0x53 +#endif + +/* The Netx API does not require Host to Network conversion or vice versa. The following macro's are provided for source compatibility reasons only. */ + +#ifndef htons +#define htons(a) a +#endif +#ifndef htonl +#define htonl(a) a +#endif +#ifndef ntohs +#define ntohs(a) a +#endif +#ifndef ntohl +#define ntohl(a) a +#endif + +/* Define error handling macro. */ + +#ifdef NX_BSD_PRINT_ERRORS +#define NX_BSD_ERROR(status, line) printf(" NX BSD debug error message:, NX status: %x source line: %i \n", status, line) +#else +#define NX_BSD_ERROR(status, line) +#endif + + +/* Define file descriptor operation flags. */ + +/* Note: FIONREAD is hardware dependant. The default is for i386 processor. */ +#ifndef FIONREAD +#define FIONREAD 0x541B /* Read bytes available for the ioctl() command */ +#endif + +#define F_GETFL 3 /* Get file descriptors */ +#define F_SETFL 4 /* Set a subset of file descriptors (e.g. O_NONBlOCK */ +#define O_NONBLOCK 0x4000 /* Option to enable non blocking on a file (e.g. socket) */ + +#ifndef FIONBIO +#define FIONBIO 0x5421 /* Enables socket non blocking option for the ioctl() command */ +#endif + + +/* Define the minimal TCP socket listen backlog value. */ +#ifndef NX_BSD_TCP_LISTEN_MIN_BACKLOG +#define NX_BSD_TCP_LISTEN_MIN_BACKLOG 1 +#endif + +/* Define the maximum number of packets that can be queued on a UDP socket or RAW socket. */ +#ifndef NX_BSD_SOCKET_QUEUE_MAX +#define NX_BSD_SOCKET_QUEUE_MAX 5 +#endif + +/* Define the constants that determine how big the hash table is for raw socket Protocol. The + value must be a power of two, so subtracting one gives us the mask. */ + +#ifndef NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE +#define NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE 32 +#endif /* NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE */ + +#define NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK (NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE-1) + +/* Define additional BSD socket errors. */ + +/* From errno-base.h in /usr/include/asm-generic; */ +#define EPERM 1 /* Operation not permitted */ +#define E_MIN 1 /* Minimum Socket/IO error */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +/* From errno.h in /usr/include/asm-generic; */ + +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK EDEADLK +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ +#define EOWNERDEAD 130 /* Owner died - for robust mutexes*/ +#define ENOTRECOVERABLE 131 /* State not recoverable */ +#define ERFKILL 132 /* Operation not possible due to RF-kill */ + + +/* List of BSD sock options from socket.h in /usr/include/asm/socket.h and asm-generic/socket.h. + Note: not all of these are implemented in NetX Duo Extended socket options. + + The first set of socket options take the socket level (category) SOL_SOCKET. */ + +#define SOL_SOCKET 1 /* Define the socket option category. */ +#define IPPROTO_IP 2 /* Define the IP option category. */ +#define SO_MIN 1 /* Minimum Socket option ID */ +#define SO_DEBUG 1 /* Debugging information is being recorded.*/ +#define SO_REUSEADDR 2 /* Enable reuse of local addresses in the time wait state */ +#define SO_TYPE 3 /* Socket type */ +#define SO_ERROR 4 /* Socket error status */ +#define SO_DONTROUTE 5 /* Bypass normal routing */ +#define SO_BROADCAST 6 /* Transmission of broadcast messages is supported.*/ +#define SO_SNDBUF 7 /* Enable setting trasnmit buffer size */ +#define SO_RCVBUF 8 /* Enable setting receive buffer size */ +#define SO_KEEPALIVE 9 /* Connections are kept alive with periodic messages */ +#define SO_OOBINLINE 10 /* Out-of-band data is transmitted in line */ +#define SO_NO_CHECK 11 /* Disable UDP checksum */ +#define SO_PRIORITY 12 /* Set the protocol-defined priority for all packets to be sent on this socket */ +#define SO_LINGER 13 /* Socket lingers on close pending remaining send/receive packets. */ +#define SO_BSDCOMPAT 14 /* Enable BSD bug-to-bug compatibility */ +#define SO_REUSEPORT 15 /* Rebind a port already in use */ + +#ifndef SO_PASSCRED /* Used for passing credentials. Not currently in use. */ +#define SO_PASSCRED 16 /* Enable passing local user credentials */ +#define SO_PEERCRED 17 /* Obtain the process, user and group ids of the other end of the socket connection */ +#define SO_RCVLOWAT 18 /* Enable receive "low water mark" */ +#define SO_SNDLOWAT 19 /* Enable send "low water mark" */ +#define SO_RCVTIMEO 20 /* Enable receive timeout */ +#define SO_SNDTIMEO 21 /* Enable send timeout */ +#endif /* SO_PASSCRED */ +#define SO_SNDBUFFORCE 22 /* Enable setting trasnmit buffer size overriding user limit (admin privelege) */ +#define SO_RCVBUFFORCE 23 /* Enable setting trasnmit buffer size overriding user limit (admin privelege) */ +#define SO_MAX SO_RCVBUFFORCE /* Maximum Socket option ID */ + +/* This second set of socket options take the socket level (category) IPPROTO_IP. */ + +#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. */ +#define IP_BLOCK_SOURCE 30 /* Block multicast from certain source. */ +#define IP_UNBLOCK_SOURCE 31 /* Unblock multicast from certain source. */ +#define IP_ADD_MEMBERSHIP 32 /* Join IPv4 multicast membership */ +#define IP_DROP_MEMBERSHIP 33 /* Leave IPv4 multicast membership */ +#define IP_HDRINCL 34 /* Raw socket IPv4 header included. */ +#define IP_RAW_RX_NO_HEADER 35 /* NetX proprietary socket option that does not include + IPv4/IPv6 header (and extension headers) on received raw sockets.*/ +#define IP_RAW_IPV6_HDRINCL 36 /* Transmitted buffer over IPv6 socket contains IPv6 header. */ +#define IP_OPTION_MAX IP_RAW_IPV6_HDRINCL + + + +/* + * User-settable options (used with setsockopt). + */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_MAXSEG 0x02 /* set maximum segment size */ +#define TCP_NOPUSH 0x04 /* don't push last block of write */ +#define TCP_NOOPT 0x08 /* don't use TCP options */ + + +/* Define data types used in structure timeval. */ + +typedef LONG suseconds_t; + +struct timeval +{ + time_t tv_sec; /* Seconds */ + suseconds_t tv_usec; /* Microseconds */ +}; + +struct sockaddr_storage +{ + USHORT ss_len; + USHORT ss_family; +}; + +struct sockaddr +{ + USHORT sa_family; /* Address family (e.g. , AF_INET). */ + UCHAR sa_data[14]; /* Protocol- specific address information. */ +}; + +struct in6_addr +{ + union + { + UCHAR _S6_u8[16]; + ULONG _S6_u32[4]; + } _S6_un; +}; + +#define s6_addr _S6_un._S6_u8 +#define s6_addr32 _S6_un._S6_u32 + +struct sockaddr_in6 +{ + USHORT sin6_family; /* AF_INET6 */ + USHORT sin6_port; /* Transport layer port. */ + ULONG sin6_flowinfo; /* IPv6 flow information. */ + struct in6_addr sin6_addr; /* IPv6 address. */ + ULONG sin6_scope_id; /* set of interafces for a scope. */ + +}; + +/* Internet address (a structure for historical reasons). */ + +struct in_addr +{ + ULONG s_addr; /* Internet address (32 bits). */ +}; + +typedef ULONG in_addr_t; +typedef ULONG socklen_t; + + + +/* Socket address, Internet style. */ + +struct sockaddr_in +{ + USHORT sin_family; /* Internet Protocol (AF_INET). */ + USHORT sin_port; /* Address port (16 bits). */ + struct in_addr sin_addr; /* Internet address (32 bits). */ + CHAR sin_zero[8]; /* Not used. */ +}; + + + +typedef struct FD_SET_STRUCT /* The select socket array manager. */ +{ + INT fd_count; /* How many are SET? */ + ULONG fd_array[(NX_BSD_MAX_SOCKETS + 31)/32]; /* Bit map of SOCKET Descriptors. */ +} fd_set; + + + +typedef struct NX_BSD_SOCKET_SUSPEND_STRUCT +{ + ULONG nx_bsd_socket_suspend_actual_flags; + fd_set nx_bsd_socket_suspend_read_fd_set; + fd_set nx_bsd_socket_suspend_write_fd_set; + fd_set nx_bsd_socket_suspend_exception_fd_set; + +} NX_BSD_SOCKET_SUSPEND; + + +struct ip_mreq +{ + struct in_addr imr_multiaddr; /* The IPv4 multicast address to join. */ + struct in_addr imr_interface; /* The interface to use for this group. */ +}; + + +/* Define additional BSD data structures for supporting socket options. */ + +struct sock_errno +{ + INT error; /* default = 0; */ +}; + +struct linger +{ + INT l_onoff; /* 0 = disabled; 1 = enabled; default = 0;*/ + INT l_linger; /* linger time in seconds; default = 0;*/ +}; + +struct sock_keepalive +{ + INT keepalive_enabled; /* 0 = disabled; 1 = enabled; default = 0;*/ +}; + +struct sock_reuseaddr +{ + INT reuseaddr_enabled; /* 0 = disabled; 1 = enabled; default = 1; */ +}; + +struct sock_winsize +{ + INT winsize; /* receive window size for TCP sockets ; */ +}; + +/* Define an union struct for master ID and secondary ID used in NX_BSD_SOCKET_STRUCT. */ +union UNION_ID +{ + INT nx_bsd_socket_master_socket_id; + INT nx_bsd_socket_secondary_socket_id; +}; + + +struct addrinfo +{ + INT ai_flags; + INT ai_family; + INT ai_socktype; + INT ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + CHAR *ai_canonname; + struct addrinfo *ai_next; +}; + +struct NX_BSD_SERVICE_LIST +{ + CHAR *service_name; + USHORT service_port; + INT service_socktype; + INT service_protocol; +}; + +/* Define the Errors return by getaddrinfo. */ + +/* The specified host doesn't have addresses in the specified address family. */ +#define EAI_ADDRFAMILY 40 +/* Name server temporary failure. */ +#define EAI_AGAIN 41 +/* hints.si_flags contains invalid flag. */ +#define EAI_BADFLAGS 42 +/* DNS fail. */ +#define EAI_FAIL 43 +/* Invalid address family. */ +#define EAI_FAMILY 44 +/* memory failure. */ +#define EAI_MEMORY 45 +/* host exsits, but doesn't have address in specified family. */ +#define EAI_NODATA 46 +#define EAI_NONAME 47 +/* service not available for the specified socket type. */ +#define EAI_SERVICE 48 +#define EAI_OVERFLOW 49 +/* invalid socktype. */ +#define EAI_SOCKTYPE 50 +#define EAI_SYSTEM 51 + + +/* Define ai_flags value. */ +#define AI_PASSIVE 0x0001 +/* request CNAME. */ +#define AI_CANONNAME 0x0002 +/* host must be a address string. */ +#define AI_NUMERICHOST 0x0004 +/* service must be a port string. */ +#define AI_NUMERICSERV 0x0008 +#define AI_V4MAPPED 0x0010 +#define AI_ALL 0x0020 +#define AI_ADDRCONFIG 0x0040 + +/* Return numeric string for hostname. */ +#define NI_NUMERICHOST 0x0001 +/* Return numeric string for service name. */ +#define NI_NUMERICSERV 0x0002 +/* Return only hostname portion of FQDN. */ +#define NI_NOFQDN 0x0004 +/* Return error if name can't be resolved from address. */ +#define NI_NAMEREQD 0x0008 +/* Datagram service. */ +#define NI_DGRAM 0x0010 + + +/* Defines maximum IPv4 addresses for getaddrinfo. */ +#ifndef NX_BSD_IPV4_ADDR_MAX_NUM +#define NX_BSD_IPV4_ADDR_MAX_NUM 5 +#endif /* NX_BSD_IPV4_ADDR_MAX_NUM */ + +/* Defines maximum IPv6 addresses for getaddrinfo. */ +#ifndef NX_BSD_IPV6_ADDR_MAX_NUM +#define NX_BSD_IPV6_ADDR_MAX_NUM 5 +#endif /* NX_BSD_IPV6_ADDR_MAX_NUM */ + +/* Defines maximum IPv4 addresses stored from DNS. */ +#ifndef NX_BSD_IPV4_ADDR_PER_HOST +#define NX_BSD_IPV4_ADDR_PER_HOST 5 +#endif /* NX_BSD_IPV4_ADDR_PER_HOST */ + +/* Defines maximum IPv6 addresses stored from DNS. */ +#ifndef NX_BSD_IPV6_ADDR_PER_HOST +#define NX_BSD_IPV6_ADDR_PER_HOST 2 +#endif /* NX_BSD_IPV6_ADDR_PER_HOST */ + +/* Define the BSD socket status bits. */ +#define NX_BSD_SOCKET_CONNECTION_INPROGRESS 1 +#define NX_BSD_SOCKET_ERROR (1 << 1) +#define NX_BSD_SOCKET_CONNECTED (1 << 2) +/* Disconnected from the stack. */ +#define NX_BSD_SOCKET_DISCONNECT_FROM_STACK (1 << 3) +#define NX_BSD_SOCKET_SERVER_MASTER_SOCKET (1 << 4) +#define NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET (1 << 5) +#define NX_BSD_SOCKET_TX_HDR_INCLUDE (1 << 6) +#define NX_BSD_SOCKET_RX_NO_HDR (1 << 7) +#define NX_BSD_SOCKET_IN_USE (1 << 8) +#define NX_BSD_SOCKET_CLIENT (1 << 9) +#define NX_BSD_SOCKET_ENABLE_LISTEN (1 << 10) +#define NX_BSD_SOCKET_BOUND (1 << 11) +#define NX_BSD_SOCKET_ACCEPTING (1 << 12) +#define NX_BSD_SOCKET_CONNECTION_REQUEST (1 << 13) +#define NX_BSD_SOCKET_DISCONNECTION_REQUEST (1 << 14) + +/* Define the BSD socket options bits. */ +#define NX_BSD_SOCKET_ENABLE_RAW_SOCKET 1 +#define NX_BSD_SOCKET_ENABLE_OPTION_LINGER (1 << 1) +#define NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR (1 << 2) +#define NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING (1 << 3) + +/* Define the internal management structure for the BSD layer. */ + +typedef struct NX_BSD_SOCKET_STRUCT +{ + NX_TCP_SOCKET *nx_bsd_socket_tcp_socket; + NX_UDP_SOCKET *nx_bsd_socket_udp_socket; + ULONG nx_bsd_socket_family; + /* Store the protocol number. For example TCP is 6, UDP is 17. For raw socket + it is the protocol it wishes to receive. */ + USHORT nx_bsd_socket_protocol; + TX_THREAD *nx_bsd_socket_busy; + union UNION_ID nx_bsd_socket_union_id; + NX_PACKET* nx_bsd_socket_received_packet; + NX_PACKET* nx_bsd_socket_received_packet_tail; + UINT nx_bsd_socket_received_byte_count; + UINT nx_bsd_socket_received_byte_count_max; + UINT nx_bsd_socket_received_packet_count; + UINT nx_bsd_socket_received_packet_count_max; + ULONG nx_bsd_socket_received_packet_offset; + INT nx_bsd_socket_source_port; + ULONG nx_bsd_socket_local_bind_interface; + UINT nx_bsd_socket_local_bind_interface_index; + NXD_ADDRESS nx_bsd_socket_source_ip_address; + NXD_ADDRESS nx_bsd_socket_peer_ip; + + /* For TCP/UDP, the local port is the port number this socket receives on. + For raw socket this field is not used. */ + USHORT nx_bsd_socket_local_port; + USHORT nx_bsd_socket_peer_port; + INT nx_bsd_option_linger_time; + UINT nx_bsd_option_linger_time_closed; + UINT nx_bsd_option_linger_start_close; + UINT nx_bsd_socket_time_wait_remaining; + ULONG nx_bsd_option_receive_timeout; + ULONG nx_bsd_option_send_timeout; + INT nx_bsd_file_descriptor_flags; + ULONG nx_bsd_socket_status_flags; + ULONG nx_bsd_socket_option_flags; + int nx_bsd_socket_error_code; + + struct NX_BSD_SOCKET_STRUCT + *nx_bsd_socket_next; + struct NX_BSD_SOCKET_STRUCT + *nx_bsd_socket_previous; + + INT nx_bsd_socket_id; +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + UINT nx_bsd_socket_create_id; +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) + UCHAR nx_bsd_socket_sll_addr[6]; + USHORT nx_bsd_socket_sll_protocol; + INT nx_bsd_socket_sll_ifindex; +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + +} NX_BSD_SOCKET; + + +/* Define the BSD function prototypes for use by the application. */ + +INT accept(INT sockID, struct sockaddr *ClientAddress, INT *addressLength); +INT bsd_initialize(NX_IP *default_ip, NX_PACKET_POOL *default_pool, CHAR *bsd_thread_stack_area, ULONG bsd_thread_stack_size, UINT bsd_thread_priority); +INT bind(INT sockID, struct sockaddr *localAddress, INT addressLength); +INT connect(INT sockID, struct sockaddr *remoteAddress, INT addressLength); +INT getpeername(INT sockID, struct sockaddr *remoteAddress, INT *addressLength); +INT getsockname(INT sockID, struct sockaddr *localAddress, INT *addressLength); +INT ioctl(INT sockID, INT command, INT *result); +in_addr_t inet_addr(const CHAR *buffer); +CHAR *inet_ntoa(struct in_addr address_to_convert); +INT inet_aton(const CHAR *cp_arg, struct in_addr *addr); +INT inet_pton(INT af, const CHAR *src, VOID *dst); +const CHAR *inet_ntop(INT af, const VOID *src, CHAR *dst, socklen_t size); +INT listen(INT sockID, INT backlog); +#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER +UINT nx_bsd_raw_packet_receive(NX_BSD_SOCKET *bsd_socket_ptr, NX_PACKET **packet_ptr); +UINT nx_bsd_raw_packet_info_extract(NX_PACKET *packet_ptr, NXD_ADDRESS *nxd_address, UINT *interface_index); +VOID nx_bsd_raw_receive_notify(NX_IP *ip_ptr, UINT bsd_socket_index); +#endif +UINT nx_bsd_socket_set_inherited_settings(UINT master_sock_id, UINT secondary_sock_id); +INT recvfrom(INT sockID, CHAR *buffer, INT buffersize, INT flags,struct sockaddr *fromAddr, INT *fromAddrLen); +INT recv(INT sockID, VOID *rcvBuffer, INT bufferLength, INT flags); +INT sendto(INT sockID, CHAR *msg, INT msgLength, INT flags, struct sockaddr *destAddr, INT destAddrLen); +INT send(INT sockID, const CHAR *msg, INT msgLength, INT flags); +INT select(INT nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +INT soc_close( INT sockID); +INT socket(INT protocolFamily, INT type, INT protocol); +INT fcntl(INT sock_ID, UINT flag_type, UINT f_options); +INT getsockopt(INT sockID, INT option_level, INT option_name, VOID *option_value, INT *option_length); +INT setsockopt(INT sockID, INT option_level, INT option_name, const VOID *option_value, INT option_length); +INT getaddrinfo(const CHAR *node, const CHAR *service, const struct addrinfo *hints, struct addrinfo **res); +VOID freeaddrinfo(struct addrinfo *res); +INT getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); +VOID nx_bsd_set_service_list(struct NX_BSD_SERVICE_LIST *serv_list_ptr, ULONG serv_list_len); + +#undef FD_SET +#undef FD_CLR +#undef FD_ISSET +#undef FD_ZERO + +VOID FD_SET(INT fd, fd_set *fdset); +VOID FD_CLR(INT fd, fd_set *fdset); +INT FD_ISSET(INT fd, fd_set *fdset); +VOID FD_ZERO(fd_set *fdset); +VOID set_errno(INT tx_errno); +int _nxd_get_errno(VOID); +#define errno (_nxd_get_errno()) + +#ifdef NX_BSD_RAW_PPPOE_SUPPORT + +#define ETHERTYPE_PPPOE_DISC 0x8863 /* PPPoE Discovery protocol type */ +#define ETHERTYPE_PPPOE_SESS 0x8864 /* PPPoE Session Protocol type */ + +#define NX_LINK_PACKET_PPPOE_SESS_SEND ETHERTYPE_PPPOE_SESS +#define NX_LINK_PACKET_PPPOE_DISC_SEND ETHERTYPE_PPPOE_DISC + + +UINT _nx_bsd_pppoe_packet_received(NX_PACKET *packet_ptr, UINT frame_type, UINT interface_id); +#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ + +#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) +/* Link Layer Socket Addressing */ +struct sockaddr_ll +{ + USHORT sll_family; /* Address Family. Must be AF_PACKET */ + USHORT sll_protocol; /* LL frame type */ + INT sll_ifindex; /* Interface Index. */ + USHORT sll_hatype; /* Header type */ + UCHAR sll_pkttype; /* Packet type */ + UCHAR sll_halen; /* Length of address */ + UCHAR sll_addr[8]; /* Physical layer address */ +}; +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + +#ifdef NX_BSD_RAW_SUPPORT +extern UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr); /* Send hardware packet. */ +extern VOID (*_nx_driver_hardware_packet_received_callback)(NX_PACKET *packet_ptr, UCHAR *consumed);/* Callback function pointer when packet is received. */ +#endif /* NX_BSD_RAW_SUPPORT */ + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_BSD_H */ + diff --git a/addons/CMakeLists.txt b/addons/CMakeLists.txt new file mode 100644 index 00000000..8a7e8aa2 --- /dev/null +++ b/addons/CMakeLists.txt @@ -0,0 +1,70 @@ +# Each protocol handler is listed below. If you want +# to disable some / all of these, comment out the block(s) in question + +set(SOURCES + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/auto_ip/nx_auto_ip.c + # ${CMAKE_CURRENT_LIST_DIR}/BSD/nxd_bsd.c + ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcpv6_client.c + ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcpv6_server.c + ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcp_client.c + ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcp_server.c + ${CMAKE_CURRENT_LIST_DIR}/dns/nxd_dns.c + ${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_client.c + ${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_server.c + ${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_client.c + ${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_server.c + ${CMAKE_CURRENT_LIST_DIR}/mdns/nxd_mdns.c + ${CMAKE_CURRENT_LIST_DIR}/mqtt/nxd_mqtt_client.c + ${CMAKE_CURRENT_LIST_DIR}/nat/nx_nat.c + ${CMAKE_CURRENT_LIST_DIR}/pop3/nxd_pop3_client.c + ${CMAKE_CURRENT_LIST_DIR}/ppp/nx_ppp.c + ${CMAKE_CURRENT_LIST_DIR}/pppoe/nx_pppoe_client.c + ${CMAKE_CURRENT_LIST_DIR}/pppoe/nx_pppoe_server.c + ${CMAKE_CURRENT_LIST_DIR}/smtp/nxd_smtp_client.c + ${CMAKE_CURRENT_LIST_DIR}/snmp/nxd_snmp.c + ${CMAKE_CURRENT_LIST_DIR}/snmp/nx_des.c + ${CMAKE_CURRENT_LIST_DIR}/snmp/nx_sha1.c + ${CMAKE_CURRENT_LIST_DIR}/sntp/nxd_sntp_client.c + ${CMAKE_CURRENT_LIST_DIR}/telnet/nxd_telnet_client.c + ${CMAKE_CURRENT_LIST_DIR}/telnet/nxd_telnet_server.c + ${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_client.c + ${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_server.c + ${CMAKE_CURRENT_LIST_DIR}/web/nx_tcpserver.c + ${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_client.c + ${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_server.c + # {{END_TARGET_SOURCES}} +) + +# Remove the file server files if the user doesn't want them +if(NOT NXD_ENABLE_FILE_SERVERS) + list(REMOVE_ITEM SOURCES + "${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_server.c" + "${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_server.c" + "${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_server.c" + "${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_server.c" + ) +endif() + +target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/auto_ip + ${CMAKE_CURRENT_LIST_DIR}/BSD + ${CMAKE_CURRENT_LIST_DIR}/dhcp + ${CMAKE_CURRENT_LIST_DIR}/dns + ${CMAKE_CURRENT_LIST_DIR}/ftp + ${CMAKE_CURRENT_LIST_DIR}/http + ${CMAKE_CURRENT_LIST_DIR}/mdns + ${CMAKE_CURRENT_LIST_DIR}/mqtt + ${CMAKE_CURRENT_LIST_DIR}/nat + ${CMAKE_CURRENT_LIST_DIR}/pop3 + ${CMAKE_CURRENT_LIST_DIR}/ppp + ${CMAKE_CURRENT_LIST_DIR}/pppoe + ${CMAKE_CURRENT_LIST_DIR}/smtp + ${CMAKE_CURRENT_LIST_DIR}/snmp + ${CMAKE_CURRENT_LIST_DIR}/sntp + ${CMAKE_CURRENT_LIST_DIR}/telnet + ${CMAKE_CURRENT_LIST_DIR}/tftp + ${CMAKE_CURRENT_LIST_DIR}/web +) diff --git a/addons/auto_ip/nx_auto_ip.c b/addons/auto_ip/nx_auto_ip.c new file mode 100644 index 00000000..5f0cdcb3 --- /dev/null +++ b/addons/auto_ip/nx_auto_ip.c @@ -0,0 +1,1223 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** AutoIP (AutoIP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_AUTO_IP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_ip.h" +#include "nx_arp.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_auto_ip.h" + +/* Keep the AutoIP instance for callback notify. */ +static NX_AUTO_IP *_nx_auto_ip_ptr; + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the AutoIP create function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* name Pointer to AutoIP name */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to start of stack */ +/* stack_size Size of stack in bytes */ +/* priority Priority of AutoIP thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_create AutoIP create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id == NX_AUTO_IP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual AutoIP create routine. */ + status = _nx_auto_ip_create(auto_ip_ptr, name, ip_ptr, stack_ptr, stack_size, priority); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an AutoIP instance for the associated IP */ +/* instance. There must be only one AutoIP instance per IP instance. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* name Pointer to AutoIP name */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to start of stack */ +/* stack_size Size of stack in bytes */ +/* priority Priority of AutoIP thread */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_create Create AutoIP thread */ +/* tx_event_flags_create Create event flags group */ +/* tx_event_flags_delete Delete event flags group */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority) +{ + +UINT status; + + + /* Initialize the AutoIP control block to zero. */ + memset((void *) auto_ip_ptr, 0, sizeof(NX_AUTO_IP)); + + /* Create the AutoIP event flags. */ + status = tx_event_flags_create(&(auto_ip_ptr -> nx_auto_ip_conflict_event), "NetX AutoIP Collision Event"); + + /* Determine if successful. */ + if (status) + { + + /* No, return an error. */ + return(NX_AUTO_IP_ERROR); + } + + /* Create the AutoIP processing thread. */ + status = tx_thread_create(&(auto_ip_ptr -> nx_auto_ip_thread), "NetX AutoIP", _nx_auto_ip_thread_entry, (ULONG) auto_ip_ptr, + stack_ptr, stack_size, priority, priority, 1, TX_DONT_START); + + /* Determine if the thread creation was successful. */ + if (status) + { + + /* Delete the event flags. */ + tx_event_flags_delete(&(auto_ip_ptr -> nx_auto_ip_conflict_event)); + + /* No, return an error. */ + return(NX_AUTO_IP_ERROR); + } + + /* Save the IP pointer and interface fields. */ + auto_ip_ptr -> nx_auto_ip_ip_ptr = ip_ptr; + + /* Default the auto IP interface to the primary interface. */ + auto_ip_ptr -> nx_ip_interface_index = 0; + + /* Save the AutoIP name. */ + auto_ip_ptr -> nx_auto_ip_name = name; + + /* Update the AutoIP structure ID. */ + auto_ip_ptr -> nx_auto_ip_id = NX_AUTO_IP_ID; + + /* Keep the AutoIP instance for callback notify. */ + _nx_auto_ip_ptr = auto_ip_ptr; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking services for the set interface*/ +/* index service. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* interface_index Index into IP interface table */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + status = _nx_auto_ip_set_interface(auto_ip_ptr, interface_index); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the index for the interface on the local host */ +/* needing auto IP to set the address. The default value is zero */ +/* (primary interface). */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* interface_index Index into IP interface table */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index) +{ + + /* Determine if a local IP address was successfully setup. */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + /* Bad interface index. */ + return(NX_AUTO_IP_BAD_INTERFACE_INDEX); + } + + + /* Set the index to the specified value. */ + auto_ip_ptr -> nx_ip_interface_index = interface_index; + + /* Return successful outcome. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_get_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the AutoIP get address function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* local_ip_address Destination for local IP addr */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_get_address AutoIP get address function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID) || (local_ip_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual AutoIP get address routine. */ + status = _nx_auto_ip_get_address(auto_ip_ptr, local_ip_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_get_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the local IP address resolved by the AutoIP */ +/* protocol. If there is no valid local IP address this routine */ +/* returns an error and an IP address of all zeros. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* local_ip_address Destination for local IP addr */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address) +{ + +ULONG host_ip_address; +NX_IP *ip_ptr; + + + /* Set local variables for convenience. */ + ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; + host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; + + /* Determine if a local IP address was successfully setup. */ + if (auto_ip_ptr -> nx_auto_ip_current_local_address == host_ip_address) + { + + /* Yes, a local IP address is setup. */ + *local_ip_address = auto_ip_ptr -> nx_auto_ip_current_local_address; + + /* Return success! */ + return(NX_SUCCESS); + } + else + { + + /* No, a local IP address has not been setup. Clear the return value. */ + *local_ip_address = 0; + + /* Return an error. */ + return(NX_AUTO_IP_NO_LOCAL); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the AutoIP start function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_start AutoIP start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual AutoIP start routine. */ + status = _nx_auto_ip_start(auto_ip_ptr, starting_local_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the AutoIP thread of a previously created */ +/* AutoIP instance. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* starting_local_address Starting local IP address, */ +/* only IP addresses from */ +/* 169.254.1.0 through */ +/* 169.254.254.255 are valid,*/ +/* where a value of 0 implies*/ +/* a random generated value */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_resume Resume AutoIP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address) +{ + + + /* First, start the local IP address to that supplied. */ + auto_ip_ptr -> nx_auto_ip_current_local_address = starting_local_address; + + /* Set the restart flag. */ + auto_ip_ptr -> nx_auto_ip_restart_flag = NX_TRUE; + + /* Set the event flags to ensure AutoIP thread wakes up. */ + tx_event_flags_set(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR); + + /* Resume the AutoIP thread. */ + tx_thread_resume(&(auto_ip_ptr -> nx_auto_ip_thread)); + + /* Return status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the AutoIP stop function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_stop AutoIP stop function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual AutoIP stop routine. */ + status = _nx_auto_ip_stop(auto_ip_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops the AutoIP thread of a previously created and */ +/* started AutoIP instance. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend AutoIP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr) +{ + +UINT status; + + + /* Suspend the AutoIP thread. */ + status = tx_thread_suspend(&(auto_ip_ptr -> nx_auto_ip_thread)); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_auto_ip_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the AutoIP delete function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_delete AutoIP delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual AutoIP delete routine. */ + status = _nx_auto_ip_delete(auto_ip_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the previously created and stopped AutoIP */ +/* AutoIP instance. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* Completion Status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_delete Delete event flags */ +/* tx_thread_delete Delete AutoIP thread */ +/* tx_thread_terminate Terminate AutoIP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr) +{ + +NX_IP *ip_ptr; + + + /* First, set the ID to show it is invalid. */ + auto_ip_ptr -> nx_auto_ip_id = 0; + + /* Pickup the IP pointer. */ + ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; + + /* Get IP mutex so IP conflict notification can be setup. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Clear the handler to avoid conflict notification callbacks. */ + ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_conflict_notify_handler = NX_NULL; + ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_probe_address = 0; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Terminate the AutoIP thread. */ + tx_thread_terminate(&(auto_ip_ptr -> nx_auto_ip_thread)); + + /* Delete the AutoIP thread. */ + tx_thread_delete(&(auto_ip_ptr -> nx_auto_ip_thread)); + + /* Delete the AutoIP event flags. */ + tx_event_flags_delete(&(auto_ip_ptr -> nx_auto_ip_conflict_event)); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point of the AutoIP thread. All AutoIP */ +/* actions are coordinated by this thread. */ +/* */ +/* INPUT */ +/* */ +/* auto_ip_ptr Pointer to AutoIP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_auto_ip_arp_packet_send Send AutoIP probe and */ +/* announce ARP messages */ +/* nx_ip_interface_address_set Set interface address */ +/* nx_ip_interface_status_check Get interface status */ +/* tx_event_flags_get Get event flags */ +/* tx_mutex_get Get IP protection */ +/* tx_mutex_put Put IP protection */ +/* tx_thread_sleep Thread sleep */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_auto_ip_thread_entry(ULONG auto_ip_ptr_info) +{ + +NX_AUTO_IP *auto_ip_ptr; +NX_IP *ip_ptr; +UINT i, status; +ULONG addresses; +ULONG conflict; +ULONG temp; +ULONG delay; +ULONG hw_address_lsw; +ULONG host_ip_address; + + + /* Pickup the AutoIP pointer. */ + auto_ip_ptr = (NX_AUTO_IP *) auto_ip_ptr_info; + + /* Pickup the associated IP pointer. */ + ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; + + /* Wait for the IP instance to be initialized before proceeding. This will ensure the + MAC address is valid before a random local IP address is generated. */ + nx_ip_interface_status_check(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, NX_IP_LINK_ENABLED, &temp, NX_WAIT_FOREVER); + + /* Set LSW of hardware address */ + hw_address_lsw = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_physical_address_lsw; + + /* Setup the conflict flag to false. */ + conflict = NX_FALSE; + + /* Loop forever inside the AutoIP thread! */ + while(1) + { + + /* Probe for local IP address use! */ + + /* Update the local variable in case anything has changed. */ + host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; + + /* Wait until the IP address is non-zero. The only way this can be non-zero is + if the application has changed it or it was resolved by the DHCP protocol. */ + while (host_ip_address) + { + + /* Sleep for the maximum probe period. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MAX); + + /* Get the IP address from the IP task and see if it has changed from non zero. */ + host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; + } + + /* Determine if the restart flag is set. */ + if (auto_ip_ptr -> nx_auto_ip_restart_flag) + { + + /* Clear the restart flag. */ + auto_ip_ptr -> nx_auto_ip_restart_flag = NX_FALSE; + + /* Reset the conflict count. */ + auto_ip_ptr -> nx_auto_ip_conflict_count = 0; + + /* Clear the conflict flag, since we might have an new starting local IP address. */ + conflict = NX_FALSE; + } + + /* Determine if a conflict condition is present. This flag is set at various places + below. */ + if (conflict) + { + + /* Yes, a conflict was detected. */ + + /* Increment the conflict count. */ + auto_ip_ptr -> nx_auto_ip_conflict_count++; + + /* Determine if we have reached the maximum number of conflicts. */ + if (auto_ip_ptr -> nx_auto_ip_conflict_count > NX_AUTO_IP_MAX_CONFLICTS) + { + + /* Yes, we have had excessive conflicts... we must now add extra delay. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_RATE_LIMIT_INTERVAL); + } + + /* Clear the the local IP address in order to generate another random one. */ + auto_ip_ptr -> nx_auto_ip_current_local_address = 0; + + /* Clear the conflict flag. */ + conflict = NX_FALSE; + } + + /* Determine if a starting local IP address needs to be derived. */ + if (auto_ip_ptr -> nx_auto_ip_current_local_address == 0) + { + + /* Yes, the starting local IP address must be derived. */ + + /* Get pseudo random value with LSW of MAC address. */ + temp = ((ULONG) NX_RAND()) + hw_address_lsw; + + /* Determine the address range of local IP addresses. */ + addresses = NX_AUTO_IP_END_ADDRESS - NX_AUTO_IP_START_ADDRESS; + + /* Make sure that the random number fits within this range. */ + temp = temp % addresses; + + /* Now create a starting local IP address. */ + auto_ip_ptr -> nx_auto_ip_current_local_address = NX_AUTO_IP_START_ADDRESS + temp; + } + + /* Register with NetX for ARP conflict detection for this local IP address. */ + + /* Get IP mutex so ARP notification can be setup. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Finally, setup the handler to indicate the we want collision notification. */ + ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_conflict_notify_handler = _nx_auto_ip_conflict; + + /* Clear any outstanding events. */ + tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, TX_NO_WAIT); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Calculate the delay time. */ + delay = (ULONG)NX_RAND() % (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_WAIT); + + /* Sleep for a small period of time. */ + tx_thread_sleep(delay); + + /* Loop to probe for the specified local IP address. */ + for (i = 0; i < NX_AUTO_IP_PROBE_NUM; i++) + { + + /* Increment the total probe count. */ + auto_ip_ptr -> nx_auto_ip_probe_count++; + + /* Send the ARP probe. */ + _nx_arp_probe_send(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, auto_ip_ptr -> nx_auto_ip_current_local_address); + + /* Calculate the delay time. */ + delay = ((ULONG) NX_RAND()) % (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MAX); + + /* Determine if this is less than the minimum. */ + if (delay < (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MIN)) + { + + /* Set the delay to the minimum. */ + delay = (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MIN); + } + + /* Delay by waiting for conflict events before sending the next ARP probe. This event is + set by the conflict callback function when an ARP entry is received that matches + the registered address. */ + status = tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, delay); + + /* Determine if conflict was detected. */ + if (status == NX_SUCCESS) + { + + /* Yes, a conflict is present. */ + + /* Set the conflict flag and get out of the loop. */ + conflict = NX_TRUE; + break; + } + + /* Update the local variable in case anything has changed. */ + host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; + + /* Check for a restart or an IP address change. */ + if (host_ip_address || (auto_ip_ptr -> nx_auto_ip_restart_flag)) + break; + } + + /* Determine if there was a conflict. If so, continue at the top of the loop. */ + if (conflict) + { + +#ifdef NX_AUTO_IP_DEBUG + printf("AutoIP %s, CONFLICT for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); +#endif + continue; + } + + /* Check for a restart or an IP address change. */ + if (host_ip_address || (auto_ip_ptr -> nx_auto_ip_restart_flag)) + continue; + + /* At this point, the local IP address has been successfully probed via ARP messages without + any collisions. It is now time to go into an announce phase to indicate local IP address + is ours! */ + +#ifdef NX_AUTO_IP_DEBUG + printf("AutoIP %s, RESOLVED for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); +#endif + + /* Set the NetX IP address. */ + nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, auto_ip_ptr -> nx_auto_ip_current_local_address, 0xFFFF0000); + + /* Delay before announcing: NX_AUTO_IP_ANNOUNCE_WAIT. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_ANNOUNCE_WAIT); + + /* It is now time to go into an announce phase to indicate local IP address is ours! */ + for (i = 0; i < NX_AUTO_IP_ANNOUNCE_NUM; i++) + { + + /* Increment the total announcement count. */ + auto_ip_ptr -> nx_auto_ip_announce_count++; + + /* Send the ARP announcement. */ + _nx_arp_announce_send(ip_ptr, auto_ip_ptr -> nx_ip_interface_index); + + /* Calculate the delay time. */ + delay = (NX_IP_PERIODIC_RATE * NX_AUTO_IP_ANNOUNCE_INTERVAL); + + /* Delay by waiting for conflict events before sending the next ARP announcement. This event is + set by the conflict callback function when an ARP entry is received that matches + the registered address. */ + status = tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, delay); + + /* Determine if conflict was detected. */ + if (status == NX_SUCCESS) + { + + /* Yes, a conflict is present. */ + + /* Set the conflict flag and get out of the loop. */ + conflict = NX_TRUE; + break; + } + } + + /* Determine if there was a conflict. If so, continue at the top of the loop. */ + if (conflict) + { + +#ifdef NX_AUTO_IP_DEBUG + printf("AutoIP %s, CONFLICT for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); +#endif + + /* Conflict, clear the IP address. */ + nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, 0, 0); + + continue; + } + + /* Now, wait infinitely for another conflict situation. */ + tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, TX_WAIT_FOREVER); + + /* Update the local variable in case anything has changed. */ + host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; + + /* Determine if a conflict is present. */ + + /* If we get here a late conflict is present. */ + if (auto_ip_ptr -> nx_auto_ip_current_local_address == host_ip_address) + { + + /* Increment the total defend count. */ + auto_ip_ptr -> nx_auto_ip_defend_count++; + +#ifdef NX_AUTO_IP_DEBUG + printf("AutoIP %s, DEFEND for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), + (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); +#endif + + /* No defense currently, just clear the IP address once a late collision is detected + and start over. */ + nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, 0, 0); + + /* Set the conflict flag. */ + conflict = NX_TRUE; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_auto_ip_conflict PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the AutoIP instance that a conflict was */ +/* detected by the NetX ARP receive packet handling routine. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* interface_index IP Interface Index */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_auto_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw) +{ + + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(interface_index); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(physical_msw); + NX_PARAMETER_NOT_USED(physical_lsw); + + /* Set the event flags to indicate that a collision was detected by NetX ARP processing. */ + tx_event_flags_set(&(_nx_auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR); +} +#endif /* NX_DISABLE_IPV4 */ diff --git a/addons/auto_ip/nx_auto_ip.h b/addons/auto_ip/nx_auto_ip.h new file mode 100644 index 00000000..e5de5ea0 --- /dev/null +++ b/addons/auto_ip/nx_auto_ip.h @@ -0,0 +1,215 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** AutoIP (AutoIP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_auto_ip.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX AutoIP Protocol (AutoIP) component, */ +/* including all data types and external references. It is assumed */ +/* that nx_api.h and nx_port.h have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_AUTO_IP_H +#define NX_AUTO_IP_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +/* Define the AutoIP ID that is used to mark the AutoIP structure as created. */ + +#define NX_AUTO_IP_ID 0x4155544FUL + + +/* Define the timing and retry constants for AutoIP. */ + +#ifndef NX_AUTO_IP_PROBE_WAIT +#define NX_AUTO_IP_PROBE_WAIT 1 +#endif + +#ifndef NX_AUTO_IP_PROBE_NUM +#define NX_AUTO_IP_PROBE_NUM 3 +#endif + +#ifndef NX_AUTO_IP_PROBE_MIN +#define NX_AUTO_IP_PROBE_MIN 1 +#endif + +#ifndef NX_AUTO_IP_PROBE_MAX +#define NX_AUTO_IP_PROBE_MAX 2 +#endif + +#ifndef NX_AUTO_IP_MAX_CONFLICTS +#define NX_AUTO_IP_MAX_CONFLICTS 10 +#endif + +#ifndef NX_AUTO_IP_RATE_LIMIT_INTERVAL +#define NX_AUTO_IP_RATE_LIMIT_INTERVAL 60 +#endif + +#ifndef NX_AUTO_IP_ANNOUNCE_WAIT +#define NX_AUTO_IP_ANNOUNCE_WAIT 2 +#endif + +#ifndef NX_AUTO_IP_ANNOUNCE_NUM +#define NX_AUTO_IP_ANNOUNCE_NUM 2 +#endif + +#ifndef NX_AUTO_IP_ANNOUNCE_INTERVAL +#define NX_AUTO_IP_ANNOUNCE_INTERVAL 2 +#endif + +#ifndef NX_AUTO_IP_DEFEND_INTERVAL +#define NX_AUTO_IP_DEFEND_INTERVAL 10 +#endif + + +/* Define the starting and ending local IP addresses. */ + +#define NX_AUTO_IP_START_ADDRESS IP_ADDRESS(169,254,1,0) +#define NX_AUTO_IP_END_ADDRESS IP_ADDRESS(169,254,254,255) + + +/* Define error codes from AutoIP API. */ + +#define NX_AUTO_IP_ERROR 0xA00 +#define NX_AUTO_IP_NO_LOCAL 0xA01 +#define NX_AUTO_IP_BAD_INTERFACE_INDEX 0xA02 + + +/* Define the AutoIP structure that holds all the information necessary for this AutoIP + instance. */ + +typedef struct NX_AUTO_IP_STRUCT +{ + ULONG nx_auto_ip_id; + CHAR *nx_auto_ip_name; + NX_IP *nx_auto_ip_ip_ptr; + UINT nx_ip_interface_index; + ULONG nx_auto_ip_current_local_address; + ULONG nx_auto_ip_restart_flag; + ULONG nx_auto_ip_conflict_count; + ULONG nx_auto_ip_probe_count; + ULONG nx_auto_ip_announce_count; + ULONG nx_auto_ip_defend_count; + TX_EVENT_FLAGS_GROUP nx_auto_ip_conflict_event; + TX_THREAD nx_auto_ip_thread; +} NX_AUTO_IP; + + +#ifndef NX_AUTO_IP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map AutoIP API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_auto_ip_create _nx_auto_ip_create +#define nx_auto_ip_get_address _nx_auto_ip_get_address +#define nx_auto_ip_set_interface _nx_auto_ip_set_interface +#define nx_auto_ip_start _nx_auto_ip_start +#define nx_auto_ip_stop _nx_auto_ip_stop +#define nx_auto_ip_delete _nx_auto_ip_delete + +#else + +/* Services with error checking. */ + +#define nx_auto_ip_create _nxe_auto_ip_create +#define nx_auto_ip_get_address _nxe_auto_ip_get_address +#define nx_auto_ip_set_interface _nxe_auto_ip_set_interface +#define nx_auto_ip_start _nxe_auto_ip_start +#define nx_auto_ip_stop _nxe_auto_ip_stop +#define nx_auto_ip_delete _nxe_auto_ip_delete + +#endif + +/* Define the prototypes accessible to the application software. */ + +UINT nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); +UINT nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); +UINT nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); +UINT nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); +UINT nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); + + +#else + +/* AutoIP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT _nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT _nxe_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); +UINT _nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); +UINT _nxe_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); +UINT _nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); +UINT _nxe_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); +UINT _nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); +UINT _nxe_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); +UINT _nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); +UINT _nxe_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); +UINT _nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); +VOID _nx_auto_ip_thread_entry(ULONG auto_ip_address); +VOID _nx_auto_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw); + +#endif + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_AUTO_IP_H */ + diff --git a/addons/dhcp/nxd_dhcp_client.c b/addons/dhcp/nxd_dhcp_client.c new file mode 100644 index 00000000..23ee2eba --- /dev/null +++ b/addons/dhcp/nxd_dhcp_client.c @@ -0,0 +1,10109 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol (DHCP) Client */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_DHCP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_system.h" +#include "nx_ip.h" +#include "nx_arp.h" +#include "nxd_dhcp_client.h" +#include "tx_timer.h" + + +/* Define the DHCP Internal Function. */ +static VOID _nx_dhcp_thread_entry(ULONG ip_instance); +static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length); +static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length); +static UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index); +static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index); +static ULONG _nx_dhcp_update_timeout(ULONG timeout); +static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout); +static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length); +static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size); +static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value); +static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size); +static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type); +static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr); +static ULONG _nx_dhcp_add_randomize(ULONG timeout); +static VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); +static VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *dhcp_interface, NX_PACKET *packet_ptr); +static VOID _nx_dhcp_timeout_entry(ULONG dhcp); +static VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr); +static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record); + + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE +static VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw); +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + + +/* Define the Request string that specifies which options are to be added + to the DHCP Client discover request to the server. Additional options + (found in nx_dhcp.h) may be added after the last option. */ + +UCHAR _nx_dhcp_request_parameters[] = { NX_DHCP_OPTION_SUBNET_MASK, + NX_DHCP_OPTION_GATEWAYS, + NX_DHCP_OPTION_DNS_SVR}; + +#define NX_DHCP_REQUEST_PARAMETER_SIZE sizeof(_nx_dhcp_request_parameters) + +static struct NX_DHCP_STRUCT *_nx_dhcp_created_ptr; + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP create function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* ip_ptr Pointer to IP instance */ +/* name_ptr DHCP name pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_create Actual DHCP create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (dhcp_ptr == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Call actual DHCP create service. */ + status = _nx_dhcp_create(dhcp_ptr, ip_ptr, name_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the DHCP structure and associated IP */ +/* instance for DHCP operation. In doing so, it creates a packet */ +/* pool for DHCP messages, a UDP socket for communication with the */ +/* server, and a DHCP processing thread. */ +/* */ +/* The primary interface is automatically enabled for DHCP. To run */ +/* DHCP on a different interface, use the nx_dhcp_set_interface_index */ +/* service. To run DHCP on multiple interfaces, see */ +/* nx_dhcp_interface_enable and nx_dhcp_interface_start */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* ip_ptr Pointer to IP instance */ +/* name_ptr DHCP name pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_pool_create Create the DHCP packet pool */ +/* nx_packet_pool_delete Delete the DHCP packet pool */ +/* nx_udp_socket_create Create the DHCP UDP socket */ +/* nx_udp_socket_delete Delete the DHCP UDP socket */ +/* tx_mutex_create Create DHCP mutex */ +/* tx_mutex_delete Delete DHCP mutex */ +/* tx_thread_create Create DHCP processing thread */ +/* tx_timer_create Create DHCP timer */ +/* tx_timer_delete Delete DHCP timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr) +{ + +UINT status; +#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK +CHAR *temp_ptr; +UINT label_length = 0; +#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */ + + +#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK + + /* Set the pointer. */ + temp_ptr = name_ptr; + + /* The total length of a domain name (host name) is restricted to 255 octets or less. */ + if (_nx_utility_string_length_check(temp_ptr, NX_NULL, 255)) + { + return (NX_DHCP_INVALID_NAME); + } + + /* The labels must follow the rules for ARPANET host names. They must + start with a letter, end with a letter or digit, and have as interior + characters only letters, digits, and hyphen. There are also some + restrictions on the length. Labels must be 63 characters or less. + RFC 1035, Section 2.3.1, Page8. */ + while (*temp_ptr) + { + + /* Is a dot? */ + if (*temp_ptr == '.') + { + + /* Current label is end. */ + + /* Labels must be 63 characters or less, and check the continuous dot '..' for host name. */ + if ((label_length == 0) || (label_length > 63)) + return (NX_DHCP_INVALID_NAME); + + /* End with a letter or digit. Only need to check the Hyphen '-' since + *(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */ + if (*(temp_ptr - 1) == '-') + return (NX_DHCP_INVALID_NAME); + + /* Continue the next lable. */ + label_length = 0; + } + else + { + + /* Update the lable length. */ + label_length++; + + /* Letter. */ + if((((*temp_ptr) | 0x20) >= 'a') && (((*temp_ptr) | 0x20) <= 'z')) + { + + /* Continue next character. */ + temp_ptr++; + continue; + } + + /* Start with a letter. */ + if (label_length == 1) + return (NX_DHCP_INVALID_NAME); + + /* Hyphen or Digits. */ + if ((*temp_ptr != '-') && + ((*temp_ptr < '0') || (*temp_ptr > '9'))) + return (NX_DHCP_INVALID_NAME); + } + + /* Continue next character. */ + temp_ptr++; + } + + /* Check again if the host name have not the 'dot' terminator. */ + if (*(temp_ptr - 1) != '.') + { + + /* Labels must be 63 characters or less. */ + if (label_length > 63) + return (NX_DHCP_INVALID_NAME); + + /* End with a letter or digit. Only need to check the Hyphen '-' since + *(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */ + if (*(temp_ptr - 1) == '-') + return (NX_DHCP_INVALID_NAME); + } +#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */ + + /* Initialize the DHCP control block to zero. */ + memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP)); + + /* Save the IP pointer. */ + dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr; + + /* Save the DHCP name. */ + dhcp_ptr -> nx_dhcp_name = name_ptr; + + /* If the host does not intend to supply their own packet pool, create one here. */ +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + + /* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets. + RFC 2131, Section 2, Page10. */ + if (NX_DHCP_PACKET_PAYLOAD < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM)) + { + + /* Invalid payload, return error status. */ + return(NX_DHCP_INVALID_PAYLOAD); + } + + /* Create the pool and check the status */ + status = nx_packet_pool_create(&dhcp_ptr -> nx_dhcp_pool, "NetX DHCP Client", NX_DHCP_PACKET_PAYLOAD, + dhcp_ptr -> nx_dhcp_pool_area, NX_DHCP_PACKET_POOL_SIZE); + + /* Determine if it was successful. */ + if (status != NX_SUCCESS) + { + + /* No, return error status. */ + return(status); + } + + /* Set an internal packet pool pointer to the newly created packet pool. */ + dhcp_ptr -> nx_dhcp_packet_pool_ptr = &dhcp_ptr -> nx_dhcp_pool; + +#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION + + /* Set the maximum DHCP message size. */ + dhcp_ptr -> nx_dhcp_max_dhcp_message_size = NX_DHCP_PACKET_PAYLOAD - NX_PHYSICAL_HEADER; +#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ + +#endif /* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL */ + + /* Create the Socket and check the status */ + status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Client", + NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH); + + /* Was the socket creation successful? */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* No, return error status. */ + return(status); + } + + + /* Set the UDP socket receive callback function. */ + status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_udp_receive_notify); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + } + + /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if + a client connection has gone silent and needs to be terminated. */ + status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_timer), "DHCP Client Timer", _nx_dhcp_timeout_entry, + (ULONG)(ALIGN_TYPE)dhcp_ptr, (NX_DHCP_TIME_INTERVAL), + (NX_DHCP_TIME_INTERVAL), TX_NO_ACTIVATE); + + NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_timer), dhcp_ptr) + + /* Determine if the semaphore creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* No, return error status. */ + return(status); + } + + /* Create the DHCP mutex. */ + status = tx_mutex_create(&(dhcp_ptr -> nx_dhcp_mutex), "NetX DHCP Client", TX_NO_INHERIT); + + /* Determine if the semaphore creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* Delete the timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); + + /* No, return error status. */ + return(status); + } + + /* Create the DHCP processing thread. */ + status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_thread), "NetX DHCP Client", _nx_dhcp_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, + dhcp_ptr -> nx_dhcp_thread_stack, NX_DHCP_THREAD_STACK_SIZE, + NX_DHCP_THREAD_PRIORITY, NX_DHCP_THREAD_PRIORITY, 1, TX_DONT_START); + + NX_THREAD_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_thread), dhcp_ptr) + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the mutex. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* Delete the timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); + + /* No, return error status. */ + return(status); + } + + /* Create a DHCP event flag group. . */ + status = tx_event_flags_create(&(dhcp_ptr -> nx_dhcp_events), (CHAR *)"DHCP Client Events"); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + /* Delete the thread. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Delete the mutex. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete the timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* No, return error status. */ + return(status); + } + + /* Update the dhcp structure ID. */ + dhcp_ptr -> nx_dhcp_id = NX_DHCP_ID; + + /* Save the DHCP instance. */ + _nx_dhcp_created_ptr = dhcp_ptr; + + /* Default enable DHCP on the primary interface (0). */ + _nx_dhcp_interface_enable(dhcp_ptr, 0); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_clear_broadcast_flag PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP set the clear broadcast */ +/* flag in DHCP Client messages service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* clear_flag Broadcast flag status */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_broadcast_flag Actual DHCP Client clear */ +/* broadcast flag service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag) +{ + +UINT status; + + /* Check for invalid input pointer. */ + if (dhcp_ptr == NX_NULL) + { + + return(NX_PTR_ERROR); + } + + /* Call actual DHCP clear flag service. */ + status = _nx_dhcp_clear_broadcast_flag(dhcp_ptr, clear_flag); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_clear_broadcast_flag PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service uses the clear_flag input to clear or set the broadcast*/ +/* in DHCP Client messages to the DHCP server. By default the broadcast*/ +/* flag is set. */ +/* */ +/* This function is intended for DHCP Clients whose DHCP messages are */ +/* routed through a relay agent (router) that will not accept DHCP */ +/* messages with broadcast replies requested. */ +/* */ +/* NX_TRUE broadcast flag is cleared for all messages */ +/* NX_FALSE broadcast flag set only if it normally would be */ +/* */ +/* The server reply will actually be broadcast when relayed by the */ +/* router using this strategy. */ +/* */ +/* If DHCP is enabled on multiple interfaces, this service will set the*/ +/* broadcast flag on all interfaces. To set this flag on a specific */ +/* interface, use the nx_dhcp_interface_clear_broadcast_flag. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* clear_flag Broadcast flag status */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag) +{ + +UINT i; + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Loop to set the broadcast flag for all interface record enabled. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) + { + + dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_clear_broadcast = clear_flag; + } + } + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_clear_broadcast_flag PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the interface specific clear */ +/* broadcast flag service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Network interface index */ +/* clear_flag Broadcast flag status */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_clear_broadcast_flag Actual DHCP Client clear */ +/* broadcast flag service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag) +{ + +UINT status; + + /* Check for invalid input pointer. */ + if (dhcp_ptr == NX_NULL) + { + + return(NX_PTR_ERROR); + } + + /* Check interface index. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Call actual DHCP clear flag service. */ + status = _nx_dhcp_interface_clear_broadcast_flag(dhcp_ptr, iface_index, clear_flag); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interace_clear_broadcast_flag PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service uses the clear_flag input to determine if the DHCP */ +/* Client on the specified network interface should clear the broadcast*/ +/* flag in its DHCP messages to the DHCP server (normally it sets the */ +/* broadcast flag. */ +/* */ +/* This is intended for DHCP Clients whose DHCP messages are routed */ +/* through arelay agent (router) that will not accept DHCP messages */ +/* withbroadcast replies requested. */ +/* */ +/* NX_TRUE broadcast flag is cleared for all messages */ +/* NX_FALSE broadcast flag set only if it normally would be */ +/* */ +/* The server reply will actually be broadcast when relayed by the */ +/* router using this strategy. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Network interface index */ +/* clear_flag Broadcast flag status */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_dhcp_interface_record_find Find Client record for input */ +/* DHCP interface */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Set or clear the option to request unicast/clear broadcast flag. */ + interface_record -> nx_dhcp_clear_broadcast = clear_flag; + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the set the DHCP Client */ +/* packet pool service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* packet_pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Packet pool successfully set */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_NOT_ENABLED DHCP client not enabled for */ +/* user create packet pool */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_packet_pool_set */ +/* Actual set packet pool service*/ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr) +{ + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + NX_PARAMETER_NOT_USED(dhcp_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + + /* Client not configured for the user creating the packet pool. Return an error status. */ + return NX_NOT_ENABLED; +#else + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dhcp_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + /* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets. + RFC2131, Section2, Page10. */ + if (packet_pool_ptr -> nx_packet_pool_payload_size < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM)) + { + + /* Invalid payload, return error status. */ + return(NX_DHCP_INVALID_PAYLOAD); + } + + status = _nx_dhcp_packet_pool_set(dhcp_ptr, packet_pool_ptr); + + return status; +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DHCP Client packet pool by passing in a */ +/* packet pool pointer to packet pool already create. The */ +/* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL must be set. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* packet_pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NOT_ENABLED Setting DHCP Client packet */ +/* pool not enabled */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr) +{ + + + /* Determine if the DHCP Client is configured for accepting a packet pool pointer. */ +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + NX_PARAMETER_NOT_USED(dhcp_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + + /* No, return the error status. */ + return NX_NOT_ENABLED; +#else + + /* Set the Client packet pool to the supplied packet pool. */ + dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr; + +#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION + + /* Set the maximum DHCP message size. */ + dhcp_ptr -> nx_dhcp_max_dhcp_message_size = packet_pool_ptr -> nx_packet_pool_payload_size - NX_PHYSICAL_HEADER; +#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ + + return NX_SUCCESS; +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the reinitialize service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_reinitialize(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Call the actual reinitialize service. */ + status = _nx_dhcp_reinitialize(dhcp_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reinitializes all enabled DHCP interfaces for */ +/* restarting the DHCP client protocol. Network parameters in the DHCP*/ +/* Client and IP interface(s) are both cleared, and sets the DHCP state*/ +/* back to the not started state. */ +/* */ +/* To reinitialize the DHCP Client on a specific interface when */ +/* multiple interfaces are enabled for DHCP, use the */ +/* nx_dhcp_interface_reinitialize service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_reinitialize Reinitialize DHCP interface */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Loop to reinitalize the record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) + { + + /* Reinitialize the record. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the reinitialize service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Specify interface to init */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_INVALID_INTERFACE Index exceeds max interface */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_reinitialize Actual reinitialize service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual reinitialize service. */ + status = _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reinitializes the DHCP instance for restarting the */ +/* DHCP client state machine and re-running the DHCP protocol on the */ +/* specified interface. The IP address and other network parameters in*/ +/* the DHCP Client and in the IP interface are cleared. */ +/* */ +/* This function also sets the DHCP server IP address to the broadcast */ +/* address and sets the DHCP client state back to the INIT state. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Specify interface to init */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find Client record for input */ +/* DHCP interface */ +/* nx_ip_interface_address_set Clear IP inteface address of */ +/* the input DHCP interface */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* nx_ip_gateway_address_clear Clear the gateway address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; +ULONG ip_address; +ULONG network_mask; +ULONG gateway_address; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Check if have IP address. */ + if (interface_record -> nx_dhcp_ip_address) + { + + /* Get the IP address. */ + status = nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, &ip_address, &network_mask); + + /* Check if the IP address is set by DHCP. */ + if ((status == NX_SUCCESS) && (ip_address == interface_record -> nx_dhcp_ip_address)) + { + + /* Clear the IP address. */ + nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, 0, 0); + } + } + + /* Check if have gateway address. */ + if (interface_record -> nx_dhcp_gateway_address) + { + + /* Get the gateway address. */ + status = nx_ip_gateway_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, &gateway_address); + + /* Check status. */ + if ((status == NX_SUCCESS) && (gateway_address == interface_record -> nx_dhcp_gateway_address)) + { + + /* Clear the Gateway/Router IP address. */ + nx_ip_gateway_address_clear(dhcp_ptr -> nx_dhcp_ip_ptr); + } + } + + /* Initialize the client DHCP IP address with the NULL IP address. */ + interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS; + + /* Initialize the client DHCP server IP address. */ + interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS; + + /* Clear these DHCP Client network values too.*/ + interface_record -> nx_dhcp_gateway_address = NX_BOOTP_NO_ADDRESS; + interface_record -> nx_dhcp_network_mask = NX_BOOTP_NO_ADDRESS; + + /* Clear the flag to skip the discovery step. The host application must + call the nx_dhcp_request_ip_address to reset the flag and the requested IP address. */ + interface_record -> nx_dhcp_skip_discovery = NX_FALSE; + + /* Initialize renew and rebind timeout values to zero. */ + interface_record -> nx_dhcp_rebind_time = 0; + interface_record -> nx_dhcp_renewal_time = 0; + + /* Setup for infinite lease time request. */ + interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE; + + /* Reset the seconds field for starting the DHCP request process. */ + interface_record -> nx_dhcp_seconds = 0; + + /* Reset the timeout and retransmission interval. */ + interface_record -> nx_dhcp_timeout = 0; + interface_record -> nx_dhcp_rtr_interval = 0; + + /* Set the DHCP state to the initial state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_request_client_ip PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the client ip request */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_request_address Client's requested IP address */ +/* skip_discover_message Initialize Client state to */ +/* BOOT (skip discover message)*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message) +{ + +UINT status; + + + /* Check for an invalid DHCP pointer . */ + if (dhcp_ptr == NX_NULL) + { + + /* Return an error. */ + return(NX_PTR_ERROR); + } + + /* Determine that a nonzero IP address is entered. */ + if (client_request_address == NX_BOOTP_NO_ADDRESS) + { + + return NX_DHCP_INVALID_IP_REQUEST; + } + + /* Call actual request client IP service. */ + status = _nx_dhcp_request_client_ip(dhcp_ptr, client_request_address, skip_discover_message); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_request_client_ip PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the requested client IP address in DHCP Client */ +/* messages, and enables or disables the skip discovery option */ +/* based on the skip_discover_message input. */ +/* */ +/* If multiple interfaces are enabled for DHCP, this function sets the */ +/* requested Client IP on the first valid interface it finds. */ +/* */ +/* To set the requested Client IP for a specific interface, use the */ +/* nx_dhcp_interface_request_ip() service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_request_address Client's requested IP address */ +/* skip_discover_message To set DHCP Client flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_request_client_ip Interface specific request */ +/* IP service */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ + +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message) +{ + +UINT i; +UINT status; + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Set the request IP. */ + status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, + client_request_address, skip_discover_message); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_request_client_ip PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the request IP service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Index to apply parameter to */ +/* client_request_address Client's requested IP address */ +/* skip_discover_message To set DHCP Client flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, iface_index, client_request_address, skip_discover_message); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_request_client_ip PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the requested client IP address in the client */ +/* REQUEST message on the input interface. If the skip_discover_message*/ +/* flag is set, the DISCOVER message is skipped when the DHCP Client */ +/* (re))starts. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Index to apply parameter to */ +/* client_request_address Client's requested IP address */ +/* skip_discover_message To set DHCP Client flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find Client record for the */ +/* input interface */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Use input IP address. */ + interface_record -> nx_dhcp_ip_address = client_request_address; + + /* Set the flag for skipping the discovery state. */ + interface_record -> nx_dhcp_skip_discovery = skip_discover_message; + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return success! */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP delete function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_delete Actual DHCP delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_delete(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP delete service. */ + status = _nx_dhcp_delete(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables DHCP on all enabled interfaces, deletes the */ +/* DHCP instance and releases all of its resources. All DHCP and IP */ +/* interface IP addresses and the IP gateway are cleared on all */ +/* valid DHCP interfaces. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_dhcp_interface_disable Disable DHCP on interface */ +/* nx_packet_pool_delete Delete the DHCP packet pool */ +/* nx_udp_socket_delete Delete the DHCP UDP socket */ +/* tx_thread_suspend Suspend DHCP Thread */ +/* tx_thread_terminate Terminate DHCP thread */ +/* tx_mutex_delete Delete DHCP mutex */ +/* tx_event_flags_delete Delete DHCP flag group */ +/* tx_timer_deactivate Stop the DHCP timer */ +/* tx_timer_delete Delete the DHCP timer */ +/* tx_thread_delete Delete DHCP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_delete(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Disable all the interfaces enabled for DHCP. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this interface (i) is enabled for DHCP. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Disable the interface record. */ + _nx_dhcp_interface_disable(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Terminate the DHCP processing thread. */ + tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Delete the DHCP processing thread. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Delete the DHCP event flags. */ + tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_events)); + + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); + + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Unbind the port. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + /* Delete the packet pool. */ + nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); +#endif + + /* Get the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete the DHCP mutex. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Clear the dhcp structure ID. */ + dhcp_ptr -> nx_dhcp_id = 0; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_force_renew PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP force renew function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_force_renew Actual DHCP force renew */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_force_renew(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP force renew service. */ + status = _nx_dhcp_force_renew(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_force_renew PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function forces the DHCP processing thread to renew the lease */ +/* on all valid (DHCP enabled) interfaces. To force renew on a specific*/ +/* interface if multiple interfaces are enabled for DHCP, use the */ +/* nx_dhcp_interface_force_renew service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* nx_dhcp_interface_force_renew Force renew on DHCP interface */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_force_renew(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Force renew on this interface. */ + _nx_dhcp_interface_force_renew(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_force_renew PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function forces the DHCP processing thread to renew the lease */ +/* on the specified interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to force renew on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* nx_dhcp_interface_force_renew Actual force renew service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Call the actual reinitialize service. */ + status = _nx_dhcp_interface_force_renew(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_force_renew PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows the DHCP Client to force a renew on a */ +/* previously obtained lease on the input interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to force renew on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find record for the interface */ +/* _nx_dhcp_send_request_internal Send request to DHCP server */ +/* _nx_dhcp_update_renewal_timeout Update time left on renew lease*/ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index) +{ +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record for this interface. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return status. */ + return(status); + } + + /* Determine if DHCP is in the Bound state. */ + if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND) + { + + /* Since the Client is initiating RENEW ('force' renew'), set the state to RENEW. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; + + /* Send the renew request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Reset the renew time remaining (before transition to the REBIND state) and + the dhcp timeout for retransmission of RENEW request. */ + interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + else + { + + /* Return a not bound error code. */ + status = NX_DHCP_NOT_BOUND; + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_decline PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP decline function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_decline Actual DHCP decline function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_decline(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP release service. */ + status = _nx_dhcp_decline(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_decline PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function declines the IP address(es) assigned to the DHCP */ +/* Client on all valid interfaces. The DHCP Client state is set back */ +/* to the INIT state and DHCP is automatically restarted. */ +/* */ +/* To decline an IP address on a specific interface where multiple */ +/* interfaces are enabled for DHCP, use the */ +/* nx_dhcp_interface_decline service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_decline Interface specific decline */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_decline(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);\ + + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Decline the address. */ + _nx_dhcp_interface_decline(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_decline PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the decline service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to decline IP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_decline Actual decline service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index) +{ +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual decline service. */ + status = _nx_dhcp_interface_decline(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_decline PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function declines the IP assigned to the input DHCP Client */ +/* interface. The DHCP Client state is set back to the INIT state and */ +/* DHCP is automatically restarted. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to decline IP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find record for the interface */ +/* _nx_dhcp_send_request_internal Send DHCP request */ +/* _nx_dhcp_interface_reinitialize Reset IP and DHCP Client */ +/* network parameters */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; +UINT original_state; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr ->nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Check the record state. */ + if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NOT_BOUND); + } + + /* Get the original state. */ + original_state = interface_record -> nx_dhcp_state; + + /* Send the decline DHCP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDECLINE); + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* Wait for some time before restarting the configuration process to avoid excessive network traffic in case of looping. RFC2131, Section3.1, Page17. */ + interface_record -> nx_dhcp_timeout = NX_DHCP_RESTART_WAIT; + + /* Set the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = 0; + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP release function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_release Actual DHCP release function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_release(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP release service. */ + status = _nx_dhcp_release(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases the IP previously assigned to this DHCP */ +/* instance on all interfaces enabled for DHCP. A subsequent call to */ +/* nx_dhcp_start initiates a new request to obtain an IP address. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_release Interface specific send */ +/* release request service */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_release(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Release the address. */ + _nx_dhcp_interface_release(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return. */ + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the release service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to release IP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_release Actual release service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual interface release service. */ + status = _nx_dhcp_interface_release(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases the IP previously assigned to this DHCP */ +/* interface. The DHCP state is returned back to the NOT STARTED state.*/ +/* A subsequent call to _nx_dhcp_interface_start will initiate a new */ +/* request to obtain an IP address. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to release IP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find record for the interface */ +/* _nx_dhcp_send_request_internal Send request to DHCP server */ +/* _nx_dhcp_interface_reinitialize Clear IP and DHCP network */ +/* parameters to restart DHCP */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT i; +UINT status, original_state; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); + } + + /* Determine if DHCP is in the Boot state. */ + if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return an error code. */ + return(NX_DHCP_NOT_BOUND); + } + + /* Get the original state. */ + original_state = interface_record -> nx_dhcp_state; + + /* Send the release DHCP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPRELEASE); + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + + /* Check if other interfaces are running DHCP. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) + { + + /* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX + resources need to stay activated. */ + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); + } + } + + /* Has DHCP stopped on all interfaces? */ + if (i == NX_DHCP_CLIENT_MAX_RECORDS) + { + + /* Yes, stop DHCP Thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Deactivate DHCP Timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Unbind UDP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP start function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_start Actual DHCP start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_start(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP start service. */ + status = _nx_dhcp_start(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts DHCP on all interfaces that are enabled for */ +/* DHCP. If no interfaces have previously been started on DHCP, this */ +/* function re/starts the DHCP CLient thread, binds the socket and */ +/* re/starts the timer. */ +/* */ +/* To start DHCP on a specific interface if multiple interfaces are */ +/* enabled for DHCP, use the nx_dhcp_interface_start service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCP_NO_INTERFACES_STARTED Unable to start any interfaces*/ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_start Interface specific start DHCP */ +/* Client service */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_start(NX_DHCP *dhcp_ptr) +{ + +UINT status; +UINT interfaces_started = 0; +UINT i; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Check all interfaces to find out which need to start the DHCP protocol. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) + { + + /* Start DHCP on this interface. */ + status = _nx_dhcp_interface_start(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + + /* Note, not all interfaces are enabled to run, so + status may not be successful. Skip to the next + interface. */ + + /* Check status. */ + if ((status == NX_SUCCESS) || (status == NX_DHCP_ALREADY_STARTED)) + { + interfaces_started++; + } + } + } + + /* Check if any interfaces started DHCP. */ + if (interfaces_started == 0) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Unable to start any interfaces. */ + return NX_DHCP_NO_INTERFACES_STARTED; + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the interface specific */ +/* DHCP start service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to start DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_start Actual interface start service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP interface start service. */ + status = _nx_dhcp_interface_start(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function 'starts' the specified interface. It finds the matching*/ +/* DHCP Client record for that interface and checks that the interface */ +/* has been enabled for DHCP (see nx_dhcp_interface_enable). It then */ +/* checks if any interfaces are running DHCP. If not it binds the DHCP */ +/* socket port, activates the DHCP timer, and resumes the DHCP Client */ +/* thread. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to start DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find the Client record for the*/ +/* specified interface */ +/* nx_udp_socket_bind Bind DHCP socket */ +/* nx_udp_socket_unbind Unbind DHCP socket */ +/* tx_thread_resume Initiate DHCP processing */ +/* tx_timer_activate Activate DHCP timer */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT i; +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); + } + + /* Check if DHCP is already started. */ + if (interface_record -> nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_ALREADY_STARTED); + } + + /* Check if other interface are working. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) + { + + /* Yes, other interface have started DHCP. */ + break; + } + } + + /* Check if any interfaces have started DHCP. */ + if (i == NX_DHCP_CLIENT_MAX_RECORDS) + { + + /* Bind the UDP socket to the DHCP Client port. */ + status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); + + /* Check for error */ + if (status != NX_SUCCESS) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Resume the DHCP processing thread. */ + status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Determine if the resume was successful. */ + if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED)) + { + + /* Error, unbind the DHCP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Activate DHCP Timer. */ + status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Determine if the resume was successful. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the DHCP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Start DHCP service for this interface record. */ + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the interface specific */ +/* DHCP enable interface service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to enable DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_add Actual interface enable service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Call actual DHCP interface enable service. */ + status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the specified interface as enabled to run DHCP. */ +/* It ensures all DHCP parameters are initialized to zero, and uses the */ +/* physical interface MAC address to set the unique Client ID used for */ +/* transactions with the DHCP server. */ +/* */ +/* By default the primary interface is enabled in nx_dhcp_create. An */ +/* interface must be enabled before DHCP can be started on it. */ +/* Thereafter, it is only necessary to call this function on an interface*/ +/* that has been disabled. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to enable DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCP_NO_RECORDS_AVAILABLE No more records available to */ +/* enable DHCP on an interface */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index) +{ +UINT i; +ULONG client_physical_lsw, client_physical_msw; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) + { + + /* Check if the interface is already enabled. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_INTERFACE_ALREADY_ENABLED); + } + } + else + { + + /* Yes, we found an available record. */ + if (interface_record == NX_NULL) + interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; + } + } + + /* Check if we found an valid DHCP interface record. */ + if (interface_record == NX_NULL) + { + + /* No, release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_RECORDS_AVAILABLE); + } + + /* Set this record as valid. */ + interface_record -> nx_dhcp_record_valid = NX_TRUE; + + /* Set interface index. */ + interface_record -> nx_dhcp_interface_index = iface_index; + + /* Initialize the client DHCP IP address with the NULL IP address. */ + interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS; + + /* Initialize the client DHCP server IP address. */ + interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS; + + /* Initialize renew and rebind timeout values to zero. */ + interface_record -> nx_dhcp_rebind_time = 0; + interface_record -> nx_dhcp_renewal_time = 0; + + /* Setup for infinite lease time request. */ + interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE; + + /* Get the client MAC address from the device interface. */ + client_physical_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; + client_physical_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; + + /* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */ + interface_record -> nx_dhcp_xid = (ULONG)(client_physical_msw ^ client_physical_lsw ^ (ULONG)NX_RAND()); + + /* Clear the timeout. */ + interface_record -> nx_dhcp_timeout = 0; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the disable service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to disable DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_disable Actual disable service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index) +{ +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual delete service. */ + status = _nx_dhcp_interface_disable(dhcp_ptr, iface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the input interface to run DHCP. The DHCP */ +/* Client need not be in any state or DHCP to be started on this */ +/* interface to disable it. */ +/* */ +/* This function clears the DHCP and IP interface network parameters. */ +/* Before DHCP can be restarted on this interface, it must be enabled */ +/* by calling nx_dhcp_interface_enable. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to disable DHCP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find Client record for input */ +/* interface */ +/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */ +/* parameters */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Reinitalize the DHCP. This clears network values in DHCP and IP interfaces */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); + + /* Set the record as invalid. */ + interface_record -> nx_dhcp_record_valid = NX_FALSE; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_state_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP notify function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dchp_state_change_notify Application function to call */ +/* upon DHCP state change */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_state_change_notify Actual DHCP notify function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP notify service. */ + status = _nx_dhcp_state_change_notify(dhcp_ptr, dhcp_state_change_notify); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_state_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up an application notification function that is */ +/* called whenever a DHCP interface enters a new state. If a NULL */ +/* pointer is supplied, the notification is effectively cancelled. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dchp_state_change_notify Application function to call */ +/* upon DHCP state change */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)) +{ + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Setup the DHCP notify function. */ + dhcp_ptr -> nx_dhcp_state_change_callback = dhcp_state_change_notify; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_state_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the state change notify call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dhcp_state_interface_change_notify Application function to call */ +/* upon DHCP state change */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_state_change_notify Actual DHCP notify function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_interface_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)) +{ + +UINT status; + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Call actual DHCP notify service. */ + status = _nx_dhcp_interface_state_change_notify(dhcp_ptr, dhcp_state_interface_change_notify); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_state_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up an application notification function that is */ +/* called whenever DHCP on the input interface enters a new state. If */ +/* NULL function pointer is supplied, the notification is cancelled. */ +/* The interface on which the DHCP state changed is indicated by the */ +/* iface_index input. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dchp_state_change_notify interface-specific callback */ +/* for DHCP state change */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)) +{ + + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Setup the DHCP notify function. */ + dhcp_ptr -> nx_dhcp_interface_state_change_callback = dhcp_interface_state_change_notify; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP stop function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_stop Actual DHCP stop function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_stop(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP stop service. */ + status = _nx_dhcp_stop(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function halts DHCP processing on all interfaces enabled for */ +/* DHCP. The Client state is reset to NOT STARTED, and if no */ +/* interfaces are currently running DHCP, this function suspends the */ +/* DHCP Client thread, and unbinds the DHCP socket port. */ +/* */ +/* To stop DHCP on a specific interface when multiple interfaces are */ +/* enabled for DHCP, use the nx_dhcp_interface_stop service. */ +/* */ +/* To restart DHCP Client on a stopped interface, the interface must */ +/* be reinitialized using either nx_dhcp_reinitialize() to reinitialize*/ +/* all enabled DHCP interfaces, or nx_dhcp_interface_reinitialize() for*/ +/* a specific interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_stop Interface specific DHCP stop */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_stop(NX_DHCP *dhcp_ptr) +{ + +UINT i; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Check all interfaces to find out which need to stop the DHCP protocol. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) + { + + /* Stop DHCP. */ + _nx_dhcp_interface_stop(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); + } + } + + /* Stop DHCP Thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Deactivate DHCP Timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Ubind UDP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the interface specific */ +/* DHCP stop service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to stop DHCP */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_stop Actual interface stop service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT status; + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_dhcp_interface_stop(dhcp_ptr, iface_index); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops DHCP processing on the specified interface. It */ +/* sets the DHCP state to the unstarted status. If any state changes */ +/* occurred it calls the record state change callback. */ +/* */ +/* If DHCP is not started on any of the DHCP Client interfaces, this */ +/* function will suspend the thread, unbind the socket and stop the */ +/* timer. */ +/* */ +/* Note: before DHCP Client can be restarted on the interface, the */ +/* DHCP Client must be reinitialized by calling */ +/* nx_dhcp_interface_reinitialize(). */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to stop DHCP on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find record assigned to the */ +/* input interface */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT i; +UINT status; +UINT original_state; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Not found. Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Get the original state. */ + original_state = interface_record -> nx_dhcp_state; + + /* Determine if DHCP is started. */ + if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* DHCP is not started so it can't be stopped. */ + return(NX_DHCP_NOT_STARTED); + } + + /* Set the state to NX_DHCP_STATE_NOT_STARTED. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record->nx_dhcp_state); + } + } + + /* Check if other interfaces are running DHCP. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) + { + + /* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX + resources need to stay activated. */ + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_SUCCESS); + } + } + + /* Has DHCP stopped on all interfaces? */ + if (i == NX_DHCP_CLIENT_MAX_RECORDS) + { + + /* Yes, stop DHCP Thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Deactivate DHCP Timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Unbind UDP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_user_option_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP user option function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* option_request Option request */ +/* destination_ptr Pointer to return buffer */ +/* destination_size Size of return buffer (and */ +/* modified to reflect how */ +/* much information is in the */ +/* response) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_user_option_request Actual DHCP user option */ +/* function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) || + (destination_ptr == NX_NULL) || (destination_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP user option request service. */ + status = _nx_dhcp_user_option_retrieve(dhcp_ptr, option_request, destination_ptr, destination_size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_user_option_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches the DHCP options buffer to obtain the */ +/* specified option. If successful, the option is placed in the */ +/* supplied destination string. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* option_request Option request */ +/* destination_ptr Pointer to return buffer */ +/* destination_size Size of return buffer (and */ +/* modified to reflect how */ +/* much information is in the */ +/* response) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interfaces enabled */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_user_option_retrieve */ +/* Search DHCP interface options */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) +{ + +UINT i; +UINT status; + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Retrieve the user option. */ + status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, + option_request, destination_ptr, destination_size); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_user_option_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP user option function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface index */ +/* option_request Option request */ +/* destination_ptr Pointer to return buffer */ +/* destination_size Size of return buffer (and */ +/* modified to reflect how */ +/* much information is in the */ +/* response) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_user_option_request Actual DHCP user option */ +/* function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) || + (destination_ptr == NX_NULL) || (destination_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check interface index. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP interface user option request service. */ + status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, iface_index, option_request, destination_ptr, destination_size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_user_option_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches the DHCP options buffer to obtain the */ +/* specified option. If successful, the option is placed in the */ +/* supplied destination string. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface index */ +/* option_request Option request */ +/* destination_ptr Pointer to return buffer */ +/* destination_size Size of return buffer (and */ +/* modified to reflect how */ +/* much information is in the */ +/* response) */ +/* */ +/* OUTPUT */ +/* */ +/* destination_size Size of returned option */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_search_buffer Search the buffer */ +/* _nx_dhcp_interface_record_find Find record of input interface*/ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) +{ + +UCHAR *buffer_ptr; +UINT size; +UINT status; +UINT i; +ULONG *long_ptr; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Check state. */ + if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return an error. */ + return(NX_DHCP_NOT_BOUND); + } + + /* Setup a pointer to the previous buffer. */ + buffer_ptr = _nx_dhcp_search_buffer(interface_record -> nx_dhcp_options_buffer, + option_request, interface_record -> nx_dhcp_options_size); + + /* Determine if the option was found. */ + if (!buffer_ptr) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return an error. */ + return(NX_DHCP_PARSE_ERROR); + } + + /* Calculate the size of the option. */ + size = (UINT) *buffer_ptr; + + /* Determine if the destination is large enough. */ + if (size > *destination_size) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Server did not respond. */ + return(NX_DHCP_DEST_TO_SMALL); + } + + /* Skip the option size field. */ + buffer_ptr++; + + /* Check to see which option data is requested: */ + switch (option_request) + { + case NX_DHCP_OPTION_SUBNET_MASK: + case NX_DHCP_OPTION_TIME_OFFSET: + case NX_DHCP_OPTION_GATEWAYS: + case NX_DHCP_OPTION_TIMESVR: + case NX_DHCP_OPTION_DNS_SVR: + case NX_DHCP_OPTION_NTP_SVR: + case NX_DHCP_OPTION_DHCP_LEASE: + case NX_DHCP_OPTION_DHCP_SERVER: + case NX_DHCP_OPTION_RENEWAL: + case NX_DHCP_OPTION_REBIND: + { + + /* The length of these options must always be a multiple of 4 octets. */ + /* Store the value as host byte order. */ + long_ptr = (ULONG *) destination_ptr; + + /* Loop to set the long value. */ + for (i = 0; i < size;) + { + + /* Set the long value. */ + *long_ptr = _nx_dhcp_get_data(buffer_ptr + i, 4); + + /* Update the pointer. */ + long_ptr ++; + i += 4; + } + break; + } + default: + { + + /* Directly copy the data into destination buffer. */ + memcpy(destination_ptr, buffer_ptr, size); + break; + } + } + + /* Return the actual option size. */ + *destination_size = size; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_user_option_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the option convert service.*/ +/* */ +/* INPUT */ +/* */ +/* source_ptr Source of string area */ +/* */ +/* OUTPUT */ +/* */ +/* value Pointer to conversion value */ +/* NULL Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_user_option_convert Actual option convert service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG _nxe_dhcp_user_option_convert(UCHAR *source_ptr) +{ + +ULONG temp; + + /* Check for invalid input. */ + if (source_ptr == NX_NULL) + { + return NX_NULL; + } + + /* Pickup the ULONG. */ + temp = _nx_dhcp_user_option_convert(source_ptr); + + /* Return the ULONG. */ + return(temp); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_user_option_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the four bytes pointed to by the input */ +/* string pointer to an ULONG and returns the value. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Source of string area */ +/* */ +/* OUTPUT */ +/* */ +/* value Pointer to conversion value */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG _nx_dhcp_user_option_convert(UCHAR *source_ptr) +{ + +ULONG temp; + + + /* Pickup the ULONG. */ + temp = (((ULONG) *(source_ptr)) << 24) | + (((ULONG) *(source_ptr+1)) << 16) | + (((ULONG) *(source_ptr+2)) << 8) | + ((ULONG) *(source_ptr+3)); + + /* Return the ULONG. */ + return(temp); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_user_option_add_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the user option add */ +/* callback set service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dhcp_user_option_add Pointer to application's */ +/* option add function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_user_option_add_callback_set Actual user option callback */ +/* set service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, + UCHAR *user_option_ptr, UINT *user_option_length)) +{ + +UINT status; + + /* Check for invalid input. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_user_option_add == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Call actual DHCP user option callback set service. */ + status = _nx_dhcp_user_option_add_callback_set(dhcp_ptr, dhcp_user_option_add); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_user_option_add_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the user option add callback. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dhcp_user_option_add Pointer to application's */ +/* option add function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, + UCHAR *user_option_ptr, UINT *user_option_length)) +{ + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Set the callback. */ + dhcp_ptr -> nx_dhcp_user_option_add = dhcp_user_option_add; + + /* Release the mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_udp_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the IP thread task detects a UDP packet*/ +/* has been received on this socket. It allows the DHCP Client to make */ +/* a non blocking nx_udp_socket_receive call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to DHCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event packet is received */ +/* */ +/* CALLED BY */ +/* */ +/* IP thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + + NX_PARAMETER_NOT_USED(socket_ptr); + + /* Set the data received event flag. */ + tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_RECEIVE_EVENT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the DHCP Client timer expires. It */ +/* loops through all valid interfaces that have started DHCP, and */ +/* updates their DHCP timeout. If an interface timeout has expired, it*/ +/* processes that interface depending on which DHCP state it is in. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set an event that timer expired*/ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX timer */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_timeout_entry(ULONG dhcp) +{ + +NX_DHCP *dhcp_ptr; + + + /* Setup DHCP pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP, dhcp) + + /* Set the data event flag. */ + tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_TIMER_EVENT, TX_OR); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the processing thread for the DHCP Client. */ +/* Its processing consists of executing a while-forever loop that */ +/* checks for events (e.g. packet receive, timer expiration). For */ +/* received packets, some initial packet validation is done before */ +/* calling _nx_dhcp_packet_process. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_instance Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Check for events */ +/* _nx_udp_socket_receive Retrieve packet from socket */ +/* _nx_dhcp_interface_record_find Find record of this interface */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* _nx_dhcp_packet_process Process received packet */ +/* _nx_dhcp_timout_entry Process timer expiration */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_thread_entry(ULONG dhcp_instance) +{ + +NX_DHCP *dhcp_ptr; +NX_PACKET *packet_ptr; +ULONG events; +UINT status; +UINT iface_index; +UINT source_port; +ULONG source_ip_address; +UINT protocol; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + /* Setup the DHCP pointer. */ + NX_THREAD_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP, dhcp_instance) + + /* Obtain the DHCP mutex before processing an. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Enter the DHCP Client task loop. */ + do + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Wait for a DHCP client activity. */ + tx_event_flags_get(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_ALL_EVENTS, + TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Obtain the DHCP mutex before processing an. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Check for DHCP data received event. */ + if (events & NX_DHCP_CLIENT_RECEIVE_EVENT) + { + + /* Loop to receive DHCP message. */ + while(1) + { + + /* Check for an incoming DHCP packet with non blocking option. */ + status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT); + + /* Check for packet receive errors. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Find the source IP address, port, interface this packet is on. */ + status = nx_udp_packet_info_extract(packet_ptr, &source_ip_address, &protocol, &source_port, &iface_index); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + continue; + } + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the original packet . */ + nx_packet_release(packet_ptr); + continue; + } + + /* Process DHCP packet. */ + _nx_dhcp_packet_process(dhcp_ptr, interface_record, packet_ptr); + } + } + + /* Timer event. */ + if (events & NX_DHCP_CLIENT_TIMER_EVENT) + { + _nx_dhcp_timeout_process(dhcp_ptr); + } + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + + /* IP address conflict event. */ + if (events & NX_DHCP_CLIENT_CONFLICT_EVENT) + { + + /* Loop to check the interface. */ + for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++) + { + + /* Check the flag. */ + if (dhcp_ptr -> nx_dhcp_interface_conflict_flag == 0) + { + break; + } + + /* Check if IP address conflict for this interface. */ + if (dhcp_ptr -> nx_dhcp_interface_conflict_flag & ((UINT)(1 << iface_index))) + { + + /* Handle notice of address conflict event. Let the server know we + did not get assigned a unique IP address. */ + _nx_dhcp_interface_decline(dhcp_ptr, iface_index); + + /* Clear the flag. */ + dhcp_ptr -> nx_dhcp_interface_conflict_flag &= (UINT)(~(1 << iface_index)); + } + } + } +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + } while (1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the DHCP Client thread is notified of a*/ +/* receive event. If verifies the packet is intended for this host, */ +/* and checks the transaction ID from the Server to match its ID, */ +/* processing the packet based on DHCP state. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* interface_record Pointer to DHCP interface */ +/* packet_ptr Pointer to received packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_find_matching_record Find Client record matching */ +/* the packet interface */ +/* nx_packet_allocate Allocate new packet from DHCP */ +/* Client packet pool */ +/* nx_packet_release Release packet back to DHCP */ +/* Client packet pool */ +/* nx_packet_data_extract_offset Copy data to new packet buffer*/ +/* _nx_dhcp_get_option_value Get data for input option */ +/* _nx_dhcp_extract_information Extract basic info from packet*/ +/* _nx_dhcp_send_request_internal Send DHCP message */ +/* nx_ip_interface_address_set Set IP interface address */ +/* nx_ip_gateway_address_set Set IP gateway address */ +/* _nx_dhcp_interface_reinitialize Clear DHCP interface data */ +/* for restarting DHCP */ +/* */ +/* CALLED BY */ +/* */ +/* nx_dhcp_thread_entry DHCP Client thread entry fcn */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, NX_PACKET *packet_ptr) +{ + +UINT status; +NX_PACKET *new_packet_ptr; +ULONG dhcp_type; +UCHAR *work_ptr; +ULONG bytes_copied; +UINT offset; +NX_IP *ip_ptr; +UINT iface_index; +ULONG packet_client_mac_msw, packet_client_mac_lsw; +ULONG dhcp_client_mac_msw, dhcp_client_mac_lsw; +UINT original_state; +UCHAR *buffer; +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE +ULONG probing_delay; +#endif + + /* Set the IP pointer and interface index. */ + ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; + iface_index = interface_record -> nx_dhcp_interface_index; + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length <= NX_BOOTP_OFFSET_OPTIONS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } + + /* Copy the received packet (datagram) over to a packet from the DHCP Client pool and release + the packet back to receive packet pool as soon as possible. */ + status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Error allocating packet, return error status. */ + return; + } + + /* Verify the incoming packet does not exceed our DHCP Client packet payload. */ + if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < ((packet_ptr) -> nx_packet_length)) + { + + /* Release the newly allocated packet . */ + nx_packet_release(new_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Initialize the offset to the beginning of the packet buffer. */ + offset = 0; + status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, (packet_ptr) -> nx_packet_length, &bytes_copied); + + /* Check status. */ + if ((status != NX_SUCCESS) || (bytes_copied == 0)) + { + + /* Release the allocated packet we'll never send. */ + nx_packet_release(new_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Error extracting packet buffer, return error status. */ + return; + } + + /* Update the new packet with the bytes copied. For chained packets, this will reflect the total + 'datagram' length. */ + new_packet_ptr -> nx_packet_length = bytes_copied; + + + /* Now we can release the original packet. */ + nx_packet_release(packet_ptr); + + /* Set the interface index and MAC address. */ + dhcp_client_mac_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; + dhcp_client_mac_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; + + /* Set work_ptr. */ + work_ptr = new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_CLIENT_HW; + + /* Pickup the target MAC address in the DHCP message. */ + packet_client_mac_msw = (((ULONG)work_ptr[0]) << 8) | ((ULONG)work_ptr[1]); + packet_client_mac_lsw = (((ULONG)work_ptr[2]) << 24) | + (((ULONG)work_ptr[3]) << 16) | + (((ULONG)work_ptr[4]) << 8) | + ((ULONG)work_ptr[5]); + + /* Determine if the MAC address matches ours. */ + if ((packet_client_mac_msw != dhcp_client_mac_msw) || (packet_client_mac_lsw != dhcp_client_mac_lsw)) + { + + /* Release the allocated packet. */ + nx_packet_release(new_packet_ptr); + return; + } + + /* Check if XIDs match. */ + if (_nx_dhcp_get_data(new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_XID, 4) != interface_record -> nx_dhcp_xid) + { + + /* Release the original packet . */ + nx_packet_release(new_packet_ptr); + + /* Error with XID data, return error status. */ + return; + } + + /* Save the original state for the state change callback; after this point we will likely change it. */ + original_state = interface_record -> nx_dhcp_state; + + /* The action depends on the current state of the dhcp client. */ + switch (interface_record -> nx_dhcp_state) + { + + case NX_DHCP_STATE_SELECTING: + { + + /* Set up a buffer pointer. */ + buffer = new_packet_ptr -> nx_packet_prepend_ptr; + + /* Get what type of DHCP message it is. */ + status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr -> nx_packet_length); + + /* Determine if it is an Offer. */ + if ((status == NX_SUCCESS) && (dhcp_type == NX_DHCP_TYPE_DHCPOFFER)) + { + + /* Yes, a valid Offer is received! */ + + /* Increment the number of offers received. */ + interface_record -> nx_dhcp_offers_received++; + + /* Update the DHCP Client interface parameters (IP address, server IP, lease, renewal and rebind times */ + if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) + break; + + /* Send the DHCP Request to accept the offer. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Reset the initial timeout to NX_DHCP_MIN_RETRANS_TIMEOUT seconds */ + interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT; + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; + + /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); + + /* Check if the timeout is zero. */ + if (interface_record -> nx_dhcp_timeout == 0) + interface_record -> nx_dhcp_timeout = 1; + + /* Update the state to Requesting state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; + } + + /* Let the timeout processing handle retransmissions. We're done here */ + break; + } + + case NX_DHCP_STATE_REQUESTING: + { + +#ifdef NX_DHCP_ENABLE_BOOTP + + /* Initialize the value of dhcp type since we do not care for BOOTP. */ + dhcp_type = NX_DHCP_TYPE_DHCPACK; + + /* Also initialize status to success since we won't make the get option call. */ + status = NX_SUCCESS; +#endif + + /* Setup buffer pointer. */ + buffer = new_packet_ptr -> nx_packet_prepend_ptr; + +#ifndef NX_DHCP_ENABLE_BOOTP + /* There is a valid DHCP response, see if it is an ACK. */ + status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); +#endif + /* Proceed to processing the server response? */ + if (status == NX_SUCCESS) + { + + /* Yes, check and see if it is an ACK back to our previous request. */ + if (dhcp_type == NX_DHCP_TYPE_DHCPACK) + { + + /* Increment the number of ACKs received. */ + interface_record -> nx_dhcp_acks_received++; + + /* Either we got an ACK or we are using BOOTP. */ + + /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ + if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) + break; + + /* If the host is configured to send an ARP probe to verify Client address is + not in use, do so now. */ + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + + /* Change to the Address Probing state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_ADDRESS_PROBING; + + /* Initalize the time for probing. */ + probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_WAIT); + + /* Check the probing_delay for timer interval. */ + if (probing_delay) + interface_record -> nx_dhcp_timeout = probing_delay; + else + interface_record -> nx_dhcp_timeout = 1; + + /* Set the probing count. */ + interface_record -> nx_dhcp_probe_count = NX_DHCP_ARP_PROBE_NUM; + + /* Setup the handler to indicate the we want collision notification. */ + ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_conflict_notify_handler = _nx_dhcp_ip_conflict; + +#else /* NX_DHCP_CLIENT_SEND_ARP_PROBE not defined: */ + + nx_ip_interface_address_set(ip_ptr, iface_index, + interface_record -> nx_dhcp_ip_address, + interface_record -> nx_dhcp_network_mask); + + /* Check if the gateway address is valid. */ + if (interface_record -> nx_dhcp_gateway_address) + { + + /* Set the gateway address. */ + nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); + } + + /* No ARP probe performed. OK to change to the Bound state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; + +#ifdef NX_DHCP_ENABLE_BOOTP + /* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */ + interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER; +#else + /* Set the renewal time received from the server. */ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; +#endif /* NX_DHCP_ENABLE_BOOTP */ + +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE*/ + + break; + } + else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) + { + + /* Increment the number of NACKs received. */ + interface_record -> nx_dhcp_nacks_received++; + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); + + /* Restart DHCP service for this interface record. */ + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + + /* Check if the timeout is less than 1 second. */ + if (interface_record -> nx_dhcp_timeout < NX_IP_PERIODIC_RATE) + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + } + } + break; + } + + case NX_DHCP_STATE_BOUND: + { + + /* Silently discard all received packets in the BOUND state, RFC2131, Section 4.4 Figure 5 */ + + break; + } + + case NX_DHCP_STATE_RENEWING: + { + + /* Setup the buffer pointer. */ + buffer = new_packet_ptr -> nx_packet_prepend_ptr; + + /* Check the server response if it accepts are renewal. */ + status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); + + /* Was the option retrieved? */ + if (status == NX_SUCCESS) + { + + /* Yes, Check for an ACK. */ + if (dhcp_type == NX_DHCP_TYPE_DHCPACK) + { + + /* Increment the number of ACKs received. */ + interface_record -> nx_dhcp_acks_received++; + + /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ + if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) + break; + + /* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */ + nx_ip_interface_address_set(ip_ptr, iface_index, + interface_record -> nx_dhcp_ip_address, + interface_record -> nx_dhcp_network_mask); + + /* Check if the gateway address is valid. */ + if (interface_record -> nx_dhcp_gateway_address) + { + + /* Set the gateway address. */ + nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); + } + + /* Lease has been renewed, set the countdown timer back to the renewal time and go back + to the Bound state*/ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; + + /* Change the state back to bound. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; + + } + else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) + { + + /* Increment the number of NACKs received. */ + interface_record -> nx_dhcp_nacks_received++; + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); + + /* Restart DHCP service for this interface record. */ + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + } + } + break; + } + + case NX_DHCP_STATE_REBINDING: + { + + /* Setup buffer pointer. */ + buffer = new_packet_ptr -> nx_packet_prepend_ptr; + + /* There is a valid DHCP response, pickup the type of response. */ + status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); + + /* Valid response? */ + if (status == NX_SUCCESS) + { + + /* Is it an ACK response? */ + if (dhcp_type == NX_DHCP_TYPE_DHCPACK) + { + + /* Increment the number of ACKs received. */ + interface_record -> nx_dhcp_acks_received++; + + /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ + if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) + break; + + /* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */ + nx_ip_interface_address_set(ip_ptr, iface_index, + interface_record -> nx_dhcp_ip_address, + interface_record -> nx_dhcp_network_mask); + + /* Check if the gateway address is valid. */ + if (interface_record -> nx_dhcp_gateway_address) + { + + /* Set the gateway address. */ + nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); + } + + /* Lease has been renewed, set the countdown timer back to the renewal time and go back + to the Bound state. */ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; + + /* Change to bound state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; + } + else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) + { + + /* Increment the number of NACKs received. */ + interface_record -> nx_dhcp_nacks_received++; + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); + + /* Restart DHCP service for this interface record. */ + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + } + } + break; + } + + default: + break; + + } /* End of switch case */ + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_timeout_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is by the DHCP Client when it checks for a timer */ +/* expiration event. It checks all the DHCP interface records who have */ +/* started DHCP and updates the time remaining on their timeout. */ +/* If a timeout has expired, this function then processes it according */ +/* to the DHCP state it is in. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_send_request_internal Send a request to DHCP server */ +/* _nx_dhcp_update_timeout Reset the DHCP timeout */ +/* _nx_dhcp_add_randomize Modify timeout by random value*/ +/* _nx_dhcp_update_renewal_timeout Set the retransmission timeout*/ +/* _nx_arp_probe_send Send ARP probe for IP address */ +/* uniqueness if ARP probe */ +/* enabled */ +/* nx_ip_interface_address_set Set the IP interface address */ +/* nx_ip_gateway_address_set Set the IP gateway address */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr) +{ + +UINT i; +UINT original_state; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE +ULONG probing_delay; +NX_IP *ip_ptr; + + + /* Pickup the associated IP pointer. */ + ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; + +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + /* Update the timeout on both interfaces. Check what needs to be done + if a timeout expires, based on Client state. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if the DHCP Client is active on this interface. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE) + continue; + + /* Set the interface reocrd pointer. */ + interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; + + /* Update the count. */ + interface_record -> nx_dhcp_seconds ++; + + /* Check the timer. */ + if (interface_record -> nx_dhcp_timeout != 0) + { + + /* Apply the timer interval to the current DHCP Client timeout. */ + if (interface_record -> nx_dhcp_timeout > NX_DHCP_TIME_INTERVAL) + { + + /* Update the timeout. */ + interface_record -> nx_dhcp_timeout -= (ULONG)NX_DHCP_TIME_INTERVAL; + } + else + { + + /* The DHCP Client timeout has expired. */ + interface_record -> nx_dhcp_timeout = 0; + + /* Save the current state for state change callback. */ + original_state = interface_record -> nx_dhcp_state; + + /* Process according to what state the Client is in. */ + switch (interface_record -> nx_dhcp_state) + { + + case NX_DHCP_STATE_INIT: + { + + /* Reset the seconds field for starting the DHCP address acquistiion. */ + interface_record -> nx_dhcp_seconds = 0; + + /* Initial state when there is no address. Send a DHCPDISCOVER message + to find a DHCP server and switch to the SELECTING state. + Initial timeout is NX_DHCP_MIN_RETRANS_TIMEOUT seconds. */ +#ifndef NX_DHCP_ENABLE_BOOTP + /* Only if the DHCP Client is requesting an IP address and is configured to skip the Discovery message. */ + if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && + (interface_record -> nx_dhcp_skip_discovery)) + { + + /* Send out the DHCP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* And change to the Requesting state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; + } + else + { + + /* Send out the DHCP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER); + + /* And change to the Selecting state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_SELECTING; + } +#else + /* Send the BOOTP Request message. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); + + /* And change to the Requesting state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; +#endif + + /* Check if the retransmission interval is zero. */ + if (interface_record -> nx_dhcp_rtr_interval == 0) + { + + /* Set the interval to min retransmission timeout. */ + interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT; + } + else + { + + /* Record the retransmission interval for next retransmission. */ + interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); + } + + /* Update the timeout for next retransmission. */ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; + + /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); + + /* Check if the timeout is zero. */ + if (interface_record -> nx_dhcp_timeout == 0) + interface_record -> nx_dhcp_timeout = 1; + + break; + } + + case NX_DHCP_STATE_SELECTING: + { + +#ifndef NX_DHCP_ENABLE_BOOTP + /* Retransmit the Discover message. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER); +#else + /* Retransmit the BOOTP Request message. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); +#endif + + /* Update the retransmision interval. */ + interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); + + /* Update the timeout for next retransmission. */ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; + + /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); + + /* Check if the timeout is zero. */ + if (interface_record -> nx_dhcp_timeout == 0) + interface_record -> nx_dhcp_timeout = 1; + + break; + } + + case NX_DHCP_STATE_REQUESTING: + { + +#ifndef NX_DHCP_ENABLE_BOOTP + /* Send a DHCP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); +#else + /* Send a BOOTP request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); +#endif + + /* Update the retransmision interval. */ + interface_record->nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); + + /* Reset the timeout for next retransmision. */ + interface_record -> nx_dhcp_timeout = interface_record->nx_dhcp_rtr_interval; + + /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); + + /* Check if the timeout is zero. */ + if (interface_record -> nx_dhcp_timeout == 0) + interface_record -> nx_dhcp_timeout = 1; + + break; + } + + case NX_DHCP_STATE_ADDRESS_PROBING: + { + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + + /* Send the ARP probe. */ + _nx_arp_probe_send(ip_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_ip_address); + + /* Decrease the probe count. */ + interface_record -> nx_dhcp_probe_count--; + + /* Check the probe count. */ + if (interface_record -> nx_dhcp_probe_count) + { + + /* Calculate the delay time. */ + probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_MAX); + + /* Determine if this is less than the minimum. */ + if (probing_delay < NX_DHCP_ARP_PROBE_MIN) + { + + /* Set the delay to the minimum. */ + probing_delay = NX_DHCP_ARP_PROBE_MIN; + } + + /* Check the probing_delay for timer interval. */ + if (probing_delay) + interface_record -> nx_dhcp_timeout = probing_delay; + else + interface_record -> nx_dhcp_timeout = 1; + } + else + { + + /* No address conflict. */ + ip_ptr -> nx_ip_interface[interface_record -> nx_dhcp_interface_index].nx_interface_ip_conflict_notify_handler = NX_NULL; + + /* Set the IP address. */ + nx_ip_interface_address_set(ip_ptr, interface_record -> nx_dhcp_interface_index, + interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask); + + /* Check if the gateway address is valid. */ + if (interface_record -> nx_dhcp_gateway_address) + { + + /* Set the gateway address. */ + nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); + } + + /* Change to the Bound state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; + + #ifdef NX_DHCP_ENABLE_BOOTP + /* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */ + interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER; +#else + /* Set the renewal time received from the server. */ + interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; +#endif /* NX_DHCP_ENABLE_BOOTP */ + } + +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + break; + } + + case NX_DHCP_STATE_BOUND: + { + + /* Reset the seconds field for starting the DHCP request process. */ + interface_record -> nx_dhcp_seconds = 0; + + /* The lease has timed out. Time to renew. */ + + /* And change to the Renewing state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; + + /* Send the renewal request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Set the time remaining based on RFC 2131 when T1 expires. */ + interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + + break; + } + + case NX_DHCP_STATE_RENEWING: + { + + /* Check if we have reached the end of the renewal time. */ + if (interface_record -> nx_dhcp_renewal_remain_time >= interface_record -> nx_dhcp_rtr_interval) + { + interface_record -> nx_dhcp_renewal_remain_time -= interface_record -> nx_dhcp_rtr_interval; + } + else + { + interface_record -> nx_dhcp_renewal_remain_time = 0; + } + + /* Update the timeout for renew retranmission. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); + + /* Check if we are at the limit on retransmission. */ + if (interface_record -> nx_dhcp_timeout == 0) + { + + /* And change to the Rebinding state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING; + + /* Send the rebind request. */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Calculate the rebind time based on the RFC 2131. */ + interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time; + + /* Calculate the timeout for the response. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + } + else + { + + /* Retransmit the Renewing message and wait again */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + } + + break; + } + + case NX_DHCP_STATE_REBINDING: + { + + /* No response yet, the response must have timed out, + update the timeout and check if we have reached the + end of the rebinding time. */ + if (interface_record -> nx_dhcp_rebind_remain_time >= interface_record -> nx_dhcp_rtr_interval) + { + interface_record -> nx_dhcp_rebind_remain_time -= interface_record -> nx_dhcp_rtr_interval; + } + else + { + interface_record -> nx_dhcp_rebind_remain_time = 0; + } + + /* Update the timeout for renew retranmission. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); + + /* Check if we are at the limit on retransmission. */ + if (interface_record -> nx_dhcp_timeout == 0) + { + + /* Timeout. Restart DHCP service for this interface record. */ + + /* Reinitialize DHCP. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + } + else + { + + /* Retransmit the Renewing message and wait again */ + _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + } + break; + } + + default: + { + + break; + } + } + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + + } /* End of switch statement. */ + } + + } /* Try the next interface record. */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_send_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the DHCP client send */ +/* request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dhcp_message_type Type of DHCP message to send , */ +/* */ +/* OUTPUT */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_dhcp_send_request Actual send request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type) +{ + +UINT status; + + + /* Check for invalid input. */ + if (!dhcp_ptr || (dhcp_message_type == 0) || (dhcp_message_type > NX_DHCP_TYPE_DHCPFORCERENEW)) + { + return (NX_PTR_ERROR); + } + + /* Call the actual service and return completion status. */ + status = _nx_dhcp_send_request(dhcp_ptr, dhcp_message_type); + + return(status); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_send_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the specified request to the first DHCP enabled */ +/* interface found. To send a RELEASE or DECLINE message, use the */ +/* nx_dhcp_release/nx_dhcp_interface_release or nx_dhcp_decline/ */ +/* nx_dhcp_interface_decline respectively. */ +/* */ +/* To send a request on a specific DHCP interface if multiple */ +/* interfaces are DHCP enabled, use the */ +/* nx_dhcp_interface_send_request service. */ +/* */ +/* Note: Except for an INFORM REQUEST message, the application should */ +/* not need to send DHCP messages out independently of the DHCP Client */ +/* processing thread. It is not recommended to use this function once */ +/* the DHCP Client has started until it is BOUND. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* dhcp_message_type Type of DHCP message to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_send_request Send DHCP request to server */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type) +{ + +UINT status; +UINT i; + + /* Obtain the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Set the request on only the first (only) valid interface. */ + status = _nx_dhcp_interface_send_request(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, dhcp_message_type); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_send_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the send request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to send message on */ +/* dhcp_message_type DHCP messages to send: */ +/* NX_DHCP_TYPE_DHCPDECLINE */ +/* NX_DHCP_TYPE_DHCPRELEASE */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_send_request Actual send the DHCP request */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type) +{ + +UINT status; + + + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_dhcp_interface_send_request(dhcp_ptr, iface_index, dhcp_message_type); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_send_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows the host application to send a specific request*/ +/* on the specified interface. The interface must be enabled for DHCP. */ +/* */ +/* To send a RELEASE or DECLINE message on a specific interface, use */ +/* the nx_dhcp_interface_release or nx_dhcp_interface_decline */ +/* respectively. */ +/* */ +/* Note: Except for an INFORM REQUEST message, the application should */ +/* not need to send DHCP messages out independently of the DHCP Client */ +/* processing thread. It is not recommended to use this function once */ +/* the DHCP Client has started until it is BOUND. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to send message on */ +/* dhcp_message_type Type of DHCP message to send, */ +/* NX_DHCP_TYPE_DHCPDECLINE */ +/* NX_DHCP_TYPE_DHCPRELEASE */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCP_INVALID_MESSAGE Message type not allowed */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find Client record for the */ +/* specified interface */ +/* _nx_dhcp_send_request_internal Send the DHCP request */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); + } + + /* If the message is a RELEASE or DECLINE request, the host should call nx_dhcp_release + or nx_dhcp_decline respectively. */ + if ((dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE)) + { + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return NX_DHCP_INVALID_MESSAGE; + } + + /* The DHCP INFORM message is independent of the Client thread task activity. */ + if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM) + { + + /* Determine if DHCP is started. */ + if (dhcp_ptr -> nx_dhcp_interface_record[iface_index].nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* DHCP is not started so it should not 'send' a request to the server. */ + return(NX_DHCP_NOT_STARTED); + } + } + + + status = _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, dhcp_message_type); + + /* Release the DHCP mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return status; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_send_request_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a DHCP request to the server. Any additional */ +/* options are appended to the request structure for certain types of */ +/* DHCP requests. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to send message on */ +/* dhcp_message_type Type of DHCP message to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a DHCP packet */ +/* nx_packet_release Release DHCP packet */ +/* nx_udp_socket_send Send DHCP packet */ +/* _nx_dhcp_store_data Write data into message */ +/* _nx_dhcp_add_option_value Add an option to the request */ +/* _nx_dhcp_add_option_string Add an option string to the */ +/* request */ +/* nx_udp_socket_interface_send Send packet out on interface */ +/* _nx_dhcp_client_send_with_zero_source_address */ +/* Send broadcast packet with */ +/* zero source IP address */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_interface_send_request Send request on specified */ +/* interface */ +/* _nx_dhcp_interface_force_renew Send Force Renew message */ +/* _nx_dhcp_interface_decline Send DECLINE message */ +/* _nx_dhcp_interface_release Send RELEASE message */ +/* _nx_dhcp_packet_process Process received packets */ +/* _nx_dhcp_timeout_process Process timer expirations */ +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +/* _nx_dhcp_resume Resume the DHCP Client thread */ +#endif +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer; +ULONG targetIP; +UINT status; +ULONG dhcp_client_mac_msw; +ULONG dhcp_client_mac_lsw; +UINT iface_index; +UINT index = 0; +UCHAR *user_option_ptr; +UINT user_option_length; +UINT name_length; + + + /* Set the interface idnex. */ + iface_index = interface_record -> nx_dhcp_interface_index; + + /* Allocate a DHCP packet. */ + status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Increment the DHCP internal error counter. */ + interface_record -> nx_dhcp_internal_errors++; + + /* Return status. */ + return(status); + } + + /* Set the interface index and MAC address. */ + dhcp_client_mac_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; + dhcp_client_mac_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; + + /* Setup the buffer pointer. */ + buffer = packet_ptr -> nx_packet_prepend_ptr; + + /* Clear the buffer out... just in case. */ + memset((void *) buffer, 0, NX_BOOTP_OFFSET_END); + + /* Setup the standard BootP fields. */ + buffer[NX_BOOTP_OFFSET_OP] = NX_BOOTP_OP_REQUEST; + buffer[NX_BOOTP_OFFSET_HTYPE] = NX_BOOTP_TYPE_ETHERNET; + buffer[NX_BOOTP_OFFSET_HLEN] = NX_BOOTP_HLEN_ETHERNET; + buffer[NX_BOOTP_OFFSET_HOPS] = 0; + buffer[NX_BOOTP_OFFSET_SERVER_NM] = 0; + buffer[NX_BOOTP_OFFSET_BOOT_FILE] = 0; + + /* Setup the 'Xid' field. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_XID, 4, interface_record -> nx_dhcp_xid); + + /* Set the 'secs' field according to RFC2131, Secion4.4.1, Page37, Table5. */ + if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) + { + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, 0); + } + else + { + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, interface_record -> nx_dhcp_seconds); + } + + /* Set the broadcast flag according to RFC2131, Secion4.4.1, Page38, Table5. */ + + /* Set the broadcast flag to 0 for DHCP Decline and DHCP Release. */ + if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) + { + + /* Request the response be sent unicast. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST); + } + + /* Set the 'broadcast' flag according to user requirement for DHCP Discover, DHCP Request and DHCP Inform. */ + else if (interface_record -> nx_dhcp_clear_broadcast == NX_TRUE) + { + + /* Request the response be sent unicast. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST); + } + else + { + + /* Request the response be sent broadcast. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_BROADCAST); + } + + /* RFC 2131 4.4.1: Do not set the Client IP ("ciaddr" field) address...*/ + if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM) + { + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, NX_BOOTP_NO_ADDRESS); + } + /* ...unless this is an INFORM REQUEST message. */ + else + { + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); + } + + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_YOUR_IP, 4, NX_BOOTP_NO_ADDRESS); + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, NX_BOOTP_NO_ADDRESS); + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_GATEWAY_IP, 4, NX_BOOTP_NO_ADDRESS); + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW, 2, dhcp_client_mac_msw); + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_mac_lsw); + +#ifndef NX_DHCP_ENABLE_BOOTP + /* Update the index. */ + index = NX_BOOTP_OFFSET_OPTIONS; + + /* A BOOTP Client should not request DHCP option data. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_VENDOR, 4, NX_BOOTP_MAGIC_COOKIE); + + /* Add the actual DHCP request. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, NX_DHCP_OPTION_DHCP_TYPE_SIZE, dhcp_message_type, &index); +#endif + + /* Determine if any additional options need to be added relative to the DHCP message type. + RFC 2131, Table 5: Fields and options used by DHCP Clients. */ + switch (dhcp_message_type) + { + +#ifdef NX_DHCP_ENABLE_BOOTP + + case NX_DHCP_TYPE_BOOT_REQUEST: + + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, interface_record -> nx_dhcp_server_ip); + + break; +#endif + + case NX_DHCP_TYPE_DHCPDISCOVER: + + + /* Determine if we have a valid IP address. */ + if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && + (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS)) + { + + /* Add a IP request option if we have a valid IP address */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, + interface_record -> nx_dhcp_ip_address, &index); + } + + /* Add an option request for an infinite lease. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index); + + /* Add the system name */ + if (dhcp_ptr -> nx_dhcp_name) + { + + /* Check name length. */ + if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) + { + nx_packet_release(packet_ptr); + return(NX_DHCP_INVALID_NAME); + } + + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, + (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); + } + + /* Add an option request for DHCP parameters (gateway, subnet mask, etc.). */ + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, NX_DHCP_REQUEST_PARAMETER_SIZE, _nx_dhcp_request_parameters, &index); + +#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION + + /* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept. + RFC2132, Section9.10, Page28. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index); +#endif + + /* Increment the number of Discovery messages sent. */ + interface_record -> nx_dhcp_discoveries_sent++; + break; + + case NX_DHCP_TYPE_DHCPREQUEST: + + /* Add the system name */ + if (dhcp_ptr -> nx_dhcp_name) + { + + /* Check name length. */ + if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) + { + nx_packet_release(packet_ptr); + return(NX_DHCP_INVALID_NAME); + } + + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); + } + + /* Determine if we have a valid IP address. Must not include if Renewing or Rebinding RCV 2131 4.3.2. */ + if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && + (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS) && + (interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) && + (interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING)) + { + + /* Add an IP request option if we have a valid IP address. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, + interface_record -> nx_dhcp_ip_address, &index); + } + + /* Add a request for an infinite lease if we haven't already set the timers. */ + if ((interface_record -> nx_dhcp_rebind_time == 0) || + (interface_record -> nx_dhcp_renewal_time == 0)) + { + + /* Add the infinite lease option. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index); + } + + /* Should add server ID if not renewing. */ + if ((interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) && + (interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING) && + (interface_record -> nx_dhcp_server_ip != NX_BOOTP_BC_ADDRESS) + ) + { + + /* Add Server identifier option. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, + interface_record -> nx_dhcp_server_ip, &index); + } + else if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) || + (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)) + + { + + /* Ensure the renewal message fields are correct. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); + } + + /* Add the request for the DHCP parameters (gateway, subnet mask, etc.) if not renewing. */ + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, NX_DHCP_REQUEST_PARAMETER_SIZE, _nx_dhcp_request_parameters, &index); + +#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION + + /* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept. + RFC2132, Section9.10, Page28. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index); +#endif + + /* Increment the number of Request messages sent. */ + interface_record -> nx_dhcp_requests_sent++; + break; + + case NX_DHCP_TYPE_DHCPDECLINE: + + /* Does the Client have a nonzero requested address it is declining? */ + if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && + (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS)) + { + + /* Yes; add Request IP address option. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, + interface_record -> nx_dhcp_ip_address, &index); + } + + /* Add Server identifier option. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, + interface_record -> nx_dhcp_server_ip, &index); + + break; + + case NX_DHCP_TYPE_DHCPRELEASE: + + /* Added the 'ciaddr', Indicate the IP address being released. */ + _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); + + /* Add Server identifier option. */ + _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, + interface_record -> nx_dhcp_server_ip, &index); + + /* Increment the number of Release messages sent. */ + interface_record -> nx_dhcp_releases_sent++; + break; + + case NX_DHCP_TYPE_DHCPINFORM: + + /* Add the system name */ + if (dhcp_ptr -> nx_dhcp_name) + { + + /* Check name length. */ + if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) + { + nx_packet_release(packet_ptr); + return(NX_DHCP_INVALID_NAME); + } + + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); + } + + /* Add an option request for DHCP parameters (gateway, subnet mask, etc.). */ + _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, 1, &(interface_record -> nx_dhcp_user_option), &index); + + /* Increment the number of Inform messages sent. */ + interface_record -> nx_dhcp_informs_sent++; + + break; + + default: + break; + } + + /* Add any user supplied options to the buffer. */ + if (dhcp_ptr -> nx_dhcp_user_option_add) + { + + /* Set the pointer for adding user option. */ + user_option_ptr = buffer + index; + + /* Calculate the available length for user options. Minus 1 to add the END option. */ + user_option_length = (UINT)(packet_ptr -> nx_packet_data_end - user_option_ptr - 1); + + /* Add the specific DHCP option user wanted. */ + if (dhcp_ptr -> nx_dhcp_user_option_add(dhcp_ptr, iface_index, dhcp_message_type, user_option_ptr, &user_option_length) == NX_TRUE) + { + + /* Update the index to include the user options. */ + index += user_option_length; + } + else + { + + /* Invalid user options. Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_DHCP_UNKNOWN_OPTION); + } + } + + /* Setup the packet pointers. */ + packet_ptr -> nx_packet_length = NX_BOOTP_OFFSET_END; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_END; + +#ifndef NX_DHCP_ENABLE_BOOTP + + /* Added the END option. */ + *(buffer + index) = NX_DHCP_OPTION_END; + index ++; + + /* Check the option length. */ + if (index > NX_BOOTP_OFFSET_END) + { + packet_ptr -> nx_packet_length = index; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; + } +#endif + + /* Set the target address according to RFC2131, Section4.3.6, Page33, Table4 and Section4.4.4, Page40. + DHCP Request for renewing and DHCP Release message must be unicast. */ + if (((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING)) || + (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) + { + + /* Use the current server's IP address. */ + targetIP = interface_record -> nx_dhcp_server_ip; + } + else + { + + /* Set the server target IP address to broadcast. */ + targetIP = NX_BOOTP_BC_ADDRESS; + } + + /* DHCP messages broadcast by a client prior to that client obtaining + its IP address must have the source address field in the IP header + set to 0. RFC2131, Section4.1, Page23. */ + if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDISCOVER) || + ((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND))) + { + + /* Call function to send the special packet with zero source address.*/ + status = _nx_dhcp_client_send_with_zero_source_address(dhcp_ptr, iface_index, packet_ptr); + } + else + { + + /* Send the packet. */ + status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, targetIP, NX_DHCP_SERVER_UDP_PORT, iface_index); + } + + /* If an error is detected, release the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_send_with_zero_source_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds the UDP and IP header with zero source address,*/ +/* then sends the packet to the appropriate link driver. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to send message on */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_send_request_internal Send DHCP Request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr) +{ + +NX_IP *ip_ptr; +NX_UDP_SOCKET *socket_ptr; +NX_UDP_HEADER *udp_header_ptr; +NX_IPV4_HEADER *ip_header_ptr; +NX_INTERFACE *interface_ptr; +ULONG ip_src_addr, ip_dest_addr; +UINT compute_checksum; +ULONG checksum; +ULONG val; +NX_IP_DRIVER driver_request; + + /* Set up the pointer to the associated IP instance. */ + ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; + + /* Set up the pointer to the associated socket. */ + socket_ptr = &dhcp_ptr -> nx_dhcp_socket; + + /* Set up the pointer to the interface. */ + interface_ptr = &(ip_ptr -> nx_ip_interface[iface_index]); + packet_ptr -> nx_packet_ip_interface = interface_ptr; + + /* Set up the address. */ + ip_src_addr = NX_BOOTP_NO_ADDRESS; + ip_dest_addr = NX_BOOTP_BC_ADDRESS; + + /* Check the interface. */ + if ((!interface_ptr -> nx_interface_valid) || (!interface_ptr -> nx_interface_link_up)) + { + + /* None found; return the error status. */ + return(NX_INVALID_INTERFACE); + } + + /* Build UDP header. */ + + /* Prepend the UDP header to the packet. First, make room for the UDP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER); + + /* Set the correct IP version. */ + packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V4; + +#ifndef NX_DISABLE_UDP_INFO + /* Increment the total UDP packets sent count. */ + ip_ptr -> nx_ip_udp_packets_sent++; + + /* Increment the total UDP bytes sent. */ + ip_ptr -> nx_ip_udp_bytes_sent += packet_ptr -> nx_packet_length; + + /* Increment the total UDP packets sent count for this socket. */ + socket_ptr -> nx_udp_socket_packets_sent++; + + /* Increment the total UDP bytes sent for this socket. */ + socket_ptr -> nx_udp_socket_bytes_sent += packet_ptr -> nx_packet_length; +#endif + + /* Increase the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_UDP_HEADER); + + /* Setup the UDP header pointer. */ + udp_header_ptr = (NX_UDP_HEADER *) packet_ptr -> nx_packet_prepend_ptr; + + /* Build the first 32-bit word of the UDP header. */ + udp_header_ptr -> nx_udp_header_word_0 = (((ULONG)socket_ptr -> nx_udp_socket_port ) << NX_SHIFT_BY_16) | (ULONG) NX_DHCP_SERVER_UDP_PORT; + + /* Build the second 32-bit word of the UDP header. */ + udp_header_ptr -> nx_udp_header_word_1 = (packet_ptr -> nx_packet_length << NX_SHIFT_BY_16); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the UDP header. */ + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + +#ifdef NX_DISABLE_UDP_TX_CHECKSUM + compute_checksum = 0; +#else /* NX_DISABLE_UDP_TX_CHECKSUM */ + compute_checksum = 1; +#endif /* NX_DISABLE_UDP_TX_CHECKSUM */ + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + if (compute_checksum) + { + /* Yes, we need to compute the UDP checksum. */ + checksum = _nx_ip_checksum_compute(packet_ptr, + NX_PROTOCOL_UDP, + (UINT)packet_ptr -> nx_packet_length, + &ip_src_addr, + &ip_dest_addr); + + checksum = ~checksum & NX_LOWER_16_MASK; + + /* If the computed checksum is zero, it will be transmitted as all ones. */ + /* RFC 768, page 2. */ + if (checksum == 0) + checksum = 0xFFFF; + + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; + + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + /* Set CHECKSUM flag so the driver would invoke the HW checksum. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build the IP header. */ + + /* Prepend the IP header to the packet. First, make room for the IP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 20; + + /* Increase the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 20; + + /* Setup the IP header pointer. */ + ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; + + /* Build the first 32-bit word of the IP header. */ + ip_header_ptr -> nx_ip_header_word_0 = (NX_IP_VERSION | socket_ptr -> nx_udp_socket_type_of_service | (0xFFFF & packet_ptr -> nx_packet_length)); + + /* Build the second 32-bit word of the IP header. */ + ip_header_ptr -> nx_ip_header_word_1 = (ip_ptr -> nx_ip_packet_id++ << NX_SHIFT_BY_16) | socket_ptr -> nx_udp_socket_fragment_enable; + + /* Build the third 32-bit word of the IP header. */ + ip_header_ptr -> nx_ip_header_word_2 = ((socket_ptr -> nx_udp_socket_time_to_live << NX_IP_TIME_TO_LIVE_SHIFT) | NX_IP_UDP); + + /* Place the source IP address in the IP header. */ + ip_header_ptr -> nx_ip_header_source_ip = ip_src_addr; + + /* Place the destination IP address in the IP header. */ + ip_header_ptr -> nx_ip_header_destination_ip = ip_dest_addr; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the IP header. */ + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip); + +#ifdef NX_DISABLE_IP_TX_CHECKSUM + compute_checksum = 0; +#else /* NX_DISABLE_IP_TX_CHECKSUM */ + compute_checksum = 1; +#endif /* NX_DISABLE_IP_TX_CHECKSUM */ + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + if (compute_checksum) + { + checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4, 20, NULL, NULL); + + val = (ULONG)(~checksum); + val = val & NX_LOWER_16_MASK; + + /* Convert to network byte order. */ + NX_CHANGE_ULONG_ENDIAN(val); + + /* Now store the checksum in the IP header. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + +#ifdef NX_ENABLE_IP_PACKET_FILTER + /* Check if the IP packet filter is set. */ + if (ip_ptr -> nx_ip_packet_filter) + { + + /* Yes, call the IP packet filter routine. */ + if ((ip_ptr -> nx_ip_packet_filter((VOID *)(ip_header_ptr), NX_IP_PACKET_OUT)) != NX_SUCCESS) + { + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not successful status. */ + return(NX_NOT_SUCCESSFUL); + } + } +#endif /* NX_ENABLE_IP_PACKET_FILTER */ + + /* Build the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_ip_interface; + driver_request.nx_ip_driver_command = NX_LINK_PACKET_BROADCAST; + driver_request.nx_ip_driver_physical_address_msw = 0xFFFFUL; + driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFFUL; + + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_mtu_size) + { + +#ifndef NX_DISABLE_FRAGMENTATION + /* Check the DF bit flag. */ + if ((ip_ptr -> nx_ip_fragment_processing) && (socket_ptr -> nx_udp_socket_fragment_enable != NX_DONT_FRAGMENT)) + { + + /* Fragmentation is needed, call the IP fragment processing routine. */ + (ip_ptr -> nx_ip_fragment_processing) (&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); + } + else +#endif /* NX_DISABLE_FRAGMENTATION */ + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not successful status. */ + return(NX_NOT_SUCCESSFUL); + } + } + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet sent count. */ + ip_ptr -> nx_ip_total_packets_sent++; + + /* Increment the IP bytes sent count. */ + ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - 20; +#endif + + /* Broadcast packet. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_extract_information PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts important information from the server's */ +/* response DHCP message. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* interface_record Pointer to DHCP interface */ +/* dhcp_message Pointer to DHCP message */ +/* length Size of DHCP message buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_ip_address_set Set the DHCP IP address */ +/* nx_ip_gateway_address_set Set the Gateway address */ +/* _nx_dhcp_get_option_value Get DHCP option from buffer */ +/* _nx_dhcp_get_data Get data from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_packet_process Data received handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length) +{ + +ULONG value; + + + /* Extract the IP address. */ + value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_YOUR_IP, 4); + + /* Determine if it is valid. */ + if ((value != NX_BOOTP_NO_ADDRESS) && + (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || + ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || + ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) + { + + /* Store the IP address. */ + interface_record -> nx_dhcp_ip_address = value; + } + else + { + return(NX_DHCP_BAD_IP_ADDRESS); + } + + /* Determine if there is a subnet mask. Note a DHCP Server receiving a BOOTP request + may send DHCP option data for subnet masks as per RFC 1534 Section 2. */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_SUBNET_MASK, &value, length) == NX_SUCCESS) + { + + /* Make sure there is a valid IP address too. */ + if (value != NX_BOOTP_NO_ADDRESS) + { + + interface_record -> nx_dhcp_network_mask = value; + } + else + { + ULONG ip_address; + + /* No valid network mask info supplied; use the current network mask if any. Don't + care about current IP address for now. */ + nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, + interface_record -> nx_dhcp_interface_index, + &ip_address, + &(interface_record -> nx_dhcp_network_mask)); + } + } + +#ifdef NX_DHCP_ENABLE_BOOTP + + /* Update the IP address. */ + value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_SERVER_IP, 4); + + /* Determine if it is valid. */ + if (value != NX_BOOTP_NO_ADDRESS) + { + + /* Store the IP address. */ + interface_record -> nx_dhcp_server_ip = value; + } + + /* Update the IP address. */ + value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_GATEWAY_IP, 4); + + /* Determine if it is valid. */ + if ((value != NX_BOOTP_NO_ADDRESS) && + (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || + ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || + ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) + { + + /* Store the gateway/Router IP address to the Client record. */ + interface_record -> nx_dhcp_gateway_address = value; + } + else + { + + /* The gateway may be sent as an option: See note above about BOOTP Clients + parsing DHCP option data. */ + + /* Determine if the IP gateway/router IP address is present. */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS) + { + + /* Determine if it is valid. */ + if ((value != NX_BOOTP_NO_ADDRESS) && + (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || + ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || + ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) + { + + /* Store the gateway/Router IP address to the Client record. */ + interface_record -> nx_dhcp_gateway_address = value; + } + else + { + return(NX_DHCP_BAD_IP_ADDRESS); + } + } + } + +#else + + /* NX_DHCP_ENABLE_BOOTP not defined */ + + /* Overwrite the server ID if there is a DHCP option for Server ID */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_SERVER, &value, length) == NX_SUCCESS) + { + + /* Determine if it is valid. */ + if ((value != NX_BOOTP_NO_ADDRESS) && + (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || + ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || + ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) + { + + /* Store the server IP address. */ + interface_record -> nx_dhcp_server_ip = value; + } + else + { + return(NX_DHCP_BAD_IP_ADDRESS); + } + } + + /* Get the lease time. */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_LEASE, &value, length) == NX_SUCCESS) + { + + /* Check for an infinite lease. */ + if (value == 0xFFFFFFFF) + { + /* Store the 'infinite' lease time . */ + interface_record -> nx_dhcp_lease_time = value; + interface_record -> nx_dhcp_renewal_time = value; + interface_record -> nx_dhcp_rebind_time = value; + } + else + { + + /* Store the lease time in timer ticks. */ + interface_record -> nx_dhcp_lease_time = value * (ULONG)NX_IP_PERIODIC_RATE; + + /* Set the renew and rebind times. */ + interface_record -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_lease_time / 2; + interface_record -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_lease_time - (interface_record -> nx_dhcp_lease_time / 8); + } + } + + /* Overwrite the renew and rebind times with the specified values if the options are present. */ + if ((_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_RENEWAL, &value, length) == NX_SUCCESS) && + (value <= interface_record -> nx_dhcp_lease_time)) + { + + /* Check for an infinite lease. */ + if (value == 0xFFFFFFFF) + { + /* Set the 'infinite least time. */ + interface_record -> nx_dhcp_renewal_time = value; + } + else + { + + /* Store the renewal time in timer ticks */ + interface_record -> nx_dhcp_renewal_time = value * (ULONG)NX_IP_PERIODIC_RATE; + } + } + + /* Determine if there is a rebind time. */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_REBIND, &value, length) == NX_SUCCESS) + { + + /* Check for an infinite lease. */ + if (value == 0xFFFFFFFF) + { + + /* Set the 'infinite least time. */ + interface_record -> nx_dhcp_rebind_time = value; + } + else + { + + /* Convert to timer ticks. */ + value = value * (ULONG)NX_IP_PERIODIC_RATE; + + /* Sanity check*/ + if ((value <= interface_record -> nx_dhcp_lease_time) && + (value >= interface_record -> nx_dhcp_renewal_time)) + { + + /* Store the rebind time. */ + interface_record -> nx_dhcp_rebind_time = value; + } + } + } + + /* Determine if this is an ACK from a server response, which can only happen from a handful of states. */ + if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_REQUESTING) || + (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) || + (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)) + { + + /* Determine if the IP gateway/router IP address is present. */ + if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS) + { + + /* Determine if it is valid. */ + if ((value != NX_BOOTP_NO_ADDRESS) && + (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || + ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || + ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) + { + + /* Store the gateway/Router IP address to the Client record. */ + interface_record -> nx_dhcp_gateway_address = value; + } + else + { + return(NX_DHCP_BAD_IP_ADDRESS); + } + } + } + + /* Check the DHCP options size. */ + if ((length - NX_BOOTP_OFFSET_OPTIONS) > NX_DHCP_OPTIONS_BUFFER_SIZE) + interface_record -> nx_dhcp_options_size = NX_DHCP_OPTIONS_BUFFER_SIZE; + else + interface_record -> nx_dhcp_options_size = length - NX_BOOTP_OFFSET_OPTIONS; + + /* Copy the DHCP options into DHCP Client options buffer. */ + memcpy(interface_record -> nx_dhcp_options_buffer, + &dhcp_message[NX_BOOTP_OFFSET_OPTIONS], interface_record -> nx_dhcp_options_size); + +#endif /* NX_DHCP_ENABLE_BOOTP */ + + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_get_option_value PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches through a buffer containing a BootP message */ +/* for a DHCP option parameter and gets the value of that option if */ +/* it exists. The function is restricted to options that are less */ +/* than 4 octets (bytes) in size. */ +/* */ +/* INPUT */ +/* */ +/* bootp_message Pointer to option buffer */ +/* option Option requested */ +/* value Pointer to return value var */ +/* length Size of option buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_search_buffer Search the buffer */ +/* _nx_dhcp_get_data Get data from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_packet_process Data received handler */ +/* _nx_dhcp_extract_information Extract info from server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length) +{ + +UCHAR *data; +UCHAR *option_message; +UINT option_length; + + + /* Setup buffer pointer. */ + option_message = &bootp_message[NX_BOOTP_OFFSET_OPTIONS]; + option_length = length - NX_BOOTP_OFFSET_OPTIONS; + + /* Find the option. */ + if ((option != NX_DHCP_OPTION_PAD) && (option != NX_DHCP_OPTION_END)) + { + + /* Search the buffer for the option. */ + data = _nx_dhcp_search_buffer(option_message, option, option_length); + + /* Check to see if the option was found. */ + if (data != NX_NULL) + { + + /* Check for the proper size. */ + if (*data > 4) + { + + /* Check for the gateway option. */ + if (option == NX_DHCP_OPTION_GATEWAYS) + { + + /* Pickup the first gateway address. */ + *value = _nx_dhcp_get_data(data + 1, 4); + + /* For now, just disregard any additional gateway addresses. */ + return(NX_SUCCESS); + } + else + { + + /* Invalid size, return error. */ + return(NX_SIZE_ERROR); + } + } + else + { + + /* Get the actual value. */ + *value = _nx_dhcp_get_data(data + 1, *data); + return(NX_SUCCESS); + } + } + } + + /* Return an error if not found. */ + return(NX_OPTION_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_add_option_value PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine adds a DHCP vendor option value to the BootP message */ +/* in the supplied buffer. Adding the option includes adding the */ +/* option code, length and option data value. */ +/* */ +/* INPUT */ +/* */ +/* bootp_message Pointer to message buffer */ +/* option Option to add */ +/* value Value of Option to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_store_data Store data value */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_send_request_internal Send DHCP request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index) +{ + + + /* Store the option. */ + *(bootp_message + (*index)) = (UCHAR)option; + (*index) ++; + + /* Store the option size. */ + *(bootp_message + (*index)) = (UCHAR)size; + (*index) ++; + + /* Store the option value. */ + _nx_dhcp_store_data(bootp_message + (*index), size, value); + (*index) += size; + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_add_option_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine adds a DHCP option string to the BootP message in */ +/* supplied buffer. Adding the option includes adding the option */ +/* code, length and option string. */ +/* */ +/* INPUT */ +/* */ +/* bootp_message Pointer to message buffer */ +/* option Option to add */ +/* size Size of option string */ +/* value Option string pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_move_string Store option string */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_send_request_internal Internal DHCP message send */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index) +{ + + /* Store the option. */ + *(bootp_message + (*index)) = (UCHAR)option; + (*index) ++; + + /* Store the option size. */ + *(bootp_message + (*index)) = (UCHAR)size; + (*index) ++; + + /* Store the option value. */ + _nx_dhcp_move_string(bootp_message + (*index), value, size); + (*index) += size; + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_add_randomize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine adds randomized variance to the input timeout up to */ +/* +/- one second. */ +/* */ +/* INPUT */ +/* */ +/* timeout Timeout to randomize */ +/* */ +/* OUTPUT */ +/* */ +/* ULONG Modified timeout value */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* nx_dhcp_process Process the current state of */ +/* the DHCP Client state machine*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dhcp_add_randomize(ULONG timeout) +{ + +ULONG adjustment; + + /* Uniform random number chosen from the range -1 to +1 second as recommended by RFC2131, Section4.1, Page24. */ + + /* Calculate random time adjustment in timer ticks from the range 0 to NX_IP_PERIODIC_RATE * 2. */ + adjustment = (ULONG)NX_RAND() % ((NX_IP_PERIODIC_RATE << 1) + 1); + + /* Check for adjustment. */ + if (adjustment < NX_IP_PERIODIC_RATE) + { + + /* Updated timeout, minus NX_IP_PERIODIC_RATE - adjustment. */ + + /* Check for timeout. */ + if (timeout > (NX_IP_PERIODIC_RATE - adjustment)) + timeout -= (ULONG)(NX_IP_PERIODIC_RATE - adjustment); + else + timeout = 0; + } + else + { + + /* Updated timeout, add adjustment- NX_IP_PERIODIC_RATE. */ + timeout += (ULONG)(adjustment - NX_IP_PERIODIC_RATE); + } + + return timeout; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_update_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCP timeout for retransmission. When the */ +/* current timeout expires, this function doubles the timeout, but */ +/* limits the timeout value to NX_DHCP_MAX_RETRANS_TIMEOUT (seconds). */ +/* */ +/* INPUT */ +/* */ +/* timeout The current Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* timeout The updated timeout */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_convert_delay_to_ticks Convert the delay to ticks */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_timeout_process Timer expiration handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dhcp_update_timeout(ULONG timeout) +{ + + /* Timed out, double the timeout, limited to NX_DHCP_MAX_RETRANS_TIMEOUT */ + if ((2 * timeout) >= NX_DHCP_MAX_RETRANS_TIMEOUT) + { + + /* Set the timeout as NX_DHCP_MAX_RETRANS_TIMEOUT. */ + timeout = NX_DHCP_MAX_RETRANS_TIMEOUT; + } + else + { + + /* Double timeout value. */ + timeout = timeout * 2; + } + + /* Return the sequence timeout. */ + return(timeout); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_update_renewal_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCP timeout when trying to renew a */ +/* lease according to the RFC. When the current period has timed out, */ +/* this function halves the timeout, limiting the minimum timeout */ +/* value to NX_DHCP_MIN_RENEW_TIMEOUT seconds. */ +/* */ +/* INPUT */ +/* */ +/* timeout The current Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* timeout Renewal time remaining */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_client_interface_update_time_remaining */ +/* Apply input time elapsed to */ +/* the DHCP Client record */ +/* _nx_dhcp_timeout_process Timer expiration handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout) +{ + + /* check if the timeout is non zero */ + if (timeout != 0) + { + + /* Timed out, halve the timeout, limited to NX_DHCP_MIN_RENEW_TIMEOUT or + the remaining timeout if it is less than NX_DHCP_MIN_RENEW_TIMEOUT */ + if (timeout > NX_DHCP_MIN_RENEW_TIMEOUT) + { + + /* Timeout can still decrease, either + force it to the minimum or halve it */ + if (timeout > (2 * NX_DHCP_MIN_RENEW_TIMEOUT )) + { + + /* Halve timeout. */ + timeout = timeout / 2; + } + else + { + + /* set timeout to minimum. */ + timeout = NX_DHCP_MIN_RENEW_TIMEOUT ; + } + } + } + + /* Return the sequence timeout. */ + return(timeout); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_search_buffer PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine searches through a buffer containing a BootP message */ +/* for a DHCP option parameter and returns a pointer to the byte */ +/* containing the size of the data section of that option if it */ +/* exists. If the option cannot be found then function returns NULL. */ +/* If the option has no data (PAD and END) then the pointer is not */ +/* usable. */ +/* */ +/* INPUT */ +/* */ +/* option_message Pointer to option buffer area */ +/* option Option to search for */ +/* length Length of search buffer */ +/* */ +/* OUTPUT */ +/* */ +/* pointer Pointer to found option */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_get_option_value Get the value of an option */ +/* _nx_dhcp_get_option_data Get the string of an option */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length) +{ + +UCHAR *data; +UINT i; +UINT size; + + /* Setup buffer pointer. */ + data = option_message; + i = 0; + + /* Search as long as there are valid options. */ + while (i < length - 1) + { + + /* Simply skip any padding */ + if (*data == NX_DHCP_OPTION_PAD) + { + + data++; + i++; + } + + /* On a match, return a pointer to the size. */ + else if (*data == option) + { + + size = *(data + 1); + + /* Check if the option data is in the packet. */ + if ((i + size + 1) > length) + return(NX_NULL); + + /* Return a pointer to the option size byte. */ + return(data + 1); + } + + /* Otherwise skip the option by adding the size to the pointer. */ + else + { + + size = *(++data); + + /* skip the data plus the size byte */ + data += size + 1; + i += size + 1; + } + } + + /* Return NULL to indicate the option was not found. */ + return(NX_NULL); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_get_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine gets a data value from a buffer, assuming the data is */ +/* stored in standard Network format (big endian). Up to 4 bytes of */ +/* data are used, if there are more than 4 bytes, only the lower 4 */ +/* bytes are returned. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* */ +/* OUTPUT */ +/* */ +/* value Data value retrieved */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_get_response Get response from server */ +/* _nx_dhcp_extract_information Extract server information */ +/* _nx_dhcp_get_option_value Retrieve option value */ +/* _nx_dhcp_update_address_list Update address list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size) +{ + +ULONG value = 0; + + + /* Process the data retrieval request. */ + while (size-- > 0) + { + + /* Build return value. */ + value = (value << 8) | *data++; + } + + /* Return value. */ + return(value); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_store_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores a data value in a buffer in standard Network */ +/* format (big endian) where the destination may be unaligned. Up to */ +/* 4 bytes of data are stored, if the size is larger than 4 bytes, the */ +/* remaining bytes are set to zero. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* value Value to store */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_send_request_internal Send DHCP request */ +/* _nx_dhcp_add_option_value Add a DHCP option */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value) +{ + + /* Make sure that data is left justified. */ + switch (size) + { + + case 1: + + value <<= 24; + break; + + case 2: + + value <<= 16; + break; + + case 3: + + value <<= 8; + break; + + default: + break; + } + + /* Store the value. */ + while (size-- > 0) + { + + *data = (UCHAR) ((value >> 24) & 0xff); + data++; + value <<= 8; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_move_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores a sequence of data bytes to a buffer. */ +/* */ +/* INPUT */ +/* */ +/* dest Pointer to destination buffer */ +/* source Pointer to source buffer */ +/* size Number of bytes to move */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_add_option_string Add option string */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size) +{ + + /* Loop to copy all bytes. */ + while (size-- > 0) + { + + /* Copy a byte. */ + *dest++ = *source++; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_server_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the DHCP server get */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Client task */ +/* server_address Pointer to DHCP server address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_server_address_get Actual get DHCP IP server */ +/* address service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address) +{ + +UINT status ; + + + if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_dhcp_server_address_get(dhcp_ptr, server_address); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the DHCP Client's DHCP server IP address on */ +/* the first DHCP enabled interface found. */ +/* */ +/* Note that the caller should only call this service when the Client */ +/* is bound to an IP address from a DHCP server. See the */ +/* nx_dhcp_state_change_notify for notification of state changes. */ +/* */ +/* If multiple interfaces are enabled for DHCP, use */ +/* nx_dhcp_interface_server_address_get() to get the server IP address */ +/* on a specified interface. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Client task */ +/* server_address Pointer to DHCP server address*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_server_address_get Interface specific server IP */ +/* address get service */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address) +{ + +UINT i; +UINT status; + + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check the interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Get the server address of first valid record. */ + status = _nx_dhcp_interface_server_address_get(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, server_address); + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); + } + } + + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_interface_server_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the DHCP server get */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Client task */ +/* iface_index Interface of the Server */ +/* server_address Pointer to DHCP server address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_server_address_get Actual get server IP address */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address) +{ + +UINT status; + + if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL)) + { + return NX_PTR_ERROR; + } + + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual reinitialize service. */ + status = _nx_dhcp_interface_server_address_get(dhcp_ptr, iface_index, server_address); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_server_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the DHCP Client's DHCP server IP address on */ +/* the specified interface. */ +/* */ +/* Note that the caller should only call this service when the Client */ +/* is in the bound state. See nx_dhcp_state_change_notify for */ +/* notification when the Client state changes. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Client task */ +/* iface_index Interface of the DHCP server */ +/* server_address Pointer to DHCP server address */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCP_NOT_BOUND Client state not Bound */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_dhcp_interface_record_find Find record for the interface */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); + } + + /* Check the record state. */ + if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND) + { + + /* Set the server IP address from the DHCP Client instance. */ + *server_address = interface_record -> nx_dhcp_server_ip; + status = NX_SUCCESS; + } + else + status = NX_DHCP_NOT_BOUND; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return status; +} + + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_ip_conflict PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the DHCP instance that a conflict was */ +/* detected by the NetX ARP receive packet handling routine. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* iface_index IP Interface Index */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT iface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw) +{ + + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(physical_msw); + NX_PARAMETER_NOT_USED(physical_lsw); + + /* Set the interface index. */ + _nx_dhcp_created_ptr -> nx_dhcp_interface_conflict_flag |= (UINT)(1 << iface_index); + + /* Set the address conflict event flag. */ + tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_CONFLICT_EVENT, TX_OR); +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_set_interface_index PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function does error checking for the set interface index call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* interface_index Interface the DHCP Client task*/ +/* is associated with */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_set_interface_index Actual set interface index */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (dhcp_ptr == NX_NULL) + { + + return(NX_PTR_ERROR); + } + /* Check for invalid non pointer input. */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + return(NX_INVALID_INTERFACE); + } + + /* Call the actual set DHCP Client interface service */ + status = _nx_dhcp_set_interface_index(dhcp_ptr, interface_index); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_set_interface_index PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables DHCP on the specified interface. This function*/ +/* should be called before the DHCP Client is started. The intended use*/ +/* of this function is for DHCP to run on only one interface. To enable*/ +/* multiple interfaces for DHCP, use the nx_dhcp_interface_enable */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface to enable DHCP on */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_enable Enable DHCP on interface */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT iface_index) +{ + +UINT i; +UINT status; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); + + /* Invalidate all the interfaces enabled for DHCP. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Invalidate this interface. */ + dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid = NX_FALSE; + + /* Change the state. */ + dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; + } + + /* Enable DHCP on this interface. */ + status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_interface_record_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Find the Client record that is assigned to the input interface */ +/* index, and return a pointer to that record. The interface index must*/ +/* match the interface index of the Client record, and the interface */ +/* must be enabled for DHCP. If no matching records are found, an */ +/* error status is returned, and the interface record pointer is NULL. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* interface_index Interface to find */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_DHCP_INTERFACE_NOT_ENABLED No matching record found */ +/* */ +/* CALLS */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record) +{ + +UINT i; + + /* Find which DHCP Client interface record is assigned the input interface. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if this record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE) + continue; + + /* Check if the interface index matches. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index) + { + + /* Yes, we found the record. */ + *interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; + + /* Return. */ + return (NX_SUCCESS); + } + } + + /* No matching record found. */ + return (NX_DHCP_INTERFACE_NOT_ENABLED); +} + + +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get DHCP Client record */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_record_ptr Pointer to memory to save */ +/* Client record to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status from */ +/* internal DHCP calls */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_create_record */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr) +{ + +UINT status; + + if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_dhcp_client_get_record(dhcp_ptr, client_record_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a DHCP Client record for restoring the Client */ +/* state between power cycles or idle (sleep) mode. It copies the */ +/* first DHCP enabled Client record found to the supplied client record*/ +/* pointer. If DHCP is enabled on multiple interfaces, use */ +/* nx_dhcp_client_interface_record_get to get a record of a specific */ +/* interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_record_ptr Pointer to Client record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_get_record Get record for specified index*/ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr) +{ + +UINT i; +UINT status; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check if the interface record is valid. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) + { + + /* Find a record of the current state of the DHCP CLient. */ + status = _nx_dhcp_client_interface_get_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, client_record_ptr); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_interface_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get DHCP Client */ +/* interface record service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface index */ +/* client_record_ptr Pointer to memory to save */ +/* Client record to */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_create_record */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Check interface index. */ + if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) + { + return NX_INVALID_INTERFACE; + } + + status = _nx_dhcp_client_interface_get_record(dhcp_ptr, iface_index, client_record_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_interface_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a DHCP Client record for restoring the Client */ +/* state between power cycles or idle (sleep) mode. It then copies the*/ +/* Client record to the supplied client record pointer. */ +/* */ +/* The DHCP Client state should be restored from a Client record saved */ +/* to memory (client_record_ptr). */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface index */ +/* client_record_ptr Pointer to memory to save */ +/* Client record to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCP_NOT_BOUND Client not Bound to address */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_interface_record_find Find interface record matching*/ +/* the input interface */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Check the state. */ + if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) + { + + /* The DHCP Client is not bound to an IP address. Cannot create a record for restoring Client + state if the Client not bound to an IP address. */ + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return NX_DHCP_NOT_BOUND; + } + + /* Clear memory before filling with data. */ + memset(client_record_ptr, 0, sizeof(NX_DHCP_CLIENT_RECORD)); + + /* Set the record. */ + client_record_ptr -> nx_dhcp_state = interface_record -> nx_dhcp_state; + client_record_ptr -> nx_dhcp_ip_address = interface_record -> nx_dhcp_ip_address; /* Server assigned IP Address */ + client_record_ptr -> nx_dhcp_network_mask = interface_record -> nx_dhcp_network_mask; /* Server assigned network mask */ + client_record_ptr -> nx_dhcp_gateway_address = interface_record -> nx_dhcp_gateway_address; + client_record_ptr -> nx_dhcp_server_ip = interface_record -> nx_dhcp_server_ip; + client_record_ptr -> nx_dhcp_timeout = interface_record -> nx_dhcp_timeout; + client_record_ptr -> nx_dhcp_lease_time = interface_record -> nx_dhcp_lease_time ; + client_record_ptr -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_renewal_time; + client_record_ptr -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_rebind_time; + client_record_ptr -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_renewal_remain_time; + client_record_ptr -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_rebind_remain_time; + client_record_ptr -> nx_dhcp_interface_index = interface_record -> nx_dhcp_interface_index; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the client restore service.*/ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed Time elapsed in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERRPR Invalid pointer input */ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_restore_record Actual restore record service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT status; + + + if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Note: zero time elapsed is an acceptable value. */ + + status = _nx_dhcp_client_restore_record(dhcp_ptr, client_record_ptr, time_elapsed); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCP Client state of the first DHCP */ +/* enabled interface found with the supplied DHCP Client record */ +/* pointed to by the client_record_ptr pointer. It then updates the */ +/* time out parameters of the DHCP Client with the time_elapsed */ +/* input (in timer ticks). */ +/* */ +/* If DHCP is enabled on multiple interfaces, use */ +/* nx_dhcp_client_interface_restore_record to restore a record to a */ +/* specific interface. */ +/* */ +/* This function is intended for restoring Client state between reboots*/ +/* and assumes the DHCP Client state was previously obtained and stored*/ +/* in non volatile memory before power down. */ +/* */ +/* Note: his should not be called in addition to _nx_dhcp_client_update*/ +/* _time_remaining. _nx_dhcp_client_restore_ calls that function, */ +/* so calling t_nx_dhcp_client_update_time_remaining separately would */ +/* effectively apply the time elapsed a second time. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_restore_record */ +/* Interface specific restore */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT i; +UINT status; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Create a record of the current state of the DHCP Client. */ + status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, + client_record_ptr, time_elapsed); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_interface_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the client restore service.*/ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* iface_index Interface index */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERRPR Invalid pointer input */ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_restore_record */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Check interface index. */ + if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) + { + return NX_INVALID_INTERFACE; + } + + status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, iface_index, client_record_ptr, time_elapsed); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_interface_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCP Client state with the input DHCP */ +/* Client record for the specified interface. It copies data from the */ +/* Client record to the interface racord, and updates the time out */ +/* parameters of the DHCP Client with the time_elapsed inpur (in timer */ +/* ticks). */ +/* */ +/* This function is intended for restoring Client state between reboots*/ +/* and assumes the DHCP Client record was previously obtained and */ +/* stored in non volatile memory before power down. */ +/* */ +/* Note: this should not be called in addition to */ +/* nx_dhcp_client_update_time_remaining. */ +/* nx_dhcp_client_interface_restore_record calls that function, so */ +/* calling nx_dhcp_client_update_time_remaining would apply the time */ +/* elapsed a second time. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_dhcp_interface_record_find Find client record for */ +/* specified interface */ +/* nx_ip_interface_address_set Set IP interface address */ +/* _nx_dhcp_client_update_time_remaining Update time remaining for time*/ +/* elapsed while powered down */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT status; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + interface_record -> nx_dhcp_state = client_record_ptr -> nx_dhcp_state; + interface_record -> nx_dhcp_gateway_address = client_record_ptr -> nx_dhcp_gateway_address; + interface_record -> nx_dhcp_server_ip = client_record_ptr -> nx_dhcp_server_ip; + interface_record -> nx_dhcp_timeout = client_record_ptr -> nx_dhcp_timeout; + interface_record -> nx_dhcp_lease_time = client_record_ptr -> nx_dhcp_lease_time ; + interface_record -> nx_dhcp_renewal_time = client_record_ptr -> nx_dhcp_renewal_time; + interface_record -> nx_dhcp_rebind_time = client_record_ptr -> nx_dhcp_rebind_time; + interface_record -> nx_dhcp_renewal_remain_time = client_record_ptr -> nx_dhcp_renewal_remain_time; + interface_record -> nx_dhcp_rebind_remain_time = client_record_ptr -> nx_dhcp_rebind_remain_time; + + /* Restore directly from the client record. */ + interface_record -> nx_dhcp_ip_address = client_record_ptr -> nx_dhcp_ip_address; + interface_record -> nx_dhcp_network_mask = client_record_ptr -> nx_dhcp_network_mask; + interface_record -> nx_dhcp_interface_index = iface_index; + + /* Update the IP instance with saved network parameters.*/ + status = nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return status; + } + + /* Now apply the time elapsed to update the DHCP Client time remaining on its lease and current DHCP state. */ + status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, interface_record-> nx_dhcp_interface_index, time_elapsed); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_update_time_remaining PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the update time remaining */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_update_time_remaining Update DHCP timeout for time */ +/* elapsed while powered down */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed) +{ + +UINT status; + + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + status = _nx_dhcp_client_update_time_remaining(dhcp_ptr, time_elapsed); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_update_time_remaining PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function applies the input time_elapsed to the DHCP Client */ +/* time remaining and determines if a state change occurred meanwhile. */ +/* Note that time_elapsed is in timer ticks. */ +/* */ +/* There is no need to call this function if also calling */ +/* _nx_dhcp_client_restore_record which applies the elapsed time. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCP_NO_INTERFACES_ENABLED No interface enabled for DHCP */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_update_time_remaining */ +/* Apply the elapsed time to the */ +/* specified DHCP timeout */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_client_restore_record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed) +{ + +UINT i; +UINT status; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the DHCP interface record. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Create a record of the current state of the DHCP CLient. */ + status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, time_elapsed); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(NX_DHCP_NO_INTERFACES_ENABLED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_client_interface_update_time_remaining PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the update time remaining */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_interface_update_time_remaining */ +/* Actual update time service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Check interface index. */ + if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) + { + return NX_INVALID_INTERFACE; + } + + status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, iface_index, time_elapsed); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_client_interface_update_time_remaining PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function applies the input time_elapsed data to the DHCP Client*/ +/* state and determines what state it should be in (e.g. BOUND, */ +/* IP address. Note, time_elapsed is in timer ticks. If called from the*/ +/* application it is assumed the application device is sleeping, not */ +/* powering up. If the device is waking up from sleeping, it does not */ +/* need to restore the DHCP client state but only to update the time */ +/* elapsed. */ +/* */ +/* Therefore this should not be called in addition to */ +/* _nx_dhcp_client_restore_record. The restore record service handles */ +/* updating time remaining, such that calling this service would */ +/* effectively apply the time elapsed a second time. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_dhcp_update_renewal_timeout Update time remaining on lease*/ +/* _nx_dhcp_interface_record_find Find record for the interface */ +/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */ +/* parameters */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed) +{ + +UINT status; +UINT accrued_time_adjusted = 0; +UINT time_accrued; +UINT original_state; +NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; + + + /* Obtain DHCP Client protection mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Find the interface record. */ + status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Get the original state. */ + original_state = interface_record -> nx_dhcp_state; + + /* Compute the time since the lease was assigned before we suspended the Client. */ + if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_BOUND) + { + if (interface_record -> nx_dhcp_renewal_time >= interface_record -> nx_dhcp_timeout) + { + /* Since the Client is in a BOUND state, we know the timeout is less than T2 + or nx_dhcp_renew_time. */ + time_accrued = interface_record -> nx_dhcp_renewal_time - interface_record -> nx_dhcp_timeout; + } + else + { + /* Invalid DHCP timeout. If it is in the BOUND state, set to the renewal time. */ + time_accrued = interface_record -> nx_dhcp_renewal_time; + } + } + else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) + { + + /* Since the Client is in the RENEWING state, the total time on the lease is the + lease rebind time - the time out in the RENEW state: */ + time_accrued = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_remain_time; + + /* Note if dhcp_ptr -> nx_dhcp_rebind_time < dhcp_ptr -> nx_dhcp_renewal_remain_time, + the CLient either received invalid DHCP parameters or there is an internal error. + The renewal time should never exceed the rebind time. */ + } + else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING) + { + + /* Since the Client is in the REBINDING state, the total time on the lease is the + lease time - the time remaining in the REBIND state: */ + time_accrued = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_remain_time; + + /* Note if dhcp_ptr -> nx_dhcp_lease_time < dhcp_ptr -> nx_dhcp_rebind_remain_time, + the CLient either received invalid DHCP parameters or there is an internal error. + The rebind time should never exceed the lease time. */ + } + else + { + /* Expired! */ + accrued_time_adjusted = 0xFFFFFFFF; + } + + /* Adjust the time accrued to include the interval while the Client was suspended. */ + if (accrued_time_adjusted != 0xFFFFFFFF) + { + accrued_time_adjusted = time_accrued + time_elapsed; + } + + /* Determine if the DHCP Client needs to renew. */ + if (accrued_time_adjusted < interface_record -> nx_dhcp_renewal_time) + { + + /* Not yet. Update the nx_dhcp_timeout for the time elapsed and we're done. */ + interface_record -> nx_dhcp_timeout -= time_elapsed; + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* We are done. Ok to resume the Client. */ + return NX_SUCCESS; + } + + /* Determine if the Client should renew. */ + else if (accrued_time_adjusted < interface_record -> nx_dhcp_rebind_time) + { + + /* Yes; it has not reached the expiration on the renew period. */ + + /* Check if it is already in the RENEW state. */ + if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) + { + + /* Yes it is, so do nothing. Let the Client continue renewing. */ + + /* Update the time remaining for the Client to renew its lease. */ + interface_record -> nx_dhcp_renewal_remain_time -= time_elapsed; + + /* Reset the timeout based on the updated time remaining to renew. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + } + else + { + + /* No it wasn't so update the Client for the RENEW state. */ + + /* Compute how many seconds into the renew period the Client is (total time on lease over and above + the time to start renewing. */ + if (accrued_time_adjusted == interface_record -> nx_dhcp_renewal_time) + { + + interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; + } + else + { + + interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - accrued_time_adjusted; + } + + /* Set the DHCP timeout for being in the RENEW phase. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + + /* And change to the Renewing state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* We are done. Ok to resume the Client. */ + return NX_SUCCESS; + } + + /* Determine if it is time for the Client to rebind (e.g. check the lease has not completely expired). */ + else if (accrued_time_adjusted < interface_record -> nx_dhcp_lease_time) + { + + /* Check if it is already in the REBIND state. */ + if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING) + { + /* Yes it is, so do nothing. Let the Client complete its rebind task*/ + + /* Update the time remaining for the Client to rebind an IP address. */ + interface_record -> nx_dhcp_rebind_remain_time -= time_elapsed; + + /* Reset the timeout based on the updated time remaining to rebind. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + } + else + { + + /* No it wasn't so update the Client for the REBIND state. */ + + /* Compute how many seconds into the rebind period the Client is (total time on lease over and above + the time to start rebinding. */ + if (accrued_time_adjusted == interface_record -> nx_dhcp_rebind_time) + { + + interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time; + } + else + { + + interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - accrued_time_adjusted; + } + + /* Set the DHCP timeout for being in the RENEW phase. */ + interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + + /* Record the retransmission interval. */ + interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; + + /* And change to the Rebinding state. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING; + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* We are done. Ok to resume the Client. */ + return NX_SUCCESS; + } + else + { + + /* Clear the existing DHCP Client network parameters for restarting in the INIT state. */ + _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); + + /* Start the DHCP protocol again by setting the state back to INIT. */ + interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; + + /* The client begins in INIT state and forms a DHCPDISCOVER message. + The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. + RFC2131, Section4.4.1, Page36. */ + + /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ + interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; + interface_record -> nx_dhcp_rtr_interval = 0; + } + + /* Check if the state is changed. */ + if (original_state != interface_record -> nx_dhcp_state) + { + + /* Determine if the application has specified a routine for DHCP state change notification. */ + if (dhcp_ptr -> nx_dhcp_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); + } + + /* Determine if the application has specified a routine for DHCP interface state change notification. */ + if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) + { + + /* Yes, call the application's state change notify function with the new state. */ + (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the Client resume service.*/ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_resume Actual Client resume service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_resume(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + status = _nx_dhcp_resume(dhcp_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes the DHCP Client thread and timer. It then */ +/* checks the state on all DHCP enabled interfaces if renewing or */ +/* rebinding. If so it sends a REQUEST to the DHCP server. */ +/* */ +/* The DHCP Client application can then call the */ +/* nx_dhcp_client_udpate_remaining_time() service to update the time */ +/* remaining on the client lease, before calling nx_dhcp_resume. */ +/* */ +/* This function does not change the Client state, lease timeout or */ +/* time remaining on the current lease. It requires the */ +/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* NX_DHCP_ALREADY_STARTED DHCP Client thread started */ +/* status NetX or ThreadX completion */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_send_request_internal Send message to DHCP server */ +/* nx_udp_socket_bind Bind UDP socket to port */ +/* tx_thread_resume Resume the DHCP Client thread */ +/* tx_mutex_get Obtain mutex protection */ +/* tx_mutex_put Release mutex protectiob */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_resume(NX_DHCP *dhcp_ptr) +{ + +UINT i; +UINT status; +NX_IP *ip_ptr; +ULONG client_physical_msw; +ULONG client_physical_lsw; +UINT iface_index; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Resume the DHCP processing thread. */ + status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Determine if the resume was successful. */ + if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED)) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Active the timer. */ + status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Bind the UDP socket to the DHCP Client port. */ + status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + return(status); + } + + /* Set IP pointer. */ + ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; + + /* Loop to process interface records. */ + for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) + { + + /* Check which interface record is valid. */ + if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) + { + + /* Get the interface index. */ + iface_index = dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index; + + /* Get the client MAC address from the device interface. */ + client_physical_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; + client_physical_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; + + /* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */ + dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_xid = client_physical_msw ^ client_physical_lsw ^ NX_RAND(); + + /* If the DHCP Client is renewing or rebinding on being resumed, send a DHCP request. */ + if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_RENEWING) || + (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_REBINDING)) + { + + /* Transmit the request message. */ + _nx_dhcp_send_request_internal(dhcp_ptr, &dhcp_ptr -> nx_dhcp_interface_record[i], NX_DHCP_TYPE_DHCPREQUEST); + } + } + } + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the Client suspend */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_suspend Actual Client suspend service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_suspend(NX_DHCP *dhcp_ptr) +{ + +UINT status; + + + if (dhcp_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + status = _nx_dhcp_suspend(dhcp_ptr); + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends the DHCP Client task thread and unbinds the */ +/* socket port. The intented use of this service is to combine with the*/ +/* resume service such that the calling application can 'pause' the */ +/* DHCP Client for a certain amount of time, and resume it in the same */ +/* state. The DHCP Client application can then call the */ +/* nx_dhcp_client_udpate_remaining_time service to update the time */ +/* remaining on the client lease, then nx_dhcp_resume to actually */ +/* resume the DHCP Client task. */ +/* */ +/* This function does not change the Client state, lease timeout or */ +/* time remaining on the current lease. It requires the */ +/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind port from UDP socket */ +/* tx_timer_deactivate Stop the timer */ +/* tx_thread_suspend Suspend the DHCP Client thread*/ +/* tx_mutex_get Obtain mutex protection */ +/* tx_mutex_put Release mutex protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_suspend(NX_DHCP *dhcp_ptr) +{ + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Suspend the DHCP thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); + + /* Deactive the timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); + + /* Unbind the port. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ +#endif /* NX_DISABLE_IPV4 */ diff --git a/addons/dhcp/nxd_dhcp_client.h b/addons/dhcp/nxd_dhcp_client.h new file mode 100644 index 00000000..0ebf5887 --- /dev/null +++ b/addons/dhcp/nxd_dhcp_client.h @@ -0,0 +1,750 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol (DHCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_dhcp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Dynamic Host Configuration Protocol */ +/* (DHCP) component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_DHCP_CLIENT_H +#define NXD_DHCP_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_ip.h" + + +/* Enable BOOTP protocol instead of DHCP, define this option. +#define NX_DHCP_ENABLE_BOOTP +*/ + +/* Enable support for client state preserved between reboots +#define NX_DHCP_CLIENT_RESTORE_STATE +*/ + +/* Enable the DHCP Client to accept a pointer to the DHCP packet pool. +#define NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL +*/ + +/* Enables an ARP probe for verifying the assigned DHCP address is + not owned by another host. This is recommended, but not required by RFC 2131 (4.4.1). +#define NX_DHCP_CLIENT_SEND_ARP_PROBE +*/ + +/* Enables DHCP Client send Maximum DHCP Message Size Option. RFC2132, Section9.10, Page29. +#define NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION +*/ + +/* Defined, the host name is checked, the host name must follow the rules for ARPANET host names. + RFC 1035, Section 2.3.1, Page 8. The default is disabled. +#define NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK +*/ + +/* Define the DHCP ID that is used to mark the DHCP structure as created. */ +#define NX_DHCP_ID 0x44484350UL + + +/* Define the DHCP stack size. */ +#ifndef NX_DHCP_THREAD_STACK_SIZE +#define NX_DHCP_THREAD_STACK_SIZE (4096) +#endif + + +/* Define the number of interfaces the Client is running on. This can be any + size but practically speaking should be less than or equal to the number + of physical interfaces attached to the IP instance (NX_MAX_PHYSICAL_INTERFACES). */ +/* Note: User can redefine the symbol to reduce the size of records if the dhcp interfaces + are less than true physical interfaces. + For example: There are three physical interfaces, but only two interfaces enable DHCP, + the recommended value for NX_DHCP_CLIENT_MAX_RECORDS should be 2. */ +#ifndef NX_DHCP_CLIENT_MAX_RECORDS +#define NX_DHCP_CLIENT_MAX_RECORDS (NX_MAX_PHYSICAL_INTERFACES) +#endif + + +/* Define the DHCP stack priority. This priority must be high enough to insure the + DHCP client gets scheduled promptly, and thus assigned an IP address. Assigning + it a higher priority increases the risk of 'starving' out the IP thread task which + needs to initialize the network driver (which is required to be able to transmit packets). */ +#ifndef NX_DHCP_THREAD_PRIORITY +#define NX_DHCP_THREAD_PRIORITY 3 +#endif + + +/* Define DHCP timer expiration interval. */ +#ifndef NX_DHCP_TIME_INTERVAL +#define NX_DHCP_TIME_INTERVAL (1 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define the size of DHCP options buffer. */ +/* A DHCP client must be prepared to receive DHCP messages with an 'options' field of + at least length 312 octets. RFC 2131; Section 2. Protocol Summary. */ +#ifndef NX_DHCP_OPTIONS_BUFFER_SIZE +#define NX_DHCP_OPTIONS_BUFFER_SIZE 312 +#endif + + +/* Define the size of the BOOT buffer. This should be large enough for all the + required DHCP header fields plus the minimum requirement of 312 bytes of option data + (total: 548 bytes) as per RFC 2131; Section 2. Protocol Summary. */ +#define NX_BOOT_CLIENT_BUFFER_SIZE 548 + + +/* Define the minimum IP datafram size as per RFC 2131; Section 2. Protocol Summary. + A DHCP Client must be prepared to receive a message of up to 576 bytes: + IP header(20 bytes), UDP header (8 bytes), required DHCP header fields (236 bytes) + and the minimum requirement of option data(312 bytes). */ +#define NX_DHCP_MINIMUM_IP_DATAGRAM 576 + + +/* Define the packet payload size, keeping in mind the DHCP Client must be prepared to + receive a message of up to 576 octets and allow room for physical network header, + as per RFC 2131; Section 2. Protocol Summary. */ +#ifndef NX_DHCP_PACKET_PAYLOAD +#define NX_DHCP_PACKET_PAYLOAD (NX_DHCP_MINIMUM_IP_DATAGRAM + NX_PHYSICAL_HEADER) +#endif /* NX_DHCP_PACKET_PAYLOAD */ + + +/* Define the packet pool size. */ +#ifndef NX_DHCP_PACKET_POOL_SIZE +#define NX_DHCP_PACKET_POOL_SIZE (5 * NX_DHCP_PACKET_PAYLOAD) +#endif + + +/* Define time out options for retransmission in seconds. */ +/* Define the minimum amount of time to retransmit a DHCP IP address request. The + recommended wait time is 4 seconds in RFC 2131. */ +#ifndef NX_DHCP_MIN_RETRANS_TIMEOUT +#define NX_DHCP_MIN_RETRANS_TIMEOUT (4 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define the maximum amount of time to retransmit a DHCP IP address request. The + recommended wait time is 64 seconds in RFC 2131. */ +#ifndef NX_DHCP_MAX_RETRANS_TIMEOUT +#define NX_DHCP_MAX_RETRANS_TIMEOUT (64 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define the minimum amount of time to retransmit a DHCP renew/rebind request. The + recommended wait time is 60 seconds in RFC 2131. */ +#ifndef NX_DHCP_MIN_RENEW_TIMEOUT +#define NX_DHCP_MIN_RENEW_TIMEOUT (60 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define UDP socket create options. */ +#ifndef NX_DHCP_TYPE_OF_SERVICE +#define NX_DHCP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_DHCP_FRAGMENT_OPTION +#define NX_DHCP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_DHCP_TIME_TO_LIVE +#define NX_DHCP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_DHCP_QUEUE_DEPTH +#define NX_DHCP_QUEUE_DEPTH 4 +#endif + + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + +/* Define the timing and retry constants for ARP probe. RFC5227, Section1.1, Page 5. */ +#ifndef NX_DHCP_ARP_PROBE_WAIT +#define NX_DHCP_ARP_PROBE_WAIT (1 * NX_IP_PERIODIC_RATE) +#endif + +/* Define the number of ARP probes sent. */ +#ifndef NX_DHCP_ARP_PROBE_NUM +#define NX_DHCP_ARP_PROBE_NUM 3 +#endif + +/* Define the minimum and maximum variation in the interval between ARP probe transmissions. */ +#ifndef NX_DHCP_ARP_PROBE_MIN +#define NX_DHCP_ARP_PROBE_MIN (1 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_DHCP_ARP_PROBE_MAX +#define NX_DHCP_ARP_PROBE_MAX (2 * NX_IP_PERIODIC_RATE) +#endif +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + +/* Define the wait time before restarting the configuration process when DHCP detects that the address is + already in use. + + The client SHOULD wait a minimum of ten seconds before restarting the configuration process + to avoid excessive network traffic in case of looping. RFC2131, Section 3.1, Page 17. */ +#ifndef NX_DHCP_RESTART_WAIT +#define NX_DHCP_RESTART_WAIT (10 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define the BootP Message Area Offsets. The DHCP message format is identical to that of BootP, except + for the Vendor options that start at the offset specified by NX_BOOTP_OFFSET_OPTIONS. */ +#define NX_BOOTP_OFFSET_OP 0 /* 1 BootP Operation 1=req, 2=reply */ +#define NX_BOOTP_OFFSET_HTYPE 1 /* 1 Hardware type 1 = Ethernet */ +#define NX_BOOTP_OFFSET_HLEN 2 /* 1 Hardware address length, 6 for Ethernet */ +#define NX_BOOTP_OFFSET_HOPS 3 /* 1 Number of hops, usually 0 */ +#define NX_BOOTP_OFFSET_XID 4 /* 4 Transaction ID, pseudo random number */ +#define NX_BOOTP_OFFSET_SECS 8 /* 2 Seconds since boot */ +#define NX_BOOTP_OFFSET_FLAGS 10 /* 2 Flags, 0x80 = Broadcast response, 0 = unicast response */ +#define NX_BOOTP_OFFSET_CLIENT_IP 12 /* 4 Initial client IP, used as dest for unicast response */ +#define NX_BOOTP_OFFSET_YOUR_IP 16 /* 4 Assigned IP, initialized to 0.0.0.0 */ +#define NX_BOOTP_OFFSET_SERVER_IP 20 /* 4 Server IP, usually initialized to 0.0.0.0 */ +#define NX_BOOTP_OFFSET_GATEWAY_IP 24 /* 4 gateway IP, usually 0.0.0.0, only for BootP and TFTP */ +#define NX_BOOTP_OFFSET_CLIENT_HW 28 /* 16 Client hardware address */ +#define NX_BOOTP_OFFSET_SERVER_NM 44 /* 64 Server name, nulls if unused */ +#define NX_BOOTP_OFFSET_BOOT_FILE 108 /* 128 Boot file name, null if unused */ +#define NX_BOOTP_OFFSET_VENDOR 236 /* 64 Vendor options, set first 4 bytes to a magic number */ +#define NX_BOOTP_OFFSET_OPTIONS 240 /* First variable vendor option */ +#define NX_BOOTP_OFFSET_END 300 /* End of BOOTP buffer */ + + +/* Define the DHCP Specific Vendor Extensions. */ +#define NX_DHCP_OPTION_PAD 0 +#define NX_DHCP_OPTION_PAD_SIZE 0 +#define NX_DHCP_OPTION_SUBNET_MASK 1 +#define NX_DHCP_OPTION_SUBNET_MASK_SIZE 4 +#define NX_DHCP_OPTION_TIME_OFFSET 2 +#define NX_DHCP_OPTION_TIME_OFFSET_SIZE 4 +#define NX_DHCP_OPTION_GATEWAYS 3 +#define NX_DHCP_OPTION_TIMESVR 4 +#define NX_DHCP_OPTION_DNS_SVR 6 +#define NX_DHCP_OPTION_HOST_NAME 12 +#define NX_DHCP_OPTION_DNS_NAME 15 +#define NX_DHCP_OPTION_NTP_SVR 42 +#define NX_DHCP_OPTION_VENDOR_OPTIONS 43 +#define NX_DHCP_OPTION_DHCP_IP_REQ 50 +#define NX_DHCP_OPTION_DHCP_IP_REQ_SIZE 4 +#define NX_DHCP_OPTION_DHCP_LEASE 51 +#define NX_DHCP_OPTION_DHCP_LEASE_SIZE 4 +#define NX_DHCP_OPTION_DHCP_TYPE 53 +#define NX_DHCP_OPTION_DHCP_TYPE_SIZE 1 +#define NX_DHCP_OPTION_DHCP_SERVER 54 +#define NX_DHCP_OPTION_DHCP_SERVER_SIZE 4 +#define NX_DHCP_OPTION_DHCP_PARAMETERS 55 +#define NX_DHCP_OPTION_DHCP_MESSAGE 56 +#define NX_DHCP_OPTION_MAX_DHCP_MESSAGE 57 +#define NX_DHCP_OPTION_RENEWAL 58 +#define NX_DHCP_OPTION_RENEWAL_SIZE 4 +#define NX_DHCP_OPTION_REBIND 59 +#define NX_DHCP_OPTION_REBIND_SIZE 4 +#define NX_DHCP_OPTION_CLIENT_ID 61 +#define NX_DHCP_OPTION_CLIENT_ID_SIZE 7 /* 1 byte for address type (01 = Ethernet), 6 bytes for address */ +#define NX_DHCP_OPTION_FDQN 81 +#define NX_DHCP_OPTION_FDQN_FLAG_N 8 +#define NX_DHCP_OPTION_FDQN_FLAG_E 4 +#define NX_DHCP_OPTION_FDQN_FLAG_O 2 +#define NX_DHCP_OPTION_FDQN_FLAG_S 1 +#define NX_DHCP_OPTION_END 255 +#define NX_DHCP_OPTION_END_SIZE 0 + + +/* Define various BootP/DHCP constants. */ +#define NX_DHCP_SERVER_UDP_PORT 67 +#define NX_DHCP_SERVER_TCP_PORT 67 +#define NX_DHCP_CLIENT_UDP_PORT 68 +#define NX_DHCP_CLIENT_TCP_PORT 68 + +#define NX_BOOTP_OP_REQUEST 1 +#define NX_BOOTP_OP_REPLY 2 +#define NX_BOOTP_TYPE_ETHERNET 1 +#define NX_BOOTP_HLEN_ETHERNET 6 +#define NX_BOOTP_FLAGS_BROADCAST 0x80 +#define NX_BOOTP_FLAGS_UNICAST 0x00 +#define NX_BOOTP_MAGIC_COOKIE IP_ADDRESS(99, 130, 83, 99) +#define NX_BOOTP_NO_ADDRESS IP_ADDRESS(0, 0, 0, 0) +#define NX_BOOTP_BC_ADDRESS IP_ADDRESS(255, 255, 255, 255) +#define NX_AUTO_IP_ADDRESS IP_ADDRESS(169, 254, 0, 0) +#define NX_AUTO_IP_ADDRESS_MASK 0xFFFF0000UL + +#define NX_DHCP_INFINITE_LEASE 0xffffffffUL + + +/* Define the DHCP Message Types. */ +#define NX_DHCP_TYPE_DHCPDISCOVER 1 +#define NX_DHCP_TYPE_DHCPOFFER 2 +#define NX_DHCP_TYPE_DHCPREQUEST 3 +#define NX_DHCP_TYPE_DHCPDECLINE 4 +#define NX_DHCP_TYPE_DHCPACK 5 +#define NX_DHCP_TYPE_DHCPNACK 6 +#define NX_DHCP_TYPE_DHCPRELEASE 7 +#define NX_DHCP_TYPE_DHCPINFORM 8 +#define NX_DHCP_TYPE_DHCPFORCERENEW 9 +#ifdef NX_DHCP_ENABLE_BOOTP +#define NX_DHCP_TYPE_BOOT_REQUEST 10 +#endif + + +/* Define the states of the DHCP state machine. */ +#define NX_DHCP_STATE_NOT_STARTED 0 /* Not started */ +#define NX_DHCP_STATE_BOOT 1 /* Started with a previous address */ +#define NX_DHCP_STATE_INIT 2 /* Started with no previous address */ +#define NX_DHCP_STATE_SELECTING 3 /* Waiting to identify a DHCP server */ +#define NX_DHCP_STATE_REQUESTING 4 /* Address requested, waiting for the Ack */ +#define NX_DHCP_STATE_BOUND 5 /* Address established, no time outs */ +#define NX_DHCP_STATE_RENEWING 6 /* Address established, renewal time out */ +#define NX_DHCP_STATE_REBINDING 7 /* Address established, renewal and rebind time out */ +#define NX_DHCP_STATE_FORCERENEW 8 /* Address established, force renewal */ +#define NX_DHCP_STATE_ADDRESS_PROBING 9 /* Address probing, address conflict detection */ + +/* Define error codes from DHCP API. */ +#define NX_DHCP_ERROR 0x90 /* General DHCP error code */ +#define NX_DHCP_NO_RESPONSE 0x91 /* No response from server for option request */ +#define NX_DHCP_BAD_IP_ADDRESS 0x92 /* Bad IP address or invalid interface input */ +#define NX_DHCP_ALREADY_STARTED 0x93 /* DHCP was already started */ +#define NX_DHCP_NOT_BOUND 0x94 /* DHCP is not in a bound state */ +#define NX_DHCP_DEST_TO_SMALL 0x95 /* DHCP response is too big for destination */ +#define NX_DHCP_NOT_STARTED 0x96 /* DHCP was not started when stop was issued */ +#define NX_DHCP_PARSE_ERROR 0x97 /* Error extracting DHCP option data */ +#define NX_DHCP_BAD_XID 0x98 /* DHCP packet received with mismatched XID */ +#define NX_DHCP_BAD_MAC_ADDRESS 0x99 /* DHCP packet received with mismatched MAC address */ +#define NX_DHCP_INVALID_MESSAGE 0x9B /* Invalid message received or requested to send */ +#define NX_DHCP_INVALID_PAYLOAD 0x9C /* Client receives DHCP message exceeding packet payload */ +#define NX_DHCP_INVALID_IP_REQUEST 0x9D /* Null IP address input for requesting IP address */ +#define NX_DHCP_UNKNOWN_OPTION 0x9F /* This option is unknow. */ +#define NX_DHCP_INTERFACE_ALREADY_ENABLED 0xA3 /* Interface is already enabled */ +#define NX_DHCP_INTERFACE_NOT_ENABLED 0xA4 /* If interface not enabled for DHCP interaction */ +#define NX_DHCP_NO_INTERFACES_ENABLED 0xA5 /* No interfaces enabled for DHCP interaction */ +#define NX_DHCP_NO_INTERFACES_STARTED 0xA6 /* If DHCP CLient fails to start any interfacers */ +#define NX_DHCP_NO_RECORDS_AVAILABLE 0xA7 /* No Client record available to start DHCP on an interface */ +#define NX_DHCP_INVALID_NAME 0xA8 /* Client host name has invalid characters */ + + +/* Define DHCP Client thread events. */ +#define NX_DHCP_CLIENT_RECEIVE_EVENT 0x00000001 /* DHCP Server data received */ +#define NX_DHCP_CLIENT_TIMER_EVENT 0x00000002 /* DHCP timer expires */ +#define NX_DHCP_CLIENT_CONFLICT_EVENT 0x00000004 /* IP conflict event detected */ +#define NX_DHCP_CLIENT_ALL_EVENTS 0xFFFFFFFF /* All DHCP events */ + + +#ifdef NX_DHCP_CLIENT_RESTORE_STATE + +/* Define a Client record for restore DHCP Client state from non volatile memory/across reboots. */ +typedef struct NX_DHCP_CLIENT_RECORD_STRUCT +{ + UCHAR nx_dhcp_state; /* The current state of the DHCP Client */ + ULONG nx_dhcp_ip_address; /* Server assigned IP Address */ + ULONG nx_dhcp_network_mask; /* Server assigned network mask */ + ULONG nx_dhcp_gateway_address; /* Server assigned gateway address */ + UINT nx_dhcp_interface_index; /* Index of DHCP Client network interface */ + ULONG nx_dhcp_timeout; /* The current value of any timeout, in seconds */ + ULONG nx_dhcp_server_ip; /* The server IP Address */ + ULONG nx_dhcp_lease_remain_time; /* Time remaining before lease expires */ + ULONG nx_dhcp_lease_time; /* The current Lease Time in seconds */ + ULONG nx_dhcp_renewal_time; /* Renewal Time in seconds */ + ULONG nx_dhcp_rebind_time; /* Rebind Time in seconds */ + ULONG nx_dhcp_renewal_remain_time;/* Time remaining to renew (before rebinding necessary) */ + ULONG nx_dhcp_rebind_remain_time; /* Time remaining to rebind (before lease expires) */ +} NX_DHCP_CLIENT_RECORD; +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ + +/* Define the DHCP interface record that contains all the information necessary for a DHCP + instance on each interface. */ +typedef struct NX_DHCP_INTERFACE_RECORD_STRUCT +{ + UCHAR nx_dhcp_record_valid; /* The flag indicate this record is valid. NX_TRUE: valid */ + UCHAR nx_dhcp_state; /* The current state of the DHCP Client */ + UCHAR nx_dhcp_user_option; /* User option request */ + UCHAR reserved; + ULONG nx_dhcp_xid; /* Unique transaction ID */ + ULONG nx_dhcp_seconds; /* Track number of seconds for a DHCP request process */ + ULONG nx_dhcp_ip_address; /* Server assigned IP Address */ + ULONG nx_dhcp_gateway_address; /* Server assigned gateway address */ + ULONG nx_dhcp_server_ip; /* The server IP Address */ + ULONG nx_dhcp_network_mask; /* Server assigned network mask */ + UINT nx_dhcp_interface_index; /* Index of DHCP Client network interface */ + ULONG nx_dhcp_timeout; /* Count down timer for sending out DHCP message */ + ULONG nx_dhcp_rtr_interval; /* Interval between sending out another DHCP message */ + ULONG nx_dhcp_lease_remain_time; /* Time remaining before lease expires */ + ULONG nx_dhcp_lease_time; /* The current Lease Time in seconds */ + ULONG nx_dhcp_renewal_time; /* Renewal Time in seconds */ + ULONG nx_dhcp_rebind_time; /* Rebind Time in seconds */ + ULONG nx_dhcp_renewal_remain_time;/* Time remaining to renew (before rebinding necessary) */ + ULONG nx_dhcp_rebind_remain_time; /* Time remaining to rebind (before lease expires) */ +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + UINT nx_dhcp_probe_count; /* Number of ARP probes to send to prove IP address unique */ +#endif + UINT nx_dhcp_clear_broadcast; /* Client sends messages with unicast reply requested */ + UINT nx_dhcp_skip_discovery; /* Indicate if host should skip the discovery message */ + UCHAR nx_dhcp_options_buffer[NX_DHCP_OPTIONS_BUFFER_SIZE]; + UINT nx_dhcp_options_size; /* The total size of DHCP options. */ + + ULONG nx_dhcp_internal_errors; /* The number of internal DHCP errors encountered */ + ULONG nx_dhcp_discoveries_sent; /* The number of Discovery sent by the Client */ + ULONG nx_dhcp_offers_received; /* The number of Offers received by the Client */ + ULONG nx_dhcp_requests_sent; /* The number of Request attempts made by the Client */ + ULONG nx_dhcp_acks_received; /* The number of ACKs received by the Client */ + ULONG nx_dhcp_nacks_received; /* The number of NACKs received by the Client */ + ULONG nx_dhcp_releases_sent; /* The number of Releases sent by the Client */ + ULONG nx_dhcp_declines_sent; /* The number of Declines sent by the Client */ + ULONG nx_dhcp_force_renewal_rec; /* The number of Forced Renewal received by the Client */ + ULONG nx_dhcp_informs_sent; /* The number of Inform (option requests) sent by the Client*/ + ULONG nx_dhcp_inform_responses; /* The number of Inform responses */ + +} NX_DHCP_INTERFACE_RECORD; + + +/* Define the DHCP structure that contains all information common to all interfaces on + which DHCP Client may run. */ +typedef struct NX_DHCP_STRUCT +{ + + ULONG nx_dhcp_id; /* DHCP Structure ID */ + CHAR *nx_dhcp_name; /* DHCP name supplied at create */ + NX_IP *nx_dhcp_ip_ptr; /* The associated IP pointer for this DHCP instance */ +#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL + NX_PACKET_POOL nx_dhcp_pool; /* The pool of UDP data packets for DHCP messages */ + UCHAR nx_dhcp_pool_area[NX_DHCP_PACKET_POOL_SIZE]; +#endif + NX_PACKET_POOL *nx_dhcp_packet_pool_ptr; /* Pointer to DHCP Client packet pool */ + NX_UDP_SOCKET nx_dhcp_socket; /* The Socket used for DHCP messages */ + TX_THREAD nx_dhcp_thread; /* The DHCP processing thread */ + UCHAR nx_dhcp_thread_stack[NX_DHCP_THREAD_STACK_SIZE]; + TX_MUTEX nx_dhcp_mutex; /* The DHCP mutex for protecting access */ + TX_EVENT_FLAGS_GROUP + nx_dhcp_events; /* DHCP Client thread events */ + TX_TIMER nx_dhcp_timer; /* DHCP Client timeout timer */ + NX_DHCP_INTERFACE_RECORD + nx_dhcp_interface_record[NX_DHCP_CLIENT_MAX_RECORDS]; + /* Record of DHCP Client state on specific interface */ + +#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION + ULONG nx_dhcp_max_dhcp_message_size; + /* Maximum length DHCP message DHCP Client will accept */ +#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ + +#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE + UINT nx_dhcp_interface_conflict_flag; /* The flag indicate IP addresses conflict on which interfaces, one bit represent one interface. + For examples: + 0x00000001: interface index 0; + 0x00000002: interface index 1; + 0x00000003: interface index 0 and 1; */ +#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ + + /* Define the callback function for DHCP state change notification. If specified + by the application, this function is called whenever a state change occurs for + the DHCP associated with this IP instance. */ + VOID (*nx_dhcp_state_change_callback)(struct NX_DHCP_STRUCT *dhcp_ptr, UCHAR new_state); + + /* Define the callback function for DHCP interface state change notification. + this function is similar as nx_dhcp_state_change_callback, + + Note: Suggest using state change notification, and use nx_dhcp_interface_state_change_callback + if DHCP is running on multiple interfaces. */ + VOID (*nx_dhcp_interface_state_change_callback)(struct NX_DHCP_STRUCT *dhcp_ptr, UINT iface_index, UCHAR new_state); + + /* Define the callback function for adding specific DHCP user option. */ + UINT (*nx_dhcp_user_option_add)(struct NX_DHCP_STRUCT *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length); + + /* This pointer is reserved for application specific use. */ + void *nx_dhcp_reserved_ptr; + +} NX_DHCP; + + +#ifndef NX_DHCP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map DHCP API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_dhcp_create _nx_dhcp_create +#define nx_dhcp_packet_pool_set _nx_dhcp_packet_pool_set +#define nx_dhcp_request_client_ip _nx_dhcp_request_client_ip +#define nx_dhcp_delete _nx_dhcp_delete +#define nx_dhcp_decline _nx_dhcp_decline +#define nx_dhcp_force_renew _nx_dhcp_force_renew +#define nx_dhcp_release _nx_dhcp_release +#define nx_dhcp_start _nx_dhcp_start +#define nx_dhcp_stop _nx_dhcp_stop +#define nx_dhcp_server_address_get _nx_dhcp_server_address_get +#define nx_dhcp_state_change_notify _nx_dhcp_state_change_notify +#define nx_dhcp_user_option_retrieve _nx_dhcp_user_option_retrieve +#define nx_dhcp_user_option_convert _nx_dhcp_user_option_convert +#define nx_dhcp_user_option_add_callback_set _nx_dhcp_user_option_add_callback_set +#define nx_dhcp_reinitialize _nx_dhcp_reinitialize +#define nx_dhcp_send_request _nx_dhcp_send_request +#define nx_dhcp_set_interface_index _nx_dhcp_set_interface_index +#define nx_dhcp_clear_broadcast_flag _nx_dhcp_clear_broadcast_flag +#define nx_dhcp_interface_clear_broadcast_flag _nx_dhcp_interface_clear_broadcast_flag +#define nx_dhcp_interface_enable _nx_dhcp_interface_enable +#define nx_dhcp_interface_disable _nx_dhcp_interface_disable +#define nx_dhcp_interface_decline _nx_dhcp_interface_decline +#define nx_dhcp_interface_force_renew _nx_dhcp_interface_force_renew +#define nx_dhcp_interface_reinitialize _nx_dhcp_interface_reinitialize +#define nx_dhcp_interface_release _nx_dhcp_interface_release +#define nx_dhcp_interface_request_client_ip _nx_dhcp_interface_request_client_ip +#define nx_dhcp_interface_start _nx_dhcp_interface_start +#define nx_dhcp_interface_stop _nx_dhcp_interface_stop +#define nx_dhcp_interface_send_request _nx_dhcp_interface_send_request +#define nx_dhcp_interface_server_address_get _nx_dhcp_interface_server_address_get +#define nx_dhcp_interface_state_change_notify _nx_dhcp_interface_state_change_notify +#define nx_dhcp_interface_user_option_retrieve _nx_dhcp_interface_user_option_retrieve +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +#define nx_dhcp_resume _nx_dhcp_resume +#define nx_dhcp_suspend _nx_dhcp_suspend +#define nx_dhcp_client_get_record _nx_dhcp_client_get_record +#define nx_dhcp_client_restore_record _nx_dhcp_client_restore_record +#define nx_dhcp_client_update_time_remaining _nx_dhcp_client_update_time_remaining +#define nx_dhcp_client_interface_get_record _nx_dhcp_client_interface_get_record +#define nx_dhcp_client_interface_restore_record _nx_dhcp_client_interface_restore_record +#define nx_dhcp_client_interface_update_time_remaining _nx_dhcp_client_interface_update_time_remaining +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ + +#else + +/* Services with error checking. */ + +#define nx_dhcp_create _nxe_dhcp_create +#define nx_dhcp_packet_pool_set _nxe_dhcp_packet_pool_set +#define nx_dhcp_request_client_ip _nxe_dhcp_request_client_ip +#define nx_dhcp_delete _nxe_dhcp_delete +#define nx_dhcp_decline _nxe_dhcp_decline +#define nx_dhcp_force_renew _nxe_dhcp_force_renew +#define nx_dhcp_release _nxe_dhcp_release +#define nx_dhcp_start _nxe_dhcp_start +#define nx_dhcp_stop _nxe_dhcp_stop +#define nx_dhcp_server_address_get _nxe_dhcp_server_address_get +#define nx_dhcp_state_change_notify _nxe_dhcp_state_change_notify +#define nx_dhcp_user_option_retrieve _nxe_dhcp_user_option_retrieve +#define nx_dhcp_user_option_convert _nxe_dhcp_user_option_convert +#define nx_dhcp_user_option_add_callback_set _nxe_dhcp_user_option_add_callback_set +#define nx_dhcp_reinitialize _nxe_dhcp_reinitialize +#define nx_dhcp_send_request _nxe_dhcp_send_request +#define nx_dhcp_set_interface_index _nxe_dhcp_set_interface_index +#define nx_dhcp_clear_broadcast_flag _nxe_dhcp_clear_broadcast_flag +#define nx_dhcp_interface_clear_broadcast_flag _nxe_dhcp_interface_clear_broadcast_flag +#define nx_dhcp_interface_enable _nxe_dhcp_interface_enable +#define nx_dhcp_interface_disable _nxe_dhcp_interface_disable +#define nx_dhcp_interface_decline _nxe_dhcp_interface_decline +#define nx_dhcp_interface_force_renew _nxe_dhcp_interface_force_renew +#define nx_dhcp_interface_reinitialize _nxe_dhcp_interface_reinitialize +#define nx_dhcp_interface_release _nxe_dhcp_interface_release +#define nx_dhcp_interface_request_client_ip _nxe_dhcp_interface_request_client_ip +#define nx_dhcp_interface_start _nxe_dhcp_interface_start +#define nx_dhcp_interface_stop _nxe_dhcp_interface_stop +#define nx_dhcp_interface_send_request _nxe_dhcp_interface_send_request +#define nx_dhcp_interface_server_address_get _nxe_dhcp_interface_server_address_get +#define nx_dhcp_interface_state_change_notify _nxe_dhcp_interface_state_change_notify +#define nx_dhcp_interface_user_option_retrieve _nxe_dhcp_interface_user_option_retrieve +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +#define nx_dhcp_resume _nxe_dhcp_resume +#define nx_dhcp_suspend _nxe_dhcp_suspend +#define nx_dhcp_client_get_record _nxe_dhcp_client_get_record +#define nx_dhcp_client_restore_record _nxe_dhcp_client_restore_record +#define nx_dhcp_client_update_time_remaining _nxe_dhcp_client_update_time_remaining +#define nx_dhcp_client_interface_get_record _nxe_dhcp_client_interface_get_record +#define nx_dhcp_client_interface_restore_record _nxe_dhcp_client_interface_restore_record +#define nx_dhcp_client_interface_update_time_remaining _nxe_dhcp_client_interface_update_time_remaining +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); +UINT nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); +UINT nx_dhcp_delete(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_decline(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_force_renew(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_release(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_start(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_stop(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); +UINT nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); +UINT nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); +ULONG nx_dhcp_user_option_convert(UCHAR *source_ptr); +UINT nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); +UINT nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); +UINT nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); +UINT nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); +UINT nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); +UINT nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); +UINT nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); +UINT nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); +UINT nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); +UINT nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); + +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +UINT nx_dhcp_resume(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_suspend(NX_DHCP *dhcp_ptr); +UINT nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); +UINT nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ + +#else + +/* DHCP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); +UINT _nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); +UINT _nxe_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT _nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT _nxe_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); +UINT _nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); +UINT _nxe_dhcp_delete(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_delete(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_decline(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_decline(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_force_renew(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_force_renew(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_release(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_release(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_start(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_start(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_stop(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_stop(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); +UINT _nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); +UINT _nxe_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); +UINT _nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); +UINT _nxe_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); +UINT _nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); +ULONG _nxe_dhcp_user_option_convert(UCHAR *source_ptr); +ULONG _nx_dhcp_user_option_convert(UCHAR *source_ptr); +UINT _nxe_dhcp_reinitialize(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); +UINT _nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); +UINT _nxe_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); +UINT _nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); +UINT _nxe_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); +UINT _nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); +UINT _nxe_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); +UINT _nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); +UINT _nxe_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); +UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); +UINT _nxe_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); +UINT _nxe_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); +UINT _nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); +UINT _nxe_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); +UINT _nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); +UINT _nxe_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); +UINT _nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); +UINT _nxe_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); +UINT _nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); +UINT _nxe_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); +UINT _nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); + +#ifdef NX_DHCP_CLIENT_RESTORE_STATE +UINT _nxe_dhcp_resume(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_resume(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_suspend(NX_DHCP *dhcp_ptr); +UINT _nx_dhcp_suspend(NX_DHCP *dhcp_ptr); +UINT _nxe_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT _nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT _nxe_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT _nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT _nxe_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); +UINT _nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); +UINT _nxe_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT _nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); +UINT _nxe_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT _nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); +UINT _nxe_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); +UINT _nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); +#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ + +#endif /* NX_DHCP_SOURCE_CODE */ + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* NXD_DHCP_CLIENT_H */ diff --git a/addons/dhcp/nxd_dhcp_server.c b/addons/dhcp/nxd_dhcp_server.c new file mode 100644 index 00000000..3190f209 --- /dev/null +++ b/addons/dhcp/nxd_dhcp_server.c @@ -0,0 +1,5532 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol (DHCP) Server */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_DHCP_SERVER_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_ip.h" +#include "nx_udp.h" +#include "nxd_dhcp_server.h" +#include "tx_timer.h" +#include "nx_packet.h" +#include "nx_system.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +#ifdef EL_PRINTF_ENABLE +#define EL_PRINTF printf +#endif + +/* Define the DHCP Internal Function. */ +static VOID _nx_dhcp_server_thread_entry(ULONG ip_instance); +static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info); +static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info); +static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr); +static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); +static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, NX_PACKET *packet_ptr, UINT iface_index); +static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_ptr, CHAR *buffer, ULONG value, UINT get_option_data, UINT size); +static UINT _nx_dhcp_add_option(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index); +static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index); +static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_length); +static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index); +static UINT _nx_dhcp_parse_next_option(CHAR **buffer, UINT *digit, UINT length); +static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value); +static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value); +static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); +static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); +static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw, ULONG client_mac_lsw,NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on); +static UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, UINT iface_index, ULONG assigned_ip_address); +static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); +static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address, NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address); +static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, ULONG ip_address, UINT assign_status); +static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client); +static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time); +static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner); +static VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr); + + +/* To enable dhcp server output, define TESTOUTPUT. */ +/* #define TESTOUTPUT 1 */ + +/* To enable packet dump, define PACKET_DUMP. */ +/* #define PACKET_DUMP 1 */ + +#ifdef TESTOUTPUT + +static int add_client = 0; + +/* Define how often to print the server table of current clients. + For no output set to zero. For low volume, set to 1; + for very high volume, set higher so as not to overwelm the processor. */ + +#define TRACE_NTH_CLIENT_PACKET 1 + +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP create function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to free memory */ +/* stack_size Size of DHCP server stack */ +/* name_ptr DHCP name pointer */ +/* packet_pool Server packet pool for sending*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_server_create Actual DHCP create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + CHAR *name_ptr, NX_PACKET_POOL *packet_pool) +{ + +UINT status; + + + /* Check for pointer invalid input. */ + if ((dhcp_ptr == NX_NULL) || (packet_pool == NX_NULL) ||(stack_ptr == NX_NULL) ||(ip_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + if (stack_size == 0) + { + return(NX_DHCP_PARAMETER_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual DHCP create service. */ + status = _nx_dhcp_server_create(dhcp_ptr, ip_ptr, stack_ptr, stack_size, name_ptr, packet_pool); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the DHCP Server with necessary components.*/ +/* It creates a packet pool for sending Server DHCP messages and a */ +/* thread task for the DHCP server operation. It also sets the standard*/ +/* DHCP options (e.g. lease time etc) for granting IP addresses. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to server thread on */ +/* the stack */ +/* stack_size Size of DHCP server stack */ +/* name_ptr DHCP name pointer */ +/* packet_pool Server packet pool for sending*/ +/* DHCP replies to client */ +/* */ +/* OUTPUT */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD */ +/* Packet payload too small error*/ +/* NX_DHCP_NO_SERVER_OPTION_LIST Missing option list error */ +/* */ +/* status Completion status of socket */ +/* and thread create calls */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_create Create the DHCP UDP socket */ +/* nx_udp_socket_delete Delete the DHCP UDP socket */ +/* tx_thread_create Create DHCP processing thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr) +{ + +UINT status; +UINT timer_ticks; +UINT i, j; + + + /* Initialize the DHCP control block to zero. */ + memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP_SERVER)); + + /* Check the Server packet pool is at least large enough for a full sized DHCP message as per + RFC 2131, plus header data. */ + if (packet_pool_ptr -> nx_packet_pool_payload_size < NX_DHCP_MINIMUM_PACKET_PAYLOAD) + { + + /* Return the error status. */ + return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD); + } + + /* Set the packet pool pointer. */ + dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr; + + /* Save the DHCP name. */ + memcpy(&dhcp_ptr -> nx_dhcp_name[0], name_ptr, NX_DHCP_SERVER_HOSTNAME_MAX); + + /* Set the DHCP Server attributes. */ + dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr; + + /* Loop through all the interface tables and clear table memory. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Clear all the table's IP address entries. */ + for (j = 0; j < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE; j++) + { + + memset(&dhcp_ptr -> nx_dhcp_interface_table[i].nx_dhcp_ip_address_list[j], + 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS)); + } + + /* Clear the DHCP interface itself. */ + memset(&dhcp_ptr -> nx_dhcp_interface_table[i], 0, sizeof(NX_DHCP_INTERFACE_TABLE)); + } + + /* Loop through the entire client record table. */ + for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++) + { + + /* Clear the client record. */ + memset(&dhcp_ptr -> client_records[i], 0, sizeof(NX_DHCP_CLIENT)); + } + + /* Verify the application has defined a server option list. */ + if (sizeof(NX_DHCP_SERVER_OPTION_LIST) == 1) + { + + /* No, return the error status. */ + return(NX_DHCP_NO_SERVER_OPTION_LIST); + } + + /* Create the list of DHCP options the server can provide for the client. */ + status = _nx_dhcp_set_server_options(dhcp_ptr, (CHAR *)NX_DHCP_SERVER_OPTION_LIST, sizeof(NX_DHCP_SERVER_OPTION_LIST) - 1); + + /* Was the option list set successful? */ + if (status != NX_SUCCESS) + { + + /* No, return error status. */ + return(status); + } + + /* Update the dhcp structure ID. */ + dhcp_ptr -> nx_dhcp_id = NX_DHCP_SERVER_ID; + + /* Create the Socket and check the status */ + status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Server Socket", + NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH); + + /* Was the socket creation successful? */ + if (status != NX_SUCCESS) + { + + /* No, return error status. */ + return(status); + } + + /* Save the DHCP instance pointer in the socket. */ + dhcp_ptr -> nx_dhcp_socket.nx_udp_socket_reserved_ptr = (void *) dhcp_ptr; + + /* Set the DHCP request handler for packets received on the DHCP server socket. */ + status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_server_socket_receive_notify); + + /* Was the socket receive_notify set successful? */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* No, return error status. */ + return status; + } + + /* Create the DHCP processing thread. */ + status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_server_thread), "NetX DHCP Server Thread", + _nx_dhcp_server_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, + stack_ptr, stack_size, NX_DHCP_SERVER_THREAD_PRIORITY, + NX_DHCP_SERVER_THREAD_PRIORITY, 1, TX_DONT_START); + + NX_THREAD_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_server_thread), dhcp_ptr) + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* No, return error status. */ + return(status); + } + + /* Create the DHCP mutex. */ + status = tx_mutex_create(&dhcp_ptr -> nx_dhcp_mutex, "DHCP Server Mutex", TX_NO_INHERIT); + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Delete DHCP thead. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* No, return error status. */ + return(status); + } + + /* Convert seconds to timer ticks. */ + timer_ticks = NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE; + + /* Create the timer for Client DHCP session. This will keep track of when leases expire + and when a client session has timed out. */ + status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), "DHCP Server IP Lease Timer", + _nx_dhcp_slow_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, + timer_ticks, timer_ticks, TX_NO_ACTIVATE); + + NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), dhcp_ptr) + + /* Convert seconds to timer ticks. */ + timer_ticks = NX_DHCP_FAST_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE; + + /* Create the timer for Client DHCP session. This will keep track of when leases expire + and when a client session has timed out. */ + status += tx_timer_create(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), "DHCP Server Session Timer", + _nx_dhcp_fast_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, + timer_ticks, timer_ticks, TX_NO_ACTIVATE); + + NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), dhcp_ptr) + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Delete DHCP thead. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Delete ThreadX resources. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete DHCP timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); + + /* Return the error status. */ + return(status); + } + + /* Create the DHCP event flag instance. */ + status = tx_event_flags_create(&dhcp_ptr -> nx_dhcp_server_events, "DHCP Server Events"); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Delete DHCP thread. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Delete ThreadX resources. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete DHCP Timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); + + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); + + /* Return the error status. */ + return(status); + } + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_fast_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function watches the session timeout on each active client */ +/* session. WHen it does it clears session data from the client record */ +/* and resets the client state to INIT. If a iP address had been */ +/* assigned, it is returned back to the server pool. */ +/* */ +/* INPUT */ +/* */ +/* info Generic pointer to DHCP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Adds a fast periodic event */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info) +{ + +NX_DHCP_SERVER *dhcp_ptr; + + + /* Setup DHCP pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) + + /* Signal the DHCP Server fast periodic event. */ + tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_FAST_PERIODIC_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_slow_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function watches lease timeout on assigned IP address in the */ +/* server database. When one has expired, the address is returned to */ +/* the available pool and the Client is reset to the INIT state. */ +/* */ +/* INPUT */ +/* */ +/* info Generic pointer to DHCP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Adds a slow periodic event */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX system timer thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info) +{ + +NX_DHCP_SERVER *dhcp_ptr; + + + /* Setup DHCP pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) + + /* Signal the DHCP Server slow periodic event. */ + tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_SLOW_PERIODIC_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is notified by NetX Duo when a packet arrives in the */ +/* server socket. It sets a flag which the DHCP server thread */ +/* detect so it will know to process the incoming packet . */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to Server Socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* tx_event_flags_set Adds a packet receive event */ +/* CALLED BY */ +/* */ +/* Threads */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + +NX_DHCP_SERVER *dhcp_server_ptr; + + + /* Get a pointer to the DHCP server. */ + dhcp_server_ptr = (NX_DHCP_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr; + + /* Signal the DHCP Server it has a UDP packet on its socket receive queue. */ + tx_event_flags_set(&(dhcp_server_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_RECEIVE_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP delete function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_server_delete Actual DHCP delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (dhcp_ptr == NX_NULL) + return(NX_PTR_ERROR); + + if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) + { + return(NX_DHCP_PARAMETER_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP delete service. */ + status = _nx_dhcp_server_delete(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DHCP server and releases all of its */ +/* resources. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Free the UDP socket port */ +/* nx_udp_socket_delete Delete the DHCP UDP socket */ +/* tx_thread_terminate Terminate DHCP thread */ +/* tx_thread_terminate Terminate DHCP thread */ +/* tx_thread_delete Delete DHCP thread */ +/* tx_timer_delete Delete DHCP timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr) +{ + + + /* Determine if DHCP is stopped. */ + if (dhcp_ptr -> nx_dhcp_started != NX_FALSE) + { + + /* Stop the DHCP server. */ + _nx_dhcp_server_stop(dhcp_ptr); + } + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Delete the session ("fast") timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); + + /* Delete the IP lease ("slow") timer. */ + tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); + + /* Suspend the DHCP processing thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Terminate the DHCP processing thread. */ + tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Delete the DHCP processing thread. */ + tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Delete the mutexes. */ + tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Delete the flag event. */ + tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_server_events)); + + /* Clear the dhcp structure ID. */ + dhcp_ptr -> nx_dhcp_id = 0; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_create_server_ip_address_list PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the IP address list create*/ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* iface_index IP interface index to specify the */ +/* DHCP server interface to use */ +/* start_ip_address Starting IP address */ +/* end_ip_address Ending IP address */ +/* addresses_added Pointer to addresses added counter */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_create_server_ip_address_list */ +/* Actual IP address create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, + ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added) +{ + +UINT status; + + + /* Check for invalid input. */ + if ((dhcp_ptr == NX_NULL) || (addresses_added == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if ((start_ip_address > end_ip_address) || + (iface_index >= NX_MAX_PHYSICAL_INTERFACES) || + (start_ip_address == NX_DHCP_NO_ADDRESS)) + { + + return(NX_DHCP_INVALID_IP_ADDRESS); + } + + status = _nx_dhcp_create_server_ip_address_list(dhcp_ptr, iface_index, start_ip_address, end_ip_address, addresses_added); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_create_server_ip_address_list PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a list of available IP addresses for DHCP */ +/* clients on the specified interface. The caller supplies a start and */ +/* end IP address and all addresses in between are flagged as available.*/ +/* The start ip address is assumed to be the first entry in the list, */ +/* not appended to a previously started list. All the IP addresses may */ +/* not fit in the server interface table; the number actually added is */ +/* written to the 'addresses added' variable. The caller should check */ +/* this output. */ +/* */ +/* If some addresses within the specified range need to be reserved or */ +/* statically assigned the host application needs to set their lease to */ +/* infinity (0xffffffff) and assigned status is set. This function also */ +/* add the interface subnet, router, dns server for specified index. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP server */ +/* iface_index Index specifying server interface*/ +/* start_ip_address Beginning IP address in list. */ +/* end_ip_address Ending IP address in list. */ +/* addresses_added Number of addresses added to list*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP list creation */ +/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */ +/* NX_DHCP_INVALID_IP_ADDRESS_LIST Invalid IP list parameter input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_update_assignable_ip_address */ +/* Updates interface table entry */ +/* with IP address status and owner*/ +/* _nx_dhcp_clear_client_session Clears client record of session */ +/* data from most recent client */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, + ULONG start_ip_address, ULONG end_ip_address, + UINT *addresses_added) +{ + +UINT i; +ULONG next_ip_address; +NX_IP *ip_ptr; +NX_DHCP_INTERFACE_IP_ADDRESS *ip_address_entry_ptr; +NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; + + + /* Check for an invalid interface index. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_DHCP_SERVER_BAD_INTERFACE_INDEX; + } + + /* Obtain DHCP Server mutex protection,. */ + tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); + + *addresses_added = 0; + next_ip_address = start_ip_address; + + /* Set local pointer to the list being created for convenience. */ + dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; + + /* Fill in the interface table with DHCP attributes for the specified interface. */ + + /* Set up a local variable for convenience. */ + ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; + + /* Assign the IP interface specified by the IP interface index to the DHCP interface. */ + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_incoming_interface = &(ip_ptr -> nx_ip_interface[iface_index]); + + /* Set the server ip address based on the specified interface. */ + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address; + + /* Set the dns server, subnet mask, and router (default gateway) for this interface. */ + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address; + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask; + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = ip_ptr -> nx_ip_gateway_address; + + + /* Make sure the start/end address subnet match the interface subnet. */ + if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & start_ip_address) != + (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) + { + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); + } + if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & end_ip_address) != + (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) + { + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); + } + + /* Zero out the list size. */ + dhcp_interface_table_ptr -> nx_dhcp_address_list_size = 0; + + /* Check for invalid list parameters. */ + if ((start_ip_address > end_ip_address) || !start_ip_address || !end_ip_address) + { + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_DHCP_INVALID_IP_ADDRESS_LIST); + } + + /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ + i = 0; + + /* Fit as many IP addresses in the specified range as will fit in the table. */ + while (i < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE && next_ip_address <= end_ip_address) + { + + /* Set local pointer to the next entry for convenience. */ + ip_address_entry_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; + + /* Clear existing entry; client identifier and available status + must be initialized to NULL and not assigned respectively. */ + memset(ip_address_entry_ptr, 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS)); + + /* Add the next IP address to the list. */ + ip_address_entry_ptr -> nx_assignable_ip_address = next_ip_address; + + /* Increase the list size. */ + dhcp_interface_table_ptr -> nx_dhcp_address_list_size++; + + next_ip_address++; + i++; + } + + /* Set the actual number of available addresses added to the table. */ + *addresses_added = dhcp_interface_table_ptr -> nx_dhcp_address_list_size; + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_set_interface_network_parameters PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking services for the set interface */ +/* network parameters service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP server */ +/* iface_index Index specifying server interface*/ +/* subnet_mask Network mask for DHCP clients */ +/* default_gateway_address Router/default gateway for client*/ +/* dns_server_address DNS server for DHCP clients */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid interface index input */ +/* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_update_assignable_ip_address */ +/* Updates interface table entry */ +/* with IP address status and owner*/ +/* _nx_dhcp_clear_client_session Clears client record of session */ +/* data from most recent client */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, + ULONG subnet_mask, ULONG default_gateway_address, + ULONG dns_server_address) +{ +UINT status; + + /* Check for invalid pointer input. */ + if (dhcp_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Check for non pointer input. */ + if ((subnet_mask == 0) || (default_gateway_address == 0) || (dns_server_address == 0)) + { + return(NX_DHCP_INVALID_NETWORK_PARAMETERS); + } + + /* Call the actual service. */ + status = _nx_dhcp_set_interface_network_parameters(dhcp_ptr, iface_index, + subnet_mask, default_gateway_address, + dns_server_address); + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_set_interface_network_parameters PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DHCP server default options for 'network */ +/* critical parameters:' gateway, dns server and network mask for the */ +/* specified interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP server */ +/* iface_index Index specifying server interface*/ +/* subnet_mask Network mask for DHCP clients */ +/* default_gateway_address Router/default gateway for client*/ +/* dns_server_address DNS server for DHCP clients */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Valid parameters received */ +/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */ +/* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, + ULONG subnet_mask, ULONG default_gateway_address, + ULONG dns_server_address) +{ + + /* Check for invalid non pointer input. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); + } + + /* The default gateway should be on the same network as the dhcp server interface. */ + if ((default_gateway_address & subnet_mask) != + (dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address & + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask)) + { + return(NX_DHCP_INVALID_NETWORK_PARAMETERS); + } + + /* Obtain DHCP Server mutex protection,. */ + tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); + + /* Set the subnet, dns server, and router address for this interface. */ + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = dns_server_address; + + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = subnet_mask; + + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = default_gateway_address; + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP start function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_start Actual DHCP start function */ +/* nx_udp_socket_bind Bind the DHCP UDP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if (dhcp_ptr == NX_NULL) + return(NX_PTR_ERROR); + + if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) + { + return(NX_DHCP_PARAMETER_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual DHCP start service. */ + status = _nx_dhcp_server_start(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initiates the DHCP processing thread. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_bind Bind DHCP socket */ +/* nx_udp_socket_unbind Unbind DHCP socket */ +/* tx_thread_resume Initiate DHCP processing */ +/* tx_mutex_get Get the DHCP mutex */ +/* tx_mutex_put Release the DHCP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr) +{ + +UINT status; + + + /* Determine if DHCP has already been started. */ + if (dhcp_ptr -> nx_dhcp_started) + { + + /* Error DHCP has already been started. */ + + /* Return completion status. */ + return(NX_DHCP_SERVER_ALREADY_STARTED); + } + + dhcp_ptr -> nx_dhcp_started = NX_TRUE; + + /* Bind the UDP socket to the DHCP Socket port. */ + status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_SERVER_UDP_PORT, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the DHCP socket. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Set status to DHCP error code. */ + return(status); + } + + /* Start the session ("fast") timer. */ + tx_timer_activate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); + + /* Start the IP lease ("slow") timer. */ + tx_timer_activate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); + + /* Start the DHCP server thread. */ + tx_thread_resume(&(dhcp_ptr -> nx_dhcp_server_thread)); + + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DHCP stop function call. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_stop Actual DHCP stop function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if (dhcp_ptr == NX_NULL) + return(NX_PTR_ERROR); + + if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) + { + return(NX_DHCP_PARAMETER_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP stop service. */ + status = _nx_dhcp_server_stop(dhcp_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function halts the DHCP processing thread. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind the DHCP UDP socket */ +/* tx_thread_preemption_change Change the thread preemption */ +/* tx_thread_suspend Suspend DHCP processing */ +/* tx_thread_wait_abort Remove any thread suspension */ +/* tx_timer_deactivate Deactivate timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr) +{ + +UINT current_preemption; + + + /* Determine if DHCP is started. */ + if (dhcp_ptr -> nx_dhcp_started == NX_FALSE) + { + + /* DHCP is not started so it can't be stopped. */ + return(NX_DHCP_SERVER_NOT_STARTED); + } + + /* Obtain mutex protection, which is to say don't interrupt a DHCP server + if it is processing a packet from a DHCP client. */ + tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); + + /* Stop the session ("fast") timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); + + /* Stop the IP lease ("slow") timer. */ + tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); + + /* Clear the started flag here to ensure other threads can't issue a stop while + this stop is in progress. */ + dhcp_ptr -> nx_dhcp_started = NX_FALSE; + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Suspend the DHCP thread. */ + tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread)); + + /* Unbind the port. */ + nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); + + /* Restore preemption. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is top level server processing thread for the DHCP */ +/* service. It listens for and processes client requests in an infinite*/ +/* loop. */ +/* */ +/* Note that the current implementation expects a Client to initiate */ +/* a session with DISCOVER message rather than using the option of */ +/* skipping to the REQUEST message. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_instance Pointer to the DHCP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_process Main DHCP processing function */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_server_thread_entry(ULONG info) +{ + +NX_DHCP_SERVER *dhcp_ptr; +ULONG dhcp_events; +NX_DHCP_INTERFACE_TABLE *iface_table_ptr; +NX_DHCP_INTERFACE_IP_ADDRESS *iface_address_ptr; +NX_DHCP_CLIENT *dhcp_client_ptr; +UINT iface_index, i; +UINT status; +NX_PACKET *packet_ptr; + + + /* Setup the DHCP pointer. */ + NX_THREAD_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) + + /* Enter while loop. */ + while(1) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); + + /* Pick up IP event flags. */ + tx_event_flags_get(&dhcp_ptr -> nx_dhcp_server_events, NX_DHCP_SERVER_ALL_EVENTS, + TX_OR_CLEAR, &dhcp_events, TX_WAIT_FOREVER); + + /* Obtain the DHCP mutex before processing the DHCP event. */ + tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); + + /* Check events. */ + + /* Packet receive event. */ + if (dhcp_events & NX_DHCP_SERVER_RECEIVE_EVENT) + { + + /* Loop to receive DHCP message. */ + while(1) + { + + /* Check for an incoming DHCP packet with non blocking option. */ + status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT); + + /* Check for packet receive errors. */ + if (status != NX_SUCCESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Error receiving DHCP packet 0x%x\n", status); +#endif + break; + } + + /* Process DHCP packet. */ + _nx_dhcp_server_packet_process(dhcp_ptr, packet_ptr); + } + } + + /* FAST periodic event. */ + if (dhcp_events & NX_DHCP_SERVER_FAST_PERIODIC_EVENT) + { + + /* Check the clients in active session with the server. */ + for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++) + { + + /* Create a local pointer for convenience. */ + dhcp_client_ptr = &dhcp_ptr -> client_records[i]; + + /* Skip empty records. */ + if ((dhcp_client_ptr -> nx_dhcp_client_mac_lsw == 0) && (dhcp_client_ptr -> nx_dhcp_client_mac_msw == 0)) + continue; + + /* Skip clients not in active session with the Server, static members, + or client in the bound state. */ + if (dhcp_client_ptr -> nx_dhcp_session_timeout == TX_WAIT_FOREVER) + continue; + if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND) + continue; + + /* Skip clients whose session timeout is not set e.g. previous session + failed and no longer configured with this server. */ + if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0) + continue; + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) + continue; + + /* Check how much time is left before decreasing the time remaining on the session timeout. */ + if (dhcp_client_ptr -> nx_dhcp_session_timeout >= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL) + { + /* Ok to decrement the full amount. */ + dhcp_client_ptr -> nx_dhcp_session_timeout -= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL; + } + else + { + + /* Set to zero. Time's up! */ + dhcp_client_ptr -> nx_dhcp_session_timeout = 0; + } + + /* Has time expired on this session? */ + if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0) + { + + /* Yes, the client has bailed on the session, intentionally or otherwise. If it wants to + get an IP address it must start again. Reset status to 'INIT'. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: client session has timed out. Clear session data\n"); +#endif + + /* Does the client have an assigned IP address? */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) + { + + /* Yes, return it back to the available pool. */ + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, + dhcp_client_ptr -> nx_dhcp_assigned_ip_address, + NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); + + /* The assigned address must be removed. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + /* Clear the session data, including any data read from last client DHCP message. */ + _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr); + } + } + } + } + + /* Slow periodic event. */ + if (dhcp_events & NX_DHCP_SERVER_SLOW_PERIODIC_EVENT) + { + + for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++) + { + + /* Set a local pointer for convenience. */ + iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; + + /* Check the interface addresses in the table for lease expiration. */ + for (i = 0; i < iface_table_ptr -> nx_dhcp_address_list_size; i++) + { + + iface_address_ptr = &iface_table_ptr -> nx_dhcp_ip_address_list[i]; + + /* Skip all the entries who are not assigned or assigned indefinately (static). */ + if(iface_address_ptr -> assigned == NX_FALSE) + continue; + if(iface_address_ptr -> lease_time == TX_WAIT_FOREVER) + continue; + + /* Check how much time is left before decreasing the time remaining on the lease timeout. */ + if (iface_address_ptr -> lease_time >= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL) + { + + /* Ok to decrement the full amount. */ + iface_address_ptr -> lease_time -= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL; + } + else + { + + /* Set to zero. Time's up! */ + iface_address_ptr -> lease_time = 0; + } + + /* Has time expired on this lease? */ + if (iface_address_ptr -> lease_time == 0) + { + + /* Yes, make this address available. */ + + /* Clear the 'owner' field. */ + _nx_dhcp_clear_ip_address_owner(iface_address_ptr); + + /* Look up the client in the server database by its assigned address. */ + _nx_dhcp_find_client_record_by_ip_address(dhcp_ptr, &dhcp_client_ptr, iface_index, + iface_address_ptr -> nx_assignable_ip_address); + + /* Did we find it? */ + if (dhcp_client_ptr != NX_NULL) + { + + /* Remove the assigned IP address and reset the Client to the INIT state. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: client IP lease expired. Clear client data, release IP address\n"); +#endif + + /* Clear all session data if there is any for this client. */ + _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr); + + /* No, we should have this client in the server client records table but we don't. + That's all we can do right now. */ + } + } + } + } + } + }; + + /* We only break out of this loop in the event of the server stopping + or a fatal error occurring.*/ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_respond_to_client_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function prepares a DHCP message response and sends it back to */ +/* the Client. Most of the information is obtained from specified */ +/* input or from client session record. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to client to respond to*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status from various*/ +/* NetX calls */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a DHCP packet */ +/* nx_packet_release Release DHCP packet */ +/* nx_udp_socket_send Send DHCP packet */ +/* _nx_dhcp_add_option Add an option to the request */ +/* _nx_dhcp_add_requested_option Adds non standard option to */ +/* server reply to client */ +/* _nx_dhcp_load_server_options Load option data from server */ +/* option list */ +/* _nx_dhcp_server_store_data Store data into buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_listen_for_messages Service Client DHCP messages */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer; +UINT status; +UINT destination_ip_address; +UINT destination_port; +UINT index = 0; + + +#ifdef EL_PRINTF_ENABLE + /* Set local variables for convenience. */ + EL_PRINTF("DHCPserv: respond to client message on interface %d\n", dhcp_client_ptr -> nx_dhcp_client_iface_index); +#endif + + /* Allocate a DHCP packet. */ + status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Setup the packet buffer pointer. */ + buffer = packet_ptr -> nx_packet_prepend_ptr; + + /* Clear the buffer memory. */ + memset((void *) buffer, 0, NX_DHCP_OFFSET_END); + + /* Setup the standard DHCP fields. */ + buffer[NX_DHCP_OFFSET_OP] = NX_DHCP_OP_REPLY; + buffer[NX_DHCP_OFFSET_HTYPE] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwtype; + buffer[NX_DHCP_OFFSET_HLEN] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwlen; + buffer[NX_DHCP_OFFSET_HOPS] = 0; + buffer[NX_DHCP_OFFSET_BOOT_FILE] = 0; + + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_XID, 4, dhcp_client_ptr -> nx_dhcp_xid); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SECS, 2, 0); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_IP, 4, NX_DHCP_NO_ADDRESS); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SERVER_IP, 4, NX_DHCP_NO_ADDRESS); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_RELAY_IP, 4, NX_DHCP_NO_ADDRESS); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_FLAGS, 1, dhcp_client_ptr -> nx_dhcp_broadcast_flag_set); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW, 2, dhcp_client_ptr -> nx_dhcp_client_mac_msw); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_ptr -> nx_dhcp_client_mac_lsw); + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_VENDOR, 4, NX_DHCP_MAGIC_COOKIE); + + /* Update the index. */ + index = NX_DHCP_OFFSET_OPTIONS; + + /* Add the list of options that go out with ALL server messages. */ + status = _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_ALL_REPLIES, &index); + + /* Unless the server is sending a NACK, there are more options to add for the server reply. */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) + { + + /* Add the list of options that go out with server ACK replies (standard network parameters). */ + _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_GENERIC_ACK, &index); + + /* Determine if there are any message specific options to add. */ + switch (dhcp_client_ptr -> nx_dhcp_message_type) + { + + case NX_DHCP_TYPE_DHCPDISCOVER: + + /* Are we returning an OFFER to the Client? */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER) + { + + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_your_ip_address); + + /* Add the list of options that go out with server OFFER replies. */ + _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER, &index); + } + + /* Increment the number of Discovery messages received. */ + dhcp_ptr -> nx_dhcp_discoveries_received++; + break; + + + case NX_DHCP_TYPE_DHCPREQUEST: + + /* Are we returning an ACK to the Client? */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) + { + + _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_assigned_ip_address); + + /* Add the list of options that go out with server ACKs replies. */ + _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST, &index); + } + + /* Increment the number of Request messages received. */ + dhcp_ptr -> nx_dhcp_requests_received++; + break; + + /* Note: DHCP Servers should not reply to NX_DHCP_REPLY_TO_RELEASE or NX_DHCP_REPLY_TO_DECLINE messages. */ + case NX_DHCP_TYPE_DHCPRELEASE: + dhcp_ptr -> nx_dhcp_releases_received++; + break; + + case NX_DHCP_TYPE_DHCPDECLINE: + dhcp_ptr -> nx_dhcp_declines_received++; + break; + + case NX_DHCP_TYPE_DHCPINFORM: + + /* At this time the server sends just standard network parameters to INFORM requests. + so no additional options to add. */ + + /* Increment the number of Inform messages received. */ + dhcp_ptr -> nx_dhcp_informs_received++; + break; + + /* No other DHCP messages are supported by NetX DHCP Server at this time. */ + default: + break; + } + + /* Determine which of the remaining client requested options the server has information for. */ + _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT, &index); + } + + /* Setup the packet pointers. */ + /* Added the END option. */ + *(buffer + index) = NX_DHCP_SERVER_OPTION_END; + index ++; + + /* Check the option length. */ + if (index > NX_DHCP_OFFSET_END) + { + packet_ptr -> nx_packet_length = index; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; + } + else + { + packet_ptr -> nx_packet_length = NX_DHCP_OFFSET_END; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_END; + } + + /* DHCP Server set the correct destination address and port to send resposne. RFC2131, Section4.1, Page23. + 1. If the 'giaddr' field in a DHCP message from a client is non-zero, the server sends any return messages to the 'DHCP server' port on the + BOOTP relay agent whose address appears in 'giaddr'. + 2. If the 'giaddr'field is zero and the 'ciaddr' field is nonzero, then the server unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'. + 3. If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set, then the server broadcasts DHCPOFFER and DHCPACK messages to 0xffffffff. + 4. If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware address and 'yiaddr' address. + 5. In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK messages to 0xffffffff. */ + + /* Check the 'giaddr' field. */ + if (dhcp_client_ptr -> nx_dhcp_relay_ip_address) + { + + /* Set the destination address and port. */ + destination_ip_address = dhcp_client_ptr -> nx_dhcp_relay_ip_address; + destination_port = NX_DHCP_SERVER_UDP_PORT; + } + else + { + /* Check the DHCP response message type. */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) + { + + /* Check the 'ciaddr' field*/ + if (dhcp_client_ptr -> nx_dhcp_clientip_address) + { + destination_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address; + } + /* Check the broadcast bit. */ + else if (dhcp_client_ptr -> nx_dhcp_broadcast_flag_set & NX_DHCP_FLAGS_BROADCAST) + { + destination_ip_address = NX_DHCP_BC_ADDRESS; + } + else + { + destination_ip_address = dhcp_client_ptr -> nx_dhcp_your_ip_address; + + /* Add the dynamic arp entry. */ + status = nx_arp_dynamic_entry_set(dhcp_ptr -> nx_dhcp_ip_ptr, destination_ip_address, dhcp_client_ptr -> nx_dhcp_client_mac_msw, dhcp_client_ptr -> nx_dhcp_client_mac_lsw); + + /* Check the status. */ + if (status) + { + nx_packet_release(packet_ptr); + + return(status); + } + } + } + else + { + destination_ip_address = NX_DHCP_BC_ADDRESS; + } + + /* Set the destination port. */ + destination_port = NX_DHCP_CLIENT_UDP_PORT; + } + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: DHCP reply packet destination 0x%x\n", destination_ip_address); + EL_PRINTF("DHCPserv: DHCP reply buffer size (bytes) %d\n", packet_ptr -> nx_packet_length); + EL_PRINTF("DHCPserv: DHCP reply packet payload size (bytes) %d\n\n", packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_payload_size); +#endif + +#ifdef PACKET_DUMP +{ + + ULONG *work_ptr; + ULONG uword; + UINT i = 0; + UINT index = 0; + UINT length; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: server reply to client - packet dump:\n"); +#endif + + work_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)); + + while(i < length) + { + uword = *work_ptr; + + if (index == 10) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\n"); +#endif + index = 0; + } + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF(" %08x", uword); +#endif + work_ptr++; + index++; + i++; + } +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\n\n"); +#endif +} +#endif /* #ifdef PACKET_DUMP */ + + /* Send the packet. */ + status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, destination_ip_address, destination_port, dhcp_client_ptr -> nx_dhcp_client_iface_index); + + if (status != NX_SUCCESS) + { + nx_packet_release(packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_clear_client_session PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears data from the current client session (e.g. read*/ +/* from the most recent client message. It does remove anything in the */ +/* interface table associated with this client's subnet, nor change the*/ +/* client state. */ +/* */ +/* Permanent client info such as client host name, client mac address */ +/* assigned IP address, or lease time is not cleared (left to the */ +/* caller). */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to DHCP Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful outcome */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_listen_for_messages Handle Client DHCP messages */ +/* _nx_dhcp_fast_periodic_timer_entry Session timer entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +UINT i; + + NX_PARAMETER_NOT_USED(dhcp_ptr); + + dhcp_client_ptr -> nx_dhcp_message_type = 0; + dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0; + dhcp_client_ptr -> nx_dhcp_xid = 0; + dhcp_client_ptr -> nx_dhcp_requested_ip_address = 0x0; + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0x0; + dhcp_client_ptr -> nx_dhcp_your_ip_address = 0x0; + dhcp_client_ptr -> nx_dhcp_clientip_address = 0x0; + dhcp_client_ptr -> nx_dhcp_server_id = 0x0; + dhcp_client_ptr -> nx_dhcp_clientrec_server_ip = 0x0; + dhcp_client_ptr -> nx_dhcp_broadcast_flag_set = NX_DHCP_FLAGS_BROADCAST; + dhcp_client_ptr -> nx_dhcp_session_timeout = 0; + dhcp_client_ptr -> nx_dhcp_destination_ip_address = 0; + dhcp_client_ptr -> nx_dhcp_source_ip_address = 0; + + /* Clear out the option data. */ + dhcp_client_ptr -> nx_dhcp_client_option_count = 0; + for (i = 0; i < NX_DHCP_CLIENT_OPTIONS_MAX; i++) + { + dhcp_client_ptr -> nx_dhcp_user_options[0] = 0; + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcp_clear_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the clear client record */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to DHCP Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful outcome */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_client_record Actual clear client record service */ +/* */ +/* CALLED BY */ +/* */ +/* Host Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +UINT status; + + + /* Check for invalid input. */ + if ((dhcp_ptr == NX_NULL) || (dhcp_client_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCP clear client record service. */ + status = _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_clear_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the entire client record from the server table.*/ +/* It also frees up the client's IP address in the server IP address */ +/* table. */ +/* */ +/* The DHCP server does not use this function, it is strictly for the */ +/* host application to remove clients from the table (e.g. to free up */ +/* room for new clients by removing old 'stale' client entries no */ +/* longer configured with the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to DHCP Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful outcome */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_ip_address_owner Clear IP address owner */ +/* */ +/* CALLED BY */ +/* */ +/* Host Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +UINT i; +NX_DHCP_INTERFACE_TABLE *iface_table_ptr; + + + if (dhcp_client_ptr == 0x0) + { + /* Benign error. Return success. */ + return(NX_SUCCESS); + } + + /* Obtain DHCP Server mutex protection,. */ + tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); + + /* Set local pointer for convenience. */ + iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index]; + + i = 0; + + /* Does the client have an assigned IP address? */ + if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address) + { + + /* Yes, We need to free up the Client's assigned IP address in the server database. */ + while (i < iface_table_ptr -> nx_dhcp_address_list_size) + { + + /* Find the interface table entry by matching IP address. */ + if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address == + dhcp_client_ptr -> nx_dhcp_assigned_ip_address) + { + + /* Clear the owner information. */ + _nx_dhcp_clear_ip_address_owner(&(iface_table_ptr -> nx_dhcp_ip_address_list[i])); + + /* Address now available for DHCP client. */ + break; + } + i++; + } + } + + /* Ok to clear the Client record. */ + memset(dhcp_client_ptr, 0, sizeof(NX_DHCP_CLIENT)); + + /* Update the total number of dhcp clients. */ + if (dhcp_ptr -> nx_dhcp_number_clients > 0) + { + + dhcp_ptr -> nx_dhcp_number_clients--; + } + + /* Release DHCP Server mutex. */ + tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_load_server_options PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the specified options in the server's DHCP option */ +/* list to the DHCP server response to the Client message. There is a */ +/* required set of options that go out with all server messages, as well */ +/* as a standard (user configurable) set of options for all 'ACK' */ +/* messages. Lastly, there are certain options that are specific to the */ +/* client message request e.g. RENEW vs OFFER etc */ +/* */ +/* There is no support for responding to specific client options in this */ +/* revision. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to client session record*/ +/* buffer Packet buffer to load options to*/ +/* option_type Category of options to load */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_add_option Add option to response (specify */ +/* option and data to add)*/ +/* _nx_dhcp_add_requested_option Add option to response */ +/* (specify option and client */ +/* interface) */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_respond_to_dhcp_message Create and send response back */ +/* DHCP Client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index) +{ + +UINT i; +UINT iface_index; +UINT renew_time; +UINT rebind_time; +UINT lease_time; + + + /* Compute default lease, renew and rebind times to offer the client. */ + lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time; + +#if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF) + if (lease_time == 0) +#else + if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME)) +#endif + { + lease_time = NX_DHCP_DEFAULT_LEASE_TIME; + } + + renew_time = lease_time/2; + rebind_time = 7 * (lease_time/8); + + /* Set a local pointer for convenience. */ + iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + + /* Determine what set of options to apply based on caller input. */ + if (option_type == NX_DHCP_OPTIONS_FOR_ALL_REPLIES) + { + + /* This is the generic set of options for ALL server replies. */ + + /* Set the DHCP message type the server is sending back to client. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_TYPE, NX_DHCP_SERVER_OPTION_DHCP_TYPE_SIZE, + dhcp_client_ptr -> nx_dhcp_response_type_to_client, index); + + /* Add the server identifier to all messages to the client. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_SERVER_ID, NX_DHCP_SERVER_OPTION_DHCP_SERVER_SIZE, + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address, index); + + return(NX_SUCCESS); + } + else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER) + { + + /* Offer an IP lease. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index); + /* With the computed renew time. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index); + /* And rebind time. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index); + } + else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST) + { + + /* Confirm the assigned IP lease, renew and rebind times. */ + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index); + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index); + _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index); + } + else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_INFORM) + { + + /* The NetX DHCP Server reply to Inform messages includes the standard server option + list which is automatically included. */ + } + else if (option_type == NX_DHCP_OPTIONS_FOR_GENERIC_ACK) + { + + /* Add the standard DHCP server information (e.g. subnet, router IP etc) which are + appended to the required server options. */ + for (i= NX_DHCP_REQUIRED_SERVER_OPTION_SIZE; i < dhcp_ptr -> nx_dhcp_server_option_count; i++) + { + + /* Append this DHCP option to the client message. */ + _nx_dhcp_add_requested_option(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index, + buffer, dhcp_ptr -> nx_dhcp_server_options[i], index); + } + } + else if (option_type == NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT) + { + + /* The NetX DHSP Server does not (yet) support this feature in the current release. */ + + /* Clear the current DHCP Client's requested option list. */ + for (i = 0; i < dhcp_client_ptr -> nx_dhcp_client_option_count; i++) + { + + dhcp_client_ptr -> nx_dhcp_user_options[i] = 0; + } + + dhcp_client_ptr -> nx_dhcp_client_option_count = 0; + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_set_default_server_options PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses a set of options from the supplied buffer into */ +/* the server's list of options to supply data to the DHCP Client. If the*/ +/* server is configured to use default option data, it will use this list*/ +/* of options to compose the response to the Client. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* buffer Pointer to option list */ +/* size Size of option list buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual error status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_server_create Create the DHCP Server instance*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_size) +{ + +UINT j; +UINT digit; +UINT status; +CHAR *work_ptr; + + + j = 0; + /* Search through the text for all options to load. */ + while(buffer_size && (j < NX_DHCP_SERVER_OPTION_LIST_SIZE)) + { + + /* Check if we're off the end of the buffer. */ + if (buffer == 0x0) + { + break; + } + + work_ptr = buffer; + + /* This should advance the buffer past the digit.*/ + status = _nx_dhcp_parse_next_option(&buffer, &digit, buffer_size); + if (status) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Unable to set server DHCP option data list. Status 0x%x\n", status); +#endif + + return(status); + } + + buffer_size -= (UINT)(buffer - work_ptr); + + /* Load the parsed option into the server 'option list.' */ + dhcp_ptr -> nx_dhcp_server_options[j] = digit; + j++; + } + + /* Update the number of server options in the list. */ + dhcp_ptr -> nx_dhcp_server_option_count = j; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_parse_next_option PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses space or comma separated numeric data from the */ +/* supplied buffer, for example, the server option list. */ +/* */ +/* INPUT */ +/* */ +/* option_list Pointer to buffer to parse */ +/* option Data parsed from buffer */ +/* length Size of option list buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCP_INTERNAL_OPTION_PARSE_ERROR Parsing error status */ +/* */ +/* CALLS */ +/* */ +/* atoi Convert ascii number to integer*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_set_default_server_options Creates the server option list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_parse_next_option(CHAR **option_list, UINT *option, UINT length) +{ + +CHAR c; +UINT j; +UINT buffer_index; +CHAR num_string[3]; +CHAR *buffer; + + + /* Check for invalid input. */ + if ((option_list == 0x0) || (option == 0) || (length == 0)) + { + return(NX_DHCP_INTERNAL_OPTION_PARSE_ERROR); + } + + buffer = *option_list; + memset(&num_string[0], 0, 3); + + /* Initialize parsed option to undefined option (sorry, zero is taken by the PAD option + which I personally think was a bad programming decision). */ + *option = 999; + j = 0; + buffer_index = 0; + + /* Get the first character in the buffer. */ + c = *buffer++; + + /* Get the first digit (non separator character)*/ + while ((c == ' ') || (c == ',')) + { + + c = *buffer++; + j++; + } + + /* Now parse the next characters until the end of the buffer or next separator character. */ + while ((j < length) && (buffer_index < 3)) + { + + /* Check for separator marking the end of the option string. */ + if ((c == ' ') || (c == ',') || (c == 0x0)) + break; + + /* Check for an invalid digit or out of range option. */ + if (c < 0x30 || c > 0x39 || buffer_index > 2) + { + return(NX_DHCP_BAD_OPTION_LIST_ERROR); + } + + num_string[buffer_index] = c; + j++; + + /* Append the character ('digit') into a number buffer. */ + c = *buffer++; + buffer_index++; + } + + *option_list += j; + + /* Convert the number string to an actual integer. */ + *option = (UINT) atoi(num_string); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a Client DHCP message and extracts */ +/* information from a client DHCP message to create or update the */ +/* client record. It handles the DHCP message based on type, sets */ +/* a timer on the client record if a response is expected from the */ +/* client, and waits for another DHCP packet. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Message handled successfully */ +/* NO_PACKET No packet received */ +/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Packet interface not recognized*/ +/* status Actual completion outcome */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release DHCP packet */ +/* nx_udp_socket_receive Receive DHCP packet */ +/* _nx_dhcp_server_extract_information Extract DHCP packet info */ +/* _nx_dhcp_validate_client_message Process the Client message */ +/* _nx_dhcp_server_assign_ip_address Assign IP address to Client */ +/* _nx_dhcp_respond_to_client_message Create and send response back */ +/* _nx_dhcp_clear_client_session Clears client session data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_server_thread_entry DHCP Server thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +UINT iface_index; +NX_DHCP_CLIENT *dhcp_client_ptr = NX_NULL; +NX_PACKET *new_packet_ptr; +ULONG bytes_copied = 0; +ULONG offset; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\n"); + EL_PRINTF("DHCPserv: Waiting to receive next packet\n"); +#endif + + /* Check for minimum sized DHCP packet (e.g. just the DHCP header and 0 bytes of option data). */ + if (packet_ptr -> nx_packet_length < NX_DHCP_HEADER_SIZE) + { +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Client DHCP packet is malformed or empty. Invalid DHCP packet.\n"); +#endif + + /* No; Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return successful completion status. */ + return(NX_DHCP_MALFORMED_DHCP_PACKET); + } + + /* Get the interface index. */ + nx_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index); + + /* Does the DHCP server have a table for this packet interface? */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: No interface found for DHCP packet\n"); +#endif + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* No, return the error status. */ + return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); + } + + /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release + the packet from the receive packet pool as soon as possible. */ + status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Error allocating packet, return error status. */ + return(status); + } + + /* Verify the incoming packet does not exceed our DHCP Server packet payload. */ + if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length)) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the newly allocated packet and return an error. */ + nx_packet_release(new_packet_ptr); + + return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD); + } + + /* Update the prepend pointer to make sure that the IP header and UDP header also are copied into new packet. */ + packet_ptr -> nx_packet_prepend_ptr -= 28; + packet_ptr -> nx_packet_length += 28; + + /* Initialize the offset to the beginning of the packet buffer. */ + offset = 0; + status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); + + /* Check status. */ + if ((status != NX_SUCCESS) || (bytes_copied != packet_ptr -> nx_packet_length)) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the allocated packet we'll never send. */ + nx_packet_release(new_packet_ptr); + + /* Error extracting packet buffer, return error status. */ + return(status); + } + + /* Update the new packet with the bytes copied, and removed. + For chained packets, this will reflect the total 'datagram' length. */ + new_packet_ptr -> nx_packet_prepend_ptr += 28; + new_packet_ptr -> nx_packet_length = bytes_copied - 28; + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + new_packet_ptr -> nx_packet_length; + + /* Now we can release the original packet. */ + nx_packet_release(packet_ptr); + + /* Extract the DHCP specific information from the packet. This will create new record or update existing + client record in the server database. */ + status = _nx_dhcp_server_extract_information(dhcp_ptr, &dhcp_client_ptr, new_packet_ptr, iface_index); + +#ifdef PACKET_DUMP +{ + + ULONG *work_ptr; + ULONG uword; + UINT i = 0; + UINT index = 0; + UINT length; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: received client packet dump:\n"); +#endif + + /* Get a pointer to the IP header and adjust the packet length for IP and UDP header size. */ + work_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); + length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)) + sizeof(NX_UDP_HEADER) + sizeof(NX_IPV4_HEADER); + + while(i < length) + { + uword = *work_ptr; + + if (index == 10) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\n"); +#endif + index = 0; + } +#ifdef EL_PRINTF_ENABLE + EL_PRINTF(" %08x", uword); +#endif + work_ptr++; + index++; + i++; + } +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\n\n"); +#endif +} +#endif /* #ifdef PACKET_DUMP */ + + /* We are done with this packet now regardless of the success of the above operations. */ + nx_packet_release(new_packet_ptr); + + /* Check if we have an invalid client record. */ + if ((status != NX_SUCCESS) && dhcp_client_ptr) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Error extracting DHCP packet (invalid): 0x%x\n", status); +#endif + + /* Client record was created but there was a problem with the packet + or client message. Since we're not sure what got written to the Client record, + remove packet data out completely. */ + _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr); + } + + /* Check for general errors or failure to produce a client record. */ + if ((status != NX_SUCCESS) || !dhcp_client_ptr) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Internal error extracting DHCP packet: 0x%x\n", status); +#endif + + /* Return the error from extracting packet data. */ + return(status); + } + + /* Clear any previous response type in the client record. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0; + + /* Validate the client message including how the server should respond to it. */ + status = _nx_dhcp_validate_client_message(dhcp_ptr, dhcp_client_ptr); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: DHCP packet failed validation: 0x%x\n", status); +#endif + + /* Return all other errors as completion status. Do not send a message to the client. */ + return(status); + } + + /* Assign/confirm the assigned IP address of the Client if the server is not returning + a NACK, responding to an INFORM message, or not responding at all. */ + if ((dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) && + (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT) && + (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: assigning IP address to DHCP client...\n"); +#endif + + /* Assign/confirm an IP address to the client. If the client is renewing or rebinding + this will verify they sent the correct IP address and reset the lease time. */ + status = _nx_dhcp_server_assign_ip_address(dhcp_ptr, dhcp_client_ptr); + + /* Has the server run out of available addresses? Handle this 'error' + condition separately. */ + if (status == NX_DHCP_NO_AVAILABLE_IP_ADDRESSES) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Unable to assign IP address; none available\n"); +#endif + + /* Actually as yet, there is no callback to the host application + for handling this situation. + + The server should still send a NACK to the Client that it cannot + provide what it requests. */ + } + /* Check for errors other than running out of available IP addresses. */ + else if (status != NX_SUCCESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Unable to assign IP address. Status: 0x%x\n", status); +#endif + + /* Return all other errors as completion status. Do not send a message to the client. */ + return(status); + } + } + +#ifdef EL_PRINTF_ENABLE + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER) + EL_PRINTF("DHCPserv: response to client: OFFER\n"); + else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) + EL_PRINTF("DHCPserv: response to client: ACK\n"); + else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK) + EL_PRINTF("DHCPserv: response to client: NACK\n"); + else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPSILENT) + EL_PRINTF("DHCPserv: response to client: SILENT (no response)\n"); +#endif + + + /* Is there a response to send to the Client? */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT) + { + + /* Yes; use the session data in the client record to compose the server reply. */ + status = _nx_dhcp_respond_to_client_message(dhcp_ptr, dhcp_client_ptr); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Error sending response to DHCP client. Status: 0x%x\n", status); +#endif + + /* Return error completion status. Error sending a message to client. */ + return(status); + } + + /* Update the client state if an ACK was sent successfully. */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) + { + + /* Was the client was in a requesting, renewing or rebinding state? */ + if ((dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_RENEWING) || + (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REBINDING) || + (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REQUESTING)) + { + + /* Yes, the client should now be bound to an IP address. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOUND; + } + } + } + + /* + If the Client is BOUND, the session is over. Clear the session including + the sesison timeout. + + If the Client is still in the BOOT or INIT state something was wrong with their + message or else the server had a problem. Clear the record and they + can start a new session with a retransmission of their request. + */ + + /* Do we need to clear the session data depending? */ + if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOOT || + dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_INIT || + dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: client session completed. Clear session data.\n"); +#endif + + /* Yes, clear all data from the session. Client assigned IP address + and hardware address are not cleared.*/ + _nx_dhcp_clear_client_session(dhcp_ptr,dhcp_client_ptr); + } + else + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Waiting for DHCP client response...\n"); +#endif + + /* No; assume the Client is Renewing, rebinding, or selecting, + to set the session timeout to await the next Client response; + (not finished with this DHCP session yet). */ + + /* Assume we have received at least one message from the Client, so + reset the timer on the client session timeout. */ + dhcp_client_ptr -> nx_dhcp_session_timeout = NX_DHCP_CLIENT_SESSION_TIMEOUT; + } + + +/* Output Server session data if enabled. */ +#ifdef TESTOUTPUT + add_client++; + + /* Only print out the session table depending on trace interval. */ + if ((TRACE_NTH_CLIENT_PACKET > 0) && (add_client % TRACE_NTH_CLIENT_PACKET == 0)) + { + + UINT i; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\nClient\t\tAssigned\tLease\t\tSession\tState\n"); +#endif + for (i = 0; i < dhcp_ptr -> nx_dhcp_number_clients; i++) + { + NX_DHCP_CLIENT *client_ptr; + + client_ptr = &(dhcp_ptr -> client_records[i]); + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("0x%x 0x%x\t0x%08x\t0x%08x\t%d\t%d\n", + client_ptr -> nx_dhcp_client_mac_msw, + client_ptr -> nx_dhcp_client_mac_lsw, + client_ptr -> nx_dhcp_assigned_ip_address, + client_ptr -> nx_dhcp_requested_lease_time, + client_ptr -> nx_dhcp_session_timeout, + client_ptr -> nx_dhcp_client_state); +#endif + } + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("\nHost\tIP address\tAssigned? Lease\n"); + EL_PRINTF("Interface 0\n"); + for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_address_list_size; i++) + { + NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; + + interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_ip_address_list[i]); + EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n", + interface_address_ptr -> owner_mac_msw, + interface_address_ptr -> owner_mac_lsw, + interface_address_ptr -> nx_assignable_ip_address, + interface_address_ptr -> assigned, + interface_address_ptr -> lease_time); + } + + EL_PRINTF("\nInterface 1\n"); + for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_address_list_size; i++) + { + NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; + + interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_ip_address_list[i]); + EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n", + interface_address_ptr -> owner_mac_msw, + interface_address_ptr -> owner_mac_lsw, + interface_address_ptr -> nx_assignable_ip_address, + interface_address_ptr -> assigned, + interface_address_ptr -> lease_time); + } +#endif + } +#endif + + /* Return actual outcome status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_find_client_record_by_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks up a client record using the client's last known*/ +/* assigned IP address. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP server */ +/* dhcp_client_ptr Pointer to DHCP client */ +/* iface_index Client network interface index*/ +/* assigned_ip_address Client's assigned IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_DHCP_CLIENT_RECORD_NOT_FOUND Client record not found in */ +/* Server database */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_client_record Remove Client record from */ +/* Server database */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, + UINT iface_index, ULONG assigned_ip_address) +{ + +UINT i; +NX_DHCP_CLIENT *client_record_ptr; + + + /* Initialize the search results to unsuccessful. */ + *dhcp_client_ptr = NX_NULL; + + i = 0; + + /* Records are not necessarily added and deleted sequentially, + so search the whole table until a match is found. */ + while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE) + { + /* Set local pointer for convenience. */ + client_record_ptr = &dhcp_ptr -> client_records[i]; + + /* Check the mac address for a match. */ + if (client_record_ptr -> nx_dhcp_assigned_ip_address == assigned_ip_address) + { + + /* Verify the client packet interface matches the interface on record. */ + if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index) + { + /* Return the client record location. */ + *dhcp_client_ptr = client_record_ptr; + + return(NX_SUCCESS); + } + else + { + + /* It appears the client has changed its subnet location but not hardware type e.g. + same mac address/hardware type but not interface. Clear the old record. */ + + /* This will remove the client record both in the + server's client table and in the IP address database. */ + _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr); + + /* Search through the rest of the server records for + another instance of this client. Either way, if not found + with the expected interface a null pointer is returned, + or new record created depending on the caller. */ + } + } + i++; + } + + return(NX_DHCP_CLIENT_RECORD_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks up a client record by the client hardware mac */ +/* address. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* iface_index Client interface index */ +/* client_mac_msw MSB of client hardware address*/ +/* client_mac_lsw LSB of client hardware address*/ +/* dhcp_client_ptr Pointer to client record entry*/ +/* add_on Option to add if not found */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Message handled successfully */ +/* NX_DHCP_CLIENT_TABLE_FULL No more room in Client table */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_client_record Removes client record from */ +/* server table */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_server_extract_information Extract DHCP info from Client */ +/* message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw, + ULONG client_mac_lsw, NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on) +{ + +UINT i; +UINT available_index; +NX_DHCP_CLIENT *client_record_ptr; + + + /* Initialize the search results to unsuccessful. */ + *dhcp_client_ptr = NX_NULL; + + /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */ + available_index = NX_DHCP_CLIENT_RECORD_TABLE_SIZE; + + /* Records are not necessarily added and deleted sequentially, + so search the whole table until a match is found. */ + i = 0; + while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE) + { + + /* Set local pointer for convenience. */ + client_record_ptr = &dhcp_ptr -> client_records[i]; + + /* Skip empty records. Assume a client with no mac address is empty. */ + if ((client_record_ptr -> nx_dhcp_client_mac_msw == 0) && (client_record_ptr -> nx_dhcp_client_mac_lsw == 0)) + { + + /* Flag the first empty record in case we need to add the current client to the table. */ + if (i < available_index) + available_index = i; + + i++; + continue; + } + + /* Check the mac address of each record for a match. */ + if ((client_record_ptr -> nx_dhcp_client_mac_msw == client_mac_msw) && + (client_record_ptr -> nx_dhcp_client_mac_lsw == client_mac_lsw)) + { + + /* Verify the client packet interface matches the interface on record. */ + if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index) + { + /* Return the client record location. */ + *dhcp_client_ptr = client_record_ptr; + + return(NX_SUCCESS); + } + else + { + + /* It appears the client has changed its location (subnet) but not hardware type e.g. same mac + address/hware type but not interface. Remove the client record entirely and + free up any assigned IP address in the server database. */ + _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr); + + /* Continue searching through the rest of the server records for + another instance of this client. Either way, if not found + with the expected interface a null pointer is returned, + or new record created depending on the caller. */ + } + } + + i++; + } + + /* Not found. Create a record for this client? */ + if (add_on == NX_FALSE) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Client HW address not found. Do not add to server database\n"); +#endif + + /* No, we're done then. */ + return(NX_SUCCESS); + } + + /* Check if there is available room in the table for a new client. */ + if (available_index >= NX_DHCP_CLIENT_RECORD_TABLE_SIZE) + { + + /* No, we cannot add this client so the server's table. */ + return(NX_DHCP_CLIENT_TABLE_FULL); + } + + /* Set local pointer to an available slot. */ + client_record_ptr = &dhcp_ptr -> client_records[available_index]; + + /* Add this client to the server's total number of clients. */ + dhcp_ptr -> nx_dhcp_number_clients++; + + /* Add the supplied information to the new client record. */ + client_record_ptr -> nx_dhcp_client_mac_msw = client_mac_msw; + client_record_ptr -> nx_dhcp_client_mac_lsw = client_mac_lsw; + client_record_ptr -> nx_dhcp_client_iface_index = iface_index; + + /* Initialize the client state as the init state. */ + client_record_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + /* Return the location of the newly created client record. */ + *dhcp_client_ptr = client_record_ptr; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_find_interface_table_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks up a table entry by IP address in the specified */ +/* server interface table. If not found, a NULL entry pointer is */ +/* returned but successful search completion. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* iface_index Network interface index */ +/* ip_address IP address to look up */ +/* return_interface_address Pointer to table entry */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Message handled successfully */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_client_record Removes client record from */ +/* server table */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_server_extract_information Extract DHCP info from Client */ +/* message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address, + NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address) +{ + +UINT i; +NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; + + + /* Initialize search results to NULL (not found). */ + *return_interface_address = NX_NULL; + + /* Set a local varible to the IP address list for this client. */ + dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[iface_index]); + + /* Yes, search for an available ip address in the IP list for this interface */ + for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++) + { + + /* Is this address a match? */ + if (dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address == ip_address) + { + /* Yes, set a pointer to the location and return. */ + *return_interface_address = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; + + /* And we're done! */ + return(NX_SUCCESS); + } + } + + /* Not found, so return null pointer and successful search status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_update_assignable_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the IP address status in the server interface */ +/* table address for the current client. This will return an error */ +/* status if the IP address being updated is not owned by the client. */ +/* */ +/* Note: No changes are made to the associated client record. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to DHCP client */ +/* ip_address IP address to update */ +/* assign_status Status to assign */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Entry updated successfully */ +/* NX_DHCP_IP_ADDRESS_NOT_FOUND IP address not found */ +/* NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER IP address not assigned to */ +/* current client */ +/* NX_DHCP_INVALID_UPDATE_ADDRESS_CMD Unknown status input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_find_interface_table_ip_address */ +/* Find IP address in server */ +/* interface table */ +/* _nx_dhcp_find_ip_address_owner Verify Client is address owner */ +/* _nx_dhcp_clear_ip_address_owner Clear IP address owner */ +/* _nx_dhcp_record_ip_address_owner Sets Client as IP address owner */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_validate_client_message Process DHCP Client message*/ +/* _nx_dhcp_fast_periodic_timer_entry Timer on client sessions */ +/* _nx_dhcp_slow_periodic_timer_entry Timer on IP address leases */ +/* message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, + ULONG ip_address, UINT assign_status) +{ + +UINT iface_index; +UINT assigned_to_client; +UINT lease_time; +NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; + + + /* Create a local variable for convenience. */ + iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + + /* Look up the IP address in the server interface IP address table. */ + _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, iface_index, ip_address, &interface_address_ptr); + + /* Was it found? */ + if (interface_address_ptr == 0x0) + { + + /* No, return an error status address not found. */ + return(NX_DHCP_IP_ADDRESS_NOT_FOUND); + } + + /* Is the Client releasing IP address? */ + if (assign_status == NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE) + { + + /* Check if owner of this IP address matches with this client's record. */ + _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client); + + /* Is the IP address owned (leased) to this client? */ + if (assigned_to_client == NX_FALSE) + { + + /* No, this IP address is assigned to another host. We cannot change + the IP address status. */ + return(NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER); + } + + /* Yes, clear the owner information. */ + _nx_dhcp_clear_ip_address_owner(interface_address_ptr); + } + + /* Was the IP address assigned externally from the DHCP process? */ + else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT) + { + + /* Check the lease time. */ + if (interface_address_ptr -> lease_time) + { + /* If this already has a lease time (because we assigned it most likely) don't change it. */ + lease_time = interface_address_ptr -> lease_time; + } + else + { + /* Otherwise, make this lease time infinity e.g. the time out will not expire on it.*/ + lease_time = NX_WAIT_FOREVER; + } + + /* Set the current client as the owner. */ + _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time); + } + + /* Is the client informing us the IP address is already in use (e.g. it has + sent the server a DECLINE message) or accepting another DHCP server's offer? */ + else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER) + { + + /* Yes; Is the client is declining the IP address? */ + if (dhcp_client_ptr -> nx_dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) + { + + /* Yes, remove the Client as owner of this IP lease. + Record owner information with null 'owner' ID since we don't know who the owner is. */ + _nx_dhcp_record_ip_address_owner(interface_address_ptr, NX_NULL, NX_WAIT_FOREVER); + } + else + { + + /* Record owner information. */ + _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, NX_WAIT_FOREVER); + } + } + else + { + + /* Received an invalid update address command. */ + return(NX_DHCP_INVALID_UPDATE_ADDRESS_CMD); + } + + /* Successful completion! */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_find_ip_address_owner PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the owner of the specified IP address and checks*/ +/* it against the specified client record to insure the client is the */ +/* owner of the IP address. The result of the search is updated in the */ +/* assigned_to_client pointer. */ +/* */ +/* INPUT */ +/* */ +/* iface_owner Pointer to table entry */ +/* dhcp_client_ptr Pointer to DHCP client */ +/* assign_status Status to assign */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Table searched successfully */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ +/* the server database */ +/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ +/* current client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client) +{ + + + /* Initialize the value. */ + *assigned_to_client = NX_FALSE; + + /* Compare the owner in the interface table entry with the client record mac address. */ + if ((iface_owner -> owner_hwtype == client_record_ptr -> nx_dhcp_client_hwtype) && + (iface_owner -> owner_mac_msw == client_record_ptr -> nx_dhcp_client_mac_msw) && + (iface_owner -> owner_mac_lsw == client_record_ptr -> nx_dhcp_client_mac_lsw)) + { + + /* They match; This verifies the IP address is assigned to this client. */ + *assigned_to_client = NX_TRUE; + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_record_ip_address_owner PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function fills in the address owner in the interface table from*/ +/* the specified client record. */ +/* */ +/* INPUT */ +/* */ +/* iface_owner Pointer to table entry */ +/* client_record_ptr Pointer to DHCP client */ +/* lease_time Lease duration in secs */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Table searched successfully */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ +/* the server database */ +/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ +/* current client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time) +{ + + /* Check the client_record_ptr. */ + if (client_record_ptr) + { + + /* Parse the mac address and hardware type from the client record. */ + iface_owner -> owner_hwtype = client_record_ptr -> nx_dhcp_client_hwtype; + iface_owner -> owner_mac_msw = client_record_ptr -> nx_dhcp_client_mac_msw; + iface_owner -> owner_mac_lsw = client_record_ptr -> nx_dhcp_client_mac_lsw; + } + else + { + + /* We don't know who the owner is, set the owner information as zero. */ + iface_owner -> owner_hwtype = 0; + iface_owner -> owner_mac_msw = 0; + iface_owner -> owner_mac_lsw = 0;; + } + + /* Record the lease time. */ + iface_owner -> lease_time = lease_time; + + /* Set the assigned status. */ + iface_owner -> assigned = NX_TRUE; + + /* Return. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_clear_ip_address_owner PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the address owner information. */ +/* */ +/* INPUT */ +/* */ +/* iface_owner Pointer to table entry */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */ +/* _nx_dhcp_clear_client_record Clear Client record */ +/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ +/* the server database */ +/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ +/* current client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner) +{ + + /* Clear the owner information. */ + iface_owner -> owner_hwtype = 0; + iface_owner -> owner_mac_msw = 0; + iface_owner -> owner_mac_lsw = 0; + + /* Clear the lease time. */ + iface_owner -> lease_time = 0; + + /* Clear the assigned status. */ + iface_owner -> assigned = NX_FALSE; + + /* Return. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_validate_client_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function verifies the client message is a valid DHCP request, */ +/* determines if an IP address need to be assigned, what state the DHCP*/ +/* Client should be advanced to, and what the server DHCP response type*/ +/* should be. in the client record the specified client record. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_ptr Pointer to DHCP Server */ +/* client_record_ptr Pointer to DHCP client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Table searched successfully */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ +/* the server database */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_listen_for_messages Listen for, process and respond*/ +/* to DHCP Client messages */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +ULONG server_ip_address; +UINT iface_index; +NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; + + + /* Create a local variable for the client's interface for convenience. */ + iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; + + if (dhcp_client_ptr -> nx_dhcp_xid == 0x0) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: DHCP packet missing transaction ID. Reject the packet silently. \n"); +#endif + + /* Return the request denied message to clients and return. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + return(NX_SUCCESS); + } + + /* Client messages should never fill in the "Your (Client) IP" or "Next Server IP" fields. */ + else if ((dhcp_client_ptr -> nx_dhcp_your_ip_address != NX_DHCP_NO_ADDRESS) || + (dhcp_client_ptr -> nx_dhcp_clientrec_server_ip != NX_DHCP_NO_ADDRESS)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! 'Your IP'/'Server IP' fields should not be filled in.\n"); +#endif + + /* Return the 'request denied' message to the client. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + } + + /* Check for missing required fields. */ + else if ((dhcp_client_ptr -> nx_dhcp_client_hwtype == 0) || + (dhcp_client_ptr -> nx_dhcp_client_hwlen == 0)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! DHCP packet missing MAC and/or hardware type\n"); +#endif + + /* Return the request denied message to clients and return. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + } + + else + { + + /* Do validation specific the for message type. This section will also + advance the Client DHCP state and set the server response message type. + */ + switch (dhcp_client_ptr -> nx_dhcp_message_type) + { + + + case NX_DHCP_TYPE_DHCPDISCOVER: + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received DISCOVER message\n"); +#endif + + /* Determine if server needs to assign an IP address based on assigned IP address. + e.g. If this appears to be a retransmission of a previous IP address DISOVERY request, + only assign another IP address if the client appears not to have been assigned one already.*/ + /* Initialize response back to be an offer pending validation check. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPOFFER; + + /* Check for invalid IP address field(s). */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Client IP address field must not be filled in.\n"); +#endif + + /* Let the client know it has an invalid request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + } + else + { + + /* DHCP client state advances to SElECTING state. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_SELECTING; + } + + break; + } + + case NX_DHCP_TYPE_DHCPREQUEST: + { + + + /* This is a more complex message since a client request can be generated from + 4 different states: boot, selecting, renew, rebind. This requires that + we determine the Client state based on what's previously known about + the client and which fields are filled in the Request message. */ + + /* Get the DHCP server IP address for the client package interface. */ + server_ip_address = dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address; + + /* Get the index of the client packet interface. */ + iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + + /* If the client does not specify a server id but is requesting an IP address... */ + if ((dhcp_client_ptr -> nx_dhcp_server_id == 0) && + (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received REQUEST (BOOT state) message\n"); +#endif + /* ...Then it is in the boot state as per RFC 2131 4.3.2 (requests + an IP address but is skipping the DISCO message). */ + + /* This client may NOT specify a Client IP address e.g. that field must + be left blank. */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n"); +#endif + + /* Let the client know it has an invalid request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + break; + } + + /* Server SHOULD send a DHCPNAK message to the client if the 'requested IP address' is incorrect, or is on the wrong network. + RFC 2131, Section 4.3.2, Page31. */ + if ((dhcp_client_ptr -> nx_dhcp_assigned_ip_address != 0) && + (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address)) + { + + ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message contains incorrect requested IP address. \n"); +#endif + + /* No; invalid request. Return the IP address tentatively assigned to + the client back to the available IP address pool. */ + + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, + NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); + + /* Clear requested IP lease time because the client is not granted an IP address lease. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + /* Let the client know it made an invalid request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + break; + } + + /* Set the client state to the BOOT state */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOOT; + + /* Indicate the server will grant the IP lease. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; + + /* Advance the client state to requesting (waiting for an ACK). */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING; + break; + } + /* Else if the client is specifying a server id, and a requested IP address... */ + else if (dhcp_client_ptr -> nx_dhcp_server_id && + (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received REQUEST (SELECT state) message\n"); +#endif + + /* ...Then the client is in the SELECT state as per RFC 2131 4.3.2 (sent a + DISCOVERY message and is responding to a server OFFER message). */ + + /* Client may NOT specify a Client IP address. */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n"); +#endif + + /* Let the client know it has an invalid request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + break; + } + + /* Check if the Client has chosen this server's offer (e.g.server ID option in the + REQUEST message). */ + if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip_address) + { + + ULONG ip_address_assigned; + + /* We are not. */ + + /* Is the Client accepting the same IP address this server offered? */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == dhcp_client_ptr -> nx_dhcp_requested_ip_address) + { + + /* Yes, so do not change the client record IP address and IP address + status in the server interface table as assigned. */ + ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; + } + else + { + + /* No, it is accepting a different IP address from another server. */ + ip_address_assigned = dhcp_client_ptr -> nx_dhcp_requested_ip_address; + + /* So update the client record's assigned address to the one it is accepting + from another server. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address; + } + + /* Update the server interface table with the information. */ + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, + NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER); + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: SILENCE! REQUEST message indicates Client accepting another server IP.\n"); +#endif + + /* If this client wants an IP address from this server it must start + over at the init state. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + /* No need to respond. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + + return(NX_SUCCESS); + } + + /* Make sure the Client did in fact receive an OFFER from this server (e.g. has + been tentatively assigned an IP address from us). */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message does not indicate valid assigned IP address.\n"); +#endif + + /* It did not. This is an invalid request. Let the client know. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + + /* Clear requested IP lease times because the client was not assigned an IP address. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + /* Nothing more to do! */ + break; + } + + /* Does the Client's requested IP address match the "Your IP" field in the server OFFER + previously sent to this client (e.g. Client's assigned IP address)? */ + else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address) + { + + ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message contains requested IP address. \n"); +#endif + + /* No; invalid request. Return the IP address tentatively assigned to + the client back to the available IP address pool. */ + + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, + NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); + + /* Clear requested IP lease time because the client is not granted an IP address lease. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + /* Let the client know it made an invalid request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + break; + } + + /* The Client accepts this Server's offer. We will grant the client the IP lease now. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; + + /* UPdate the client state to REQUESTING (waiting on an ACK). */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING; + } + + /* Is this a RENEW or REBIND request? If so the server ID and requested IP options must + NOT be filled in as per RFC 2131 4.3.2. */ + else if ((dhcp_client_ptr -> nx_dhcp_server_id == NX_DHCP_NO_ADDRESS) && + (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS)) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received REQUEST (RENEW/REBIND state) message\n"); +#endif + + /* Yes, this is a renew/rebind request! */ + + /* Extending an IP lease is a administration decision vs RFC mandate. The + NetX DHCP Server automatically extends IP leases. */ + + /* Go ahead and ACK the renew request pending any DHCP violations. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; + + /* The "Client IP" address field MUST be filled in. */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message no 'Client IP' address specified. \n"); +#endif + + /* This is an invalid renew/rebind request. Reject the request but + do not change or advance the Client state (SHOULD be bound). */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + + break; + } + + /* The "Client IP" address subnet should match the Client packet source IP address subnet. */ + if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_client_ptr -> nx_dhcp_clientip_address) != + (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) + { +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message; the 'Client IP' address subnet does not match the DHCP server subnet. \n"); +#endif + + /* This is an invalid renew/rebind request. Reject the request but + do not change or advance the Client state (SHOULD be bound). */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + break; + } + + /* Is there an assigned IP address in the Client record? */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! REQUEST message; server has no record of assigned IP address.\n"); +#endif + + /* No; possibly assigned by another DHCP server or outside of DHCP protocol. + Reject the renewal request. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + + /* This client needs to start the configuration process with this + server from the INIT start if it wants an IP address from it. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + break; + } + + /* Determine if this is a renew or a rebind request. */ + if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received REQUEST (renewing) message\n"); +#endif + + /* Renewing: DHCP clients' renew requests must be unicast. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_RENEWING; + } + else + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received REQUEST (rebinding) message\n"); +#endif + + /* Rebinding DHCP clients' rebind request must be broadcast. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REBINDING; + } + } + else + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Received unknown REQUEST message type.\n"); +#endif + + /* Do not respond to unknown requests. This is kind of a dealer's choice + because it is not specified in the RFC 2132 how to handle undefined + request IDs or message types. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + return(NX_SUCCESS); + } + + break; + } + + case NX_DHCP_TYPE_DHCPRELEASE: + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received RELEASE response type.\n"); +#endif + + + /* The Client is releasing it's IP address back to the server. A client is not + required to do this; usually it indicates the client may have moved on the + network. + + Clear the client record and mark the IP address as available. If the request proves + invalid, this server will ignore it and let the Client's assigned IP lease expire. */ + + /* Regardless what happens the server does not send a reply to a RELEASE message. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + + /* Was an address previously assigned? */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) + { + + /* No; nothing to do here. */ + return(NX_SUCCESS); + } + + /* The client IP field must be filled in for RELEASE requests. Was it? */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) + { + + /* No; This is an invalid release request. */ + return(NX_SUCCESS); + } + + /* Does client IP field match what this Server assigned the Client? */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address != dhcp_client_ptr -> nx_dhcp_assigned_ip_address) + { + + /* No; Not sure how this happened but let the existing assigned + IP address lease expire. Ignore this message. */ + return(NX_SUCCESS); + } + + /* A RELEASE request must be unicasted to the server. Was this a broadcast + message? */ + if (dhcp_client_ptr -> nx_dhcp_destination_ip_address == NX_DHCP_BC_ADDRESS) + { + + /* Yes, so not a valid RELEASE request. */ + return(NX_SUCCESS); + } + else + { + + UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address; + + /* Check that we are the intended server. */ + if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != server_ip) + { + + /* We are not. Not a valid Release request. */ + return(NX_SUCCESS); + } + } + + /* Legitimate release request: return the IP address to the available pool, + and clear the client session. */ + + /* Release the client's assigned IP address (in the "CI-ADDR" field). */ + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, + dhcp_client_ptr -> nx_dhcp_assigned_ip_address, + NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); + + /* Clear the Client's assigned IP address. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + /* If this client wants to configure its network parameters with us it + must start at the INIT state. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + + break; + } + + case NX_DHCP_TYPE_DHCPDECLINE: + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received DECLINE response type.\n"); +#endif + + /* The Client is informing us an IP address we assigned to it is apparently already + in use by another host. It needs to restart in the INIT/BOOT state for this + server to assign it another IP address. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + /* Regardless what happens do not send a reply. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + + /* If no address previously assigned, silently ignore this message. */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) + { + + /* This client never had an address assigned by this server. Do nothing. */ + return(NX_SUCCESS); + } + + /* A DECLINE message must specify the requested address. */ + if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS) + { + + /* This is an invalid decline request. Reject it silently. */ + return(NX_SUCCESS); + } + + /* A Decline request is supposed to be unicasted to the server. If it is not, + ignore it. */ + if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS) + { + + return(NX_SUCCESS); + } + else + { + + UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index; + ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address; + + /* Check that we are the intended server. */ + if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip) + { + + /* We are not. Ignore the request. */ + return(NX_SUCCESS); + } + } + + /* Release the client's assigned IP address. */ + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, + dhcp_client_ptr -> nx_dhcp_assigned_ip_address, + NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER); + + /* Clear the Client's assigned IP address. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + break; + } + + case NX_DHCP_TYPE_DHCPINFORM: + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: Received INFORM response type.\n"); +#endif + + + /* A DHCP client sends an INFORM message when it has been assigned an IP address + with another server or outside DHCP but still needs local configuration data. + The DHCP server must update its database with their address (specified in the "CI-ADDR" field) + as no longer available. When the server forms a reply ACK, it must leave the + 'Your IP' and lease time fields blank as per RFC 2131 3.4. */ + + + /* A DHCP server must respond (ACK) to INFORM messages unless the message + is invalid. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; + + /* The INFORM message must have the Client IP address filled in to be valid. */ + if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) + { + + /* Invalid message. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + } + + /* It cannot have a requested IP option in the options. */ + if (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS) + { + + /* Invalid message. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + } + + /* Make sure the server interface table is up to date for this IP address. */ + _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, dhcp_client_ptr -> nx_dhcp_clientip_address, + NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT); + + /* And update the client record assigned IP address in case it is not set yet. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address; + + /* Has client IP address leased (bound) from this server? */ + if (dhcp_client_ptr -> nx_dhcp_client_state != NX_DHCP_STATE_BOUND) + { + + /* No, so if this client needs to configure an IP address assigned + with this server it must start at the INIT state. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + } + + break; + } + default: + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Received unknown response type.\n"); + #endif + + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + + return(NX_SUCCESS); + + /* No further processing to do. Leave the client state unchanged, whatever it was/is. */ + } + + } /* switch case on client message*/ + } + + /* Were there were any conditions requiring a NACK response? */ + if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK) + { + /* Yes, the caller knows to send the NACK message. No processing to do. */ + return NX_SUCCESS; + } + + /* If this is not a DISCOVERY or REQUEST message, we are done! */ + if ((dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER) && + (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPREQUEST)) + { + + return(NX_SUCCESS); + } + + /* If the boot/init state client did not request an address, we are done. */ + if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS) + { + + return(NX_SUCCESS); + } + + /* Check if the Client has requested a valid IP address. This is only permitted + with a DISCO or REQUEST messages while the Client is in either the BOOT/INIT + or SELECT states. + + As per RFC 2131 4.3.1, the DHCP server should assign an IP address in order of preference as follows: + 1) the client currently is bound to + 2) client ip address in client records (e.g. previously assigned to) + 3) the currently requested IP + 4) the server will assign one. */ + + /* Find the currently binding source address in the server's database. */ + if (dhcp_client_ptr -> nx_dhcp_source_ip_address != NX_DHCP_NO_ADDRESS) + { + + /* Assign this as the Client's IP address. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_source_ip_address; + } + + /* Next best option: Has the client previously been assigned an IP address? */ + else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) + { + + /* Yes, let's leave it assigned to it. */ + return(NX_SUCCESS); + } + else + { + + /* Last option: Set the client's requested IP address as the one to assign. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address; + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_assign_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service finds an available IP address for the client if none is */ +/* provided, and updates the client's record with the new IP address. It */ +/* updates the interface table entry with current client data (lease */ +/* time, owner). */ +/* */ +/* If there already is an assigned IP address on the client record, this */ +/* function will verify the IP address has not been assigned to another */ +/* client before setting the current client as owner. If it has, this */ +/* function will look for another available IP address for the client. */ +/* */ +/* Once an address is assigned, this function updates the fields in the */ +/* interface pointer entry, and the "Your IP address" in its message back*/ +/* to the client. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_cptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to client record */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_DHCP_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_find_interface_table_ip_address */ +/* Look up IP address in */ +/* server interface table */ +/* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/ +/* in server interfce table */ +/* _nx_dhcp_record_ip_address_owner Set the client as IP address */ +/* owner in interface table */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_validate_client_message Check Client DHCP messages for*/ +/* proper data and determine */ +/* server response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) +{ + +NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; +NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; +UINT assigned_to_client; +UINT assigned_ip; +UINT lease_time; + + + /* Set a flag on the outcome of finding an available address. */ + assigned_ip = NX_FALSE; + + /* Compute the client lease time based on client's requested + lease time and server default lease time. */ + lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time; + + +#if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF) + if (lease_time == 0) +#else + if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME)) +#endif + { + lease_time = NX_DHCP_DEFAULT_LEASE_TIME; + } + + + interface_address_ptr = (NX_DHCP_INTERFACE_IP_ADDRESS *)NX_NULL; + + /* Does the Client have a candidate already assigned? */ + if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) + { + + /* The client does have one assigned, but we need to verify it is available + or already assigned to the client. */ + + /* Look for this IP address in the specified interface IP address list (table). */ + _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index, + dhcp_client_ptr -> nx_dhcp_assigned_ip_address, &interface_address_ptr); + + /* Was the ip address found? */ + if (interface_address_ptr) + { + + /* Yes; Is it assigned to anyone yet? */ + if (interface_address_ptr -> assigned == NX_FALSE) + { + /* No, We will assign this one further below. */ + } + else + { + + /* Determine who if is assigned to. */ + _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client); + + /* Assigned to this client? */ + if (assigned_to_client) + { + + + /* Yes, so we're done here, except for checking a few fields. */ + + /* Renew the lease time. */ + interface_address_ptr -> lease_time = lease_time; + + /* Set the Your IP address field for the server response message. */ + dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address; + + return(NX_SUCCESS); + } + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (already assigned)\n"); +#endif + + /* No, assigned to someone else. We cannot provide this so return a NACK. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + /* Clear the client's assigned IP address since it is assigned to someone else. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + return(NX_SUCCESS); + } + } + else + { + + /* If this is a NOT discovery message, the server can not very well + assign a different IP address becaause an ACK reply cannot contain + different information. */ + if (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not owned by server)\n"); +#endif + + /* Apparently the client has asked for an IP address either not + in the server database or on another network. We cannot provide this + so return a NACK. */ + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + + /* Clear the client record's 'assigned' IP address since none was assigned. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + /* Since the client did not get assigned an IP address + make sure the requested lease time is reset to zero. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + return(NX_SUCCESS); + } + + /* For a Discovery request, the server will go ahead and find an + available IP address to offer the client. */ + } + } + + /* If the client doesn't have an address assigned yet, find one in the server table not + yet assigned. */ + if (interface_address_ptr == 0x0) + { + + UINT i; + + /* Set a local varible to the IP address list for this client. */ + dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index]); + + /* Yes, search for an available ip address in the IP list for this interface */ + for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++) + { + + /* Set a local pointer variable to the next address. */ + interface_address_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; + + /* Is this address assigned already? */ + if (interface_address_ptr -> assigned == NX_FALSE) + { + + /* No, but it is now! */ + + /* Indicate the search was successful. */ + assigned_ip = NX_TRUE; + + break; + } + } + + /* Check if we were able to find an available IP address. */ + if (assigned_ip == NX_FALSE) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not found in server IP list)\n"); +#endif + + + /* The server is not obliged to respond, but it should let the client + know if it cannot provide what it requests. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + + /* Since the client did not get assigned an IP address + make sure the requested lease time is reset to zero. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + /* No, return the error status. */ + return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES); + } + } + + /* Was the assigned ip address available? */ + if (interface_address_ptr) + { + + /* Set the client as the IP address owner in the server interface table. */ + _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time); + + /* Set the client's assigned IP address. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = interface_address_ptr -> nx_assignable_ip_address; + + /* Set the Your IP address field for the server response message. */ + dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address; + + /* We are done! */ + return(NX_SUCCESS); + } + + /* If we're here we were not able to assign an IP address. */ + + /* The server is not obliged to respond, but it should let the client + know if it cannot provide what it requests. */ + dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: NACK! Server cannot assign requested IP address\n"); +#endif + + dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; + + /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */ + dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; + + /* Since the client did not get assigned an IP address + make sure the requested lease time is reset to zero. */ + dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; + + return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_extract_information PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts information from a DHCP Client packet and */ +/* updates the server's client database. If no client record exists for*/ +/* the client this function will create one for it. It does some */ +/* message validation but primary extracts DHCP header and option */ +/* fields to the client record. */ +/* */ +/* If an internal error is encountered parsing the packet buffer, this */ +/* function returns the error status. If it finds the client DHCP */ +/* message invalid, it returns successful completion but sets the DHCP */ +/* server to respond with either NACK or silence. */ +/* */ +/* When this function is finished, the caller releases the packet. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_cptr Pointer to DHCP Server */ +/* dhcp_client_ptr Pointer to client record */ +/* packet_ptr Pointer to DHCP client packet */ +/* iface_index Interface index packet was */ +/* received on */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_find_client_record_by_chaddr Find Client record using the */ +/* parsed mac address */ +/* _nx_dhcp_server_get_data Parse DHCP data from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_listen_for_messages Process DHCP Client messages */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, + NX_PACKET *packet_ptr, UINT iface_index) +{ + +UINT status; +ULONG value; +UINT size; +ULONG xid; +UCHAR *work_ptr; +ULONG client_mac_msw; +ULONG client_mac_lsw; +NX_IPV4_HEADER *ip_header_ptr; +NX_DHCP_CLIENT *temp_client_rec_ptr; + + + /* Initialize the DHCP Client pointer to null pending successful data extraction. */ + *dhcp_client_ptr = NX_NULL; + + /* Set up UCHAR pointer to HW address field to extract client hardware address + which we will use as the client's unique identifier, since not all clients may use + Option 61/Client Identifier. */ + work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_HW; + + /* Pickup the MSW of the MAC address. */ + client_mac_msw = (((ULONG) work_ptr[0]) << 8) | ((ULONG) work_ptr[1]); + client_mac_lsw = (((ULONG) work_ptr[2]) << 24) | + (((ULONG) work_ptr[3]) << 16) | + (((ULONG) work_ptr[4]) << 8) | + ((ULONG) work_ptr[5]); + + /* Check the client hardware (mac address) field is filled in. */ + if ((client_mac_msw == 0) && (client_mac_lsw == 0)) + { + + return(NX_DHCP_INVALID_HW_ADDRESS); + } + + /* Look up the client record by IP address and interface index in Client Records table. */ + status = _nx_dhcp_find_client_record_by_chaddr(dhcp_ptr, iface_index, client_mac_msw, + client_mac_lsw, &temp_client_rec_ptr, NX_TRUE); + + + /* Check for error during search. */ + if ((status != NX_SUCCESS) || !temp_client_rec_ptr) + { + return(status); + } + + + /* Note: No need to check for NULL pointer because we asked to add the + record if no match is found. */ + + + /* Get the client's current binding IP address from the packet interface. */ + ip_header_ptr = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); + + temp_client_rec_ptr -> nx_dhcp_source_ip_address = ip_header_ptr -> nx_ip_header_source_ip; + temp_client_rec_ptr -> nx_dhcp_destination_ip_address = ip_header_ptr -> nx_ip_header_destination_ip; + + /* Get the message type. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_OP, 1, &value); + if (status) + { + return(status); + } + + /* Check this is a 'request' DHCP Client message (not to be confused with the REQUEST + message type. */ + if (value != NX_DHCP_OP_REQUEST) + { + +#ifdef EL_PRINTF_ENABLE + EL_PRINTF("DHCPserv: SILENCE! Client DHCP packet not coded as a BOOT Request. Invalid request.\n"); +#endif + + /* Set the server to ignore the 'reply'. */ + temp_client_rec_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; + + /* Return successful completion status. */ + return(NX_SUCCESS); + } + + /* Get the hardware type. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HTYPE, 1, &value); + if (status) + { + return(status); + } + + /* This is the Client interface type which is used in the default client identifier tag. */ + temp_client_rec_ptr -> nx_dhcp_client_hwtype = value; + + /* Get the hardware length. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HLEN, 1, &value); + if (status) + { + return(status); + } + + /* This is the size of the hardware address. Used in the default client identifier tag. */ + temp_client_rec_ptr -> nx_dhcp_client_hwlen = value; + + /* Extract the message ID. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_XID, 4, &xid); + if (status) + { + return(status); + } + + /* Save the client xid to use in the server's reply back. */ + temp_client_rec_ptr -> nx_dhcp_xid = xid; + + /* Check if response to client should unicast or (default) broadcast. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_FLAGS, 1, &value); + if (status) + { + return(status); + } + + /* Get the Client's preference for unicast vs broadcast. */ + temp_client_rec_ptr -> nx_dhcp_broadcast_flag_set = (value & NX_DHCP_FLAGS_BROADCAST) ? 0x80 : 0x0; + + /* Extract the Requested Client IP address, if there is one. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_IP, 4, &value); + if (status) + { + return(status); + } + + /* This is the Client IP address reported by the Client. */ + temp_client_rec_ptr -> nx_dhcp_clientip_address = value; + + /* Update the IP address assigned to the Client "Your/client IP address". */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_YOUR_IP, 4, &value); + if (status) + { + return(status); + } + + /* This is the "Your IP address" which only the server should fill in. Should be zero in + client messages. */ + temp_client_rec_ptr -> nx_dhcp_your_ip_address = value; + + /* Extract the "Next Server IP address". */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_SERVER_IP, 4, &value); + if (status) + { + return(status); + } + temp_client_rec_ptr -> nx_dhcp_clientrec_server_ip = value; + + /* Store relay IP address for DHCP server (on another subnet) if there is one. */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_RELAY_IP, 4, &value); + if (status) + { + return(status); + } + temp_client_rec_ptr -> nx_dhcp_relay_ip_address = value; + + /* Look for the marker indicating option data (magic cookie). */ + status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR, 4, &value); + if (status) + { + return(status); + } + + /* Note we don't store the magic cookie value. */ + + /* Are there user options? */ + if (value == NX_DHCP_MAGIC_COOKIE) + { + /* Yes there are user options in the Client message. */ + + /* Move up the buffer pointer past the magic cookie thing. */ + work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR + 4; + + /* Extract all the client option data. */ + while (*work_ptr != 0xFF) + { + + /* Guard against a missing "END" marker by checking if we are at the end of the DHCP packet data. */ + if (work_ptr >= packet_ptr -> nx_packet_append_ptr) + { + + /* Yes, Client must have sent a DHCP message with improperly terminated option + data (or Client is using a super large DHCP packet). */ + return(NX_DHCP_IMPROPERLY_TERMINATED_OPTION); + } + + /* Get the next option. */ + _nx_dhcp_server_get_data(work_ptr, 1, &value); + + /* Move up the buffer pointer to the option length. */ + work_ptr++; + + /* Get the option length. */ + _nx_dhcp_server_get_data(work_ptr, 1, (ULONG *)&size); + + /* Move up the buffer pointer to the next option. */ + work_ptr++; + + + /* Is this the client ID option? */ + if (value != NX_DHCP_SERVER_OPTION_CLIENT_ID) + { + + /* No, process as any other option. */ + _nx_dhcp_process_option_data(temp_client_rec_ptr, (CHAR *)work_ptr, value, NX_TRUE, size); + + /* Move up the buffer pointer past the current option data size to the next option. */ + work_ptr += size; + } + else + { + + work_ptr += size; + } + + /* Check that we haven't exceeded the limit on Client option requests. */ + if (temp_client_rec_ptr -> nx_dhcp_client_option_count >= NX_DHCP_CLIENT_OPTIONS_MAX) + { + + /* We have. This is all we have room to process. */ + break; + } + } + } + + /* Return the location of the client record. */ + *dhcp_client_ptr = temp_client_rec_ptr; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_get_option_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine extracts data from the specified location and adds the */ +/* Client's requested option to the Client record. The caller can ask */ +/* for the option data as well to be extracted and stored to client */ +/* record. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_client_ptr Pointer to DHCP Client */ +/* buffer Pointer to data buffer */ +/* option Option from Client DHCP packet */ +/* size Size of data buffer */ +/* get_option_data Indicate if server wants option*/ +/* data stored in client record */ +/* */ +/* OUTPUT */ +/* */ +/* status Error status extracting data */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_server_get_data Extract data from specified */ +/* buffer location */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_server_extract_information Extract DHCP data from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_client_ptr, CHAR *buffer, ULONG option, UINT get_option_data, UINT size) +{ + +CHAR *temp_ptr; +UINT status; +ULONG option_value = 0; + + + + /* Do we parse option data for this option? */ + if (get_option_data) + { + + /* Yes, store to local variable to be applied to the Client record below. */ + status = _nx_dhcp_server_get_data((UCHAR *)buffer, size, &option_value); + if (status) + { + return(status); + } + } + + switch (option) + { + + case 1: + /* Subnet mask */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + dhcp_client_ptr -> nx_dhcp_subnet_mask = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 3: + /* Router or gateway */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + dhcp_client_ptr -> nx_dhcp_router_ip_address = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 6: + /* Domain name server */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + dhcp_client_ptr -> nx_dhcp_dns_ip_address = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + + case 12: + /* Client host name */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + + /* Only store as much of the host name as will fit in the host name buffer. */ + size = (size <= NX_DHCP_CLIENT_HOSTNAME_MAX) ? size : NX_DHCP_CLIENT_HOSTNAME_MAX; + + /* Clear the memory buffer before writing the host name to it. */ + memset(&dhcp_client_ptr -> nx_dhcp_client_name[0], 0, NX_DHCP_CLIENT_HOSTNAME_MAX); + memcpy(&dhcp_client_ptr -> nx_dhcp_client_name[0], buffer, size); + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 50: + + /* Client's requested IP address */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + + dhcp_client_ptr -> nx_dhcp_requested_ip_address = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 51: + + /* Client's requested IP address lease time */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + + dhcp_client_ptr -> nx_dhcp_requested_lease_time = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 53: + /* Message type */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = (UCHAR)option; + dhcp_client_ptr -> nx_dhcp_message_type = (UCHAR)option_value; + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 54: + /* Server ID by which server identifies itself to client(usually server IP address). + The Client includes this option in a REQUEST message to identify which server + it wants to lease an IP address from. */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + if (get_option_data) + { + + dhcp_client_ptr -> nx_dhcp_server_id = option_value; + } + dhcp_client_ptr -> nx_dhcp_client_option_count++; + break; + + case 55: + /* Option parameter list */ + temp_ptr = buffer ; + + /* Call this function to handle options within the option 55. */ + while (size) + { + + /* Get the next option in the Option parameter list. */ + _nx_dhcp_server_get_data((UCHAR *)temp_ptr, 1, &option); + + /* Update the client record with that option. */ + _nx_dhcp_process_option_data(dhcp_client_ptr, temp_ptr, option, NX_FALSE, 1); + + /* Move down the buffer containing the option parameter list data. */ + temp_ptr++; + + /* Update the amount of option data left for option 55. */ + size--; + } + break; + + case 61: + + /* Note Client ID is handled separately. */ + dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; + dhcp_client_ptr -> nx_dhcp_client_option_count++; + + break; + + case 116: /* Auto configuration option */ + case 60: /* Vendor class Identifier. */ + + /* Not supported at this time. */ + break; + + default: + break; + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_add_requested_option PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine receives options and which interface the DHCP client is*/ +/* on and adds the server information if there is any for that option */ +/* into the packet reply buffer. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_message Pointer to message buffer */ +/* iface_index Index to server interface table*/ +/* buffer Pointer to buffer to write to */ +/* option Option to add */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_add_option Adds the actual option to the */ +/* DHCP message buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_respond_to_dhcp_message Prepare and send out DHCP */ +/* response to client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index) +{ + +UINT status = NX_SUCCESS; + + /* The NetX DHCP server provides a limited list of DHCP options for ACK responses. These do NOT + include the server's 'required' options. */ + switch (option) + { + + case 1: /* Subnet mask */ + status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_SUBNET_MASK_SIZE, + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask, index); + break; + + case 3: /* Router IP address */ + + + status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ROUTER_SIZE, + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address, index); + break; + + case 6: /* DNS IP address */ + status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ADDRESS_SIZE, + dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address, index); + break; + + /* The NetX DHCP server does not reply to other options at this time. */ + default: + break; + } + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_add_option PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine adds a DHCP option data to the DHCP message in the */ +/* supplied buffer. Adding the option includes adding the option code,*/ +/* length of the data and option data value. */ +/* */ +/* INPUT */ +/* */ +/* dhcp_message Pointer to message buffer */ +/* option Option to add */ +/* value Value of Option to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_server_store_data Store data value */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_process Process the DHCP state machine*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_add_option(UCHAR *dhcp_message, UINT option, UINT size, ULONG value, UINT *index) +{ + + + /* Store the option. */ + *(dhcp_message + (*index)) = (UCHAR)option; + (*index) ++; + + /* Store the option size. */ + *(dhcp_message + (*index)) = (UCHAR)size; + (*index) ++; + + /* Store the option value. */ + _nx_dhcp_server_store_data(dhcp_message + (*index), size, value); + (*index) += size; + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_get_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine gets a data value from a buffer, assuming the data is */ +/* stored in standard Network format (big endian). Up to 4 bytes of */ +/* data are used, if there are more than 4 bytes, only the lower 4 */ +/* bytes are returned. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* value Data value retrieved */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_DHCP_PARAMETER_ERROR Invalid parameter input */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_get_response Get response from server */ +/* _nx_dhcp_server_extract_information Extract server information */ +/* _nx_dhcp_update_address_list Update address list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value) +{ + + + /* Check for invalid buffer parameters. */ + if ((size == 0) || (data == 0x0) || (value == 0)) + { + return(NX_DHCP_PARAMETER_ERROR); + } + + /* Initialize value to zero. */ + *value = 0; + + /* Store each byte of data from buffer into result. */ + while (size > 0) + { + + /* Build return value. */ + *value = (*value << 8) | *data++; + size--; + } + + /* Return value. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_server_store_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores a data value in a buffer in standard Network */ +/* format (big endian) where the destination may be unaligned. Up to */ +/* 4 bytes of data are stored, if the size is larger than 4 bytes, the */ +/* remaining bytes are set to zero. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* value Value to store */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcp_send_request Send DHCP request */ +/* _nx_dhcp_add_option Add a DHCP option */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value) +{ + + /* Make sure that data is left justified. */ + switch (size) + { + + case 1: + + value <<= 24; + break; + + case 2: + + value <<= 16; + break; + + case 3: + + value <<= 8; + break; + + default: + break; + } + + /* Store the value. */ + while (size-- > 0) + { + + *data = (UCHAR)((value >> 24) & 0xff); + data++; + value <<= 8; + } +} + +#endif /* NX_DISABLE_IPV4 */ diff --git a/addons/dhcp/nxd_dhcp_server.h b/addons/dhcp/nxd_dhcp_server.h new file mode 100644 index 00000000..bb91b67f --- /dev/null +++ b/addons/dhcp/nxd_dhcp_server.h @@ -0,0 +1,592 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol (DHCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_dhcp_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Dynamic Host Configuration Protocol */ +/* (DHCP) server component, including all data types and external */ +/* references. It is assumed that nx_api.h and nx_port.h have already */ +/* been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_DHCP_SERVER_H +#define NXD_DHCP_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +/* Define the DHCP Server ID that is used to mark the DHCP Server structure as created. */ + +#define NX_DHCP_SERVER_ID 0x44484360UL + + +/* Define the DHCP stack size. */ + +#ifndef NX_DHCP_SERVER_THREAD_STACK_SIZE +#define NX_DHCP_SERVER_THREAD_STACK_SIZE 1024 +#endif + + +/* Define the DHCP stack priority. */ + +#ifndef NX_DHCP_SERVER_THREAD_PRIORITY +#define NX_DHCP_SERVER_THREAD_PRIORITY 2 +#endif + + +/* Define the DHCP packet allocation timeout in timer ticks. */ + +#ifndef NX_DHCP_PACKET_ALLOCATE_TIMEOUT +#define NX_DHCP_PACKET_ALLOCATE_TIMEOUT NX_IP_PERIODIC_RATE +#endif + + +/* Define UDP socket create options. */ + +#ifndef NX_DHCP_TYPE_OF_SERVICE +#define NX_DHCP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_DHCP_FRAGMENT_OPTION +#define NX_DHCP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_DHCP_TIME_TO_LIVE +#define NX_DHCP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_DHCP_QUEUE_DEPTH +#define NX_DHCP_QUEUE_DEPTH 5 +#endif + + +/* Define the server interface subnet mask (DHCP Client standard option). */ + +#ifndef NX_DHCP_SUBNET_MASK +#define NX_DHCP_SUBNET_MASK 0xFFFFFF00UL +#endif + + + +/* Define the client's host name buffer size. */ + +#ifndef NX_DHCP_CLIENT_HOSTNAME_MAX +#define NX_DHCP_CLIENT_HOSTNAME_MAX 32 +#endif + + +/* Define DHCP server's name and buffer size. */ +#ifndef NX_DHCP_SERVER_HOSTNAME_MAX +#define NX_DHCP_SERVER_HOSTNAME_MAX 32 +#endif + +#ifndef NX_DHCP_SERVER_NAME +#define NX_DHCP_SERVER_NAME "NetX DHCP Server" +#endif + + + +/* Define an interval in seconds for the session timer to check the time remaining on + all the active clients in the server database. */ + +#ifndef NX_DHCP_FAST_PERIODIC_TIME_INTERVAL +#define NX_DHCP_FAST_PERIODIC_TIME_INTERVAL 10 +#endif + +/* Set a length of time in seconds in which server can expect a client response during + Client DHCP session. Once a client is BOUND, the session timeout is set + to the IP address lease time. Note the maximum wait time between Client retransmissions + is 64 seconds, so this timeout should be in that neighborhood. Must be greater than + the fast periodic time interva. */ + +#ifndef NX_DHCP_CLIENT_SESSION_TIMEOUT +#define NX_DHCP_CLIENT_SESSION_TIMEOUT (10 * NX_DHCP_FAST_PERIODIC_TIME_INTERVAL) +#endif + + +/* Define an interval in seconds for the IP lease timer to check the time remaining on + all the assigned IP addresses in the server database. */ + +#ifndef NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL +#define NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL 1000 +#endif + + +/* Set the default lease time in seconds on the IP address the server + will assign to the Client. */ + +#ifndef NX_DHCP_DEFAULT_LEASE_TIME +#define NX_DHCP_DEFAULT_LEASE_TIME (10 * NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL) +#endif + + + +/* Set a size of the Server option list requested by the Client. Since the NetX DHCP Server + does not as yet support the complete set of options in DHCP, this number can be optimized + down to a smaller size that the largest possible number of options a Client could request. +*/ + +#ifndef NX_DHCP_CLIENT_OPTIONS_MAX +#define NX_DHCP_CLIENT_OPTIONS_MAX 12 +#endif + + +/* There are optional and required elements of the server option list. + Use the required plus the user configurable option list for the + server list to respond back to the client. +*/ + +/* At the very least, a DHCP server should supply the + Client's subnet mask, router (default gateway) address and dns server. This list must be + space separated. The combined required and optional server options + should be less than NX_DHCP_CLIENT_OPTIONS_MAX. +*/ + +#ifndef NX_DHCP_OPTIONAL_SERVER_OPTION_LIST +#define NX_DHCP_OPTIONAL_SERVER_OPTION_LIST "1 3 6" +#endif + +/* Set the number of default options in the optional server list above. */ +#ifndef NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE +#define NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE 3 +#endif + + +/* The NetX DHCP Server includes its server identifier, message type in all messages. */ +#define NX_DHCP_REQUIRED_SERVER_OPTION_LIST "53 54" +#define NX_DHCP_REQUIRED_SERVER_OPTION_SIZE 2 + +/* Compute the total option list size. */ +#define NX_DHCP_SERVER_OPTION_LIST_SIZE (NX_DHCP_REQUIRED_SERVER_OPTION_SIZE + NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE) + +/* Combine the actual lists maintaining a space between all options. */ +#define NX_DHCP_SERVER_OPTION_LIST NX_DHCP_REQUIRED_SERVER_OPTION_LIST \ + " " \ + NX_DHCP_OPTIONAL_SERVER_OPTION_LIST + + +/* Define the maximum size of each IP address list. Each interface the server assigns + IP addresses for will be limited to this size. */ + +/* Define the max size of an IP addresses list (applies to each interfaces). */ + +#ifndef NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE +#define NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE 20 +#endif + +/* Define the size of client record table (All clients e.g.on all interfaces). */ + +#ifndef NX_DHCP_CLIENT_RECORD_TABLE_SIZE +#define NX_DHCP_CLIENT_RECORD_TABLE_SIZE 50 +#endif + + /* END OF CONFIGURABLE OPTIONS */ + + +/* Define the size of the BOOT buffer. This should be large enough for all the + required DHCP fields plus the minimum requirement of 312 bytes of option data + stated in RFC 2131; 2. Protocol Summary. */ +#ifndef NX_BOOT_BUFFER_SIZE +#define NX_BOOT_BUFFER_SIZE 548 +#endif + +/* Define the size of the DHCP header as per RFC 213 Section Protocol Summery, page 10. */ + +#ifndef NX_DHCP_HEADER_SIZE +#define NX_DHCP_HEADER_SIZE 236 +#endif + + +/* + Define the packet payload size, keeping in mind the DHCP Server must support + at least a 548 byte DHCP Client message as per RFC 2131 and allow room for Ethernet, UDP and + IP headers and 4 byte alignment. +*/ +#ifndef NX_DHCP_MINIMUM_PACKET_PAYLOAD +#define NX_DHCP_MINIMUM_PACKET_PAYLOAD (NX_BOOT_BUFFER_SIZE + NX_PHYSICAL_HEADER + sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER)) +#endif /* NX_DHCP_MINIMUM_PACKET_PAYLOAD */ + + +/* Define the DHCP Message Area Offsets. The DHCP message format is identical to that of BootP, except + for the Vendor options that start at the offset specified by NX_DHCP_OFFSET_OPTIONS. */ + +#define NX_DHCP_OFFSET_OP 0 /* 1 BootP Operation 1=req, 2=reply */ +#define NX_DHCP_OFFSET_HTYPE 1 /* 1 Hardware type 1 = Ethernet */ +#define NX_DHCP_OFFSET_HLEN 2 /* 1 Hardware address length, 6 for Ethernet */ +#define NX_DHCP_OFFSET_HOPS 3 /* 1 Number of hops, usually 0 */ +#define NX_DHCP_OFFSET_XID 4 /* 4 Transaction ID, pseudo random number */ +#define NX_DHCP_OFFSET_SECS 8 /* 2 Seconds since boot */ +#define NX_DHCP_OFFSET_FLAGS 10 /* 2 Flags, 0x80 = Broadcast response, 0 = unicast response */ +#define NX_DHCP_OFFSET_CLIENT_IP 12 /* 4 Initial client IP, used as dest for unicast response */ +#define NX_DHCP_OFFSET_YOUR_IP 16 /* 4 Assigned IP, initialized to 0.0.0.0 */ +#define NX_DHCP_OFFSET_SERVER_IP 20 /* 4 Server IP, usually initialized to 0.0.0.0 */ +#define NX_DHCP_OFFSET_RELAY_IP 24 /* 4 Relay IP, usually 0.0.0.0, only for DHCP */ +#define NX_DHCP_OFFSET_CLIENT_HW 28 /* 16 Client hardware address */ +#define NX_DHCP_OFFSET_SERVER_NM 44 /* 64 Server name, nulls if unused */ +#define NX_DHCP_OFFSET_BOOT_FILE 108 /* 128 Boot file name, null if unused */ +#define NX_DHCP_OFFSET_VENDOR 236 /* 64 Vendor options, set first 4 bytes to a magic number */ +#define NX_DHCP_OFFSET_OPTIONS 240 /* First variable vendor option */ +#define NX_DHCP_OFFSET_END 300 /* End of BOOTP buffer */ +#define NX_DHCP_SERVER_OPTION_ADDRESS_SIZE 4 + +/* Define the DHCP Specific Vendor Extensions. */ + +#define NX_DHCP_SERVER_OPTION_PAD 0 +#define NX_DHCP_SERVER_OPTION_PAD_SIZE 0 +#define NX_DHCP_SERVER_OPTION_SUBNET_MASK 1 +#define NX_DHCP_SERVER_OPTION_SUBNET_MASK_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE +#define NX_DHCP_SERVER_OPTION_TIME_OFFSET 2 +#define NX_DHCP_SERVER_OPTION_TIME_OFFSET_SIZE 4 +#define NX_DHCP_SERVER_OPTION_ROUTER 3 +#define NX_DHCP_SERVER_OPTION_ROUTER_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE +#define NX_DHCP_SERVER_OPTION_TIMESVR 4 +#define NX_DHCP_SERVER_OPTION_DNS_SVR 6 +#define NX_DHCP_SERVER_OPTION_HOST_NAME 12 +#define NX_DHCP_SERVER_OPTION_DNS_NAME 15 +#define NX_DHCP_SERVER_OPTION_NTP_SVR 42 +#define NX_DHCP_SERVER_OPTION_VENDOR_OPTIONS 43 +#define NX_DHCP_SERVER_OPTION_DHCP_IP_REQ 50 +#define NX_DHCP_SERVER_OPTION_DHCP_IP_REQ_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE +#define NX_DHCP_SERVER_OPTION_DHCP_LEASE 51 +#define NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE 4 +#define NX_DHCP_SERVER_OPTION_DHCP_TYPE 53 +#define NX_DHCP_SERVER_OPTION_DHCP_TYPE_SIZE 1 +#define NX_DHCP_SERVER_OPTION_DHCP_SERVER_ID 54 +#define NX_DHCP_SERVER_OPTION_DHCP_SERVER_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE +#define NX_DHCP_SERVER_OPTION_DHCP_PARAMETERS 55 +#define NX_DHCP_SERVER_OPTION_DHCP_MESSAGE 56 +#define NX_DHCP_SERVER_OPTION_RENEWAL 58 +#define NX_DHCP_SERVER_OPTION_RENEWAL_SIZE 4 +#define NX_DHCP_SERVER_OPTION_REBIND 59 +#define NX_DHCP_SERVER_OPTION_REBIND_SIZE 4 +#define NX_DHCP_SERVER_OPTION_CLIENT_ID 61 +#define NX_DHCP_SERVER_OPTION_CLIENT_ID_SIZE 7 +#define NX_DHCP_SERVER_OPTION_FDQN 81 +#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_N 8 +#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_E 4 +#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_O 2 +#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_S 1 +#define NX_DHCP_SERVER_OPTION_END 255 +#define NX_DHCP_SERVER_OPTION_END_SIZE 0 + +#define NX_DHCP_MINIMUM_PACKET (NX_DHCP_OFFSET_END + NX_UDP_PACKET+ 100) + + +/* Define various BootP/DHCP constants. */ + +#define NX_DHCP_SERVER_UDP_PORT 67 +#define NX_DHCP_SERVER_TCP_PORT 67 +#define NX_DHCP_CLIENT_UDP_PORT 68 +#define NX_DHCP_CLIENT_TCP_PORT 68 + +#define NX_DHCP_OP_REQUEST 1 +#define NX_DHCP_OP_REPLY 2 +#define NX_DHCP_FLAGS_BROADCAST 0x80 +#define NX_DHCP_FLAGS_UNICAST 0x00 +#define NX_DHCP_MAGIC_COOKIE IP_ADDRESS(99, 130, 83, 99) +#define NX_DHCP_NO_ADDRESS IP_ADDRESS(0, 0, 0, 0) +#define NX_DHCP_BC_ADDRESS IP_ADDRESS(255, 255, 255, 255) +#define NX_AUTO_IP_ADDRESS IP_ADDRESS(169, 254, 0, 0) +#define NX_AUTO_IP_ADDRESS_MASK 0xFFFF0000UL +#define NX_DHCP_SERVER_INFINITE_LEASE 0xFFFFFFFFUL + + +/* Define the DHCP Message Types. */ + +#define NX_DHCP_TYPE_DHCPDISCOVER 1 +#define NX_DHCP_TYPE_DHCPOFFER 2 +#define NX_DHCP_TYPE_DHCPREQUEST 3 +#define NX_DHCP_TYPE_DHCPDECLINE 4 +#define NX_DHCP_TYPE_DHCPACK 5 +#define NX_DHCP_TYPE_DHCPNACK 6 +#define NX_DHCP_TYPE_DHCPRELEASE 7 +#define NX_DHCP_TYPE_DHCPINFORM 8 +#define NX_DHCP_TYPE_DHCPFORCERENEW 9 +#define NX_DHCP_TYPE_DHCPSILENT 10 + + +/* Define the states of the DHCP state machine. */ + +#define NX_DHCP_STATE_BOOT 1 /* Started with a previous address */ +#define NX_DHCP_STATE_INIT 2 /* Started with no previous address */ +#define NX_DHCP_STATE_SELECTING 3 /* Waiting to identify a DHCP server */ +#define NX_DHCP_STATE_REQUESTING 4 /* Address requested, waiting for the Ack */ +#define NX_DHCP_STATE_BOUND 5 /* Address established, no time outs */ +#define NX_DHCP_STATE_RENEWING 6 /* Address established, renewal time out */ +#define NX_DHCP_STATE_REBINDING 7 /* Address established, renewal and rebind time out */ +#define NX_DHCP_STATE_FORCERENEW 8 /* Address established, force renewal */ + + +/* Define error codes from DHCP Server operation. */ + +#define NX_DHCP_SERVER_ALREADY_STARTED 0x90 /* DHCP Server already started */ +#define NX_DHCP_SERVER_NOT_STARTED 0x91 /* DHCP Server not started when stop was issued */ +#define NX_DHCP_PARAMETER_ERROR 0x92 /* Invalid non pointer input */ +#define NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD 0x93 /* DHCP Server packet pool has inadequate packet payload for DHCP messages. */ +#define NX_DHCP_BAD_OPTION_LIST_ERROR 0x94 /* Server default option list has invalid characters. */ +#define NX_DHCP_INTERNAL_OPTION_PARSE_ERROR 0x95 /* Internal error parsing options from string to ULONG. */ +#define NX_DHCP_NO_SERVER_OPTION_LIST 0x96 /* Server default option list is empty when server is configured to use it. */ +#define NX_DHCP_IMPROPERLY_TERMINATED_OPTION 0x97 /* Improperly formatted client option data e.g missing terminating symbol 0xFF. */ +#define NX_DHCP_ADD_OPTION_ERROR 0x98 /* Unable to add option to buffer of server DHCP response packet */ +#define NX_DHCP_INVALID_IP_ADDRESS_LIST 0x99 /* Invalid start or end IP address list parameter for creating assignable IP address list. */ +#define NX_DHCP_NO_AVAILABLE_IP_ADDRESSES 0x9A /* Server has no available IP addresses for DHCP Clients */ +#define NX_DHCP_INVALID_IP_ADDRESS 0x9B /* Invalid IP address e.g. null address received or obtained from client record. */ +#define NX_DHCP_IP_ADDRESS_NOT_FOUND 0x9C /* No match found for IP address search */ +#define NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER 0x9D /* IP address not assigned to the current client */ +#define NX_DHCP_INVALID_UPDATE_ADDRESS_CMD 0x9E /* Unable to ascertain assigned ip address status (e.g. assign, mark available etc) */ +#define NX_DHCP_CLIENT_RECORD_NOT_FOUND 0x9F /* Unable to find client in Client records table. */ +#define NX_DHCP_CLIENT_TABLE_FULL 0xA0 /* Server unable to add record to client table; table is full. */ +#define NX_DHCP_SERVER_BAD_INTERFACE_INDEX 0xA1 /* Interface index exceeds the NX_MAX_PHYSICAL_INTERFACES limit. */ +#define NX_DHCP_INVALID_HW_ADDRESS 0xA2 /* Invalid hardware address e.g. null or exceeding 6 bytes. */ +#define NX_DHCP_INVALID_NETWORK_PARAMETERS 0xA3 /* Invalid network parameters (subnet, dns server, default gateway/router). */ +#define NX_DHCP_MALFORMED_DHCP_PACKET 0xA4 /* DHCP packet was malformed. */ + + +/* Define DHCP Server event flags. These events are processed by the DHCP Server thread. */ +#define NX_DHCP_SERVER_ALL_EVENTS 0xFFFFFFFFUL /* All DHCP Server event flags. */ +#define NX_DHCP_SERVER_RECEIVE_EVENT 0x00000001UL /* Packet received event. */ +#define NX_DHCP_SERVER_FAST_PERIODIC_EVENT 0x00000002UL /* Fast periodic timer event. */ +#define NX_DHCP_SERVER_SLOW_PERIODIC_EVENT 0x00000004UL /* Slow periodic timer event. */ + + +/* Define Assignable IP status 'commands'. */ + +#define NX_DHCP_ADDRESS_STATUS_NO_ACTION 0x01 /* No change in Client address. */ +#define NX_DHCP_ADDRESS_STATUS_SERVER_ASSIGN 0x02 /* Server will assign IP address to client. */ +#define NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT 0x03 /* Client assigned IP address elesewhere, mark client as owner and IP as not available. */ +#define NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE 0x04 /* Mark client's IP address as available and clear owner field. */ +#define NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER 0x05 /* Mark client's IP address as assigned already (owner unknown). */ + +/* Define types of options to load in server response to DHCP client. */ + +#define NX_DHCP_OPTIONS_FOR_ALL_REPLIES 0x01 +#define NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER 0x02 +#define NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST 0x03 +#define NX_DHCP_OPTIONS_FOR_REPLY_TO_INFORM 0x04 +#define NX_DHCP_OPTIONS_FOR_GENERIC_ACK 0x05 +#define NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT 0x06 + +/* Define the DHCP structure that contains DHCP client information during DHCP session. Note + this is not the same control block as the NX_DHCP_STRUCT in nx_dhcp.h for the NetX DHCP Client + package. */ + +typedef struct NX_DHCP_CLIENT_STRUCT +{ + + UINT nx_dhcp_client_state; /* Client DHCP state: e.g. INIT, BOOT, SELECTING, RENEWING etc */ + UCHAR nx_dhcp_message_type; /* DHCP message type (DISCOVER, REQUEST etc) received from Client. */ + CHAR nx_dhcp_client_name[NX_DHCP_CLIENT_HOSTNAME_MAX]; + /* DHCP Client host name buffer. */ + ULONG nx_dhcp_xid; /* Transaction ID for client DHCP session */ + ULONG nx_dhcp_source_ip_address; /* Source IP of the client DHCP message. */ + ULONG nx_dhcp_destination_ip_address; + /* Destination IP of the client DHCP message. */ + ULONG nx_dhcp_clientip_address; /* "Client IP address" (sometimes called "ci-addr" field). */ + ULONG nx_dhcp_your_ip_address; /* "Your IP address" field in client DHCP message. */ + ULONG nx_dhcp_requested_ip_address;/* IP address requested in client message option. */ + ULONG nx_dhcp_requested_lease_time;/* IP address lease time requested in client message option. */ + ULONG nx_dhcp_assigned_ip_address; /* IP address the Server offers/assigns the client. */ + UINT nx_dhcp_client_iface_index; /* Index into the server interface table matching the DHCP client's packet interface. */ + ULONG nx_dhcp_clientrec_server_ip; /* Next Server IP Address (may be another DHCP server) for advanced DHCP features */ + ULONG nx_dhcp_server_id; /* Requested/assigned Server ID (usually set to DHCP server IP address) */ + ULONG nx_dhcp_router_ip_address; /* Requested/assigned router on DHCP Client network. */ + ULONG nx_dhcp_dns_ip_address; /* Requested/assigned DNS IP address; usually set to zero. */ + ULONG nx_dhcp_relay_ip_address; /* Requested/assigned Relay IP address; usually set to zero. */ + ULONG nx_dhcp_subnet_mask; /* Requested/assigned network mask */ + ULONG nx_dhcp_client_mac_msw; /* Client MAC address high bits */ + ULONG nx_dhcp_client_mac_lsw; /* Client MAC address low bits */ + UINT nx_dhcp_client_hwlen; /* Length of hardware address. */ + UINT nx_dhcp_client_hwtype; /* Client interface hardware type e.g. Ethernet. */ + ULONG nx_dhcp_broadcast_flag_set; /* Parse broadcast flags from DHCP messages. */ + UINT nx_dhcp_client_option_count; /* Number of user options in client request */ + UINT nx_dhcp_user_options[NX_DHCP_CLIENT_OPTIONS_MAX]; + ULONG nx_dhcp_session_timeout; /* Time out on waiting for client's next response */ + UINT nx_dhcp_response_type_to_client; + /* DHCP code for response to send back to client. */ + +} NX_DHCP_CLIENT; + +/* Define the interface address structure which the server will use to assign IP addresses + in a previously specified network interface. */ +typedef struct NX_DHCP_INTERFACE_IP_ADDRESS_STRUCT +{ + ULONG nx_assignable_ip_address; /* IP address available to assign to DHCP Client. */ + UINT assigned; /* IP address status e.g if currently assigned to a client host. */ + UINT lease_time; /* Lease duration in secs. */ + UINT owner_hwtype; /* Hardware type. */ + UINT owner_mac_msw; /* MAC address high bits. */ + UINT owner_mac_lsw; /* MAC address low bits. */ +} NX_DHCP_INTERFACE_IP_ADDRESS; + + +typedef struct NX_DHCP_INTERFACE_TABLE_STRUCT +{ + NX_DHCP_INTERFACE_IP_ADDRESS + nx_dhcp_ip_address_list[NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE]; + /* IP address available to assign to DHCP Client. */ + NX_INTERFACE *nx_dhcp_incoming_interface; /* Pointer to DHCP Server interface. */ + ULONG nx_dhcp_server_ip_address; /* DHCP Server's IP address for this interface. */ + ULONG nx_dhcp_dns_ip_address; /* DHCP server DNS Server Address in message to DHCP Client.. */ + ULONG nx_dhcp_subnet_mask; /* DHCP server interface subnet mask. */ + ULONG nx_dhcp_subnet; /* DHCP server interface subnet. */ + ULONG nx_dhcp_router_ip_address; /* The router IP Address for DHCP client configuration */ + UINT nx_dhcp_address_list_size; /* Actual number of assignable addresses for this interface. */ + +} NX_DHCP_INTERFACE_TABLE; + +/* Define the Interface address list. */ + +/* Define the DHCP structure that contains all the server information necessary for this DHCP + instance. */ + +typedef struct NX_DHCP_SERVER_STRUCT +{ + ULONG nx_dhcp_id; /* DHCP thread ID */ + CHAR nx_dhcp_name[NX_DHCP_SERVER_HOSTNAME_MAX]; + /* DHCP server name buffer */ + NX_PACKET_POOL *nx_dhcp_packet_pool_ptr; /* Pointer to DHCP server packet pool */ + TX_TIMER nx_dhcp_slow_periodic_timer; /* Timer for watching IP lease time outs. */ + TX_TIMER nx_dhcp_fast_periodic_timer; /* Timer for watching session time outs. */ + UCHAR nx_dhcp_started; /* DHCP started flag */ + NX_IP *nx_dhcp_ip_ptr; /* The Server IP Instance */ + TX_THREAD nx_dhcp_server_thread; /* The DHCP server processing thread */ + TX_MUTEX nx_dhcp_mutex; /* Mutex protection for client and interface tables. */ + TX_EVENT_FLAGS_GROUP nx_dhcp_server_events; /* DHCP Server events. */ + UINT nx_dhcp_number_clients; /* Number of clients currently assigned IP address by this server. */ + NX_DHCP_CLIENT client_records[NX_DHCP_CLIENT_RECORD_TABLE_SIZE]; /* Table of DHCP clients.*/ + /* List of IP addresses server can assign to DHCP Clients */ + NX_UDP_SOCKET nx_dhcp_socket; /* DHCP server socket to receive DHCP messages on its interfaces. */ + UINT nx_dhcp_server_options[NX_DHCP_SERVER_OPTION_LIST_SIZE]; + /* List of max number of options in supply data to Client */ + UINT nx_dhcp_server_option_count; /* Actual number of options the server is supplying back to client. */ + + NX_DHCP_INTERFACE_TABLE nx_dhcp_interface_table[NX_MAX_PHYSICAL_INTERFACES]; + /* Interface specific table of addresses available for DHCP clients. */ + ULONG nx_dhcp_discoveries_received; /* The number of Discovery messages received */ + ULONG nx_dhcp_requests_received; /* The number of Request messages received */ + ULONG nx_dhcp_informs_received; /* The number of Inform messages received */ + ULONG nx_dhcp_declines_received; /* The number of Decline messages received */ + ULONG nx_dhcp_releases_received; /* The number of Release messages received */ + +} NX_DHCP_SERVER; + + +#ifndef NX_DHCP_SERVER_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map DHCP API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_dhcp_server_create _nx_dhcp_server_create +#define nx_dhcp_create_server_ip_address_list _nx_dhcp_create_server_ip_address_list +#define nx_dhcp_set_interface_network_parameters _nx_dhcp_set_interface_network_parameters +#define nx_dhcp_server_delete _nx_dhcp_server_delete +#define nx_dhcp_server_start _nx_dhcp_server_start +#define nx_dhcp_server_stop _nx_dhcp_server_stop +#define nx_dhcp_clear_client_record _nx_dhcp_clear_client_record + +#else + +/* Services with error checking. */ + +#define nx_dhcp_server_create _nxe_dhcp_server_create +#define nx_dhcp_create_server_ip_address_list _nxe_dhcp_create_server_ip_address_list +#define nx_dhcp_set_interface_network_parameters _nxe_dhcp_set_interface_network_parameters +#define nx_dhcp_server_delete _nxe_dhcp_server_delete +#define nx_dhcp_server_start _nxe_dhcp_server_start +#define nx_dhcp_server_stop _nxe_dhcp_server_stop +#define nx_dhcp_clear_client_record _nxe_dhcp_clear_client_record +#endif + +/* Define the prototypes accessible to the application software. */ + +UINT nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); +UINT nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); +UINT nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); +UINT nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); +UINT nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); +UINT nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); +UINT nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); + +#else + +/* DHCP source code is being compiled, do not perform any API mapping. */ + + +UINT _nxe_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); +UINT _nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); +UINT _nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); +UINT _nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); +UINT _nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); +UINT _nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); +UINT _nxe_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); +UINT _nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); +UINT _nxe_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); +UINT _nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); +UINT _nxe_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); +UINT _nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); +UINT _nxe_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); +UINT _nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); + + +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* NXD_DHCP_SERVER_H */ diff --git a/addons/dhcp/nxd_dhcpv6_client.c b/addons/dhcp/nxd_dhcpv6_client.c new file mode 100644 index 00000000..3f689710 --- /dev/null +++ b/addons/dhcp/nxd_dhcpv6_client.c @@ -0,0 +1,12222 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6 Client) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_DHCPV6_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include +#include "nx_api.h" +#include "nx_system.h" +#include "nx_ip.h" +#include "nx_ipv6.h" +#include "nx_udp.h" +#include "nxd_dhcpv6_client.h" +#include "tx_timer.h" + +#ifdef FEATURE_NX_IPV6 + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/* Define the address of All DHCP Relay Agents and Servers as per RFC3315. */ +static NXD_ADDRESS All_DHCPv6_Relay_Servers_Address; + +/* Keep the DHCPv6 instance for DAD callback notify. */ +static NX_DHCPV6 *_nx_dhcpv6_DAD_ptr; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_client_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the client DUID to the Client request packet */ +/* based on the Client DUID on record, checking to make sure it does */ +/* not go past the end of the packet payload. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the Client */ +/* DUID in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG message_word; +ULONG available_payload; +UCHAR mac[8]; +UINT i = 0; + + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index; + + /* Check if the largest possible client DUID will fit in the packet buffer. */ + if ((available_payload - 4) < ((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length))) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Build the header from the client DUID. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_op_code)) << 16); + message_word |= (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy first half of the Client DUID option to packet buffer. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); + (*index) += (ULONG)sizeof(UINT); + + /* Build the DUID type and hardware type. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type)) << 16); + message_word |= dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Set up the DUID type and hardware type. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); + (*index) += (ULONG)sizeof(UINT); + + /* Include the 'time' field if this is a Link layer time DUID type. */ + if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Build the time. */ + message_word = dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Set up the time. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + } + + /* Build the link layer address. */ + if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) + { + + /* The length of link layer address is 48 bit. */ + + /* Build the MSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw); + } + else if(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) + { + + /* The length of link layer address is 64 bits. */ + + /* Build the MSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 24); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 16); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw); + } + + /* Build the LSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 24); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 16); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw); + + /* Set up the link layer address. */ + memcpy((buffer_ptr + (*index)), mac, i); + (*index) += i; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_elapsed_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the elapsed time option to the Client request */ +/* packet using the session duration time tracked by the DHCPv6 Client */ +/* thread, and checks to make sure it does not go past the end of the */ +/* packet payload. */ +/* */ +/* Note that the elapsed time is the time from which the Client */ +/* initiates the request to the time the it gets and processes a valid */ +/* server reply. Its accuracy depends on the resolution of the session*/ +/* timer. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the elapsed */ +/* time option in the packet payload*/ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_elapsed_time(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG available_payload; + + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); + + /* Check if the data will fit in the packet buffer. */ + if (available_payload < sizeof(NX_DHCPV6_ELAPSED_TIME)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_code); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_length); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time); + + /* Set up the elapsed time option, in hundredths of seconds. */ + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_elapsed_time), sizeof(NX_DHCPV6_ELAPSED_TIME)); + *index += (ULONG)sizeof(NX_DHCPV6_ELAPSED_TIME); + + /* Swap bytes back. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_code); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_length); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_ia_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the IA address option to the Client request */ +/* packet using the Client IA on record. Also checks to make sure */ +/* adding the IA option does not go past the end of the packet payload.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* index Location into buffer to write data*/ +/* ia_index The index of IA address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_IA_ADDRESS IA address on record is NULL */ +/* NX_DHCPV6_OPTION_NO_DATA No IA option in client record */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the IA address*/ +/* option in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_add_iana Adds the IANA and optionally the */ +/* IA option to Client request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_ia_address(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index, UINT ia_index) +{ + +ULONG message_word; +ULONG available_payload; + + /* Set the IA option length. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length = (6 * sizeof(ULONG)); + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); + + /* Check if the client IA address option will fit in the packet buffer. */ + if (available_payload < (((ULONG)dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length) + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Check that the IA address option has been created. */ + if (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code != NX_DHCPV6_OP_IA_ADDRESS) + { + + /* Missing or invalid IA option and/or data. */ + return NX_DHCPV6_INVALID_IA_DATA; + } + + /* Make sure the IA address block has a non zero IP address. */ + if ((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0] == 0) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1] == 0) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2] == 0) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3] == 0)) + { + + return NX_DHCPV6_INVALID_IA_ADDRESS; + } + + /* If the client has created an address option, apply it to the message. */ + + /* Clear memory to make the first word of the IA option header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Extract the IA data from the client record. */ + message_word = (((ULONG)dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code) << 16); + message_word |= dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy IA data into the packet and update the index into the buffer. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + + /* Add the IPv6 address. */ + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]); + + /* Copy the Client preferred IPv6 address to the packet. */ + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + + /* Swap bytes back. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]); + + /* Add the preferred lifetime and valid lifetime option. */ + if((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) + { + + /* When sending a confirm request, DHCPv6 Client should set its T1,T2,preferred-lifetime and + valid-lifetime to zero, as the server will ignore these fields, RFC3315,page41. */ + memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + } + else + { + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime); + + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + + /* Swap bytes back. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime); + + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the IANA option to the Client request packet */ +/* using the Client IANA on record. Also checks to make sure adding */ +/* the IANA option does not go past the end of the packet payload. If */ +/* exist IA options, it will call the service to add the IA option */ +/* within the IANA option data. It then updates the IANA length field */ +/* for the embedded IA option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the IANA */ +/* option in the packet payload */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_add_ia_address Adds the IA option to buffer */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +UINT status; +UINT temp_index; +UINT ia_index; +UINT ia_length; +ULONG message_word; +ULONG available_payload; + + + /* Initialize the completion status variable. */ + status = NX_SUCCESS; + ia_length = 0; + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index; + + /* Check if the client IANA will fit in the packet buffer. */ + if (available_payload < (((ULONG)dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length) + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Save this location in the buffer. */ + temp_index = *index; + + /* Skip the option code and option lenght of IA_NA, write these option after padding the all IA option. */ + (*index) += (ULONG)sizeof(ULONG); + + /* Add the IA_NA ID. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id); + + /* Add the T1 and T2 option. */ + if((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) + { + + /* When sending a confirm request, DHCPv6 Client should set its T1,T2,preferred-lifetime and + valid-lifetime to zero, as the server will ignore these fields, RFC3315,page41. */ + memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + } + else + { + + /* Adjust the data. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2); + + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2), sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + + /* Swap bytes back. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2); + } + + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Check the IA address status. */ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) + { + + /* Yes, so add one...*/ + status = _nx_dhcpv6_add_ia_address(dhcpv6_ptr, buffer_ptr, index, ia_index); + + /* Was the IA address option get appended successfully? */ + if (status == NX_SUCCESS) + { + + /* Update the IA address to record the IANA option length. */ + ia_length = (UINT)(ia_length + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length + 4); + } + } + } + + /* Clear memory to make the first word of the IA-NA header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Set the IA_NA option code and option length. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code = NX_DHCPV6_OP_IA_NA; + dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length = (USHORT)(ia_length + 12); + + /* Write the IANA opcode and data length into one word. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code)) << 16); + message_word |= dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the word into the packet buffer going to the server. */ + memcpy((buffer_ptr + temp_index), &message_word, sizeof(ULONG)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_option_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the option request option to the Client request */ +/* packet using the internal 'register' in the DHCPv6 Client instance */ +/* for what DHCPv6 options have been set or cleared. Also checks to */ +/* make sure it does not go past the end of the packet payload. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the option */ +/* request in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_option_request(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +USHORT message_word; +USHORT option_list; +USHORT option_length = 0; +UCHAR *option_length_ptr; +ULONG available_payload; + + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); + + /* Check if the option request option will fit in the packet buffer. */ + if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_option_length)) + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Set a local variable for convenience. */ + option_list = dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request; + + /* Update the option code. + Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code); + + /* Copy the option code to the packet. */ + memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code), sizeof(USHORT)); + *index += (ULONG)sizeof(USHORT); + + /* Swap bytes back. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code); + + /* Record the option length pointer and skip it, update the option length after fill the option data. */ + option_length_ptr = buffer_ptr + (*index); + *index += (ULONG)sizeof(USHORT); + + /* Now check to see which options we add as option data: */ + + /* Is the DNS server option requested? */ + if(option_list & NX_DHCPV6_DNS_SERVER_OPTION) + { + + /* Yes, add this option code into the option request data. */ + message_word = NX_DHCPV6_OP_DNS_SERVER; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_word); + + memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); + + /* Update the location of the buffer write pointer. */ + *index += (ULONG)sizeof(SHORT); + option_length = (USHORT)(option_length + sizeof(SHORT)); + } + + /* Is the timeS server option requested? */ + if(option_list & NX_DHCPV6_SNTP_SERVER_OPTION) + { + + /* Yes, add this option code into the option request data. */ + message_word = NX_DHCPV6_OP_SNTP_SERVER; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_word); + + memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); + + /* Update the location of the buffer write pointer. */ + *index += (ULONG)sizeof(SHORT); + option_length = (USHORT)(option_length + sizeof(SHORT)); + } + + /* Is the time zone option requested? */ + if(option_list & NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION) + { + + /* Yes, add this option code into the option request data. */ + message_word = NX_DHCPV6_OP_NEW_POSIX_TIMEZONE; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_word); + + memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); + + /* Update the location of the buffer write pointer. */ + *index += (ULONG)sizeof(SHORT); + option_length = (USHORT)(option_length + sizeof(SHORT)); + } + + /* Is the domain name option requested? */ + if(option_list & NX_DHCPV6_DOMAIN_NAME_OPTION) + { + + /* Yes, add this option code into the option request data. */ + message_word = NX_DHCPV6_OP_DOMAIN_NAME; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_word); + + memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); + + /* Update the location of the buffer write pointer. */ + *index += (ULONG)sizeof(SHORT); + option_length = (USHORT)(option_length + sizeof(SHORT)); + } + + /* Is the fully qualified domain name option requested? + A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND message. + A client that sends the Client FQDN option MUST also include the option in the Option Requst option + if it expects the server to include the Client FQDN option in any responses. RFC4704, Section5, Page7. */ + if(((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) && + (option_list & NX_DHCPV6_CLIENT_FQDN_OPTION)) + { + + /* Yes, add this option code into the option request data. */ + message_word = NX_DHCPV6_OP_CLIENT_FQDN; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_word); + + memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); + + /* Update the location of the buffer write pointer. */ + *index += (ULONG)sizeof(SHORT); + option_length = (USHORT)(option_length + sizeof(SHORT)); + } + + /* Now record and update the option lenght. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_option_length = option_length; + NX_CHANGE_USHORT_ENDIAN(option_length); + memcpy(option_length_ptr, &option_length, sizeof(SHORT)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_server_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the server DUID to the Client request packet */ +/* based on the server DUID on record, checking to make sure it does */ +/* not go past the end of the packet payload. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the server */ +/* DUID in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG message_word; +ULONG available_payload; +UCHAR mac[8]; +UINT i = 0; + + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); + + /* Check if the largest possible server DUID will fit in the packet buffer. */ + if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length)) + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Make sure the Client has a valid Server DUID. */ + if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code != NX_DHCPV6_OP_SERVER_ID) + { + + /* Missing or invalid option data. */ + return NX_DHCPV6_INVALID_SERVER_DUID; + } + + /* Build the header from the client's record of its DHCPv6 Server DUID. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code)) << 16); + message_word |= (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy first half of the Server DUID option to packet buffer. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Build the DUID type and hardware type. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type)) << 16); + message_word |= dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Set up the DUID type and hardware type. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); + *index += (ULONG)sizeof(UINT); + + /* Include the 'time' field if this is a Link layer time DUID type. */ + if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Build the time. */ + message_word = dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Set up the time. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); + (*index) += (ULONG)sizeof(ULONG); + } + + /* Build the link layer address. */ + if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) + { + + /* The length of link layer address is 48 bit. */ + + /* Build the MSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw); + } + else if(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) + { + + /* The length of link layer address is 64 bits. */ + + /* Build the MSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 24); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 16); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw); + } + + /* Build the LSW. */ + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 24); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 16); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 8); + mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw); + + /* Set up the link layer address. */ + memcpy((buffer_ptr + (*index)), mac, i); + (*index) += i; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_client_FQDN PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the DHCPv6 Client FQDN Option to the Client */ +/* request packet , checking to make sure it does not go past the end */ +/* of the packet payload. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the server */ +/* DUID in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Client */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_client_FQDN(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG message_word; +ULONG available_payload; +UINT domain_name_length; + + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); + + /* Check if the largest possible server DUID will fit in the packet buffer. */ + if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length)) + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + memset(&message_word, 0, sizeof(ULONG)); + + /* Set the option code and option length. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_code)) << 16); + message_word |= (dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_length); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Add the option code and option length into packet buffer. */ + memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Add the flags into packet buffer. */ + *(buffer_ptr + (*index)) = dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags; + *index += 1; + + /* Encode the domain name into the packet buffer. */ + domain_name_length = _nx_dhcpv6_name_string_encode(buffer_ptr + (*index), (UCHAR *)dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_domain_name); + *index += domain_name_length; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX create dhcpv6 */ +/* client service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client */ +/* ip_ptr Pointer to Client IP instance */ +/* name_ptr DHCPV6 name pointer */ +/* packet_pool_ptr Pointer to Client packet pool */ +/* stack_ptr Pointer to free memory */ +/* stack_size Size of client stack memory */ +/* dhcpv6_state_change_notify Client state change handler */ +/* dhcpv6_server_error_handler Server error status handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_client_create Actual Client create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +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); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the DHCPv6 Client instance with a Netx packet */ +/* pool, processing thread, and various flag event queues, timers and */ +/* mutexes necessary for DHCPv6 Client operations. Reocrd the DHCPv6 */ +/* pointer for DAD callback function process. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client */ +/* ip_ptr Pointer to Client IP instance */ +/* name_ptr DHCPV6 name pointer */ +/* packet_pool_ptr Pointer to Client packet pool */ +/* stack_ptr Pointer to free memory */ +/* stack_size Size of Client stack memory */ +/* dhcpv6_state_change_notify Client state change handler */ +/* dhcpv6_server_error_handler Server error status handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create ThreadX flag event queue*/ +/* tx_mutex_create Create mutex lock on resource */ +/* nx_packet_pool_delete Delete the DHCPV6 packet pool */ +/* nx_udp_socket_create Create the DHCPV6 UDP socket */ +/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ +/* tx_mutex_create Create DHCPV6 mutex */ +/* tx_mutex_delete Delete DHCPV6 mutex */ +/* tx_thread_create Create DHCPV6 thread */ +/* tx_timer_create Create DHCPV6 timer */ +/* tx_timer_delete Delete DHCPV6 timer */ +/* nxd_ipv6_address_change_notify Set the DAD callback function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +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); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX delete dhcpv6 */ +/* client service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_client_delete Actual DHCPV6 delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 delete service. */ + status = _nx_dhcpv6_client_delete(dhcpv6_ptr); + + /* Return commpletion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DHCPV6 Client instance and releases all */ +/* NetX Duo and ThreadX resources. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Release DHCPV6 UDP socket port*/ +/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ +/* tx_thread_terminate Terminate DHCPV6 thread */ +/* tx_thread_delete Delete DHCPV6 thread */ +/* tx_timer_delete Delete DHCPV6 timers */ +/* tx_mutex_delete Delete DHCPV6 mutexes */ +/* tx_event_flags_delete Delete DHCPV6 flag queue */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr) +{ + + + /* Terminate the DHCPV6 processing thread. */ + tx_thread_terminate(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Delete the DHCPV6 processing thread. */ + tx_thread_delete(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Delete the flag event queue. */ + tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events); + + /* 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)); + + /* Release the UDP socket port. */ + nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_ptr -> nx_dhcpv6_socket)); + + /* Clear the dhcpv6 structure ID. */ + dhcpv6_ptr -> nx_dhcpv6_id = 0; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_create_client_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create Client DUID */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* duid_type Type of DUID (link layer +/- time)*/ +/* hardware_type Network hardware type e.g IEEE 802*/ +/* time Time stamp unique DUID identifier */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* NX_DHCPV6_UNSUPPORTED_DUID_TYPE Unsupported DUID type */ +/* NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE Unsupported DUID hardware type */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_create_client_duid Actual create client DUID service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + + return NX_PTR_ERROR; + } + + /* Check for valid non pointer input. */ + if ((duid_type < NX_DHCPV6_DUID_TYPE_LINK_TIME) || (duid_type > NX_DHCPV6_DUID_TYPE_LINK_ONLY)) + { + return NX_DHCPV6_PARAM_ERROR; + } + + /* Ethernet is the only a hardware type supported by this API. */ + if ((hardware_type != NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) && (hardware_type != NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64)) + { + + /* Return any other type as an error status. */ + return NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE; + } + + /* This DUID type is not supported by this API. */ + if (duid_type == NX_DHCPV6_DUID_TYPE_VENDOR_ASSIGNED) + { + + /* Return as an error status. */ + return NX_DHCPV6_UNSUPPORTED_DUID_TYPE; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_create_client_duid(dhcpv6_ptr, duid_type, hardware_type, time); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_create_client_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCPv6 client DHCP Unique Identifier */ +/* (DUID) with the input values, sets the linklocal address while the */ +/* Client does not have an assigned global IP address, after waiting */ +/* for the IPv6 thread task to read its MAC address. If the caller */ +/* does not supply a time ID, it will generate one in place for Link */ +/* Layer Plus Time DUIDs. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* duid_type Type of DUID (link layer +/- time)*/ +/* hardware_type Network hardware type e.g IEEE 802*/ +/* time Time stamp unique DUID identifier */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* rand Generate random number for time ID*/ +/* tx_thread_sleep Relinquish thread control (sleep) */ +/* nxd_ipv6_linklocal_address_set Use MAC address as temporary IP */ +/* source address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time) +{ + +NX_INTERFACE *interface_ptr; +USHORT option_length; + + + /* Set the interface pointer. */ + interface_ptr = &(dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[dhcpv6_ptr -> nx_dhcpv6_client_interface_index]); + + /* Initialize the DUID to null. */ + memset(&(dhcpv6_ptr -> nx_dhcpv6_client_duid), 0, sizeof(NX_DHCPV6_DUID)); + + /* Assign the DUID op code. */ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_op_code = NX_DHCPV6_OP_CLIENT_ID; + + /* Assign field attributes depending on the DUID type. */ + if ((duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) || (duid_type == NX_DHCPV6_DUID_TYPE_LINK_ONLY)) + { + + /* Set the option data length minus the option header and size of the time field. */ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type = (USHORT)duid_type; + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type = (USHORT)hardware_type; + option_length = 4; + + /* Is the Link Layer Time DUID type? */ + if (duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Yes; add the size of the time field to the data length. */ + option_length = (USHORT)(option_length + 4); + + /* Did the caller supplied a time? */ + if (!time) + { + /* No, create a time field using the defined time constant plus a randomizing factor.*/ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time = (SECONDS_SINCE_JAN_1_2000_MOD_32 + (ULONG)(NX_RAND())) & 0xFFFFFFFF; + } + else + { + /* Apply the input time. */ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time = time; + } + } + + /* Set the globally unique link layer address. */ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw = interface_ptr -> nx_interface_physical_address_msw; + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw = interface_ptr -> nx_interface_physical_address_lsw; + + /* Check the hardware type. */ + if (hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) + { + + /* The length of link layer address is 48 bits. */ + option_length = (USHORT)(option_length + 6); + } + else if (hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) + { + + /* The length of link layer address is 64 bits. */ + option_length = (USHORT)(option_length + 8); + } + + /* Set the option length. */ + dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length = option_length; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_add_client_ia PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the add Client IA */ +/* (Identity Association) option service, including checking for invalid*/ +/* preferred and valid lifetimes. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* ipv6_address Requested IPv6 address */ +/* preferred_lifetime Requested IP lease time before */ +/* address is deprecated */ +/* valid_lifetime Requested IP lease time before */ +/* address is expired */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_add_client_ia Actual add client IA service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, + ULONG preferred_lifetime, ULONG valid_lifetime) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr || !ipv6_address) + { + + return NX_PTR_ERROR; + } + + /* Make sure the IPv6 address valid. */ + if ((ipv6_address -> nxd_ip_address.v6[0] == 0) && + (ipv6_address -> nxd_ip_address.v6[1] == 0) && + (ipv6_address -> nxd_ip_address.v6[2] == 0) && + (ipv6_address -> nxd_ip_address.v6[3] == 0)) + { + + return NX_DHCPV6_INVALID_IA_ADDRESS; + } + + /* Check for valid non pointer input. */ + if (preferred_lifetime > valid_lifetime) + { + + /* Client preferred time must be less than valid time or + server will reject it. */ + return NX_DHCPV6_PARAM_ERROR; + } + + /* Check for an empty IANA instance. */ + if (!dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code) + { + + return NX_DHCPV6_PARAM_ERROR; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_add_client_ia(dhcpv6_ptr, ipv6_address, preferred_lifetime, valid_lifetime); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_client_ia PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the Client Identity Association address with */ +/* the input values. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* ipv6_address Requested IPv6 address */ +/* preferred_lifetime Requested IP lease time before */ +/* address is deprecated */ +/* valid_lifetime Requested IP lease time before */ +/* address is expired */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_REACHED_MAX_IA_ADDRESS No space to record IA address */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, + ULONG preferred_lifetime, ULONG valid_lifetime) +{ +UINT ia_index; + + + /* Perform duplicate address detection. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0] == ipv6_address->nxd_ip_address.v6[0]) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1] == ipv6_address->nxd_ip_address.v6[1]) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2] == ipv6_address->nxd_ip_address.v6[2]) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3] == ipv6_address->nxd_ip_address.v6[3])) + { + + /* The IA address has already exists. */ + return (NX_DHCPV6_IA_ADDRESS_ALREADY_EXIST); + } + } + + /* Find one valid space to set the IA address. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(!dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) + { + + /* Yes, got it. */ + break; + } + } + + if(ia_index < NX_DHCPV6_MAX_IA_ADDRESS) + { + + /* Yes, get it, set the IA address. */ + + /* Initialize the IA-Address to null. */ + memset(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index]), 0, sizeof(NX_DHCPV6_IA_ADDRESS)); + + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; + + /* Set the IA option length - minus the option header. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length = (7 * sizeof(ULONG)) - 4; + + /* Set the IP address parameters as a hint to the server. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_version = NX_IP_VERSION_V6; + COPY_IPV6_ADDRESS(&(ipv6_address -> nxd_ip_address.v6[0]), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0])); + + /* Set the life time parameters as a hint to the server. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime = preferred_lifetime; + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime = valid_lifetime; + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_INITIAL; + + return NX_SUCCESS; + } + else + { + return NX_DHCPV6_REACHED_MAX_IA_ADDRESS; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_create_client_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create Client IA-NA */ +/* option service, including checking for invalid T1 and T2 times. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* IA_ident Interface Association ID */ +/* T1 Requested lease time with server */ +/* assigning IP (renew) */ +/* T2 Requested lease time with any */ +/* other server (rebind) */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_create_client_iana Actual create client IANA service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr || !IA_ident) + { + + return NX_PTR_ERROR; + } + + /* Check for valid non pointer input. */ + if (T1 > T2) + { + + /* Client preferred time must be less than valid time or server will reject it. */ + return NX_DHCPV6_PARAM_ERROR; + } + + + /* Call the actual service. */ + status = _nx_dhcpv6_create_client_iana(dhcpv6_ptr, IA_ident, T1, T2); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_create_client_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the Client's Identity Association for Non */ +/* Temporary Address (IANA) with the input values. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* IA_ident Interface Association ID */ +/* T1 Requested lease time with server */ +/* assigning IP (renew) */ +/* T2 Requested lease time with any */ +/* other server (rebind) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2) +{ + + /* Initialize the IANA to null. */ + memset(&(dhcpv6_ptr -> nx_dhcpv6_iana), 0, sizeof(NX_DHCPV6_IA_NA)); + + /* Assign the IANA attributes. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code = NX_DHCPV6_OP_IA_NA; + dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id = IA_ident; + + /* Set the IANA option data length, minus the option header. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length = 3 * sizeof(ULONG); + + /* Apply the Client's preference for IP renew/rebind times. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = T1; + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = T2; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_client_duid_time_id PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get Client DUID time ID*/ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_id Pointer to DUID time field */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_client_duid_time_id Actual get Client DUID time ID */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !time_id) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_client_duid_time_id(dhcpv6_ptr, time_id); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_client_duid_time_id PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the Client DUID time ID saved to the client */ +/* record. It does not check if the DUID is properly filled out. It is*/ +/* up to the caller to check for a zero value (invalid) time ID. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_id Pointer to DUID time field */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_client_duid_time_id Actual get Client DUID time ID */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id) +{ + + /* The Time field is part of the NX_DHCPV6_DUID struct in the Client record. */ + *time_id = dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time; + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_register_IP_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers the assigned IP address to the IP task, */ +/* which adds the input address to the IP address table.In either case,*/ +/* the address index in the IP address table is recorded to the Client */ +/* record.It will require it if the DHCPv6 Client wants to clear the */ +/* IPv6 address. */ +/* */ +/* Note: the host application should perform address verification */ +/* e.g. Duplicate Address Detection to verify uniqueness of the input */ +/* address. If duplicate address detection is enabled in NetX Duo this */ +/* is done automatically. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_ipv6_address_set Add global address to IP */ +/* tx_mutex_get Get the DHCPv6 mutex */ +/* tx_mutex_put Put the DHCPv6 mutex */ +/* */ +/* CALLED BY */ +/* */ +/* nx_dhcpv6_process Process received packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_register_IP_address(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UINT address_index; +UINT ia_index; + + /* Set the DHCPv6 Client IPv6 addresses. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_INITIAL) + { + + /* Add the address to the IP instance address table. */ + status = nxd_ipv6_address_set(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_interface_index, + &dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address, 64, &address_index); + + /* Check for successful result. */ + if (status == NX_SUCCESS) + { + + /* Get the mutex protection for DHCP client. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + +#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) + + /* Set the IPv6 address status as DAD tentative, the status will be updated in _nx_dhcpv6_ipv6_address_DAD_notify. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_DAD_TENTATIVE; +#else + + /* Set the IPv6 address status as valid. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_VALID; +#endif + + /* Record the address index in the Client record. */ + dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = address_index; + + /* All done! Release the mutex.*/ + tx_mutex_put(&dhcpv6_ptr -> nx_dhcpv6_client_mutex); + } + + } + } + + /* Add the default router. */ + nxd_ipv6_default_router_add(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, &(dhcpv6_ptr-> nx_dhcpv6_server_address), + NX_WAIT_FOREVER, dhcpv6_ptr -> nx_dhcpv6_client_interface_index); + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_IP_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get Client global IP */ +/* address service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* ip_address Pointer to global IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_IP_address Actual get Client global IP */ +/* address service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !ip_address) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_IP_address(dhcpv6_ptr, ip_address); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_IP_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the IP address from the DHCPv6 */ +/* Client record. If the client address is not valid, a null IP */ +/* address is returned and an error status is set. */ +/* */ +/* Note that if the Client has received an IP address from the DHCPv6 */ +/* server the host must register that ddress with NetX Duo by calling */ +/* address with NetX Duo by calling the service nxd_ipv6_address_set. */ +/* Once the address is registered, the host can confirm its address by */ +/* calling nxd_ipv6_address_get. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* ip_address Pointer to NetX Duo address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Returned non zero IP address */ +/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Client not assigned an address */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address) +{ + +UINT status; + + + /* Clear the address buffer. */ + SET_UNSPECIFIED_ADDRESS(&ip_address -> nxd_ip_address.v6[0]); + + /* Initialize the outcome as no address assigned. */ + status = NX_DHCPV6_IA_ADDRESS_NOT_VALID; + + /* Is the client assigned a valid address? */ + if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + /* Yes; return the assigned IP address from the DHCPv6 Client record. */ + COPY_IPV6_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_global_address.nxd_ip_address.v6[0]), + &(ip_address -> nxd_ip_address.v6[0])); + + status = NX_SUCCESS; + } + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_lease_time_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get Client IP lease */ +/* time service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* T1 Pointer to T1 time */ +/* T2 Pointer to T2 time */ +/* preferred_lifetime Pointer to preferred lifetime */ +/* valid_lifetime Pointer to valid lifetime */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_lease_time_data Actual get Client IP lease time */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, + ULONG *valid_lifetime) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !T1 || !T2 || !preferred_lifetime || !valid_lifetime ) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_lease_time_data(dhcpv6_ptr, T1, T2, preferred_lifetime, valid_lifetime); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_lease_time_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the Client's global IP lease times T1 and T2*/ +/* and valid and preferred lifetimes. The address_status input field */ +/* indicates if the IP address on the Client record is valid and */ +/* registered. If so the lease and valid lifetimes are also registered */ +/* with the server (not merely Client preference or left over from an */ +/* expired IP address). */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* T1 Pointer to T1 time */ +/* T2 Pointer to T2 time */ +/* preferred_lifetime Pointer to preferred lifetime */ +/* valid_lifetime Pointer to valid lifetime */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, + ULONG *valid_lifetime) +{ + + /* Initialize data to zero. */ + *T1 = 0; + *T2 = 0; + *valid_lifetime = 0; + *preferred_lifetime = 0; + + /* If the client has a valid IP address status, return the actual lease time data. */ + if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + /* Get the time data from the Client record IA. */ + *T1 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1; + *T2 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; + *preferred_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_preferred_lifetime; + *valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_valid_lifetime; + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_DNS_server_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* index Index into DNS server list */ +/* server_address Pointer to copy address to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* _nx_dhcpv6_get_DNS_server_address Actual get DNS server address */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (dhcpv6_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_DNS_server_address(dhcpv6_ptr, index, server_address); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_DNS_server_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the DNS server address at the specified */ +/* index in the DHCP Client DNS list. The Client DNS server list is */ +/* compiled from DHCP Server messages supplying DNS server address */ +/* data. */ +/* */ +/* Note: the DHCPv6 Client is configured to store up to */ +/* NX_DHCPV6_NUM_DNS_SERVERS DNS server addresses. It is up to the */ +/* caller to supply the index to get each server in the list if there */ +/* is more than one stored. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* index Index into DNS server list */ +/* server_address Pointer to copy address to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_PARAM_ERROR Invalid index supplied */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_DNS_server_address Actual get DNS server address */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) +{ + + + /* Check for a valid input. */ + if (index >= NX_DHCPV6_NUM_DNS_SERVERS) + { + + return NX_DHCPV6_PARAM_ERROR; + } + + /* Store the specified DNS server addresses in the DHCPv6 Client list. */ + COPY_NXD_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[index]), server_address); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_time_server_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* index Index into time server list */ +/* server_address Pointer to copy address to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* _nx_dhcpv6_get_time_server_address Actual get time server address */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (dhcpv6_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_time_server_address(dhcpv6_ptr, index, server_address); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_time_server_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the time server address at the specified */ +/* index in the DHCP Client time list. The Client time server list is */ +/* compiled from DHCP Server messages supplying time server address */ +/* data. */ +/* */ +/* Note: the DHCPv6 Client is configured to store up to */ +/* NX_DHCPV6_NUM_TIME_SERVERS TIME server addresses. It is up to the */ +/* caller to supply the index to get each server in the list if there */ +/* is more than one stored. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* index Index into time server list */ +/* server_address Pointer to copy address to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_PARAM_ERROR Invalid index supplied */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_time_server_address Actual get time server address */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) +{ + + + /* Check for a valid input. */ + if (index >= NX_DHCPV6_NUM_TIME_SERVERS) + { + + return NX_DHCPV6_PARAM_ERROR; + } + + /* Store the specified time server addresses in the DHCPv6 Client list. */ + COPY_NXD_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_time_server_address[index]), server_address); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_other_option_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* option_code Option code of requested data */ +/* buffer Buffer to copy data to */ +/* buffer_length Size of buffer to copy to */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* */ +/* CALLS */ +/* _nx_dhcpv6_get_other_option_data Actual get other option data */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer,UINT buffer_length) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !buffer) + { + return NX_PTR_ERROR; + } + + /* Check for invalid non pointer input. */ + if (!option_code || !buffer_length) + { + + return NX_DHCPV6_PARAM_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_other_option_data(dhcpv6_ptr, option_code, buffer, buffer_length); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_other_option_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the option information requested in the */ +/* input parameter. Note that there are only 2 options which the */ +/* NetX DHCPv6 client supports. Some options have their own specific */ +/* API such as _nx_dhcpv6_get_DNS_server_address. The complete list */ +/* of options is not supported by the NetX Duo DHCPv6 Client. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* option_code Option code of requested data */ +/* buffer Buffer to copy data to */ +/* buffer_length Size of buffer to copy to */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCPV6_UNKNOWN_OPTION Unknown option specified */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copy specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length) +{ + + +UINT length = 0; + + /* Check to see which option data is requested: */ + switch (option_code) + { + + case NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION: + + /* Update the amount of data we are copying into the buffer. */ + length += NX_DHCPV6_TIME_ZONE_BUFFER_SIZE; + + /* Check that we don't overrun the buffer. */ + if (length > buffer_length) + { + return NX_DHCPV6_INVALID_DATA_SIZE; + } + + /* Copy the time zone data to the supplied buffer. */ + memcpy(buffer, dhcpv6_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); + + break; + + + case NX_DHCPV6_DOMAIN_NAME_OPTION: + + /* Update the amount of data we are copying into the buffer. */ + length += NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE; + + /* Check that we don't overrun the buffer. */ + if (length > buffer_length) + { + return NX_DHCPV6_INVALID_DATA_SIZE; + } + + /* Copy the domain name data to the supplied buffer. */ + memcpy(buffer, dhcpv6_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); + break; + + /* Unknown or unsupported option*/ + default: + + return NX_DHCPV6_UNKNOWN_OPTION; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_time_accrued PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get time accrued on */ +/* Client IP lease service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_accrued Pointer to time since IP lease */ +/* assigned (secs) */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_time_accrued Actual get time accrued on Client */ +/* IP address lease service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !time_accrued) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_time_accrued(dhcpv6_ptr, time_accrued); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_time_accrued PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the time accrued on the assigned global IP */ +/* address lease. IP address to verify the address is still valid. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_accrued Pointer to time since IP lease */ +/* assigned (secs) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain exclusive lock on Client */ +/* time accrued variable */ +/* tx_mutex_put Release exclusive lock in Client */ +/* time variable */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued) +{ +UINT ia_index; +UINT found_ia = 0; + + /* Initialize the time accrued to zero. */ + *time_accrued = 0; + + /* Check if the client currently has a valid IP address assigned. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + + /* Yes, got it. */ + found_ia= 1; + break; + } + } + + if(found_ia == 1) + { + + /* Get the time accrued on the IP address lease. */ + *time_accrued = dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued; + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_iana_lease_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get T1 and T2 value */ +/* of IANA option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* T1 Pointer to T1 time */ +/* T2 Pointer to T2 time */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_iana_lease_time Actual get Client IP T1/T2 time */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !T1 || !T2) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_iana_lease_time(dhcpv6_ptr, T1, T2); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_iana_lease_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the T1 and T2 of Client's global IP. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* T1 Pointer to T1 time */ +/* T2 Pointer to T2 time */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2) +{ +UINT ia_index; +UINT found_ia = 0; + + /* Initialize data to zero. */ + *T1 = 0; + *T2 = 0; + + /* Check if the client currently has a valid IP address assigned. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + + /* Yes, got it. */ + found_ia= 1; + break; + } + } + + if(found_ia == 1) + { + + /* Get the time data from the Client record IA. */ + *T1 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1; + *T2 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_valid_ip_address_count PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get valid IP address */ +/* count. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* address_count The count of valid IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_valid_ip_address_count */ +/* Actual get the valid IP count */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !address_count) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_valid_ip_address_count(dhcpv6_ptr, address_count); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_valid_ip_address_count PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the Client's global IP, then record the */ +/* count of valid IP address */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* address_count The count of valid IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count) +{ + +UINT ia_index; + + /* Initialize data to zero. */ + *address_count = 0; + + /* Check if the client currently has a valid IP address assigned. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + + /* Yes, get one, update the count. */ + (*address_count)++; + } + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_get_valid_ip_address_lease_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get valid IP address, */ +/* the preferred lifetime and the valid lifetime by the address index. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* address_index The valid address index */ +/* ip_address Pointer to IP address */ +/* preferred_lifetime Pointer to preferred lifetime */ +/* valid_lifetime Pointer to valid lifetime */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_get_lvalid_ip_address_lease_time */ +/* Actual get Client IP valid address*/ +/* and the lease time of IP */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, + ULONG *preferred_lifetime, ULONG *valid_lifetime) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr || !ip_address || !preferred_lifetime || !valid_lifetime ) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_get_valid_ip_address_lease_time(dhcpv6_ptr, address_index, ip_address, preferred_lifetime, valid_lifetime); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_get_valid_ip_address_lease_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the Client's valid global IP addresses, */ +/* preferred lifetime and valid lifetime by address index. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* address_index The valid address index */ +/* ip_address Pointer to IPv6 address */ +/* preferred_lifetime Pointer to preferred lifetime */ +/* valid_lifetime Pointer to valid lifetime */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, + ULONG *preferred_lifetime, ULONG *valid_lifetime) +{ + +UINT status; +UINT ia_index; +UINT valid_ia_count; + + + /* Initialize data to zero. */ + valid_ia_count = 0; + *valid_lifetime = 0; + *preferred_lifetime = 0; + status = NX_DHCPV6_IA_ADDRESS_NOT_VALID; + + /* Clear the address buffer. */ + SET_UNSPECIFIED_ADDRESS(&ip_address -> nxd_ip_address.v6[0]); + + /* Check if the client currently has a valid IP address assigned. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Skip empty or invalidated addresses. */ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + + if((valid_ia_count++) == address_index) + { + + /* Yes, got it. */ + break; + } + } + } + + if(ia_index < NX_DHCPV6_MAX_IA_ADDRESS) + { + + /* Yes; return the assigned IP address from the DHCPv6 Client record. */ + COPY_IPV6_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), + &(ip_address -> nxd_ip_address.v6[0])); + + /* Set the IP version. */ + ip_address -> nxd_ip_version = NX_IP_VERSION_V6; + + /* Return the preferred lifetime and valid lifetime. */ + *preferred_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime; + *valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime; + + status = NX_SUCCESS; + } + + /* Return. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_IP_lifetime_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is scheduled by the ThreadX scheduler on a user */ +/* configurable time interval. It updates the time accrued since the */ +/* Client was assigned its global IP address so that the DHCP Client */ +/* knows when to renew or rebind its IP address. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr_value Pointer to the DHCPV6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_IP_lifetime_timeout_entry(ULONG dhcpv6_ptr_value) +{ + +NX_DHCPV6 *dhcpv6_ptr; + + + /* Setup DHCPv6 Client pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, dhcpv6_ptr_value) + + /* Check if the DHCPv6 Client has valid IP address assigned and a finite IP + address lease (no point in waiting for an infinite lease to time out!) */ + if ((dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 != NX_DHCPV6_INFINITE_LEASE) && + (dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 != 0)) + { + + /* Update the time remaining on the Client IP address lease. + The current time expressed in units of seconds. */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued += NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL; + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function executes the DHCPV6 Client request. It compiles */ +/* and sends the DHCPv6 request message, and updates the Client record */ +/* with server data. It maintains the DHCPv6 Client state and calls */ +/* the state change callback if one is registered with the DHCPv6 */ +/* Client. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_send_request Send the Client DHCPv6 request */ +/* _nx_dhcpv6_waiting_on_reply Wait for valid DHCPv6 server reply*/ +/* _nx_dhcpv6_request_decline Send the DHCPv6 DECLINE request */ +/* _nx_dhcpv6_register_IP_address Register Client IP address */ +/* _nx_dhcpv6_remove_assigned_address */ +/* Remove Client global IP address */ +/* _nx_dhcpv6_update_retransmit_info Update the retransmit information */ +/* _nx_dhcpv6_send_solicit Send the DHCPv6 solicit message */ +/* _nx_dhcpv6_flush_queue_packets Flush the queue packets */ +/* tx_mutex_get Obtain lock on Client resource */ +/* tx_mutex_put Release lock on Client resourse */ +/* tx_timer_deactivate Deactivate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_thread_entry Processing thread for DHCPv6 */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_process(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UCHAR original_state; + + /* Initialize the DHCPv6 Client status as no errors. */ + dhcpv6_ptr -> nx_status_code = NX_DHCPV6_SUCCESS; + + /* Clear any previous messages from the DHCPv6 server. */ + memset(dhcpv6_ptr -> nx_status_message, 0, NX_DHCPV6_MAX_MESSAGE_SIZE); + + /* Remember the original DHCPv6 state for the changed state callback function. */ + original_state = dhcpv6_ptr -> nx_dhcpv6_state; + + /* Process the DHCPv6 Client for the state it is in. */ + switch (dhcpv6_ptr -> nx_dhcpv6_state) + { + + /* The DHCPv6 remains initial status or DHCPv6 interactive process has completed. + Just clear the timer and message ID. */ + case NX_DHCPV6_STATE_INIT: + case NX_DHCPV6_STATE_BOUND_TO_ADDRESS: + { + + /* Clear the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Flush the queue packets. */ + _nx_dhcpv6_flush_queue_packets(dhcpv6_ptr); + + return; + } + + /* The caller has requested to send a solicit message. */ + case NX_DHCPV6_STATE_SENDING_SOLICIT: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_SOLICIT; + + dhcpv6_ptr -> nx_dhcpv6_solicitations_sent++; + + /* Send the DHCPV6 Solicit message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + /* Make sure the server DUID is cleared. Client should be accepting any server reply. */ + memset(&(dhcpv6_ptr -> nx_dhcpv6_server_duid), 0, sizeof(NX_DHCPV6_DUID)); + + /* Wait for a reply from the server. This will also extract the + server packet information and update the DHCPv6 Client record (and state). */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for processing error or error code sent by server. As per RFC 3315 section 17.1.3, + the Client ignores status errors (e.g. No Addresses Available) from the server, and continues + sending Solicit messages. */ + if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* The retry limit on Solicit messages is exceeded. Set the CLient back to + the INIT state and stop sending solicit messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Request attempt failed. The state change callback if set will be called. */ + } + } + else + { + + if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_NORMAL) + { + /* Server has responded to and accepted the SOLICIT request with an ADVERTISE message. + Move to the next state to continue the DHCPv6 protocol. */ + + /* Set the DHCP Client state to Requesting. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; + + /* Reset the retransmission timeout and retry. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Increment the number of solicitation responses. */ + dhcpv6_ptr -> nx_dhcpv6_solicitation_responses++; + } + else + { + + /* Server sending the REPLY message responded to and accepted the SOLICIT request with Rapid Commit option, + Move to the next state to continue the DHCPv6 protocol. */ + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Increment the number of solicitation responses. */ + dhcpv6_ptr -> nx_dhcpv6_solicitation_responses++; + + /* Clear the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Set the DHCP Client state to Requesting. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + + /* Yes, get the IPv6 address by DHCPv6. set it. */ + status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); + + } + + } + + break; + } + + + /* The DHCP Client is in the REQUEST state; send the Request message till the server responds + or the number of retries exceeds the max. */ + case NX_DHCPV6_STATE_SENDING_REQUEST: + { + + /* Reset the initial timeout and zero out transmission count. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_REQUEST; + + /* Transmit the Request message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for transmission error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + dhcpv6_ptr -> nx_dhcpv6_requests_sent++; + + /* Send the message to the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error or Server error code. */ + if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Check the status. */ + if ((status == NX_SUCCESS) && + ((dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NOT_ON_LINK) || + (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_ADDRESS_AVAILABLE))) + { + + /* Indicate the DHCP Client process is idle. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Clear the assigned IP address. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr,NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* When the client receives a NotOnLink status from the server in response to a Request, + the client can restart the DHCP server discovery process. RFC3315, Section18.1.8, Page48. */ + _nx_dhcpv6_request_solicit(dhcpv6_ptr); + } + + else + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* The retry limit on Request messages is exceeded. Set the Client back to + the INIT state and stop sending request messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Request attempt failed. The state change callback if set will be called. */ + } + } + } + else + { + + /* The Server responded to and accepted the REQUEST message. The Client is now bound to assigned + IPv6 address. The Client must still register this IPv6 address with NetX Duo to verify it is + unique on the network. */ + + /* Clear the time accrued on the new IP lease to zero. */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Increment the number of Request responses received. */ + dhcpv6_ptr -> nx_dhcpv6_request_responses++; + + /* Indicate the Client is bound to an assigned IPv6 address. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + + /* Yes, get the IPv6 address by DHCPv6. set it. */ + status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); + } + + break; + } + + /* The caller has requested a RENEW request message be sent. */ + case NX_DHCPV6_STATE_SENDING_RENEW: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_RENEW; + + dhcpv6_ptr -> nx_dhcpv6_renews_sent++; + + /* Send the DHCPV6 RENEW message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for transmission error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + /* Send the message to the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error or Server error code. */ + if ((status != NX_SUCCESS) || + (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS) || + ((dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) == 0)) + { + + /* Process the NoBinding status. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_BINDING)) + { + + /* When the client receives a Reply message in response to a Renew or Rebind message, + send a Request message if the IA contains a Status Code option with the NoBinding status. + RFC 3315, Sectoon 18.1.8, Page 48. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; + + /* Reset the retransmission timeout and retry. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + } + else + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* Clear the assigned IP address. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* The retry limit on Renew messages is exceeded. Set the Client back to + the INIT state and stop sending Renew messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Renew attempt failed. The state change callback if set will be called. */ + } + } + } + else + { + + /* The Server responded to and accepted our RENEW request. Update the Client to a bound + state and reset the lease timers. */ + + /* Indicate the Client is bound to an assigned IPv6 address. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + + /* Reset the time keeper! */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Yes, get the IPv6 address by DHCPv6. set it. */ + status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); + + /* Increment the number of renew responses received. */ + dhcpv6_ptr -> nx_dhcpv6_renew_responses++; + } + + break; + } + + /* The caller has requested to send a rebind request message. */ + case NX_DHCPV6_STATE_SENDING_REBIND: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_REBIND; + + /* Increase the count of retries. */ + dhcpv6_ptr -> nx_dhcpv6_rebinds_sent++; + + /* Send the DHCPV6 Rebind message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for socket send error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + /* Make sure the server DUID is cleared. Client should be accepting any server reply. */ + memset(&(dhcpv6_ptr -> nx_dhcpv6_server_duid), 0, sizeof(NX_DHCPV6_DUID)); + + /* Send the message to the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error or Server error code. */ + if ((status != NX_SUCCESS) || + (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS) || + ((dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) == 0)) + { + + /* Process the NoBinding status. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_BINDING)) + { + + /* When the client receives a Reply message in response to a Renew or Rebind message, + send a Request message if the IA contains a Status Code option with the NoBinding status. + RFC 3315, Section 18.1.8, Page 48. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; + + /* Reset the retransmission timeout and retry. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + } + else + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* Clear the assigned IP address. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* The retry limit on Rebind messages is exceeded. Set the Client back to + the INIT state and stop sending Rebind messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Rebind attempt failed. The client state change callback if set will be called. */ + } + } + } + else + { + + /* Make sure the Client state is set to Bound to an assigned IPv6 address. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + + /* Reset the time keeper! */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Yes, get the IPv6 address by DHCPv6. set it. */ + status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); + + /* Increment the number of rebind responses received. */ + dhcpv6_ptr -> nx_dhcpv6_rebind_responses++; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + } + + break; + } + + case NX_DHCPV6_STATE_SENDING_CONFIRM: + { + + /* Set the message type. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_CONFIRM; + + /* Increase the count of retries. */ + dhcpv6_ptr -> nx_dhcpv6_confirms_sent++; + + /* Send the DHCPV6 Confirm message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Send the message until we get a reply from the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error or Server error code. */ + if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NOT_ON_LINK)) + { + + /* Indicate the DHCP Client process is idle. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Clear the assigned IP address. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr,NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* When the client receives a NotOnLink status from the server in response to a Confirm messag, + the client performs DHCP server solicitation. RFC3315, Section18.1.8, Page48. */ + _nx_dhcpv6_request_solicit(dhcpv6_ptr); + } + + /* Retransmit the Confirm message. */ + else + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* The retry limit on Confirm messages is exceeded. Set the Client back to + the INIT state and stop sending rebind messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Confirm request failed. The state change callback if set will be called. */ + } + } + } + else + { + + /* Successful confirmation. Set the assigned address status to valid (confirmed). */ + + /* Yes, get the IPv6 address by DHCPv6. set it. */ + status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); + + /* Increment the number of responses to confirm. */ + dhcpv6_ptr -> nx_dhcpv6_confirm_responses++; + + /* Restore the Client state depending on its IANA address status. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + } + + break; + + } + + case NX_DHCPV6_STATE_SENDING_RELEASE: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_RELEASE; + + /* Increase the count of releases. */ + dhcpv6_ptr -> nx_dhcpv6_releases_sent++; + + /* Send the DHCPV6 Release message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for socket error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + /* Send the message to the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error. For the release message, consider the release + request completed if the server responds, regardless of Server error code. RFC 3315 Section 18.1.8 */ + if (status != NX_SUCCESS) + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* Clear global ip address and lifetime parameters from the Client record. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* The retry limit on release messages is exceeded. Set the Client back to + the INIT state and stop sending rebind messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* No response to release message from server. The state change callback if set will be called. */ + } + } + else + { + /* Increment the number of responses to release request. */ + dhcpv6_ptr -> nx_dhcpv6_release_responses++; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Clear global ip address and lifetime parameters from the Client record. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* Update the Client state to not bound. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + } + + break; + } + + case NX_DHCPV6_STATE_SENDING_DECLINE: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_DECLINE; + + /* Increase the count of declines. */ + dhcpv6_ptr -> nx_dhcpv6_declines_sent++; + + /* Send the DHCPV6 Decline message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for interal error. */ + if (status != NX_SUCCESS) + { + + /* Return. Can't do any more now. */ + return; + } + + /* Send the message to the server. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error. For the decline message, consider the release + request completed if the server responds, regardless of Server error code. RFC3315,Section 18.1.7 */ + if (status != NX_SUCCESS) + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* Clear global ip address and lifetime parameters from the Client record. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* The retry limit on decline messages is exceeded. Set the Client back to + the INIT state and stop sending rebind messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* No response to decline message from server. The state change callback if set will be called. */ + } + } + else + { + + /* Increment the number of server responses to Decline request. */ + dhcpv6_ptr -> nx_dhcpv6_decline_responses++; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Clear global ip address and lifetime parameters from the Client record. */ + status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + /* Change the DHCPv6 Client to the unbound state. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + } + + break; + } + + case NX_DHCPV6_STATE_SENDING_INFORM_REQUEST: + { + + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST; + + /* Increase the count of declines. */ + dhcpv6_ptr -> nx_dhcpv6_inform_req_sent++; + + /* Send the Inform Request message. */ + status = _nx_dhcpv6_send_request(dhcpv6_ptr); + + /* Check for transmission error. */ + if (status != NX_SUCCESS) + { + + /* Return. Nothing more to do. */ + return; + } + + /* Wait for a reply from the server. This will also extract the + server packet information and update the DHCPv6 Client state. */ + status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); + + /* Check for socket receive error or Server error code. */ + if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Update the retransmission information. */ + if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) + { + + /* The retry limit on decline messages is exceeded. Set the Client back to + the INIT state and stop sending rebind messages for now. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + } + } + else + { + /* Increment the number of responses to Inform Request received. */ + dhcpv6_ptr -> nx_dhcpv6_inform_req_responses++; + + /* The next sending packet is the new packet, so reset the message id. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; + + /* Receive the correct response, so deactivate the session timer of elapsed time. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Restore the Client state depending on its IANA address status. */ + if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; + } + else + { + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + } + } + + break; + } + + default: + { + + /* Unknown or unsupported DHCPv6 request (state). */ + return; + } + } + + /* Is there a state change callback registered with the Client? */ + if ((dhcpv6_ptr -> nx_dhcpv6_state_change_callback) && (original_state != (dhcpv6_ptr -> nx_dhcpv6_state))) + { + + /* Yes, call the the state change callback with the original and new state. */ + (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_client_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the client DUID from the server reply and */ +/* verifies that it matches the Client DUID on record. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_CLIENT_DUID Client DUID is missing data or */ +/* does not match the DUID on record*/ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_data Parses data from specified buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts server reply from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +ULONG data; +UINT index; + + + /* Set an index past the option code and data length. */ + index = 4; + + /* The Client should already have its own DUID on record. So just parse the + data and compare each DUID field with the Client's DUID. */ + + /* Extract the DUID type which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); + + /* Does this match the Client DUID type on record? */ + if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type)) + { + + /* No, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + index += 2; + + /* Extract the hardware type which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); + + /* Does this match the Client DUID hardware type on record? */ + if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type)) + { + + /* No, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + index += 2; + + /* IS this a link layer plus time DUID type? */ + if ((dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type) == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Yes; Extract the time which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); + + /* Does this match the Client DUID time on record? */ + if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time)) + { + + /* No, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + index += 4; + } + + /* Check the hardware type to extract the MSW. */ + if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) + { + + /* The length of link layer address is 48 bits. */ + + /* Yes; Extract the link local address msw which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); + index += 2; + } + else if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) + { + + /* The length of link layer address is 64 bits. */ + + /* Yes; Extract the link local address msw which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); + index += 4; + } + + /* Does this match the Client DUID link layer most significant bytes on record? */ + if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw)) + { + + /* No, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + /* Yes; Extract the link local address lsw which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); + index += 4; + + /* Does this match the Client DUID link layer least significant bytes on record? */ + if (data != ((dhcpv6_ptr -> nx_dhcpv6_client_duid).nx_link_layer_address_lsw)) + { + + /* No, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + /* Are we past the end of the buffer, subtracting for the toplevel opcode and + length of the IANA option? */ + if (((index - 4) > length) || ((index - 4) < length)) + { + + /* Yes, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_CLIENT_DUID; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_domain_name PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the domain name option from the server reply.*/ +/* It will save as much of the domain name that will fit in the Client */ +/* domain name buffer. Buffer size is user configurable. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts DHCPv6 options from */ +/* server reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_domain_name(NX_DHCPV6 *dhcpv6_ptr, UCHAR *packet_start, UCHAR *received_buffer, UINT length) +{ + +UINT domain_name_length; +UINT temp_length; +UCHAR *domain_name_ptr; +UCHAR *buffer_prepend_ptr; +UINT buffer_size; +UINT i; + + + /* Initialize the value. */ + domain_name_length = 0; + temp_length = 0; + domain_name_ptr = received_buffer + 4; + buffer_prepend_ptr = &dhcpv6_ptr -> nx_dhcpv6_domain_name[0]; + buffer_size = NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE; + + /* Process the domain search list options. */ + while(temp_length < length) + { + + /* Calculate the domain name length in the Domaim Search List option,include the null flag '\0'. */ + for (i = 0; (i + temp_length < length) && (domain_name_ptr[i] != '\0'); i++); + + if (i + temp_length == length) + { + return(NX_DHCPV6_PROCESSING_ERROR); + } + else + { + temp_length += (i + 1); + } + + /* Record the real domain name and return the length, one less for NULL termination. */ + domain_name_length = _nx_dhcpv6_name_string_unencode(packet_start, (UINT)(domain_name_ptr - packet_start), buffer_prepend_ptr, (UINT)((buffer_size - 1) & 0xFFFFFFFF)); + + /* Check the domain name length. */ + if(!domain_name_length) + { + + /* Process error, return. */ + return NX_DHCPV6_PROCESSING_ERROR; + } + + else + { + + /* Update the buffer value,include the null flag '\0'. */ + domain_name_ptr += temp_length; + buffer_prepend_ptr += (domain_name_length + 1); + buffer_size -= (domain_name_length + 1); + } + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_name_string_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a string containing the name as a list of */ +/* labels separated by dots to the encoded list of labels specified */ +/* in RFC1035 for DNS servers. This conversion doesn't handle */ +/* compression and doesn't check on the lengths of the labels or the */ +/* entire name. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* count Count of characters encoded */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_add_client_FQDN Add FQDN Option to DHCPv6 packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_name_string_encode(UCHAR *ptr, UCHAR *name) +{ + +UCHAR *length; +UINT count = 1; + + + /* Point to the first character position in the buffer. This will point + to the length of the following name. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + + /* Move through string, copying bytes and updating length. + Whenever a "." is found, start a new string by updating the + pointer to the length and setting the length to zero. */ + while (*name) + { + + /* Is a dot been found? */ + if (*name == '.') + { + + /* Yes, setup a new length pointer. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + name++; + } + else + { + + /* Copy a character to the destination. */ + *ptr++ = *name++; + + /* Adjust the length of the current segment. */ + (*length)++; + } + + /* Increment the total count here. */ + count++; + } + + /* Add the final zero length, like a NULL terminator. */ + *ptr = 0; + + /* Increment the total count. */ + count++; + + /* Return the count. */ + return(count); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_name_string_unencode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts from the encoded list of labels as specified */ +/* in RFC 1035 to a string containing the name as a list of labels */ +/* separated by dots. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer to decode */ +/* start Location of start of data */ +/* buffer Pointer to decoded data */ +/* size Size of data buffer to decode */ +/* */ +/* OUTPUT */ +/* */ +/* Size of decoded data */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process_domain_name Process the domain name */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_name_string_unencode(UCHAR *data, UINT start, UCHAR *buffer, UINT size) +{ + +UCHAR *character = data + start; +UINT length = 0; + + + /* As long as there is space in the buffer and we haven't + found a zero terminating label */ + while ((size > length) && (*character != '\0')) + { + + UINT labelSize = *character++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_DHCPV6_LABEL_MAX) + { + + /* Simple count, check for space and copy the label. */ + while ((size > length) && (labelSize > 0)) + { + + *buffer++ = *character++; + length++; + labelSize--; + } + + /* Now add the '.' */ + *buffer++ = '.'; + length++; + } + else if ((labelSize & NX_DHCPV6_COMPRESS_MASK) == NX_DHCPV6_COMPRESS_VALUE) + { + + /* This is a pointer, just adjust the source. */ + character = data + ((labelSize & NX_DHCPV6_LABEL_MAX) << 8) + *character; + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + + /* Validate the length. */ + if (length == 0) + { + return(length); + } + + /* Done copying the data, set the last . to a trailing null */ + if (*(buffer - 1) == '.') + { + + buffer--; + length --; + } + + /* Null terminate name. */ + *buffer = '\0'; + + /* Return name size. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_DNS_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the DNS server option from the server reply. */ +/* It will save as many DNS name server addresses as are in the reply */ +/* for which the Client is configured to save. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_OPTION_DATA DNS server option missing data or */ +/* improperly formatted */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts DHCPv6 options from */ +/* server reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT index; +UINT w, j; + + + /* Set the location of the read pointer into the buffer. */ + index = 4; + j = 0; + + /* Loop through the length of the buffer to parse. */ + while ((index - 4) < length) + { + + /* Set the IP version. */ + dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; + + /* Get the next IPv6 DNS server address. */ + for (w = 0; w <= 3; w++) + { + + /* Is the DHCPv6 Client configured to store another DNS server address? */ + if (j < NX_DHCPV6_NUM_DNS_SERVERS) + { + + /* Yes; copy the next word into the current DNS server address. */ + memcpy(&(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_address.v6[w]), + (received_buffer + index), sizeof(ULONG)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_address.v6[w]); + } + + /* Move to the next IPv6 address word. */ + index += 4; + } + + dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; + + /* Get the next DNS server address in the reply buffer. */ + j++; + } + + /* Is there any more data in the buffer? */ + if (((index - 4 ) > length) || ((index - 4 )< length)) + { + + /* Yes, not sure what is going on with this packet. Treat as an error. */ + return NX_DHCPV6_INVALID_OPTION_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_ia PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the IA address option from the server reply. */ +/* It also checks that the server preferred and valid lifetimes are */ +/* legitamate. If the IANA option contains an IA option, that will also*/ +/* be processed as well as any status code options. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Size of server reply buffer */ +/* ia_index The index of IA address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_IA_DATA IA option is missing data or */ +/* improperly formatted */ +/* NX_DHCPV6_INVALID_IA_TIME IA option lifetime data is invalid*/ +/* NX_DHCPV6_UNKNOWN_OPTION Unkonw option type */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Get the option code and length */ +/* _nx_dhcpv6_process_status Processes STAUTS in reply buffer */ +/* nx_dhcpv6_server_error_handler Pointer to error code handler */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process_iana Processes IANA in reply buffer */ +/* DHCPv6 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_ia(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length, UINT ia_index) +{ + +ULONG preferred_lifetime; +ULONG valid_lifetime; +UINT index, w; +UINT status; +ULONG opcode, option_length; + + + /* Fill in the IA address code and length. Client might already have one on + record, but use the server's data instead. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; + + /* Set the index for the read pointer past the option header. */ + index = 4; + + for (w = 0; w <= 3; w++) + { + + /* Copy each IPv6 address word into the IA address. */ + memcpy(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[w]), + (received_buffer + index), sizeof(ULONG)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[w]); + + /* Move to the next IPv6 address word. */ + index += 4; + + /* Check if we're going past the end of the option data. */ + if ((index - 4) > length) + { + /* Yes, return an error status.*/ + return NX_DHCPV6_INVALID_IA_DATA; + } + } + + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* Copy the lifetime data from the reply buffer to temporary variables.*/ + memcpy(&preferred_lifetime, (received_buffer + index), sizeof(ULONG)); + index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(preferred_lifetime); + + memcpy(&valid_lifetime, (received_buffer + index), sizeof(ULONG)); + index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(valid_lifetime); + + /* Check for invalid lifetime data. The preferred lifetime MUST be less than + the valid lifetime. Note that a zero lifetime is acceptable + (the server is letting the Client use its own preference). */ + if (preferred_lifetime > valid_lifetime) + { + /* Discard this address. We cannot use it. */ + return NX_DHCPV6_INVALID_IA_TIME; + } + + /* OK to assign time data to the client. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime = preferred_lifetime; + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime = valid_lifetime; + + /* Update the address status. */ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_INVALID) + { + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_INITIAL; + } + + /* Update the map status, 0xFFFFFFFF indicate the IPv6 address of IA option has been processed. */ + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map = 0xFFFFFFFF; + + /* Check if we're at the end of option data yet. */ + if (index - 4 == length) + { + + /* Yes, all done. */ + return NX_SUCCESS; + } + + /* Process the status code option. */ + status = _nx_dhcpv6_utility_get_block_option_length(received_buffer + index, &opcode, &option_length); + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Check if this is an IAaddr status option request. */ + if (opcode == NX_DHCPV6_OP_STATUS_CODE) + { + /* The IAaddr option returned by the DHCPv6 server includes a status option. */ + + /* Process the status. */ + status = _nx_dhcpv6_process_status(dhcpv6_ptr, (received_buffer + index), option_length); + + /* Now check on the server status of the previous option in the DHCP message. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Does the dhcpv6 client have a server error handler? */ + if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) + { + + /* Call the error handler with status code, option (IAaddr) and which message type it refers to. */ + dhcpv6_ptr -> nx_dhcpv6_server_error_handler(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_ADDRESS, dhcpv6_ptr -> nx_status_code, + dhcpv6_ptr -> nx_dhcpv6_received_message_type); + } + } + + /* Check for errors processing the DHCPv6 message. */ + if (status != NX_SUCCESS) + { + + /* Abort further processing. Return error status. */ + return status; + } + } + + else + { + return NX_DHCPV6_UNKNOWN_OPTION; + } + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + + /* Check if we went past the reported size of IA address data. */ + if ((index - 4) != length) + { + + /* Return an error status. Cannot accept this reply. */ + return NX_DHCPV6_INVALID_IA_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the IANA option from the server reply. It */ +/* verifies the IANA option ID matches the IANA option ID on client */ +/* record. It also checks that the server T1 and T2 lease times are */ +/* legitamate. If the IANA option contains an IA option, that will also*/ +/* be processed as well as any status code options. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_BAD_IANA_ID IANA option ID does not match IANA*/ +/* option on client record */ +/* NX_DHCPV6_INVALID_IANA_TIME IANA T1 and T2 values are invalid */ +/* NX_DHCPV6_STATE_IP_FAILURE Indicates server rejected IANA/IA */ +/* NX_DHCPV6_INVALID_IANA_DATA IANA option is missing data or */ +/* improperly formatted */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_data Parses data from reply buffer */ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Parses option header from buffer */ +/* _nx_dhcpv6_process_ia Process IA option in reply buffer */ +/* _nx_dhcpv6_process_status Process status option in buffer */ +/* nx_dhcpv6_server_error_handler Pointer to server error code handler*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts server reply from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT status; +ULONG T1, T2, data; +UINT index; +ULONG opcode, option_length; +UINT ia_index; +UINT ia_count = 0; +UINT ia_status; + + + /* Set up the location of the read pointer past option header. */ + index = 4; + + /* The first word should contain the IANA option code and its option data length. */ + memcpy(&data, (received_buffer + index), sizeof(ULONG)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(data); + + /* The server response must return the correct IANA ID; this is applicable + to clients configured with more than one IANA. */ + if (data != (dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id)) + { + + /* IANA does not match. */ + return NX_DHCPV6_BAD_IANA_ID; + } + + /* Update the write location index. */ + index += 4; + + /* Copy T1 and T2 from the buffer into temporary variables. */ + memcpy(&T1, (received_buffer + index), sizeof(ULONG)); + index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(T1); + + memcpy(&T2, (received_buffer + index), sizeof(ULONG)); + index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(T2); + + /* Check for invalid T1/T2 lifetimes. */ + if (T1 > T2) + { + + /* Reject the server DHCPv6 response. */ + return NX_DHCPV6_INVALID_IANA_TIME; + } + + /* Record the T1 and T2. */ + /* Yes, the server will let the Client use its own T1 time? */ + if (T1 != 0) + { + + /* Now, assign the server T1 to the client IA-NA. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = T1; + } + + /* Yes,the server will let the Client use its own T2 time? */ + if (T2 != 0) + { + /* Now, assign the server T2 to the client IA-NA. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = T2; + } + + /* Check if we're at the end of option data yet. */ + if (index == length) + { + + /* Yes, all done. */ + return NX_SUCCESS; + } + + /* If the reply message includes IA address option, clear the record. */ + if(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) + { + + /* Clear the IA address table according to the address map value. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* The reply message does not include this IA option.*/ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == 0) + { + + /* Clear it. */ + status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, ia_index); + } + } + } + + /* Now we recurse into the options embedded in the IANA option. */ + do + { + + /* Get the next option code and length. */ + status = _nx_dhcpv6_utility_get_block_option_length((received_buffer + index), &opcode, &option_length); + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Check if this is an IA address option request. */ + if (opcode == NX_DHCPV6_OP_IA_ADDRESS) + { + + /* Set the ia count to record the IA option of reply message. */ + ia_count ++; + ia_status = 0; + + /* First, find the same IPv6 address. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* The IPv6 address is new,so find the empty space to record it. */ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == ia_count) + { + + /* Yes, find it, update the IA option. */ + status = _nx_dhcpv6_process_ia(dhcpv6_ptr, (received_buffer + index), option_length, ia_index); + + /* Check the process status. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Yes, set success. */ + ia_status = 1; + + break; + } + } + + /* Record the IA option failure. */ + if(ia_status == 0) + { + + /* Second, find one empty IA to record it. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* The IPv6 address is new,so find the empty space to record it. */ + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == 0) + { + + /* Yes, it is available, update the IA option. */ + status = _nx_dhcpv6_process_ia(dhcpv6_ptr, (received_buffer + index), option_length, ia_index); + + /* Check the process status. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + break; + } + } + } + } + + /* Check if this is an IAaddr status option request. */ + if (opcode == NX_DHCPV6_OP_STATUS_CODE) + { + /* The IAaddr option returned by the DHCPv6 server includes a status option. */ + + /* Process the status. */ + status = _nx_dhcpv6_process_status(dhcpv6_ptr, (received_buffer + index), option_length); + + /* Now check on the server status of the previous option in the DHCP message. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Does the dhcpv6 client have a server error handler? */ + if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) + { + + /* Call the error handler with status code, option (IA_NA) and which message type it refers to. */ + dhcpv6_ptr -> nx_dhcpv6_server_error_handler(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_NA, dhcpv6_ptr -> nx_status_code, + dhcpv6_ptr -> nx_dhcpv6_received_message_type); + } + } + + /* Check for errors processing the DHCPv6 message. */ + if (status != NX_SUCCESS) + { + + /* Abort further processing. Return error status. */ + return status; + } + } + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + + } while ((index - 4) < length); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_preference PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the preference option from the server reply. */ +/* It will save as much of the time zone that will fit in the Client */ +/* time zone buffer. Buffer size is user configurable. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_PREF_DATA Preference option is missing data */ +/* or improperly formatted */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts DHCPv6 options from */ +/* server reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_preference(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT index; +USHORT temp; + + + /* Fill in the option code and length. */ + dhcpv6_ptr -> nx_dhcpv6_preference.nx_op_code = NX_DHCPV6_OP_PREFERENCE; + dhcpv6_ptr -> nx_dhcpv6_preference.nx_option_length = (USHORT)length; + + /* Set the location of the read pointer into the buffer. */ + index = 4; + + /* set local variable for convenience. */ + temp = *(received_buffer + index); + + /* Get the server preference field, and apply to the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = temp; + + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value); + + /* Update the pointer past the data we just extracted. */ + index++; + + /* Is there any more data in this option? */ + if (((index - 4) > length) || ((index - 4) < length)) + { + + /* Yes, but there shouldn't be. Return as an error status. */ + return NX_DHCPV6_INVALID_PREF_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_server_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the server DUID from the server reply and, */ +/* if the Client already has a DHCPv6 server on record, verifies that */ +/* it matches the Client's server DUID. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to server reply */ +/* length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_SERVER_DUID Server DUID is missing data or */ +/* does not match the DUID on record*/ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_data Parses data from specified buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts server reply from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT index; +ULONG temp_type; +ULONG temp_hardware_type; +ULONG temp_time = 0; +ULONG temp_msw = 0; +ULONG temp_lsw = 0; + + + /* Set the DHCPv6 option header fields for a Server DUID. */ + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code = NX_DHCPV6_OP_SERVER_ID; + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length = (USHORT)length; + + /* Set the index past the option code and length. */ + index = 4; + + /* Extract the DUID type which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_type); + + /* Update the index for moving the buffer pointer forward. */ + index += 2; + + /* Extract the hardware type which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_hardware_type); + + /* Update the index for moving the buffer pointer forward. */ + index += 2; + + /* Is this a link layer plus time DUID type? */ + if (temp_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Yes; Extract the time which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_time); + + /* Update the index for moving the buffer pointer forward. */ + index += 4; + } + + /* Check the hardware type to extract the MSW. */ + if (temp_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) + { + + /* The length of link layer address is 48 bits. */ + + /* Yes; Extract the link local address msw which should be the next 2 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_msw); + + /* Update the index for moving the buffer pointer forward. */ + index += 2; + } + else if (temp_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) + { + + /* The length of link layer address is 64 bits. */ + + /* Yes; Extract the link local address msw which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_msw); + + /* Update the index for moving the buffer pointer forward. */ + index += 4; + } + + /* Yes; Extract the link local address lsw which should be the next 4 bytes. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_lsw); + + /* Update the index for moving the buffer pointer forward. */ + index += 4; + + /* Check if we are past the end of the buffer, subtracting for the toplevel opcode and + length of the IANA option. */ + if (((index - 4) > length) || ((index - 4) < length)) + { + + /* Yes, return the error status to reject the packet. */ + return NX_DHCPV6_INVALID_SERVER_DUID; + } + + /* If the client state in SENDING SOLICIT/CONFRIM/REBIND/INFORM_REQUEST, record the server DUID. */ + if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_SOLICIT || + dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_CONFIRM || + dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND || + dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_INFORM_REQUEST ) + { + + /* No previous server DUID in the Client record. Copy it over now. */ + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type = (USHORT)temp_type; + + /* Is this a TIME Duid type? */ + if (temp_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) + { + + /* Yes, write in the time data. */ + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time = temp_time; + } + + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type = (USHORT)temp_hardware_type; + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw = temp_msw; + dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw = temp_lsw; + } + else + { + + /* Yes; Verify this Server DUID matches the Server DUID from the Client record. */ + if ((dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time != temp_time) || + (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != temp_msw) || + (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw != temp_lsw)) + { + + /* It doesn't. Return an error status to reject this packet! */ + return NX_DHCPV6_INVALID_SERVER_DUID; + } + } + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_status PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the option status option from the server */ +/* reply. It also attempts to save the as much of server status message*/ +/* that will fit into the status message buffer. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process_iana Processes IANA in reply buffer */ +/* DHCPv6 request */ +/* _nx_dhcpv6_process_ia Processes IA in reply buffer */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_status(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT index; +UINT message_length; +ULONG status_code; + + + /* Set the location for the buffer read pointer. */ + index = 4; + + /* Get the status field itself. */ + _nx_dhcpv6_utility_get_data((received_buffer + index), sizeof(USHORT), &status_code); + + /* Update the index for moving the buffer pointer forward. */ + index += (ULONG)sizeof(USHORT); + + /* Set the status code. */ + dhcpv6_ptr -> nx_status_code = (USHORT)status_code; + + /* Now figure out how much of the message we can save, if not all of it. */ + if ((length - sizeof(USHORT)) > NX_DHCPV6_MAX_MESSAGE_SIZE) + { + + /* Store up to this much, message is truncated but possibly still useful. */ + message_length = NX_DHCPV6_MAX_MESSAGE_SIZE; + } + else + { + + /* Store all of it. */ + message_length = length - (ULONG)sizeof(USHORT); + } + + /* Copy the status into the Client record. */ + memcpy(dhcpv6_ptr -> nx_status_message, (received_buffer + index), message_length); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_time_zone PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the time zone option from the server reply. */ +/* It will save as much of the time zone that will fit in the Client */ +/* time zone buffer. Buffer size is user configurable. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts DHCPv6 options from */ +/* server reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_time_zone(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT i; +UINT index; + + + /* Set the location of the read pointer into the buffer. */ + index = 4; + + /* Make sure the time zone fits in the client buffer. */ + if (length > NX_DHCPV6_TIME_ZONE_BUFFER_SIZE) + { + + /* It doesn't. Fit what we can. */ + length = NX_DHCPV6_TIME_ZONE_BUFFER_SIZE; + } + + /* Copy the time zone from the buffer to the Client record. */ + for (i = 0; i < length; i++) + { + + dhcpv6_ptr -> nx_dhcpv6_time_zone[i] = *(received_buffer + 4 + i); + } + + /* Is there any more data in this option? */ + if (((index - 4 + i) > length) || ((index - 4 + i) < length)) + { + + /* Yes, treat as in improperly formatted packet. */ + return NX_DHCPV6_INVALID_OPTION_DATA; + } + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_time_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the time server option from the server reply.*/ +/* It will save as many time server addresses as are in the reply for */ +/* which the Client is configured to save. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to request packet buffer */ +/* length Location into buffer to read data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extracts DHCPv6 options from */ +/* server reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_time_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT index; +UINT w, j; + + + /* Set the location of the read pointer into the buffer. */ + index = 4; + j = 0; + + /* Loop through the length of the buffer to parse. */ + while ((index - 4) < length) + { + + /* Set the IP version. */ + dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; + + /* Get the next IPv6 time server address. */ + for (w = 0; w <= 3; w++) + { + + /* Check that the DHCPv6 Client configured to store this time server address e.g. it may + only store one address, but the server could be sending two or more. */ + if (j < NX_DHCPV6_NUM_TIME_SERVERS) + { + + /* Yes; copy each IPv6 address word into the time server address. */ + memcpy(&(dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_address.v6[w]), + (received_buffer + index), sizeof(ULONG)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_address.v6[w]); + } + + /* Move to the next IPv6 address word. */ + index += 4; + } + + dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; + + /* Start parsing the next time server address, if there is one*/ + j++; + } + + /* Is there any more data in this option? */ + if (((index - 4) > length) || ((index - 4) < length)) + { + + /* Yes, treat as in improperly formatted packet. */ + return NX_DHCPV6_INVALID_OPTION_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_remove_assigned_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the DHCPv6 Client address from the Client */ +/* record and from the IP address table. IP lease lifetimes and IP */ +/* addresses in the Client record are also cleared. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* NX_INVALID_INTERFACE Invalid index in IP address table*/ +/* status Failed mutex get */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get exclusive lock on time keeper*/ +/* tx_mutex_put Release the lock on time keeper */ +/* _nx_dhcpv6_set_IP_address_NULL Set the IP address to NULL */ +/* */ +/* CALLED BY */ +/* */ +/* nx_dhcpv6_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_remove_assigned_address(NX_DHCPV6 *dhcpv6_ptr, UINT ia_index) +{ +UINT index; + + /* Only clear one address. */ + if(ia_index != NX_DHCPV6_REMOVE_ALL_IA_ADDRESS) + { + + /* Check for invalid IA index. */ + if (ia_index >= NX_DHCPV6_MAX_IA_ADDRESS) + { + return(NX_DHCPV6_REACHED_MAX_IA_ADDRESS); + } + + if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) && + (dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] != 0) && + (dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] != 0xFFFFFFFF)) + { + + /* Now remove the address from the IP address table. */ + nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); + + /* Set the address index to invalid. */ + dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; + } + + /* Clear the IA data. */ + memset(&dhcpv6_ptr -> nx_dhcpv6_ia[ia_index], 0, sizeof(NX_DHCPV6_IA_ADDRESS)); + + } + + /* Clear the all addresses. */ + else + { + + /* Zero out time accrued on the current lease. */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + + /* Set all lease lifetime and time fields to zero. */ + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + + /* Delete the IPv6 address of IP instance. */ + for(index = 0; index < NX_DHCPV6_MAX_IA_ADDRESS; index++) + { + + if((dhcpv6_ptr -> nx_dhcpv6_ia[index].nx_address_status) && + (dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] != 0) && + (dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] != 0xFFFFFFFF)) + { + + /* Now remove the address from the IP address table. */ + nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[index]); + + /* Set the address index to invalid. */ + dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] = 0xFFFFFFFF; + } + } + + /* Clear the all IA data. */ + memset(&dhcpv6_ptr -> nx_dhcpv6_ia[0], 0, NX_DHCPV6_MAX_IA_ADDRESS * sizeof(NX_DHCPV6_IA_ADDRESS)); + + /* Removed the default router. */ + if (dhcpv6_ptr -> nx_dhcpv6_state >= NX_DHCPV6_STATE_SENDING_RENEW) + { + nxd_ipv6_default_router_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, &(dhcpv6_ptr -> nx_dhcpv6_server_address)); + memset(&(dhcpv6_ptr -> nx_dhcpv6_server_address), 0, sizeof(NXD_ADDRESS)); + } + } + + /* Clear the all address. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DHCPv6 Client state with the supplied state */ +/* (request). The DHCP Client thread will detect a state change and */ +/* process the new state. */ +/* */ +/* Note the return status only reflects the outcome of sending the */ +/* message, it does not indicate whether the request was successfully */ +/* granted. The host application is notified of "state" changes e.g. */ +/* NX_DHCPV6_STATE_SUCCESS or NX_DHCPV6_STATE_IP_FAILURE in the */ +/* callback function nx_dhcpv6_state_change_callback. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* dhcpv6_state State for making DHCPv6 request */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCP_NOT_STARTED DHCPv6 Client not started */ +/* status Get mutex status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DHCPv6 Client mutex */ +/* tx_mutex_put Releases the Client mutex */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_request_solicit Submits a SOLICIT request to Client*/ +/* _nx_dhcpv6_request_renew Submits a RENEW request to Client */ +/* _nx_dhcpv6_request_rebind Submits a REBIND request to Client */ +/* _nx_dhcpv6_request_release Submits a RELEASE request to Client*/ +/* _nx_dhcpv6_request_decline Submits a DECLINE request to Client*/ +/* _nx_dhcpv6_request_confirm Submits a CONFIRM request to Client*/ +/* _nx_dhcpv6_request_inform_request */ +/* Submits an Inform Request request */ +/* to Client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request(NX_DHCPV6 *dhcpv6_ptr, UINT dhcpv6_state) +{ + +UINT status; + + + /* First get an exclusive lock on the DHCPv6 Client. */ + status = tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + /* Return the error status. */ + return status; + } + + /* Determine if DHCP is started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started == NX_FALSE) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + + /* DHCP is not started so it can't be stopped. */ + return(NX_DHCPV6_NOT_STARTED); + } + + /* Wait for an opportunity to stop the DHCPv6 Client thread e.g. not in the midst of + modifying the host DHCP profile! */ + while (dhcpv6_ptr -> nx_dhcpv6_sleep_flag != NX_TRUE) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Sleep temporarily. */ + tx_thread_sleep(1); + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + } + + /* Set the Client state to process the DHCPv6 request. */ + dhcpv6_ptr -> nx_dhcpv6_state = (UCHAR)dhcpv6_state; + + /* Release the Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_confirm PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX DHCPv6 Confirm */ +/* request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_confirm Actual DHCPV6 process Confirm */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_confirm(dhcpv6_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_confirm PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a confirm request to the server for the Client */ +/* to know the DHCPv6 IP address already assigned to it by the server. */ +/* */ +/* A host application should call this service after a host has been */ +/* disconnected from the network or powered down to verify its address */ +/* is still valid. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + /* Set the initial and max retransmission timeouts, and max number of retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Call the internal function. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_CONFIRM); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_decline PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a decline request to the server for the Client */ +/* to tell the server it does not accept the assigned address. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process Processes server replies to */ +/* DHCPv6 Client requests */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_decline(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UINT ia_index; + + /* Set the initial and max retransmission timeout and max number of retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining + as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ + + /* Set the DHCPv6 Client IPv6 addresses. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining + as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ + + /* Verify we have a valid address index. */ + if(dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] >= NX_MAX_IPV6_ADDRESSES) + { + + return NX_INVALID_INTERFACE; + } + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE) + { + /* Remove the address from the IP instance address table. */ + + nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); + + /* Record the address index in the Client record. */ + dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; + } + } + + /* Call the internal function and return completion status. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_DECLINE); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_inform_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX DHCPv6 information*/ +/* request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_inform_request Actual DHCPV6 process Inform */ +/* Request request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_inform_request(dhcpv6_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_inform_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a inform request to the server for the Client */ +/* to obtain network parameters from any DHCPv6 server on the network. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Set the initial and max retransmission timeout and max number of retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Call the internal function and return completion status. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_INFORM_REQUEST); + + /* Return actual completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_option_DNS_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX submit and process*/ +/* the DNS server request option from the DHPCv6 Server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* enable Flag indicating if the DNS server*/ +/* request enabled or disabled */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_option_DNS_server */ +/* Actual DHCPV6 process DNS server */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_option_DNS_server(dhcpv6_ptr, enable); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_option_DNS_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables or disables the DHCPv6 DNS server option. If */ +/* enabled this option is added to the option list in DHCPv6 messages */ +/* the Client sends to the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* enable Flag indicating if the DNS server*/ +/* request enabled or disabled */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + + /* Are we enabling this feature? */ + if (enable == NX_TRUE) + { + + /* Yes, register this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_DNS_SERVER_OPTION; + } + else + { + + /* Clear this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_DNS_SERVER_OPTION); + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_option_domain_name PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX submit and process*/ +/* the domain name request option from the DHPCv6 Server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* enable Flag indicating if the domain name*/ +/* request enabled or disabled */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_option_time_server */ +/* Actual DHCPV6 process domain name*/ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_option_domain_name(dhcpv6_ptr, enable); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_option_domain_name PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables or disables the DHCPv6 domain name option. If*/ +/* enabled this option is added to the option list in DHCPv6 messages */ +/* the Client sends to the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* enable Flag indicating if the domain name*/ +/* request enabled or disabled */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + + /* Are we enabling this feature? */ + if (enable == NX_TRUE) + { + /* Yes, register this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_DOMAIN_NAME_OPTION; + } + else + { + + /* Clear this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_DOMAIN_NAME_OPTION); + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_option_time_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX submit and process*/ +/* the time server request option from the DHPCv6 Server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* enable Flag indicating if the time server*/ +/* request enabled or disabled */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_option_time_server */ +/* Actual DHCPV6 process time server*/ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_option_time_server(dhcpv6_ptr, enable); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_option_time_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables or disables the DHCPv6 time server option. If*/ +/* enabled this option is added to the option list in DHCPv6 messages */ +/* the Client sends to the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* enable Flag indicating if the time server*/ +/* request enabled or disabled */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + + /* Is the caller requesting the time server option? */ + if (enable == NX_TRUE) + { + /* Yes, register this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_SNTP_SERVER_OPTION; + } + else + { + + /* Clear this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_SNTP_SERVER_OPTION); + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_option_timezone PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX submit and process*/ +/* the time zone request option from the DHPCv6 Server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* enable Flag indicating if the time zone */ +/* request enabled or disabled */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_option_time_zone Actual DHCPV6 process time zone */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_option_timezone(dhcpv6_ptr, enable); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_option_timezone PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables or disables the DHCPv6 time zone option. If */ +/* enabled this option is added to the option list in DHCPv6 messages */ +/* the Client sends to the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* enable Flag indicating if the time zone */ +/* request enabled or disabled */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable) +{ + + /* Are we enabling this feature? */ + if (enable == NX_TRUE) + { + /* Yes, register this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION; + } + else + { + + /* Clear this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION); + } + + return NX_SUCCESS; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_option_FQDN PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the request fully qualified*/ +/* domain name option service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* domain_name DHCPv6 CLient domain name */ +/* op DHCPv6 Client operation */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_option_FQDN Actual DHCPv6 process FQDN */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((!dhcpv6_ptr) || (!domain_name)) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_option_FQDN(dhcpv6_ptr, domain_name, op); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_option_FQDN PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the DHCPv6 Client fully qualified domain */ +/* name. DHCPv6 Client sends this option to indicate if the server */ +/* SHOULD or SHOULD NOT perform the AAAA RR or DNS updates. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* domain_name DHCPv6 CLient domain name */ +/* op DHCPv6 Client operation */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op) +{ +UINT name_length; + + /* Set the Client FQDN option code. */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_code = NX_DHCPV6_OP_CLIENT_FQDN; + + /* Check domain name lengrh. The total length of a domain name is restricted to 255 octets or less. RFC1035. */ + if (_nx_utility_string_length_check(domain_name, &name_length, NX_DHCPV6_MAX_NAME_SIZE)) + { + return(NX_DHCPV6_PARAM_ERROR); + } + + /* Set the Client FQDN option length. 1 + length of domain name(domain name length + label + terminator) . */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_length = (USHORT)(1 + name_length + 2); + + /* Set the Client fully qualified domain name. */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_domain_name = domain_name; + + /* Flags Field. + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + | MBZ |N|O|S| + +-+-+-+-+-+-+-+-+ + */ + + /* Set the flags. */ + if (op == NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR) + { + + /* DHCPv6 Client chooses to update the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the Cslient. + Set the "S", "O" and "N" bits as 0. */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x00; + } + else if (op == NX_DHCPV6_CLIENT_DESIRES_SERVER_DO_DNS_UPDATE) + { + + /* DHCPv6 Client chooses to update the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the Client to the Server. + Set the "S" bit as 1, Set "O" and "N" bits as 0. */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x01; + } + else + { + + /* DHCPv6 Client choose to request that the Server perform no DNS updates on its behalf. + Set the "N" bit as 1, Set "O" and "S" bits as 0. */ + dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x04; + } + + /* Yes, register this option request with the DHCPv6 Client. */ + dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= NX_DHCPV6_CLIENT_FQDN_OPTION; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_rebind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a rebind request to the server for the Client to*/ +/* obtain or rebind an IP address with a DHCPv6 server on the network. */ +/* */ +/* Note: the Client thread task will detect when it is time to rebind */ +/* the Client IP address and call the expired address handler if one is*/ +/* set. The expired address handler is where the host should call this*/ +/* service from. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Rebind already initiated */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* _nx_dhcpv6_thread_entry DHCPv6 Client thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_rebind(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UINT ia_index; +UINT max_valid_lifetime = 0; + + + /* Is the Client state set to REBIND yet? */ + if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND) + { + + /* Yes, the rebind process is already started. No need to re-request it. + Also must not zero out retry count or reset timeout back to starting value. */ + return NX_SUCCESS; + } + + + /* Set the initial and max retransmission timeouts and max number of retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT; + + /* Find the max valid lifetime. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Check the address status. */ + if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) && + (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime > max_valid_lifetime)) + { + + /* Find the max valid lifetime of all IAs. */ + max_valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime; + } + } + + /* Set the max duration time.The message exchange is terminated when the valid lifetimes of all the addresses assigned to the IA expire, + RFC3315, Section18.1.4, Page43. */ + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = max_valid_lifetime; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Call the internal function and return completion status. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_REBIND); + + /* Return the actual completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX DHCPv6 Release */ +/* request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_release Actual DHCPV6 process Release */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_release(dhcpv6_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a release request to the server for the Client */ +/* to release a assigned IP address back to the DHCPv6 server who */ +/* previously assigned it. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Client not assigned an address */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UINT ia_index; + + /* Check if the Client is bound to an assigned address. */ + if((dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && + (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_RENEW) && + (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_REBIND)) + { + + /* It is not. The host application should use the nx_dhcpv6_stop if the DHCP Client + has simply failed to obtain an IP address from the server instead. */ + + /* Benign error so return successful outcome. */ + return NX_DHCPV6_IA_ADDRESS_NOT_VALID; + } + + /* Set the initial and max retransmission timeouts and max number of retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Set the DHCPv6 Client IPv6 addresses. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining + as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ + + /* Verify we have a valid address index. */ + if(dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] >= NX_MAX_IPV6_ADDRESSES) + { + + return NX_INVALID_INTERFACE; + } + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code) + { + /* Remove the address from the IP instance address table. */ + + nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); + + /* Record the address index in the Client record. */ + dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; + } + } + + /* Call the internal function and return completion status. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_RELEASE); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_renew PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls the internal request service to renew the */ +/* DHCPv6 IP address assigned to it by the server. */ +/* */ +/* Note: the Client thread task will detect when it is time to renew */ +/* the Client IP address and call the deprecated address handler if one*/ +/* is set. The deprecated address handler is where the host should */ +/* call this service from. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Renew already initiated */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* _nx_dhcpv6_thread_entry DHCPv6 Client thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_renew(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Is the Client state set to RENEW yet? */ + if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) + { + + /* Yes, the renew process is already started. No need to re-request it. + Also must not zero out retry count or reset timeout back to starting value. */ + return NX_SUCCESS; + } + + /* Set initial retry and timeout values for sending the Renew request. */ + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Set the Client to the Renewing state for the DHCP Client thread to process. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_RENEW); + + /* Actual completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_solicit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX DHCPv6 solicit */ +/* request service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_solicit Actual DHCPV6 process Solicit */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_solicit(dhcpv6_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_solicit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a solicit request for the Client to obtain an IP*/ +/* address from any DHCPv6 server on the network. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* _nx_dhcpv6_process Send the DHCPv6 solicit message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Set the mode of sending the solicit message. Do not override a rapid option if set. */ + if (dhcpv6_ptr ->nx_dhcpv6_request_solicit_mode != NX_DHCPV6_SOLICIT_RAPID) + { + + /* Set the mode of sending the solicit message. */ + dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode = NX_DHCPV6_SOLICIT_NORMAL; + } + + /* Set the initial and maximum timeout and retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION; + + /* Reset the preference value if the Client previously accepted an Advertise message. */ + dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = 0; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Set the Client to the Solicity state for the DHCP Client thread to process. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_SOLICIT); + + /* Return the completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_request_solicit_rapid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX DHCPv6 solicit */ +/* request service with rapid commit option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request_solicit_rapid Actual DHCPV6 process Solicit */ +/* request service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_dhcpv6_request_solicit_rapid(dhcpv6_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_request_solicit_rapid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a solicit request with rapid commit option for */ +/* the Client to rapidly obtain an IP address from any DHCPv6 server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_request Actual DHCPV6 request service */ +/* tx_timer_activate Activate the session timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Set the mode of sending the solicit message. */ + dhcpv6_ptr ->nx_dhcpv6_request_solicit_mode = NX_DHCPV6_SOLICIT_RAPID; + + /* Set the initial and maximum timeout and retries. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Set the initaial elasped time of DHCPv6 message. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + + /* Set the retransmission information(IRT, MRC, MRT, MRD). */ + dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT; + dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION; + + /* Reset the preference value if the Client previously accepted an Advertise message. */ + dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = 0; + + /* Activate the session timer to update the elapsed time. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); + + /* Set the Client to the Solicity state for the DHCP Client thread to process. */ + status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_SOLICIT); + + /* Return the completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the resume NetX DHCPv6 */ +/* client task service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_resume Actual DHCPV6 resume function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + UINT _nxe_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 stop service. */ + status = _nx_dhcpv6_resume(dhcpv6_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes DHCPV6 processing thread and updates the */ +/* DHCPv6 client state according to nx_dhcpv6_IP_lifetime_time_accrued.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_dhcpv6_start Starts DHCPV6 thread task */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; +UCHAR original_state; + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Determine if DHCPV6 has already been started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started) + { + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Error, the DHCPV6 client has already been started. */ + return(NX_DHCPV6_ALREADY_STARTED); + } + + /* Determine if Client has created its DUID and IANA yet. */ + if ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr == NX_NULL) || + (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length == 0) || + (dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length == 0)) + { + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* No, this DHCPv6 Client is not ready to run! */ + return NX_DHCPV6_MISSING_REQUIRED_OPTIONS; + } + + /* Remember the original DHCPv6 state for the changed state callback function. */ + original_state = dhcpv6_ptr -> nx_dhcpv6_state; + + /* Bind the UDP socket to the DHCPV6 Client port. */ + status = nx_udp_socket_bind(&(dhcpv6_ptr -> nx_dhcpv6_socket), NX_DHCPV6_CLIENT_UDP_PORT, TX_WAIT_FOREVER); + + /* Check for success */ + if (status) + { + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Return completion status. */ + return(status); + } + + /* Check the DHCPv6 Client state. */ + if ((dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && + (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_RENEW) && + (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_REBIND)) + { + + /* Set the DHCPv6 Client state to Init.*/ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Clear the session time, lease lifetime, retransmission counters. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 0; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + } + else + { + + /* Check the accrued time to upate the state. */ + if ((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && ((dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2))) + { + + /* Update the status as NX_DHCPV6_STATE_SENDING_RENEW to send rebinding message in _nx_dhcpv6_thread_entry function. */ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_RENEW; + } + } + + + /* Set the DHCPv6 started flag to indicate DHCPv6 Client is now running. */ + dhcpv6_ptr -> nx_dhcpv6_started = NX_TRUE; + + /* Activate the DHCPv6 timers. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer); + + /* Resume the DHCPv6 processing thread. */ + tx_thread_resume(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Is there a state change callback registered with the Client? */ + if ((dhcpv6_ptr -> nx_dhcpv6_state_change_callback) && (original_state != (dhcpv6_ptr -> nx_dhcpv6_state))) + { + + /* Yes, call the the state change callback with the original and new state. */ + (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); + } + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_send_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a DHCPV6 request to the server. All options */ +/* required for each Client DHCPv6 message are compiled into the Client */ +/* request package. Since each message must have a unique transaction */ +/* ID, it is up to the caller to set the Client transaction ID in the */ +/* Client record before calling this service. The server reply must */ +/* contain the matching message transaction ID for each message type the*/ +/* Client sends it. This function will check for invalid message types. */ +/* */ +/* To send a message, the Client allocates a packet from its own packet */ +/* pool. It then must set the IPv6 packet interface depending if the */ +/* Client has a valid global IP address or is using its link local */ +/* address till it can get a global IP address. It can send the packet */ +/* either to all servers on its network or include server and relays */ +/* (user configurable). */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Illegal message type to send */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a DHCPV6 packet */ +/* nx_packet_release Release DHCPV6 packet */ +/* nx_udp_socket_send Send DHCPV6 packet */ +/* _nx_dhcpv6_add_client_duid Add Client DUID to request */ +/* _nx_dhcpv6_add_server_duid Add server DUID to request */ +/* _nx_dhcpv6_add_elapsed_time Add elapsed time option */ +/* _nx_dhcpv6_add_iana Add IANA option to request */ +/* _nx_dhcpv6_add_ia_address Add IA address option */ +/* _nx_dhcpv6_add_option_request Add option request option */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process Process DHCPv6 client request */ +/* _nx_dhcpv6_waiting_on_reply Process replies to valid server*/ +/* reply received */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_send_request(NX_DHCPV6 *dhcpv6_ptr) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer; +UINT status; +ULONG message_word; +UINT index; +NX_INTERFACE *interface_ptr; +NXD_IPV6_ADDRESS *ipv6_address; +ULONG available_payload; + + + /* Initialize local variables. */ + index = 0; + + /* Check for invalid or illegal message type. */ + if ((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) || + (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == 0)) + { + + /* Return error status. */ + return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; + } + + /* Allocate a DHCPV6 packet. */ + status = nx_packet_allocate(dhcpv6_ptr -> nx_dhcpv6_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Indicate this is an IPv6 packet. */ + packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6; + + /* Setup the buffer pointer. */ + buffer = packet_ptr -> nx_packet_prepend_ptr; + + /* Use the message id value to judge whether the next packet is retransmit packet or not. + If the id value is 0, indicate the new dhcpv6 request, then generate a random number, else,leave the transaction ID unchanged. + A client MUST leave the transaction ID unchanged in retransmissions of a message,RFC3315,section 15.1,page 28. */ + if(dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid == 0) + { + + /* Generate "random" transaction ID using physical address and a random factor for each request + to the Server. The Server must include a matching transaction ID in its reply. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = + ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_msw) ^ + (dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_lsw) ^ + (ULONG)(NX_RAND())); + + /* Now reduce it to three bytes. */ + dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid & (ULONG)(0x0ffffff)); + } + + /* Clear memory to make the message header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Add the message type and transaction ID as the DHCPv6 header fields. */ + message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type)) << 24); + + message_word |= (((ULONG)(0x0ffffff)) & (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the message header to the packet buffer. */ + memcpy(buffer, &message_word, 4); + + /* Update the buffer 'pointer'. */ + index += (ULONG)sizeof(ULONG); + + /* Add the Client DUID to the packet buffer. */ + status = _nx_dhcpv6_add_client_duid(dhcpv6_ptr, buffer, &index); + + /* Check for error. */ + if(status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + return status; + } + + /* Determine if any additional options need to be added relative to the DHCPV6 message type. */ + switch (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type) + { + + case NX_DHCPV6_MESSAGE_TYPE_SOLICIT: + { + /* Append the IA-NA option and depending on host state. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Did the Client ask for a DHCPv6 Client FQDN option ? + A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ + if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* Did the Client ask for a requested option? */ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* Did the Client ask for rapid commit option? */ + if (dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) + { + + /* Compute the available payload for DHCP data in the packet buffer. */ + available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - + sizeof(NX_IPV6_HEADER) - sizeof(NX_UDP_HEADER) - index); + + /* Check if the data will fit in the packet buffer. */ + if (available_payload < sizeof(ULONG)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Add the rapid commit option request. */ + /* Clear memory to make the message header, and add the message type. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Add the message type. */ + message_word = (((ULONG)NX_DHCPV6_OP_RAPID_COMMIT) << 16); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the message to the packet buffer. */ + memcpy((buffer + index), &message_word, sizeof(ULONG)); + + /* Update the index. */ + index += (ULONG)sizeof(ULONG); + } + + /* Increment the number of Solicit messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_solicitations_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_REQUEST: + { + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Append an IA-NA with the IA address option received from server added to the IA-NA option. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Did the Client ask for a DHCPv6 Client FQDN option ? + A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ + if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* Did the Client ask for a requested option? */ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + } + + /* Increment the number of Request messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_requests_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_RENEW: + { + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Did the Client ask for a DHCPv6 Client FQDN option ? + A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ + if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* A client MAY include an Option Request option in a Solicit, Request, Renew, Rebind, Confirm or Information-request + message to inform the server about options the client wants the server to send to the client. RFC3315, Section22.7, Page78.*/ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + } + + dhcpv6_ptr -> nx_dhcpv6_renews_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_REBIND: + { + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Rebind message includes the current IA/IA-NA, current IA address. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Did the Client ask for a DHCPv6 Client FQDN option ? + A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ + if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* Did the Client ask for a requested option? */ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + + /* Increment the number of Solicit messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_rebinds_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_CONFIRM: + { + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Rebind message includes the current IA/IA-NA, current IA address. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + /* Return the error status and abort. */ + return status; + } + + /* A client MAY include an Option Request option in a Solicit, Request, Renew, Rebind, Confirm or Information-request + message to inform the server about options the client wants the server to send to the client. RFC3315, Section22.7, Page78.*/ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + } + + /* Increment the number of Solicit messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_confirms_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_DECLINE: + { + + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + /* Return the error status and abort. */ + return status; + } + + /* Decling the message in the current IA/IA-NA, current IA address. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Increment the number of Decline messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_declines_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_RELEASE: + { + + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Decling the message in the current IA/IA-NA, current IA address. */ + status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + + /* Increment the number of Releases messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_releases_sent++; + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST: + { + + /* Did the Client ask for a requested option? */ + if (!dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + + /* No, so don't bother sending out the request. */ + + nx_packet_release(packet_ptr); + + return NX_SUCCESS; + } + + /* Compute the session time so far and add an elapsed time option. */ + status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + + /* Did the Client ask for a requested option? */ + if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) + { + /* Add the server DUID just extracted from the Server Advertise message. */ + status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return status; + } + } + + /* Increment the number of Inform Request messages sent. */ + dhcpv6_ptr -> nx_dhcpv6_inform_req_sent++; + + break; + } + + default: + { + nx_packet_release(packet_ptr); + + return NX_DHCPV6_UNKNOWN_MSG_TYPE; + } + } + + /* Setup the packet pointers. */ + packet_ptr -> nx_packet_length = index; + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; + + + /* Select Client Source address: + 1. When a client sends a DHCP message to the All_DHCP_Relay_Agents_and_Servers address, + the client must use a link-local address assigned to the interface for which it + is requesting configuration as the source address. + 2. When a client sends a DHCP message directly to a server using unicast, + the source address must be an address assigned to the interface for which the + client is interested in obtaining configuration. + RFC 3315, Section 16. Client Source Address and Interface Selection, Page 32. */ + + /* Set the interface pointer. */ + interface_ptr = &(dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[dhcpv6_ptr ->nx_dhcpv6_client_interface_index]); + + /* Check the destination address. */ + if (CHECK_IPV6_ADDRESSES_SAME(dhcpv6_ptr -> nx_dhcpv6_client_destination_address.nxd_ip_address.v6, All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6)) + { + + /* Find the link-local address as source adress. Get first address from interface. */ + ipv6_address = interface_ptr -> nxd_interface_ipv6_address_list_head; + + /* Loop to check the address. */ + while (ipv6_address) + { + + /* Check for a valid address. */ + if (ipv6_address -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID) + { + ipv6_address = ipv6_address -> nxd_ipv6_address_next; + } + + /* Check for link-local address. */ + else if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL) + { + + /* Find the Link-Local Address. */ + break; + } + else + { + ipv6_address = ipv6_address -> nxd_ipv6_address_next; + } + } + + /* Check if found the link-local address. */ + if(ipv6_address == NX_NULL) + { + + /* No valid link-local address. */ + nx_packet_release(packet_ptr); + return(NX_IP_ADDRESS_ERROR); + } + } + else + { + + /* Find the source address. */ + status = _nxd_ipv6_interface_find(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_destination_address.nxd_ip_address.v6, + &ipv6_address, interface_ptr); + + /* Check if found the address. */ + if (status) + { + + /* No valid source address. */ + nx_packet_release(packet_ptr); + return(NX_IP_ADDRESS_ERROR); + } + } + + /* Send the packet out! */ + status = _nxd_udp_socket_source_send(&(dhcpv6_ptr -> nx_dhcpv6_socket), packet_ptr, + &dhcpv6_ptr -> nx_dhcpv6_client_destination_address, NX_DHCPV6_SERVER_UDP_PORT, + ipv6_address -> nxd_ipv6_address_index); + + /* If an error is detected, the packet was not sent and we have to release the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_session_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the Client session duration time with the */ +/* Server. This information is used for the Elapsed Time data in DHCPv6*/ +/* Client messages sends to the server as part of the DHCPv6 protocol. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr_value Pointer to the DHCPV6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_session_timeout_entry(ULONG dhcpv6_ptr_value) +{ + +NX_DHCPV6 *dhcpv6_ptr; + + + /* Setup DHCPv6 Client pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, dhcpv6_ptr_value) + + /* Check the elapsed time, the time is expressed in hundredths of 1 second, 65500 is the largest time value. */ + if(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time < 65500) + { + + /* Update the elapsed time of current DHCP session. + This time is expressed in hundredths of a second. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = (USHORT)(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time + NX_DHCPV6_SESSION_TIMER_INTERVAL * 100); + } + else + { + + /* Set the value 0xFFFF to represent any elapsed time values greater than the largest time value . */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0xFFFF; + } + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_set_time_accrued PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the set time accrued on */ +/* Client IP lease service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_accrued Pointer to time since IP lease */ +/* assigned (secs) */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_set_time_accrued Actual set time accrued on Client */ +/* IP address lease service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_set_time_accrued(dhcpv6_ptr, time_accrued); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_set_time_accrued PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the host to set the time accrued on the */ +/* Client's IP address lease. The caller must first suspend the */ +/* DHCPv6 Client using the nx_dhcpv6_suspend service before using this */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* time_accrued Pointer to time to set the */ +/* lient accrued time (secs) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued) +{ + + + /* Check if the DHCPv6 Client has been started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started) + { + /* It has. We cannot set the time accrued if the DHCPv6 client thread is running. */ + return NX_DHCPV6_ALREADY_STARTED; + } + + /* Set the time accrued on the Client IP address lease. */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = time_accrued; + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the set client interface */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* interface_index Index for DHCP network interface*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_client_set_interface Actual set interface service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index) +{ + +UINT status; + + + /* Check for valid pointer input. */ + if (!dhcpv6_ptr) + { + return NX_PTR_ERROR; + } + + /* Check for an invalid interface specified. */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_client_set_interface(dhcpv6_ptr, interface_index); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function specifies the physical interface for DHCP */ +/* communications with the server in NetX Duo environments that support*/ +/* mult-homed hosts. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* interface_index Index for DHCP network interface*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NOT_ENABLED NetXDuo version does not support*/ +/* multiple network interfaces */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index) +{ + + + /* Set the client interface. */ + dhcpv6_ptr -> nx_dhcpv6_client_interface_index = interface_index; + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_set_destination_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the set destination */ +/* address service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* destination_address Destination address */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_client_set_destination_address */ +/* Actual set address service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid address type. */ + if (destination_address -> nxd_ip_version != NX_IP_VERSION_V6) + { + + /* Invalid address type. */ + return(NX_DHCPV6_PARAM_ERROR); + } + + /* Check if the server address is unspecified (::). */ + if(CHECK_UNSPECIFIED_ADDRESS(destination_address -> nxd_ip_address.v6)) + { + + /* Null address input. */ + return(NX_DHCPV6_PARAM_ERROR); + } + + /* Call the actual service. */ + status = _nx_dhcpv6_client_set_destination_address(dhcpv6_ptr, destination_address); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_set_destination_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the destination address where DHCP message should */ +/* be sent. By default is All_DHCP_Relay_Agents_and_Servers(FF02::1:2).*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* destination_address Destination address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address) +{ + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_WAIT_FOREVER); + + /* Set the destination address. */ + COPY_NXD_ADDRESS(destination_address, &(dhcpv6_ptr -> nx_dhcpv6_client_destination_address)); + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX start the dhcpv6 */ +/* client service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_start Actual DHCPV6 start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 start service. */ + status = _nx_dhcpv6_start(dhcpv6_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the DHCPV6 processing thread and readies the */ +/* DHCPv6 Client to initiate DHCPv6 requests. The Client state is set */ +/* to INIT and awaits the host application requesting a DHCPv6 meesage */ +/* sent e.g. the SOLICIT message. For hosts binding (or attempting to */ +/* obtain) a IP address in a previous session, this will clear session */ +/* parameters such as accrued lease time and message retry count. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCPV6_ALREADY_STARTED DHCPv6 Client already started */ +/* NX_DHCPV6_MISSING_REQUIRED_OPTIONS Client missing required options */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_create Create the Client UDP socket */ +/* nx_udp_socket_bind Bind the Client socket */ +/* nx_udp_socket_unbind Unbind the Client socket */ +/* tx_timer_activate Activate Client timers */ +/* tx_timer_deactivate Deactivate Client timers */ +/* tx_thread_resume Resume Client thread task */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Determine if DHCPV6 has already been started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started) + { + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Error, the DHCPV6 client has already been started. */ + return(NX_DHCPV6_ALREADY_STARTED); + } + + /* Determine if Client has created its DUID and IANA yet. */ + if ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr == NX_NULL) || + (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length == 0) || + (dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length == 0)) + { + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* No, this DHCPv6 Client is not ready to run! */ + return NX_DHCPV6_MISSING_REQUIRED_OPTIONS; + } + + /* Set the DHCPv6 Client state to Init.*/ + dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; + + /* Clear the session time, lease lifetime, retransmission counters. */ + dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 0; + dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; + + /* Bind the UDP socket to the DHCPV6 Client port. */ + status = nx_udp_socket_bind(&(dhcpv6_ptr -> nx_dhcpv6_socket), NX_DHCPV6_CLIENT_UDP_PORT, TX_WAIT_FOREVER); + + /* Check for success */ + if (status == NX_SUCCESS) + { + + /* Resume the DHCPv6 processing thread. */ + status = tx_thread_resume(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Determine if the resume was successful. */ + if (status == NX_SUCCESS) + { + + /* Set the DHCPv6 started flag to indicate DHCPv6 Client is now running. */ + dhcpv6_ptr -> nx_dhcpv6_started = NX_TRUE; + + /* Activate the DHCPv6 timers. */ + tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer); + } + else + { + + /* Error, unbind the DHCPv6 socket. */ + nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); + } + } + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the suspend NetX DHCPv6 */ +/* client task service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_suspend Actual DHCPV6 suspend function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 stop service. */ + status = _nx_dhcpv6_suspend(dhcpv6_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends (stops) DHCPV6 processing thread, stops the */ +/* DHCP session and IP address lease timers, and clears the started */ +/* status of the DHCPv6 Client. It resets the DHCPv6 Client to the */ +/* INIT. The DHCP socket is unbound and the DHCP thread aborted. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ +/* suspended */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend DHCPV6 thread task */ +/* tx_timer_deactivate Deactivate timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + status = _nx_dhcpv6_stop(dhcpv6_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the DHCPv6 Client stop */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_stop Actual stop DHCPV6 thread task */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 stop service. */ + status = _nx_dhcpv6_stop(dhcpv6_ptr); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends (stops) DHCPV6 processing thread, stops the */ +/* DHCP session and IP address lease timers. The DHCP socket is unbound*/ +/* and the DHCP thread aborted. */ +/* */ +/* Stopping the DHCP Client is necessary to restart the DHCP client, */ +/* example if a previously assigned address is declined or released, */ +/* and the host would like to solicit an IP address again. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ +/* suspended */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend DHCPV6 thread task */ +/* tx_timer_deactivate Deactivate timer */ +/* tx_mutex_get Obtain Client mutex */ +/* tx_mutex_put Release Client mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT current_preemption; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Determine if DHCPV6 is started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started == NX_FALSE) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* DHCPV6 has not been started so we cannot stop it. */ + return(NX_DHCPV6_NOT_STARTED); + } + + /* Clear the DHCPV6 started flag to indicate DHCPV6 task is not running. */ + dhcpv6_ptr -> nx_dhcpv6_started = NX_FALSE; + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Loop to wait for the DHCP Client thread to be in a position to be stopped. */ + while (dhcpv6_ptr -> nx_dhcpv6_sleep_flag != NX_TRUE) + { + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Sleep temporarily. */ + tx_thread_sleep(1); + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + } + + /* Clear the flag. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + + /* Suspend the DHCP thread. */ + tx_thread_suspend(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Abort the wait on the DHCP Client thread. */ + tx_thread_wait_abort(&(dhcpv6_ptr -> nx_dhcpv6_thread)); + + /* Unbind the port. */ + nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); + + /* Stop the timers. */ + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer)); + tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); + + /* Restore preemption. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dhcpv6_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the reinitializes the */ +/* DHCPv6 Client service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_reinitialize Actual clear address service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + if (dhcpv6_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_dhcpv6_reinitialize(dhcpv6_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_reinitialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reinitializes the DHCP instance for restarting the */ +/* DHCP client state machine and re-running the DHCPv6 protocol. This */ +/* is not necessary if the Client has not previously obtained an */ +/* IP address from the server. The IP address in both the DHCP Client */ +/* data record and in the IP instance is cleared. */ +/* */ +/* Note: the host MUST stop the DHCPv6 client before calling this */ +/* service with the nx_dhcpv6_stop service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCPV6_ALREADY_STARTED DHCPv6 client is running */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_remove_assigned_address Clears client IP address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status; + + + /* Check that the DHCPv6 client is started. */ + if (dhcpv6_ptr -> nx_dhcpv6_started == NX_TRUE) + { + + /* Need to stop the DHCP client before we can reinitialize it. */ + return NX_DHCPV6_ALREADY_STARTED; + } + + /* This clears the assigned IP address from the Client record, as well as + removes the assigned IP address from the IP address table. */ + status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background processing thread for the DHCPV6 */ +/* Client. It waits to be notified by ThreadX event flags when to */ +/* perform certain actions. These include updating the time remaining */ +/* on the Client IP address lease time, and maintaining the duration of*/ +/* the current Client Server session (if Client has made a request). */ +/* It will terminate if a host application handler is called and */ +/* indicates the Client should abort. */ +/* */ +/* INPUT */ +/* */ +/* info Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Receive notice of event flags set */ +/* tx_mutex_get Obtain lock on Client resource */ +/* tx_mutex_put Release lock on Client resource */ +/* _nx_dhcpv6_request_renew Initiate the RENEW request */ +/* _nx_dhcpv6_request_rebind Initiate the REBIND request */ +/* _nx_dhcpv6_request_decline Initiate the DECLINE request */ +/* _nx_dhcpv6_remove_assigned_address */ +/* Remove the assigned IPv6 address */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_thread_entry(ULONG info) +{ + +UINT status; +NX_DHCPV6 *dhcpv6_ptr; +UINT current_preemption; +ULONG dhcpv6_events; +UINT ia_index; +UINT original_state; + + /* Setup the DHCPV6 Client pointer. */ + NX_THREAD_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, info) + + /* Process periodic DHCPv6 Client tasks. */ + do + { + + /* Loop to get the DHCP mutex to handle error, release, and + stop requests properly. */ + do + { + + /* Get the DHCP mutex. */ + status = tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + } while (status != TX_SUCCESS); + + + /* Check the state of the DHCP Client state for further DHCP messaging. */ + _nx_dhcpv6_process(dhcpv6_ptr); + + /* Release the DHCP mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Indicate the DHCP Client process is idle. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* Sleep for timer interval. */ + tx_thread_sleep(NX_DHCPV6_SESSION_TIMER_INTERVAL); + + /* Clear flag to indicate DHCP thread is not in a position to be stopped. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + + /* Restore original preemption. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + /* Check the expiration on valid and preferred lifetimes only if the Client is in the Bound state. */ + if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) + { + + /* At time T1 for an IA, the client initiates a Renew message exchange to extend the lifetimes. RFC3315,page 42.*/ + if (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1) + { + + /* Indicate the DHCP Client process is idle while the handler executes. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* Sending the renew message. */ + _nx_dhcpv6_request_renew(dhcpv6_ptr); + + /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + } + } + + /* Check the expiration on valid and preferred lifetimes only if the Client is in the sending renew state. */ + if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) + { + + /* At time T2 for an IA, The Client initiates a Rebind message exchanges. RFC3315, page 43. */ + if (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2) + { + + /* Indicate the DHCP Client process is idle while the handler executes. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* Sending the rebind message. */ + _nx_dhcpv6_request_rebind(dhcpv6_ptr); + + /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + } + } + + /* Check the DHCPv6 Client state. */ + if ((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) || + (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) || + (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND)) + { + + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + /* Has the IP address valid lifetime expired? */ + if ((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) && + (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime)) + { + + /* Save the existing state of the DHCPv6 Client. */ + original_state = dhcpv6_ptr -> nx_dhcpv6_state; + + /* Clear the assigned IP address. */ + _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, ia_index); + + /* Indicate the DHCP Client process is idle while the handler executes. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* Restart the Client to the solicit IP address request state. */ + _nx_dhcpv6_request_solicit(dhcpv6_ptr); + + /* Indicate the DHCP Client process is idle while the handler executes. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + + if (dhcpv6_ptr -> nx_dhcpv6_state_change_callback && (original_state != dhcpv6_ptr -> nx_dhcpv6_state)) + { + /* Yes, call the state change callback with the original and new state. */ + (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); + } + } + } + } + + + + /* Pickup IP event flags. */ + status = tx_event_flags_get(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_events), NX_IP_ALL_EVENTS, TX_OR_CLEAR, &dhcpv6_events, TX_NO_WAIT); + + /* Check for an IP receive packet event. */ + if ((status == TX_SUCCESS) && (dhcpv6_events & NX_DHCPV6_DAD_FAILURE_EVENT)) + { + + /* Indicate the DHCP Client process is idle while the handler executes. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + /* The DAD process failure, send DHCPv6 DECLINE message. */ + _nx_dhcpv6_request_decline(dhcpv6_ptr); + + dhcpv6_events = dhcpv6_events & ~(ULONG)(NX_DHCPV6_DAD_FAILURE_EVENT); + + /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + } + + } while (1); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_utility_get_block_option_length PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the input buffer (assuming to be an option */ +/* block in a server reply) for option code and length. It assumes the */ +/* buffer pointer is pointed to the first byte of the option buffer. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ Pointer to DHCPv6 Client */ +/* option Option code of requested data */ +/* buffer_ptr Buffer to copy data to */ +/* length Size of buffer */ +/* valid */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCPV6_INCOMPLETE_OPTION_BLOCK Unknown option specified */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_data Parses a specific data from the */ +/* DHCPv6 option */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Parses option code and length */ +/* _nx_dhcpv6_extract_packet_information */ +/* Parses each option from server */ +/* reply and updates Client record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length) +{ + + /* Initialize to zero. */ + *option = 0; + *length = 0; + + /* First byte should be the op code. */ + _nx_dhcpv6_utility_get_data(buffer_ptr, 2, option); + + buffer_ptr += 2; + + /* Next byte should be the option length. */ + _nx_dhcpv6_utility_get_data(buffer_ptr, 2, length); + + /* Buffer is now pointed at the data (past the length field). */ + buffer_ptr += 2; + + /* Check for null data. */ + if (*option == 0) + { + + return NX_DHCPV6_INCOMPLETE_OPTION_BLOCK; + } + + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_utility_get_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the input buffer and returns numeric data */ +/* specified by the size argument, up to 4 bytes long. Note that if */ +/* caller is using this utility to extract bytes from a DHCPv6 packet */ +/* there is no need for byte swapping, as compared to using memcpy in */ +/* which case there is for little endian processors. */ +/* */ +/* INPUT */ +/* */ +/* buffer Pointer to data buffer */ +/* value Pointer to data parsed from buffer*/ +/* size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCPV6_INVALID_DATA_SIZE Requested data size too large */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* _nx_dhcpv6_process_server_duid Process server duid in server reply*/ +/* _nx_dhcpv6_process_client_duid Process server duid in server reply*/ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Parses option code and length */ +/* _nx_dhcpv6_extract_packet_information */ +/* Parses each option from server */ +/* reply and updates Client record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_utility_get_data(UCHAR *buffer, UINT size, ULONG *value) +{ + + + /* Check that the size of the data fits in a ULONG. */ + if (size > sizeof(ULONG)) + { + return NX_DHCPV6_INVALID_DATA_SIZE; + } + + *value = 0; + + /* Process the data retrieval request. */ + while (size-- > 0) + { + + /* Build return value. */ + *value = (((*value) << 8) | (*buffer)); + buffer++; + } + + /* Return value. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_utility_time_randomize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns a value of between -1 seconds and 1 second */ +/* in system ticks. It is used to randomize timeouts as required by */ +/* the RFC's so as to not overload a network server after power out. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* ticks Number of ticks between 1 & -1*/ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_convert_delay_to_ticks Convert seconds to ticks */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT _nx_dhcpv6_utility_time_randomize(void) +{ + +UINT temp; +UINT sign; +INT temp_signed; + + temp = (UINT)(NX_RAND()); + temp &= (UINT)(0x001F); + sign = (temp & (UINT)(0x8)); + temp_signed = (INT)temp; + + /* Try for a number between 0 and 0x1F. */ + if (sign) + { + temp_signed = -temp_signed; + } + + return temp_signed; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_waiting_on_reply PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits to receive a DHCPv6 server packet for the wait */ +/* time set by the DHCPv6 client previously. If a reply is received, */ +/* call function to process it. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Valid packet received */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_receive Receive UDP packet */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_dhcpv6_packet_procss Process the dhcpv6 packet */ +/* _nx_dhcpv6_flush_queue_packets Flush the queue packets */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process Process current client state */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_waiting_on_reply(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT current_preemption; +UINT status; +NX_PACKET *packet_ptr; +ULONG start_time; +ULONG current_time; +ULONG elapsed_time; +ULONG receive_wait; +UINT time_remaining; +UINT valid_answer; + + /* Initialize the parameters. */ + packet_ptr = NX_NULL; + valid_answer = NX_FALSE; + time_remaining = dhcpv6_ptr -> nx_dhcpv6_transmission_timeout; + + /* Wait in short intervals to receive a valid packet while continuously checking for packets not intended + for this DHCP Client to be removed from the receive queue. */ + do + { + + /* Release the DHCP mutex while the Client will be blocked on a receive socket call. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Indicate the DHCP Client can be stopped. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; + + start_time = tx_time_get(); + + if (time_remaining < NX_DHCPV6_TIME_INTERVAL) + { + receive_wait = time_remaining; + } + else + { + receive_wait = NX_DHCPV6_TIME_INTERVAL; + } + + status = nx_udp_socket_receive(&(dhcpv6_ptr -> nx_dhcpv6_socket), &packet_ptr, receive_wait); + + /* Indicate the DHCP Client can not be stopped. */ + dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; + + /* Restore preemption/ end of critical section. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + /* Yes, receive a packet. */ + if (status == NX_SUCCESS) + { + + /* Get the DHCP mutex. */ + while((tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_NO_WAIT) != TX_SUCCESS) && + (time_remaining > 0)) + { + + if (time_remaining < NX_DHCPV6_TIME_INTERVAL) + { + tx_thread_sleep(time_remaining); + time_remaining = 0; + } + else + { + tx_thread_sleep(NX_DHCPV6_TIME_INTERVAL); + time_remaining -= NX_DHCPV6_TIME_INTERVAL; + } + } + + /* Process the dhcpv6 packet. */ + status = _nx_dhcpv6_packet_process(dhcpv6_ptr, packet_ptr); + + /* Check the status. */ + if(status == NX_SUCCESS) + { + + /* Yes, Get a valid advertise or reply message. */ + valid_answer = NX_TRUE; + + /* DHCPv6 client MUST collect Advertise messages for the first RT seconds, + unless it receives an Advertise message with a preference value of 255. + RFC 3315, Section 17.1.2, Page 34. */ + if((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_SOLICIT) && + (dhcpv6_ptr -> nx_dhcpv6_retransmission_count == 0)) + { + + /* Process the rapid solicit mode. */ + if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) + { + + /* Client terminates the waiting process as soon as a reply message + with a Rapid Commit option is received. RFC3315, Section17.1.2, Page34. */ + break; + } + + /* Process the normal solicit mode. */ + if(dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value == 255) + { + + /* If the client receives an Advertise message that includes a Preference option with + a preference value of 255, the client can terminates the waiting. */ + break; + } + } + else + { + + /* Yes, Get the answer. */ + break; + } + } + } + + /* How much time has elapsed? */ + current_time = tx_time_get(); + + /* Has the time wrapped? */ + if (current_time >= start_time) + { + /* No, simply subtract to get the elapsed time. */ + elapsed_time = current_time - start_time; + } + else + { + + /* Yes it has. Time has rolled over the 32-bit boundary. */ + elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; + } + + /* Update the time remaining. */ + if (time_remaining > elapsed_time) + { + time_remaining -= elapsed_time; + } + else + { + /* Time is up, break out of this loop. */ + time_remaining = 0; + + /* But not before restoring preemption/ end of critical section! */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + break; + } + + } while(time_remaining > 0); + + /* Flush the queue packets. */ + _nx_dhcpv6_flush_queue_packets(dhcpv6_ptr); + + /* Check the valid answer flag. */ + if (valid_answer == NX_TRUE) + { + return NX_SUCCESS; + } + else + { + return NX_DHCPV6_INVALID_SERVER_PACKET; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the receive pacet. the data is copied to */ +/* another packet from the DHCPv6 Client packet pool,and the original */ +/* received packet is released back to the receive pool immediately. */ +/* Then process the reply message. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* packet_ptr Pointer to received packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Process correctly */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_extract Get the reply information */ +/* nx_packet_release Release packet to packet pool */ +/* nx_packet_allocate Allocate a new packet. */ +/* nx_packet_data_extract_offset Store the received pacet data. */ +/* _nx_dhcpv6_scan_packet_options Scan and record the reply options. */ +/* _nx_dhcpv6_preprocess_packet_information */ +/* Preprocess the packet according to */ +/* the options record. */ +/* _nx_dhcpv6_extract_packet_information */ +/* Extract server reply data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_waiting_on_reply Process current client message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_packet_process(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +UINT port; +ULONG bytes_copied; +NXD_ADDRESS server_IP_Address; +NX_PACKET *new_packet_ptr; + + + /* Check for valid packet length (message type and ID). */ + if (packet_ptr -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_DHCPV6_INVALID_DATA_SIZE); + } + + /* Extract the IP and port number from the packet and set the reply address. */ + status = nxd_udp_source_extract(packet_ptr, &server_IP_Address, &port); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. We don't want it. */ + nx_packet_release(packet_ptr); + + /* Error extracting packet source information, return error status. */ + return(status); + } + + /* Copy the received packet into the packet allocated by the DHCPv6 Client. */ + status = nx_packet_allocate(dhcpv6_ptr -> nx_dhcpv6_pool_ptr, + &new_packet_ptr, NX_IPv6_UDP_PACKET, + NX_DHCPV6_PACKET_TIME_OUT); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Release the receive packet. We can't use it. */ + nx_packet_release(packet_ptr); + + return status; + } + + /* Verify the incoming packet does not exceed our DHCPv6 Client packet payload. */ + if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < packet_ptr -> nx_packet_length) + { + + /* Release the packet allocated from the Client pool*/ + nx_packet_release(new_packet_ptr); + + /* Release the received packet. We can't use it. */ + nx_packet_release(packet_ptr); + + return(NX_DHCPV6_INVALID_DATA_SIZE); + } + + /* Use a packet from the DHCP Client as a buffer to store the received packet data. + Then we can release the received packet back to its packet pool. */ + status = nx_packet_data_extract_offset(packet_ptr, 0,(VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); + + /* Check status. */ + if ((status != NX_SUCCESS) || (bytes_copied == 0)) + { + + /* Release the packet allocated from the Client pool*/ + nx_packet_release(new_packet_ptr); + + /* Release the received packet. We can't use it. */ + nx_packet_release(packet_ptr); + + /* Error extracting packet buffer, return error status. */ + return(status); + } + + /* Now we can release the received packet. */ + nx_packet_release(packet_ptr); + + /* Update the new packet with the bytes copied. For chained packets, this will reflect the total + 'datagram' length. */ + new_packet_ptr -> nx_packet_length = bytes_copied; + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + bytes_copied; + + /* Process the DHCPv6 packet.*/ + + /* Scan the packet options and record it. */ + status = _nx_dhcpv6_scan_packet_options(dhcpv6_ptr, new_packet_ptr); + + /* Check for errors processing the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the Client packet. We can't use it. */ + nx_packet_release(new_packet_ptr); + + /* Return error status. */ + return status; + } + + /* Preprocess the packet options. */ + status = _nx_dhcpv6_preprocess_packet_information(dhcpv6_ptr, new_packet_ptr); + + /* Check for errors processing the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the Client packet. We can't use it. */ + nx_packet_release(new_packet_ptr); + + /* Return error status. */ + return status; + } + + /* Extract the info from the packet buffer into the Client record. */ + status = _nx_dhcpv6_extract_packet_information(dhcpv6_ptr, new_packet_ptr); + + /* Release the Client packet. We are done with it. */ + nx_packet_release(new_packet_ptr); + + /* Store the DHCPv6 server address. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_dhcpv6_received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY)) + { + COPY_NXD_ADDRESS(&server_IP_Address, &(dhcpv6_ptr-> nx_dhcpv6_server_address)); + } + + /* Successfully processed response from the server. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_scan_packet_options PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function scan the packet options of DHCPv6 server response and */ +/* record the relevant options. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* packet_ptr Pointer to received packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Extract option and length data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_packet_process Process dhcpv6 packet. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_scan_packet_options(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +UCHAR *dhcpv6_option_ptr; +UINT index; +ULONG option_code; +ULONG option_length; +UCHAR *dhcpv6_iana_option_ptr; +UINT iana_index; +ULONG iana_option_code; +ULONG iana_option_length; +UCHAR *dhcpv6_ia_option_ptr; +ULONG ia_option_index; +ULONG ia_option_code; +ULONG ia_option_length; +ULONG ipv6_address[4]; +USHORT status_code; +UINT ia_index; +UINT w; +UINT ia_count = 0; + + /* Set a pointer to the start of DHCPv6 options. */ + dhcpv6_option_ptr = (packet_ptr -> nx_packet_prepend_ptr + 4); + + /* Initialize local variables. */ + index = 0; + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags = 0; + dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value = 0; + + /* Clear the IA address map status. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map = 0; + } + + /* Now parse all the DHCPv6 option blocks in the packet buffer. */ + /* 4 bytes is data pointer offset, and 4 bytes for option code and option length. */ + while (index <= (packet_ptr -> nx_packet_length - 4 - 4)) + { + + /* Get the option code and length of data of the current option block. */ + status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_option_ptr, &option_code, &option_length); + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Check if option data is in the packet. */ + if ((dhcpv6_option_ptr + 4 + option_length) > packet_ptr -> nx_packet_append_ptr) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + /* Process the option code with an option specific API. */ + switch (option_code) + { + + /* Note - these 'process' functions will not move the buffer pointer. */ + case NX_DHCPV6_OP_CLIENT_ID: + { + + /* Yes, The message includes the Client DUID option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION; + break; + } + + case NX_DHCPV6_OP_SERVER_ID: + { + + /* Yes, The message includes the Server DUID option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_SERVER_ID_OPTION; + break; + } + case NX_DHCPV6_OP_IA_NA: + { + + /* Yes, The message includes the Server DUID option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_IA_NA_OPTION; + + /* Skip the IA_NA header data. */ + dhcpv6_iana_option_ptr = dhcpv6_option_ptr + 16; + iana_index = 0; + + /* Process the IA and status options embedded in the IANA option. */ + /* 12 bytes is IA_NA header, 4 bytes for iana option code and option length. */ + while(iana_index <= (option_length - 12 - 4)) + { + + /* Get the next option code and length. */ + status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_iana_option_ptr, &iana_option_code, &iana_option_length); + + /* Check if the option data is in the packet. */ + if ((dhcpv6_iana_option_ptr + 4 + iana_option_length) > packet_ptr -> nx_packet_append_ptr) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + /* Check the IA address option embedded in the IANA option. */ + if(iana_option_code == NX_DHCPV6_OP_IA_ADDRESS) + { + + /* The minimum length of IA address option is 24 bytes. */ + if (iana_option_length < 24) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + /* Yes, The message includes the IA option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION; + + /* Increase the IA option count. */ + ia_count ++; + + /* Skip the IA type and length option. */ + ia_option_index = 4; + + /* Get the IPv6 address of IA option. */ + for (w = 0; w <= 3; w++) + { + + /* Copy each IPv6 address word into the IA address. */ + memcpy(&ipv6_address[w], (dhcpv6_iana_option_ptr + ia_option_index), sizeof(ULONG)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(ipv6_address[w]); + + ia_option_index += 4; + } + + /* Check the IA table, find the same IPv6 address. */ + for(w = 0; w < NX_DHCPV6_MAX_IA_ADDRESS; w++) + { + + if(!(memcmp(&(dhcpv6_ptr->nx_dhcpv6_ia[w].nx_global_address.nxd_ip_address.v6[0]), &ipv6_address[0], 16))) + { + + /* Yes, it is, record the index to store the IA option, 0 means is IA address inexistence. + Then update the IA option according to the IA count in nx_dhcpv6_update_ia function. */ + dhcpv6_ptr -> nx_dhcpv6_ia[w].nx_address_map = ia_count; + break; + } + } + + /* Check the IA option whether include the status codes or not. */ + /* 24 bytes is IA address option, 4 bytes for next option code and option length. */ + if(iana_option_length >= (24 + 4)) + { + + /* Yes, include status codes, skip the IA header data. */ + dhcpv6_ia_option_ptr = dhcpv6_iana_option_ptr + 28; + + /* Get the status code and length. */ + status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_ia_option_ptr, &ia_option_code, &ia_option_length); + + /* Check if the option data is in the packet. */ + if ((dhcpv6_ia_option_ptr + 4 + ia_option_length) > packet_ptr -> nx_packet_append_ptr) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + if(ia_option_code == NX_DHCPV6_OP_STATUS_CODE) + { + if (ia_option_length < 2) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + /* Yes, the message includes the STATUS option, get the code. */ + memcpy(&status_code, (dhcpv6_ia_option_ptr + 4), sizeof(USHORT)); + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(status_code); + + if(status_code == 0) + { + + /* Yes, The message includes the Success status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; + } + else if(status_code == 1) + { + + /* Yes, The message includes the UnspecFail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; + } + else if(status_code == 2) + { + + /* Yes, The message includes the NoAddrsAvail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; + } + else if(status_code == 3) + { + + /* Yes, The message includes the NoBinding status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; + } + else if(status_code == 4) + { + + /* Yes, The message includes the NotOnLink status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; + } + else if(status_code == 5) + { + + /* Yes, The message includes the UseMulticast status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; + } + else + { + + /* This is an unsupported or unknown option. */ + return NX_DHCPV6_UNKNOWN_OPTION; + } + + } + else + { + + /* This is an unsupported or unknown option. */ + return NX_DHCPV6_UNKNOWN_OPTION; + } + } + } + + /* Check if this is an status option request. */ + else if(iana_option_code == NX_DHCPV6_OP_STATUS_CODE) + { + if (iana_option_length < 2) + { + return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); + } + + /* Yes, the message includes the STATUS option, get the code. */ + memcpy(&status_code, (dhcpv6_iana_option_ptr + 4), sizeof(USHORT)); + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(status_code); + + if(status_code == 0) + { + + /* Yes, The message includes the Success status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; + } + else if(status_code == 1) + { + + /* Yes, The message includes the UnspecFail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; + } + else if(status_code == 2) + { + + /* Yes, The message includes the NoAddrsAvail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; + } + else if(status_code == 3) + { + + /* Yes, The message includes the NoBinding status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; + } + else if(status_code == 4) + { + + /* Yes, The message includes the NotOnLink status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; + } + else if(status_code == 5) + { + + /* Yes, The message includes the UseMulticast status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; + } + else + { + + /* This is an unsupported or unknown option. */ + return NX_DHCPV6_UNKNOWN_OPTION; + } + } + else + { + + /* This is an unsupported or unknown option. */ + return NX_DHCPV6_UNKNOWN_OPTION; + } + + /* Move to the next top level option. */ + dhcpv6_iana_option_ptr += iana_option_length + 4; + + /* Update the iana_index. */ + iana_index += iana_option_length + 4; + + } + + break; + } + + case NX_DHCPV6_OP_PREFERENCE: + { + USHORT temp; + + /* Yes, The message includes the preference option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_PREFERENCE_OPTION; + + /* Set the pointer. */ + temp = *(dhcpv6_option_ptr + 4); + + /* Record the preference option value of current advetise message. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value = temp; + + /* Adjust the endianness. */ + NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value); + break; + } + + case NX_DHCPV6_OP_STATUS_CODE: + { + + /* Yes, the message includes the STATUS option, get the code. */ + memcpy(&status_code, (dhcpv6_option_ptr + 4), sizeof(USHORT)); + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(status_code); + + if(status_code == 0) + { + + /* Yes, The message includes the Success status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; + } + else if(status_code == 1) + { + + /* Yes, The message includes the UnspecFail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; + } + else if(status_code == 2) + { + + /* Yes, The message includes the NoAddrsAvail status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; + } + else if(status_code == 3) + { + + /* Yes, The message includes the NoBinding status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; + } + else if(status_code == 4) + { + + /* Yes, The message includes the NotOnLink status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; + } + else if(status_code == 5) + { + + /* Yes, The message includes the UseMulticast status option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; + } + else + { + + /* This is an unsupported or unknown option. */ + return NX_DHCPV6_UNKNOWN_OPTION; + } + break; + } + + case NX_DHCPV6_OP_RAPID_COMMIT: + { + + /* Yes, The message includes the Rapid Commit option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION; + break; + } + + case NX_DHCPV6_OP_DNS_SERVER: + { + + /* Yes, The message includes the DNS server option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_DNS_SERVER_OPTION; + break; + } + + case NX_DHCPV6_OP_DOMAIN_NAME: + { + + /* Yes, The message includes the domain name option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_DOMAIN_NAME_OPTION; + break; + } + + case NX_DHCPV6_OP_SNTP_SERVER: + { + + /* Yes, The message includes the timer server option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_SNTP_SERVER_OPTION; + break; + } + + case NX_DHCPV6_OP_CLIENT_FQDN: + { + + /* Yes, The message includes the Client FQDN option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_CLIENT_FQDN_OPTION; + break; + } + + case NX_DHCPV6_OP_NEW_POSIX_TIMEZONE: + { + + /* Yes, The message includes the time zone option. */ + dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_NEW_POSIX_TIIMEZONE_OPTION; + break; + } + + default: + { + break; + } + } + + /* Move to the next top level option. */ + dhcpv6_option_ptr += option_length + 4; + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + } + + /* Yes, scan is complete, just return success. */ + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_preprocess_packet_information PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function preprocess packet information according to reply */ +/* message option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* packet_ptr Pointer to received packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCPv6_SUCCESS Successful completion status */ +/* NX_DHCPV6_NO_DUID_OPTION Message has no DUID option */ +/* NX_DHCPV6_NO_RAPID_COMMIT_OPTION Message has no rapid */ +/* commit option */ +/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Message has no IA option */ +/* NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE Preference value is equal to */ +/* or less than */ +/* NX_DHCPV6_UNKNOWN_MSG_TYPE Unknown message type */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_data Get the data in reply message */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_packet_process Process the packet. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_preprocess_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) +{ + +ULONG received_message_type; +ULONG returned_xid; + + /* Preprocess the DHCPv6 packet. */ + + /* Extract the message type which should be the first byte. */ + _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr, 1, &received_message_type); + + /* Check for an illegal message type. */ + if ((received_message_type != NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) && + (received_message_type != NX_DHCPV6_MESSAGE_TYPE_REPLY) && + (received_message_type != NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE)) + { + + /* These should only be sent to DHCPv6 servers! */ + return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; + } + + /* Set the received message type. */ + dhcpv6_ptr -> nx_dhcpv6_received_message_type = (UCHAR)received_message_type; + + /* This is a unicast packet (valid). Parse the transaction ID. */ + _nx_dhcpv6_utility_get_data((packet_ptr -> nx_packet_prepend_ptr + 1), 3, &returned_xid); + + /* Make sure the DHCP transaction ID matches our current session. */ + if (returned_xid != (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid)) + { + + /* Return the bad transmaction ID. */ + return NX_DHCPV6_BAD_TRANSACTION_ID; + } + + /* Check the options. */ + switch (dhcpv6_ptr -> nx_dhcpv6_state) + { + + /* The DHCPv6 remains initial status or DHCPv6 interactive process has been completed. + Just clear the timer and message ID. */ + case NX_DHCPV6_STATE_BOUND_TO_ADDRESS: + case NX_DHCPV6_STATE_INIT: + { + + /* In these state, DHCPv6 Client do not expect any packet. */ + return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; + } + + /* The DHCPv6 CLient has sent a solicit message and expect advertise message. */ + case NX_DHCPV6_STATE_SENDING_SOLICIT: + { + + /* DHCPv6 Client must discrd the received advertise messages + that meet the message does not inlcude SERVER ID or CLIENT ID. */ + if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION) || + !(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_SERVER_ID_OPTION)) + { + + /* The packet does not include DUID option.*/ + return NX_DHCPV6_NO_DUID_OPTION; + } + + /* DHcpv6 Client must ignore any advertise message that includes a status code option + containing the value NoAddrsAvail. */ + if(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION) + { + return NX_DHCPV6_IA_ADDRESS_NOT_VALID; + } + + if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) + { + if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION)) + { + + return NX_DHCPV6_NO_RAPID_COMMIT_OPTION; + } + } + else + { + + /* Check the preference value. */ + if((dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value != 0) && + (dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value <= dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value)) + { + + /* The current preference value is equal to or less than the recorded preference valude, + DHCPv6 Client need not process the message, return. */ + return NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE; + } + } + + break; + } + + /* The DHCPv6 CLien has sent a request message and expect reply message. */ + case NX_DHCPV6_STATE_SENDING_REQUEST: + case NX_DHCPV6_STATE_SENDING_RENEW: + case NX_DHCPV6_STATE_SENDING_REBIND: + case NX_DHCPV6_STATE_SENDING_CONFIRM: + case NX_DHCPV6_STATE_SENDING_RELEASE: + case NX_DHCPV6_STATE_SENDING_DECLINE: + case NX_DHCPV6_STATE_SENDING_INFORM_REQUEST: + { + + /* DHCPv6 Client must discrd the received advertise messages + that meet the message does not inlcude SERVE ID or CLIENT ID. */ + if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION) || + !(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_SERVER_ID_OPTION)) + { + + /* The packet does not include DUID option.*/ + return NX_DHCPV6_NO_DUID_OPTION; + } + break; + } + + default: + { + + /* Unknown or unsupported DHCPv6 request (state). */ + return NX_DHCPV6_UNKNOWN_MSG_TYPE; + } + } + + return NX_DHCPV6_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_extract_packet_information PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the DHCPv6 server response to Client requests. */ +/* It checks for valid reply message types for the current Client */ +/* request, and if all is well, then parses each option in sequential */ +/* order and updates the server reply data to the Client record. At the*/ +/* end of the data extraction, it then verifies that the server reply */ +/* contained both valid Client and server DUID options. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* packet_ptr Pointer to received packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal */ +/* NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up */ +/* NX_DHCPV6_PROCESSING_ERROR Packet length is different than */ +/* expected */ +/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ +/* NX_DHCPV6_MISSING_IANA_OPTION Message has no IANA option */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_utility_get_block_option_length */ +/* Extract option header data */ +/* _nx_dhcpv6_process_client_duid Extract Client DUID from reply */ +/* _nx_dhcpv6_process_server_duid Extract Server DUID from reply */ +/* _nx_dhcpv6_process_iana Extract IANA option from reply */ +/* _nx_dhcpv6_process_preference Extract server preference */ +/* _nx_dhcpv6_process_DNS_server Extract DNS server from reply */ +/* _nx_dhcpv6_process_time_server Extract time server from reply */ +/* _nx_dhcpv6_process_time_zone Extract time zone from reply */ +/* _nx_dhcpv6_process_domain_name Extract domain name from reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_packet_process Process the dhcpv6 reply message*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_extract_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +ULONG op_code; +ULONG option_length; +UCHAR *buffer_ptr; +UINT index; + + /* The DHCPv6 header has been processed in preprocess function, so process the options. */ + /* Set a pointer to the options of DHCPv6. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 4; + + /* Initialize local variables. */ + index = 0; + + /* Now parse all the DHCPv6 option blocks in the packet buffer. */ + while (index < (packet_ptr -> nx_packet_length - 4)) + { + + /* Get the option code and length of data of the current option block. */ + status = _nx_dhcpv6_utility_get_block_option_length(buffer_ptr, &op_code, &option_length); + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Process the option code with an option specific API. */ + switch (op_code) + { + /* Note - these 'process' functions will not move the buffer pointer. */ + + case NX_DHCPV6_OP_CLIENT_ID: + { + + /* Process the Client DUID. */ + status = _nx_dhcpv6_process_client_duid(dhcpv6_ptr, buffer_ptr, option_length); + + break; + } + + case NX_DHCPV6_OP_SERVER_ID: + { + + /* Process the Server DUID. */ + status = _nx_dhcpv6_process_server_duid(dhcpv6_ptr, buffer_ptr, option_length); + + break; + } + case NX_DHCPV6_OP_IA_NA: + { + + status = _nx_dhcpv6_process_iana(dhcpv6_ptr, buffer_ptr, option_length); + + /* Note: this API directly handles any server error codes received. */ + + break; + } + + /* This should not happen. The IA address option must be embedded in the IANA option. */ + case NX_DHCPV6_OP_IA_ADDRESS: + { + + /* Don't process an IA address option outside of an address association (IANA). */ + status = NX_DHCPV6_MISSING_IANA_OPTION; + + break; + } + + /* The RFC for DHCPv6 indicates any option can have a status option applied to it. So a status + option outside of an IANA option (where it is usually found) has to be handled. */ + case NX_DHCPV6_OP_STATUS_CODE: + { + status = _nx_dhcpv6_process_status(dhcpv6_ptr, buffer_ptr, option_length); + + /* Now check on the server status of the previous option in the DHCP message. */ + if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) + { + + /* Does the dhcpv6 client have a server error handler? */ + if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) + { + + /* Send the status and which option the status is reported for to the handler. */ + (dhcpv6_ptr -> nx_dhcpv6_server_error_handler)(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_OPTION_FIELD, dhcpv6_ptr -> nx_status_code, + dhcpv6_ptr -> nx_dhcpv6_received_message_type); + } + } + + break; + } + + /* Process the preference option. */ + case NX_DHCPV6_OP_PREFERENCE: + { + + status = _nx_dhcpv6_process_preference(dhcpv6_ptr, buffer_ptr, option_length); + break; + } + + /* The remainder are RFC mandated option codes for specific options. Not all of these + have been finalized by IANA as of this release. */ + + case NX_DHCPV6_OP_DNS_SERVER: + { + + status = _nx_dhcpv6_process_DNS_server(dhcpv6_ptr, buffer_ptr, option_length); + + break; + } + + case NX_DHCPV6_OP_DOMAIN_NAME: + { + status = _nx_dhcpv6_process_domain_name(dhcpv6_ptr, packet_ptr -> nx_packet_prepend_ptr, buffer_ptr, option_length); + break; + } + + case NX_DHCPV6_OP_SNTP_SERVER: + { + + status = _nx_dhcpv6_process_time_server(dhcpv6_ptr, buffer_ptr, option_length); + break; + } + + case NX_DHCPV6_OP_NEW_POSIX_TIMEZONE: + { + status = _nx_dhcpv6_process_time_zone(dhcpv6_ptr, buffer_ptr, option_length); + break; + } + + default: + { + break; + } + } + + /* Check for errors from option block processing. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Move to the next top level option. */ + buffer_ptr += option_length + 4; + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + + } + + /* Now, the index should be the packet length. */ + if(index != (packet_ptr -> nx_packet_length - 4)) + { + return NX_DHCPV6_INVALID_DATA_SIZE; + } + + /* Yes, the packet data processing is completed. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_flush_queue_packets PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function flush the useless queue packets. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_receive Receive UDP packet */ +/* nx_packet_release Release packet to packet pool */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process Process the DHCPv6 Client request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_flush_queue_packets(NX_DHCPV6 *dhcpv6_ptr) +{ + +UINT status = NX_SUCCESS; +NX_PACKET *packet_ptr; + + + /* Loop to receive the queue packets. */ + while(status == NX_SUCCESS) + { + + /* Receive the queue packets and release it. */ + status = nx_udp_socket_receive(&(dhcpv6_ptr -> nx_dhcpv6_socket), &packet_ptr, NX_NO_WAIT); + + /* Check the status. */ + if (status == NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_update_retransmit_info PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the retransmission,update the retransmission */ +/* count and retransmission timeout according to the RFC3315,Section14.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Valid retransmit */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_process Process current client state */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_update_retransmit_info(NX_DHCPV6 *dhcpv6_ptr) +{ + + /* Process the retransmission according to the RFC3315, Section 14, page26. */ + if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count != 0) || (dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration != 0)) + { + + if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count != 0) && + (dhcpv6_ptr -> nx_dhcpv6_retransmission_count >= dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count)) + { + + /* Has reached the max retransmission count, return. */ + return NX_DHCPV6_REACHED_MAX_RETRANSMISSION_COUNT; + } + + if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration != 0) && + (dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time >= (dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration * 100))) + { + + /* Has reached the max retransmission timeout, return. */ + return NX_DHCPV6_REACHED_MAX_RETRANSMISSION_TIMEOUT; + } + } + + /* Increase the count of retransmission. */ + dhcpv6_ptr -> nx_dhcpv6_retransmission_count++; + + /* Double the retransmission timeout for the next retransmit. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 2 * dhcpv6_ptr -> nx_dhcpv6_transmission_timeout; + + /* Is the retransmission timeout greater than the max allowable timeout, if there is one? */ + if ((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout != 0) && + (dhcpv6_ptr -> nx_dhcpv6_transmission_timeout > dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout)) + { + + /* Limit the transmission time to the max for the next message. */ + dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout; + } + + /* Can retransmit the request. */ + return NX_SUCCESS; +} + + +#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_ipv6_address_DAD_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the IPv6 address perform DAD notify callback. */ +/* And set the DHCPv6 event to notify DHCPv6 Client thread. If this */ +/* function is used in DHCPv6 function, nxd_ipv6_address_change_notify */ +/* function should not be used again. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* status DAD process status */ +/* interface_index The interface index */ +/* ipv6_addr_index The IPv6 address index */ +/* ipv6_address Pointer to IPv6 address */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags to wake */ +/* DHCPv6 thread to process */ +/* */ +/* CALLED BY */ +/* */ +/* UDP receive callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_ipv6_address_DAD_notify(NX_IP *ip_ptr, UINT status, UINT interface_index, UINT ipv6_addr_index, ULONG *ipv6_address) +{ +UINT ia_index; + + NX_PARAMETER_NOT_USED(interface_index); + + /* Make sure the DHCPv6 DAD instance is normal. */ + if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID) || + (!_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_name) || + (_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ip_ptr != ip_ptr) || + (_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS)) + return; + + + /* Check the DAD status. */ + if(status == NX_IPV6_ADDRESS_DAD_FAILURE) + { + + /* Now find where this address cross references in the DHCP address list. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_client_address_index[ia_index] == ipv6_addr_index) && + (!memcmp(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), ipv6_address, 16))) + { + + /* Set the IPv6 address status DAD failure. */ + _nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE; + + /* Wakeup DHCPv6 thread for processing DAD failure event. */ + tx_event_flags_set(&_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_events, NX_DHCPV6_DAD_FAILURE_EVENT, TX_OR); + + break; + } + } + } + + /* Check the DAD status. */ + if(status == NX_IPV6_ADDRESS_DAD_SUCCESSFUL) + { + + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_client_address_index[ia_index] == ipv6_addr_index) && + (!memcmp(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), ipv6_address, 16))) + { + + /* Set the IPv6 address status valid. */ + _nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_VALID; + + break; + } + } + } + + return; +} +#endif + + +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the get DHCPv6 Client */ +/* record service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 instance */ +/* client_record_ptr Pointer to memory to save */ +/* Client record to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status from */ +/* internal DHCP calls */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_client_create_record */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dhcpv6_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Call actual DHCPv6 client get record service. */ + status = _nx_dhcpv6_client_get_record(dhcpv6_ptr, client_record_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_get_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a DHCPv6 Client record for restoring the */ +/* Client state between power cycles or idle (sleep) mode. It then */ +/* copies the Client record to the supplied client record pointer. It */ +/* should be that the DHCPv6 Client state be restored from the Client */ +/* record saved to the input pointer client_record_ptr. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 instance */ +/* client_record_ptr Pointer to memory to save */ +/* Client record to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_NOT_BOUND DHCPv6 was not bound */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr) +{ + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Clear memory before filling with data. */ + memset(client_record_ptr, 0, sizeof(NX_DHCPV6_CLIENT_RECORD)); + + /* The DHCPv6 Client is not Bound to an IP address. Cannot create a record for restoring Client + state if not bound to an IP lease. */ + if (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) + { + return NX_DHCPV6_NOT_BOUND; + } + + /* Set the DHCPv6 record. */ + client_record_ptr -> nx_dhcpv6_state = dhcpv6_ptr -> nx_dhcpv6_state; + + /* Set the interface and address index. */ + client_record_ptr -> nx_dhcpv6_client_interface_index = dhcpv6_ptr -> nx_dhcpv6_client_interface_index; + memcpy(client_record_ptr -> nx_dhcpv6_client_address_index, dhcpv6_ptr -> nx_dhcpv6_client_address_index, sizeof(UINT) * NX_DHCPV6_MAX_IA_ADDRESS); + + /* Set the time since client set its IP address. */ + client_record_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued; + + /* Set the Client DUID. */ + memcpy(&client_record_ptr -> nx_dhcpv6_client_duid, &dhcpv6_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_DUID)); + + /* Set the Server DUID. */ + memcpy(&client_record_ptr -> nx_dhcpv6_server_duid, &dhcpv6_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_DUID)); + + /* Set the IANA. */ + memcpy(&client_record_ptr -> nx_dhcpv6_iana, &dhcpv6_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_IA_NA)); + + /* Set the IA Address. */ + memcpy(&client_record_ptr -> nx_dhcpv6_ia, &dhcpv6_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_IA_ADDRESS) * NX_DHCPV6_MAX_IA_ADDRESS); + + /* Set the Option request. */ + memcpy(&client_record_ptr -> nx_dhcpv6_option_request, &dhcpv6_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_OPTIONREQUEST)); + + /* Set the Client FQDN. */ + memcpy(&client_record_ptr -> nx_dhcpv6_client_FQDN, &dhcpv6_ptr -> nx_dhcpv6_client_FQDN, sizeof(NX_DHCPV6_CLIENT_FQDN)); + + /* Set the dns name server address. */ + memcpy(&client_record_ptr -> nx_dhcpv6_DNS_name_server_address, &dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_DNS_SERVERS); + + /* Set the time server address. */ + memcpy(&client_record_ptr -> nx_dhcpv6_time_server_address, &dhcpv6_ptr -> nx_dhcpv6_time_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_TIME_SERVERS); + + /* Set the domain name. */ + memcpy(client_record_ptr -> nx_dhcpv6_domain_name, dhcpv6_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); + + /* Set the time zone. */ + memcpy(client_record_ptr -> nx_dhcpv6_time_zone, dhcpv6_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_client_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the client restore service.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 instance */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERRPR Invalid pointer input */ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_client_restore_record */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dhcpv6_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Call actual DHCPv6 client get record service. */ + status = _nx_dhcpv6_client_restore_record(dhcpv6_ptr, client_record_ptr, time_elapsed); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_restore_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the DHCPv6 CLient state with the supplied DHCP*/ +/* Client record pointed to by the client_record_ptr pointer. It then */ +/* updates the time out parameters of the DHCPv6 Client with the */ +/* time_elapsed parameter (in timer ticks). It is intended for */ +/* restoring Client state between reboots and assumes the DHCPv6 Client*/ +/* state was previously obtained and stored in NVRAM before power down.*/ +/* */ +/* Note: after restore the DHCPv6 Client record, should call */ +/* nx_dhcpv6_resume to update the DHCPv6 Client state and resume the */ +/* DHCPv6 processing thread. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 instance */ +/* client_record_ptr Pointer to previously saved */ +/* Client record */ +/* time_elapsed time input in timer ticks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status NetX completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_ip_interface_address_set */ +/* nx_ip_address_set */ +/* _nx_dhcp_client_update_time_remaining */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) +{ + +UINT ia_index; + + + /* Get the DHCP mutex. */ + tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); + + /* Set the DHCPv6 record. */ + dhcpv6_ptr -> nx_dhcpv6_state = client_record_ptr -> nx_dhcpv6_state; + + /* Set the interface and address index. */ + dhcpv6_ptr -> nx_dhcpv6_client_interface_index = client_record_ptr -> nx_dhcpv6_client_interface_index; + memcpy(dhcpv6_ptr -> nx_dhcpv6_client_address_index, client_record_ptr -> nx_dhcpv6_client_address_index, sizeof(UINT) * NX_DHCPV6_MAX_IA_ADDRESS); + + /* Set the Client DUID. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_client_duid, &client_record_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_DUID)); + + /* Set the Server DUID. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_server_duid, &client_record_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_DUID)); + + /* Set the IANA. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_iana, &client_record_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_IA_NA)); + + /* Set the IA Address. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_ia, &client_record_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_IA_ADDRESS) * NX_DHCPV6_MAX_IA_ADDRESS); + + /* Set the Option request. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_option_request, &client_record_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_OPTIONREQUEST)); + + /* Set the Client FQDN. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_client_FQDN, &client_record_ptr -> nx_dhcpv6_client_FQDN, sizeof(NX_DHCPV6_CLIENT_FQDN)); + + /* Set the dns name server address. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address, &client_record_ptr -> nx_dhcpv6_DNS_name_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_DNS_SERVERS); + + /* Set the time server address. */ + memcpy(&dhcpv6_ptr -> nx_dhcpv6_time_server_address, &client_record_ptr -> nx_dhcpv6_time_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_TIME_SERVERS); + + /* Set the domain name. */ + memcpy(dhcpv6_ptr -> nx_dhcpv6_domain_name, client_record_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); + + /* Set the time zone. */ + memcpy(dhcpv6_ptr -> nx_dhcpv6_time_zone, client_record_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); + + /* Set the time since client set its IP address. */ + dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = (client_record_ptr -> nx_dhcpv6_IP_lifetime_time_accrued + time_elapsed); + + /* Set the DHCPv6 Client IPv6 addresses. */ + for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) + { + + if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) + { + + /* Add the address to the IP instance address table. */ + nxd_ipv6_address_set(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_interface_index, + &dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address, 64, &dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); + } + } + + /* Release the DHCPv6 Client mutex. */ + tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); + + return NX_SUCCESS; +} +#endif /* NX_DHCPV6_CLIENT_RESTORE_STATE */ +#endif /* FEATURE_NX_IPV6 */ diff --git a/addons/dhcp/nxd_dhcpv6_client.h b/addons/dhcp/nxd_dhcpv6_client.h new file mode 100644 index 00000000..8b2a1663 --- /dev/null +++ b/addons/dhcp/nxd_dhcpv6_client.h @@ -0,0 +1,1060 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_dhcpv6_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Dynamic Host Configuration Protocol over */ +/* IPv6 (DHCPv6) component, including all data types and external */ +/* references. It is assumed that nx_api.h and nx_port.h have already */ +/* been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_DHCPV6_CLIENT_H +#define NXD_DHCPV6_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +/* Enable support for DHCPv6 client state preserved between reboots */ +/* +#define NX_DHCPV6_CLIENT_RESTORE_STATE +*/ + + +/* Define the DHCPv6 ID "DHCPV6" that is used to mark the DHCPv6 structure as created. */ + +#define NX_DHCPV6_ID 0x44484336UL + + +/* Set the Client lease time. An infinate lease time is not recommended by the RFC + unless the Client requires a permanent IP address. Most servers will likely not + grant an infinite IP address lease. */ + +#define NX_DHCPV6_INFINITE_LEASE 0xffffffffUL +#define NX_DHCPV6_MULTICAST_MASK 0xff000000UL + +typedef enum +{ + NX_DHCPV6_DUID_TYPE_LINK_TIME = 1, + NX_DHCPV6_DUID_TYPE_VENDOR_ASSIGNED, + NX_DHCPV6_DUID_TYPE_LINK_ONLY + +} NX_DHCPV6_DUID_TYPE; + + +/* Define the Hardware types. */ +#define NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET 1 +#define NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64 27 + +/* NX_DHCPV6_HW_TYPE_IEEE_802 is defined as 1 to indicate Ethernet hardware type in old releases, for backward compatibility. + + Note: NX_DHCPV6_HW_TYPE_IEEE_802 will be deprecated by NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET + in future releases, should use above symbols to define hardware types. +*/ +#define NX_DHCPV6_HW_TYPE_IEEE_802 1 + + +/* Define approximate time since Jan 1, 2000 for computing DUID time. This will form the + basis for the DUID time ID field. */ + +#define SECONDS_SINCE_JAN_1_2000_MOD_32 2563729999UL + +/* Define the value for IA address. */ + +#define NX_DHCPV6_REMOVE_ALL_IA_ADDRESS 0xFFFFFFFF + +/* Define the DHCPv6 Message Types. */ + +#define NX_DHCPV6_MESSAGE_TYPE_SOLICIT 1 +#define NX_DHCPV6_MESSAGE_TYPE_ADVERTISE 2 +#define NX_DHCPV6_MESSAGE_TYPE_REQUEST 3 +#define NX_DHCPV6_MESSAGE_TYPE_CONFIRM 4 +#define NX_DHCPV6_MESSAGE_TYPE_RENEW 5 +#define NX_DHCPV6_MESSAGE_TYPE_REBIND 6 +#define NX_DHCPV6_MESSAGE_TYPE_REPLY 7 +#define NX_DHCPV6_MESSAGE_TYPE_RELEASE 8 +#define NX_DHCPV6_MESSAGE_TYPE_DECLINE 9 +#define NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE 10 +#define NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST 11 + +/* Define the DHCPv6 Options, RFC3315, RFC 3646 and RFC 4242,etc. */ + +#define NX_DHCPV6_OP_CLIENT_ID 1 /* Client DUID (DHCP unique identifier) */ +#define NX_DHCPV6_OP_SERVER_ID 2 /* Server DUID (DHCP unique identifier) */ +#define NX_DHCPV6_OP_IA_NA 3 /* Identity association for non temporary addresses */ +#define NX_DHCPV6_OP_IA_TA 4 /* Identity association for temporary addresses */ +#define NX_DHCPV6_OP_IA_ADDRESS 5 /* Address associated with IA_NA or IA_TA */ +#define NX_DHCPV6_OP_OPTION_REQUEST 6 /* Identifies a list of options */ +#define NX_DHCPV6_OP_PREFERENCE 7 /* Server's means of affecting Client choice of servers. */ +#define NX_DHCPV6_OP_ELAPSED_TIME 8 /* Duration of Client exchange with DHCPv6 server */ +#define NX_DHCPV6_OP_RELAY_MESSAGE 9 /* Not in use in NetX DHCPV6 */ +#define NX_DHCPV6_OP_AUTHENTICATION 11 /* Not in use in NetX DHCPV6 */ +#define NX_DHCPV6_OP_SERVER_UNICAST 12 /* Server ok's allowing the client to address it in Unicast */ +#define NX_DHCPV6_OP_STATUS_CODE 13 /* Status option. */ +#define NX_DHCPV6_OP_RAPID_COMMIT 14 /* Rapid commit option. */ +#define NX_DHCPV6_OP_USER_CLASS 15 /* User calss option. */ +#define NX_DHCPV6_OP_VENDOR_CLASS 16 /* Vendor Class option. */ +#define NX_DHCPV6_OP_VENDOR_SPEC_INFO 17 /* Vendor specific information option. */ +#define NX_DHCPV6_OP_INTERFACE_ID 18 /* Interface ID option. */ +#define NX_DHCPV6_OP_RCONF_MESSAGE 19 /* Reconfigure message option. */ +#define NX_DHCPV6_OP_RCONF_ACCEPT 20 /* Reconfigure accept option. */ + +#define NX_DHCPV6_OP_DNS_SERVER 23 /* Dns servers option. */ +#define NX_DHCPV6_OP_DOMAIN_NAME 24 /* Domain names list option. */ + +#define NX_DHCPV6_OP_SNTP_SERVER 31 /* Network time protocol servers option. */ +#define NX_DHCPV6_OP_CLIENT_FQDN 39 /* Client Fully Qualified Domain Name Option. */ +#define NX_DHCPV6_OP_NEW_POSIX_TIMEZONE 41 /* New timezone POSIX string index option. */ +#define NX_DHCPV6_OP_NEW_TZDB_TIMEZONE 42 /* New timezone database string option. */ + +/* Define the Error Status Code Location. */ +#define NX_DHCPV6_ERROR_STATUS_CODE_IN_OPTION_FIELD 0 /* An Error Status Code option appears in options field of DHCP message. */ +#define NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_NA 1 /* An Error Status Code option appears in options field of IA_NA option. */ +#define NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_ADDRESS 2 /* An Error Status Code option appears in options field of IA_ADDRESS option . */ + +/* Define the options included in the reply message. */ + +#define NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION 0x00000001 /* The reply message includes a Client Identifier option. */ +#define NX_DHCPV6_INCLUDE_SERVER_ID_OPTION 0x00000002 /* The reply message includes a Server Identifier option. */ +#define NX_DHCPV6_INCLUDE_IA_NA_OPTION 0x00000004 /* The reply message includes a IA_NA option. */ +#define NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION 0x00000008 /* The reply message includes a IA address option. */ +#define NX_DHCPV6_INCLUDE_OPTION_REQUEST_OPTION 0x00000010 /* The reply message includes a option request option. */ +#define NX_DHCPV6_INCLUDE_PREFERENCE_OPTION 0x00000020 /* The reply message includes a preference option. */ +#define NX_DHCPV6_INCLUDE_ELAPSED_TIME_OPTION 0x00000040 /* The reply message includes a elapsed time option. */ +#define NX_DHCPV6_INCLUDE_RELAY_MESSAGE_OPTION 0x00000080 /* The reply message includes a relay message option. */ +#define NX_DHCPV6_INCLUDE_AUTHENTICATION_OPTION 0x00000100 /* The reply message includes a authentication option. */ +#define NX_DHCPV6_INCLUDE_SERVER_UNICAST_OPTION 0x00000200 /* The reply message includes a server unicast option. */ +#define NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION 0x00000400 /* The reply message includes a status code option with success. */ +#define NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION 0x00000800 /* The reply message includes a status code option with failure. */ +#define NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION 0x00001000 /* The reply message includes a status code option with no addresses available. */ +#define NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION 0x00002000 /* The reply message includes a status code option with unavailable. */ +#define NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION 0x00004000 /* The reply message includes a status code option with not onlink. */ +#define NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION 0x00008000 /* The reply message includes a status code option with use multicast. */ +#define NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION 0x00010000 /* The reply message includes a rapid commit option. */ +#define NX_DHCPV6_INCLUDE_USER_CLASS_OPTION 0x00020000 /* The reply message includes a user class option. */ +#define NX_DHCPV6_INCLUDE_VENDOR_CLASS_OPTION 0x00040000 /* The reply message includes a vendor class option. */ +#define NX_DHCPV6_INCLUDE_VENDOR_SPEC_INFO_OPTION 0x00080000 /* The reply message includes a vendor specifc information option. */ +#define NX_DHCPV6_INCLUDE_INTERFACE_ID_OPTION 0x00100000 /* The reply message includes a interface Id option. */ +#define NX_DHCPV6_INCLUDE_RECONF_MESSAGE_OPTION 0x00200000 /* The reply message includes a reconfigure message option. */ +#define NX_DHCPV6_INCLUDE_RECONF_ACCEPT_OPTION 0x00400000 /* The reply message includes a reconfigure accept option. */ +#define NX_DHCPV6_INCLUDE_DNS_SERVER_OPTION 0x00800000 /* The reply message includes a dns server option. */ +#define NX_DHCPV6_INCLUDE_DOMAIN_NAME_OPTION 0x01000000 /* The reply message includes a domain name option. */ +#define NX_DHCPV6_INCLUDE_SNTP_SERVER_OPTION 0x02000000 /* The reply message includes a network time protocol servers option. */ +#define NX_DHCPV6_INCLUDE_NEW_POSIX_TIIMEZONE_OPTION 0x04000000 /* The reply message includes a new timezone POSIX string index option. */ +#define NX_DHCPV6_INCLUDE_CLIENT_FQDN_OPTION 0x08000000 /* The reply message includes a client FQDN option. */ + + +/* Define internal DHCPv6 option flags. */ + +#define NX_DHCPV6_DNS_SERVER_OPTION 0x00000001UL /* Option code for requesting DNS server IP address */ +#define NX_DHCPV6_DOMAIN_NAME_OPTION 0x00000002UL /* Option code for requesting domain name. */ +#define NX_DHCPV6_SNTP_SERVER_OPTION 0x00000004UL /* Option code for requesting time server IP address. */ +#define NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION 0x00000008UL /* Option code for requesting Time zone. */ +#define NX_DHCPV6_CLIENT_FQDN_OPTION 0x00000010UL /* Option code for requesting FQDN. */ + + +/* RFC defined DHCPv6 server status codes */ + +#define NX_DHCPV6_SUCCESS 0 /* Server indicates Client DHCPv6 request is granted. */ +#define NX_DHCPV6_UNSPECIFIED_FAILURE 1 /* Unspecified reason e.g. not found in RFC 3315 */ +#define NX_DHCPV6_NO_ADDRESS_AVAILABLE 2 /* Server unable to assign IP address because none are available. */ +#define NX_DHCPV6_NO_BINDING 3 /* Client record (binding) unavailable */ +#define NX_DHCPV6_NOT_ON_LINK 4 /* Client's IPv6 address is not on the Server link */ +#define NX_DHCPV6_USE_MULTICAST 5 /* Server indicates Client must use multicast ALL_SERVERS address to get IP address */ + +/* Internal DHCPv6 Client status codes */ + +#define NX_DHCPV6_STATE_INIT 1 /* Client state with no bound IP address */ +#define NX_DHCPV6_STATE_SENDING_SOLICIT 2 /* Client sends Sollicit to identify a DHCP server */ +#define NX_DHCPV6_STATE_SENDING_REQUEST 3 /* Address requested, Client initiating a request after receiving server advertisement */ +#define NX_DHCPV6_STATE_SENDING_RENEW 4 /* Address established, Client is initiating a renew request */ +#define NX_DHCPV6_STATE_SENDING_REBIND 5 /* Address established, Client is initiating a rebind request */ +#define NX_DHCPV6_STATE_SENDING_DECLINE 6 /* Address was established but Client can't use it e.g. duplicate address check failed. */ +#define NX_DHCPV6_STATE_SENDING_CONFIRM 7 /* Client IP Address is established but Client requires confirmation its still ok */ +#define NX_DHCPV6_STATE_SENDING_INFORM_REQUEST 8 /* Client IP Address is established but Client requests information other than IP address */ +#define NX_DHCPV6_STATE_SENDING_RELEASE 9 /* Requesting an IP address release of a recently assigned IP address. */ +#define NX_DHCPV6_STATE_BOUND_TO_ADDRESS 15 /* Client is bound to an assigned address; DHCP Client task is basically idle. */ + +/* Internal DHCPv6 Client address status codes. */ + +#define NX_DHCPV6_IA_ADDRESS_STATE_INVALID 0 /* The IA does not inlcude IPv6 address. */ +#define NX_DHCPV6_IA_ADDRESS_STATE_INITIAL 1 /* The IA inlcude one IPv6 address,but the DHCPv6 interactive is not complete. */ +#define NX_DHCPV6_IA_ADDRESS_STATE_DAD_TENTATIVE 2 /* After DHCPv6 interactive, NetX pefrome the DAD to check this IPv6 address. */ +#define NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE 3 /* DAD process failure,the DHCPv6 Client should send DECLINE message.*/ +#define NX_DHCPV6_IA_ADDRESS_STATE_VALID 4 /* The global IP address is valid and set it to the IP instance. */ + +/* Internal DHCPv6 event flags. These events are processed by the Client DHCPv6 thread. */ + +#define NX_DHCPV6_ALL_EVENTS 0xFFFFFFFFUL /* All Client DHCPv6 event flags */ +#define NX_DHCPV6_DAD_FAILURE_EVENT 0x00000001UL /* The DHCPv6 Client perform DAD failure. */ +#define NX_DHCPV6_DAD_SUCCESSFUL_EVENT 0x00000002UL /* The DHCPv6 Client perform DAD failure. */ + +/* The behavior of a DHCPv6 client that implements the Client FQDN option. RFC4704, Section5, Page7. */ + +#define NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR 0 /* DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client. */ +#define NX_DHCPV6_CLIENT_DESIRES_SERVER_DO_DNS_UPDATE 1 /* DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client to the server. */ +#define NX_DHCPV6_CLIENT_DESIRES_NO_SERVER_DNS_UPDATE 2 /* DHCPv6 Client choose to request that the server perform no DNS updatest on its behalf. */ + + +/* RFC mandated DHCPv6 client and server ports. */ + +#define NX_DHCPV6_SERVER_UDP_PORT 547 +#define NX_DHCPV6_CLIENT_UDP_PORT 546 + + +/* The solicit mode. */ + +#define NX_DHCPV6_SOLICIT_NORMAL 1 +#define NX_DHCPV6_SOLICIT_RAPID 2 + + +/* Define name compression masks. */ + +#define NX_DHCPV6_LABEL_MAX 63 /* Maximum Label (between to dots) size. */ +#define NX_DHCPV6_COMPRESS_MASK 0xc0 +#define NX_DHCPV6_COMPRESS_VALUE 0xc0 +#define NX_DHCPV6_POINTER_MASK 0xc000 + + +/* Internal error codes for DHCPv6 Client services. */ + +#define NX_DHCPV6_TASK_SUSPENDED 0xE90 /* DHCPv6 task suspended by host application. */ +#define NX_DHCPV6_ALREADY_STARTED 0xE91 /* DHCPv6 already started when API called to start it. */ +#define NX_DHCPV6_NOT_STARTED 0xE92 /* DHCPv6 was not started when API was called */ +#define NX_DHCPV6_PARAM_ERROR 0xE93 /* Invalid non pointer input to API */ +#define NX_DHCPV6_NOT_BOUND 0xE94 /* DHCPv6 was not bound when API was called. */ + +#define NX_DHCPV6_INVALID_CLIENT_DUID 0xE95 /* Client DUID received from Server with invalid data or mismatches Client server DUID on record. */ +#define NX_DHCPV6_INVALID_SERVER_DUID 0xE96 /* Server DUID received by Client has bad syntax or missing data*/ +#define NX_DHCPV6_MESSAGE_MISSING_DUID 0xE97 /* Client receives a message type missing server or client DUID. */ +#define NX_DHCPV6_UNSUPPORTED_DUID_TYPE 0xE98 /* Client configuration involves a DUID type not supported by this API. */ +#define NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE 0xE99 /* Client configuration involves a network hardware type not supported by this API. */ +#define NX_DHCPV6_NO_DUID_OPTION 0xE9A /* The reply message does not include server or client identifier option. */ +#define NX_DHCPV6_NO_RAPID_COMMIT_OPTION 0xE9B /* The reply message does not iclude rapid commit option. */ +#define NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE 0xE9C /* The current preference value is equal to or less than the recorded preference valude. */ + +#define NX_DHCPV6_INVALID_IANA_TIME 0xEA0 /* Server IA-NA option T1 vs T2 address lease time is invalid. */ +#define NX_DHCPV6_MISSING_IANA_OPTION 0xEA1 /* Client received IA address option not belonging to an IA block */ +#define NX_DHCPV6_BAD_IANA_ID 0xEA2 /* Server IA-NA option does not contain the Client's original IA-NA ID. */ +#define NX_DHCPV6_INVALID_IANA_DATA 0xEA3 /* Server IA-NA option block has bad syntax or missing data */ +#define NX_DHCPV6_INVALID_IA_ADDRESS 0xEA4 /* Client inquiring about an unknown IA address */ +#define NX_DHCPV6_INVALID_IA_DATA 0xEA5 /* Server IA address option block has bad syntax or missing data */ +#define NX_DHCPV6_INVALID_IA_TIME 0xEA6 /* Server IA option preferred vs valid lease time is invalid. */ +#define NX_DHCPV6_INVALID_PREF_DATA 0xEA7 /* Client received Preference block with missing data or bad syntax */ +#define NX_DHCPV6_INCOMPLETE_OPTION_BLOCK 0xEA8 /* Empty option block data; either zero length or zero option parsed. */ +#define NX_DHCPV6_MISSING_REQUIRED_OPTIONS 0xEA9 /* Cannot start the DHCPv6 Client because required options are missing e.g. IANA, DUID etc */ +#define NX_DHCPV6_INVALID_OPTION_DATA 0xEAA /* Client received option data with missing data or bad syntax */ +#define NX_DHCPV6_UNKNOWN_OPTION 0xEAB /* Client received an unknown or unsupported option from server */ +#define NX_DHCPV6_INVALID_SERVER_PACKET 0xEAC /* Server reply invalid e.g. bad port, invalid DHCP header or invalid reply message. */ +#define NX_DHCPV6_IA_ADDRESS_NOT_VALID 0xEAD /* Client not assigned an IP address from the DHCPv6 Server */ +#define NX_DHCPV6_REACHED_MAX_IA_ADDRESS 0xEAE /* IA address exceeds the maximum IAs specified by NX_DHCPV6_MAX_IA_ADDRESS. */ +#define NX_DHCPV6_IA_ADDRESS_ALREADY_EXIST 0xEAF /* The IA address already added to the Client. */ + +#define NX_DHCPV6_UNKNOWN_PROCESS_STATE 0xEB0 /* Internal DHCPv6 state machine in an unknown state */ +#define NX_DHCPV6_ILLEGAL_MESSAGE_TYPE 0xEB1 /* Client receives a message type intended for a DHCPv6 server e.g. REQUEST or CONFIRM */ +#define NX_DHCPV6_UNKNOWN_MSG_TYPE 0xEB2 /* NetX DHCPv6 receives an unknown message type */ +#define NX_DHCPV6_BAD_TRANSACTION_ID 0xEB3 /* Client received message with bad transaction ID */ +#define NX_DHCPV6_BAD_IPADDRESS_ERROR 0xEB4 /* Unable to parse a valid IPv6 address from specified data buffer */ +#define NX_DHCPV6_PROCESSING_ERROR 0xEB5 /* Server packet size received out of synch with NetX packet length - no assignment of blame */ +#define NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD 0xEB6 /* Client DHCPv6 message will not fit in Client packet pool packet buffer. */ +#define NX_DHCPV6_INVALID_DATA_SIZE 0xEB7 /* Attempting to parse too large a data object to/from DHCPv6 request. */ +#define NX_DHCPV6_ADDRESS_MISMATCH 0xEB8 /* Client IPv6 address index into the IP table is incorrect (addresses do not match). */ + +#define NX_DHCPV6_REACHED_MAX_RETRANSMISSION_COUNT 0xEC0 /* No response from server after maximum number of retries. */ +#define NX_DHCPV6_REACHED_MAX_RETRANSMISSION_TIMEOUT 0xEC1 /* No response from server after maximum retry timeout. */ + + +/* Define DHCPv6 timeout for checking DHCPv6 flag status. */ +#define NX_DHCPV6_TIME_INTERVAL (NX_IP_PERIODIC_RATE) + + +/* Define the conversion between timer ticks and seconds (processor dependent). */ +#define NX_DHCPV6_TICKS_PER_SECOND (NX_IP_PERIODIC_RATE) + + +/* Define the max name size. RFC1035, Section 3.1. */ +#define NX_DHCPV6_MAX_NAME_SIZE 255 + + +/* Define the DHCP stack priority. */ + +#ifndef NX_DHCPV6_THREAD_PRIORITY +#define NX_DHCPV6_THREAD_PRIORITY 2 +#endif + + +/* Define the time out option to obtain a DHCPv6 Client mutex lock. If the + the Client appears to be locking up, this can be set to a finite value + for debugging as well as restore responsiveness to the Client */ + +#ifndef NX_DHCPV6_MUTEX_WAIT +#define NX_DHCPV6_MUTEX_WAIT TX_WAIT_FOREVER +#endif + + +/* Define DHCPv6 Client record parameters */ + +/* Define the timer interval for the IP lifetime timer in seconds. */ + +#ifndef NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL +#define NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL 1 +#endif + + +/* Define the timer interval for the session duration timer in seconds. */ + +#ifndef NX_DHCPV6_SESSION_TIMER_INTERVAL +#define NX_DHCPV6_SESSION_TIMER_INTERVAL 1 +#endif + + +/* Define the number of DNS name servers the Client will store. */ + +#ifndef NX_DHCPV6_NUM_DNS_SERVERS +#define NX_DHCPV6_NUM_DNS_SERVERS 2 +#endif + + +/* Define the number of time servers the Client will store. */ + +#ifndef NX_DHCPV6_NUM_TIME_SERVERS +#define NX_DHCPV6_NUM_TIME_SERVERS 1 +#endif + + +/* Define the buffer size for storing the DHCPv6 Client domain name. */ + +#ifndef NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE +#define NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE 32 +#endif + + +/* Define the buffer size for storing the DHCPv6 Client time zone e.g. CET, PST etc. */ + +#ifndef NX_DHCPV6_TIME_ZONE_BUFFER_SIZE +#define NX_DHCPV6_TIME_ZONE_BUFFER_SIZE 16 +#endif + +/* Define the amount of packet payload to store DHCPv6 server messages. */ + +#ifndef NX_DHCPV6_MAX_MESSAGE_SIZE +#define NX_DHCPV6_MAX_MESSAGE_SIZE 100 +#endif + +/* Define the amount of IA addresses to store IPv6 addresses. */ + +#ifndef NX_DHCPV6_MAX_IA_ADDRESS +#define NX_DHCPV6_MAX_IA_ADDRESS 1 +#endif + + +/* DHCPv6 Client Network Configuration */ + +/* Define the generic time out option for NetX operations (packet allocate, packet send. */ + +#ifndef NX_DHCPV6_PACKET_TIME_OUT +#define NX_DHCPV6_PACKET_TIME_OUT (3 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + + +/* Define UDP socket type of service. */ + +#ifndef NX_DHCPV6_TYPE_OF_SERVICE +#define NX_DHCPV6_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + + +/* Define the number of routers a UDP packet passes before it is discarded. */ + +#ifndef NX_DHCPV6_TIME_TO_LIVE +#define NX_DHCPV6_TIME_TO_LIVE 0x80 +#endif + +/* Define the stored packets in the UDP socket queue. */ + +#ifndef NX_DHCPV6_QUEUE_DEPTH +#define NX_DHCPV6_QUEUE_DEPTH 5 +#endif + + +/* Define the initial retransmission timeout in timer ticks for DHCPv6 messages. + For no limit on the retransmission timeout set to 0, for no limit + on the retries, set to 0. + + Note that regardless of length of timeout or number of retries, when the IP address + valid lifetime expires, the Client can no longer use its global IP address + assigned by the DHCPv6 Server. */ + +#ifndef NX_DHCPV6_FIRST_SOL_MAX_DELAY +#define NX_DHCPV6_FIRST_SOL_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT (120 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT 0 +#endif + +#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION 0 +#endif + +#ifndef NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT (30 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT 10 +#endif + + +#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION 0 +#endif + +#ifndef NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT (10 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT (600 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT 0 +#endif + +#ifndef NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT (10 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT (600 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT 0 +#endif + +#ifndef NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT 0 +#endif + +#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT 5 +#endif + +#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION 0 +#endif + +#ifndef NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT 0 +#endif + +#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT 5 +#endif + +#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION 0 +#endif + +#ifndef NX_DHCPV6_FIRST_CONFIRM_MAX_DELAY +#define NX_DHCPV6_FIRST_CONFIRM_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT (4 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT 0 +#endif + +#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION 10 +#endif + +#ifndef NX_DHCPV6_FIRST_INFORM_MAX_DELAY +#define NX_DHCPV6_FIRST_INFORM_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT +#define NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT +#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT (120 * NX_DHCPV6_TICKS_PER_SECOND) +#endif + +#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT +#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT 0 +#endif + +#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION +#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION 0 +#endif + + +/* Define the Identity Association Internet Address option structure */ +typedef struct NX_DHCPV6_IA_ADDRESS_STRUCT +{ + + USHORT nx_op_code; /* IA internet address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ + NXD_ADDRESS nx_global_address; /* Assigned Host IPv6 address */ + ULONG nx_preferred_lifetime; /* Server's preference for IPv6 address T1 life time for itself */ + ULONG nx_valid_lifetime; /* Server's assigned valid time for T2 for any server */ + UINT nx_address_status; /* Indicates if the global address is registered and validated. */ + UINT nx_address_map; /* Map the IPv6 address with client, indicates if the IPv6 address already exists or not. */ + +} NX_DHCPV6_IA_ADDRESS; + +/* Define the Option status structure */ +typedef struct NX_DHCPV6_OP_STATUS_STRUCT +{ + + USHORT nx_op_code; /* IA address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ +} NX_DHCPV6_OP_STATUS; + + +/* Define the Preference Option structure */ +typedef struct NX_DHCPV6_PREFERENCE_STRUCT +{ + + USHORT nx_op_code; /* IA address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ + USHORT nx_pref_value; /* Assigned Host IPv6 address */ + +} NX_DHCPV6_PREFERENCE; + + +/* Define the Identity Association for Permanent ("Non Temporary" in RFC) address */ + +typedef struct NX_DHCPV6_IA_NA_STRUCT +{ + + USHORT nx_op_code; /* IA NA address option code is 3 */ + USHORT nx_option_length; /* 12 + length of variable length fields in IA_NA option . */ + ULONG nx_IA_NA_id; /* IANA identifier; must be unique among all client IANA's. Must be the same on restart per IANA */ + ULONG nx_T1; /* Time client can extend time before address lifetime expires from the server it got it from; applies to all addresses in IA_NA. */ + ULONG nx_T2; /* Same as T1 except this is when the client will request REBIND from another server. */ + +} NX_DHCPV6_IA_NA; + + +/* Define DHCPv6 Unique Identifier (DUID); both Client and Server must send messages with their own DUID. */ + +typedef struct NX_DHCPV6_DUID_STRUCT +{ + + USHORT nx_op_code; /* Client DUID option code is 1; Server DUID code is 2 */ + USHORT nx_option_length; /* Option length = 14 not including length and op code field; */ + USHORT nx_duid_type; /* 3 main types: hw; hw + time; vendor assigned ID (not supported here); requires DUID be stored in non volatile storage */ + USHORT nx_hardware_type; /* Only if LL/LLT type. Hardware type specified by IANA/RFC 826 e.g. IEEE 802; network byte order */ + ULONG nx_duid_time; /* Only if LLT type. Time based on when DUID generated; network byte order. */ + ULONG nx_link_layer_address_msw; /* Only if LL/LLT type. Pointer to Unique link layer address - most significant word (2/4 bytes)*/ + ULONG nx_link_layer_address_lsw; /* Only if LL/LLT type. Pointer to Unique link layer address - least significant word (4 bytes) */ + +} NX_DHCPV6_DUID; + + +/* Define the elapsed time option structure. This contains the length of the Client Server session. */ + +typedef struct NX_DHCPV6_ELAPSED_TIME_STRUCT +{ + + USHORT nx_op_code; /* Elapsed time option code = 8 not including length and op code field. */ + USHORT nx_op_length; /* Length of time data = 2. */ + USHORT nx_session_time; /* Time of DHCP session e.g. first msg elapsed time is zero. */ + +} NX_DHCPV6_ELAPSED_TIME; + + +/* Define the Message Option structure. Each message from the Client must have a unique message ID. */ + +typedef struct NX_DHCPV6_MESSAGE_HDR_STRUCT +{ + + USHORT nx_message_type; /* Message type (1 byte) */ + USHORT nx_reserved; /* Reserved. */ + ULONG nx_message_xid; /* Message transaction ID (3 bytes)*/ +} NX_DHCPV6_MESSAGE_HDR; + +/* Define the option request structure. This is how the Client requests information other than global IP address. + It can ask for domain name, DNS server, time zone, time server and other options. */ + +typedef struct NX_DHCPV6_OPTIONREQUEST_STRUCT +{ + USHORT nx_op_code; /* Option Request code = 6*/ + USHORT nx_option_length; /* Length in bytes of option data = 2 * number of requests */ + USHORT nx_op_request; /* e.g. DNS server = 23, ... */ + +} NX_DHCPV6_OPTIONREQUEST; + +/* Define the DHCPv6 Client FQDN Option structure, */ + +typedef struct NX_DHCPV6_CLIENT_FQDN_STRUCT +{ + USHORT nx_op_code; /* Option Client FQDN code = 39*/ + USHORT nx_op_length; /* 1 + length of domain name. */ + UCHAR nx_flags; /* Flag bits used between client and server to negotiate who performs which updates. */ + UCHAR nx_reserved[3]; /* Reserved. */ + CHAR *nx_domain_name; /* The partial or fully qualified domain name. */ + +} NX_DHCPV6_CLIENT_FQDN; + + +/* Define the Client DHCPv6 structure containind the DHCPv6 Client record (DHCPv6 status, server DUID etc). */ + +typedef struct NX_DHCPV6_STRUCT +{ + ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ + CHAR *nx_dhcpv6_name; /* DHCPv6 name supplied at create */ + UINT nx_dhcpv6_client_address_index[NX_DHCPV6_MAX_IA_ADDRESS]; + /* Index in IP address table where the Client assigned address is located. */ + UINT nx_dhcpv6_client_interface_index; /* DHCPv6 outgoing network interface index */ + TX_THREAD nx_dhcpv6_thread; /* Client processing thread */ + TX_EVENT_FLAGS_GROUP nx_dhcpv6_events; /* DHCPv6 Client event flags. */ + TX_MUTEX nx_dhcpv6_client_mutex; /* Mutex for exclusive access to the DHCP Client instance */ + TX_TIMER nx_dhcpv6_IP_lifetime_timer; /* Client IP lifetime timeout timer. */ + TX_TIMER nx_dhcpv6_session_timer; /* Client session duration timer. */ + NX_IP *nx_dhcpv6_ip_ptr; /* The associated IP pointer for this DHCPV6 instance */ + NX_PACKET_POOL *nx_dhcpv6_pool_ptr; /* Pointer to packet pool for sending DHCPV6 messages */ + NX_UDP_SOCKET nx_dhcpv6_socket; /* UDP socket for communicating with DHCPv6 server */ + UCHAR nx_dhcpv6_started; /* DHCPv6 client task has been started */ + UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ + USHORT nx_status_code; /* Status of current option received by Client */ + UINT nx_dhcpv6_sleep_flag; /* If true, the DHCPv6 client is in a position where it can be stopped */ + NX_DHCPV6_MESSAGE_HDR nx_dhcpv6_message_hdr; /* Message Header for all client messages to DHCPv6 Servers */ + NX_DHCPV6_DUID nx_dhcpv6_client_duid; /* Client DUID; ID by which Client and Server identify each other's DUID */ + NX_DHCPV6_DUID nx_dhcpv6_server_duid; /* Server DUID; ID by which Client and Server identify each other's DUID */ + NX_DHCPV6_ELAPSED_TIME nx_dhcpv6_elapsed_time; /* Time duration of the current DHCP msg exchange between Client and Server. */ + NX_DHCPV6_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ + NX_DHCPV6_IA_ADDRESS nx_dhcpv6_ia[NX_DHCPV6_MAX_IA_ADDRESS]; /* Client internet address option */ + NX_DHCPV6_PREFERENCE nx_dhcpv6_preference; /* Server's preference affecting the Client's DHCPv6 server selection. */ + NX_DHCPV6_OPTIONREQUEST nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ + NX_DHCPV6_CLIENT_FQDN nx_dhcpv6_client_FQDN; /* Set of Client options in Solicit, Request, Renew, or Rebind message types. */ + ULONG nx_dhcpv6_IP_lifetime_time_accrued; /* Time since Client set received or renewed its IP address with the DHCPv6 server. */ + UCHAR nx_status_message[NX_DHCPV6_MAX_MESSAGE_SIZE]; /* Server's message in its Option status to client. */ + NXD_ADDRESS nx_dhcpv6_server_address; /* DHCPv6 server address. */ + NXD_ADDRESS nx_dhcpv6_DNS_name_server_address[NX_DHCPV6_NUM_DNS_SERVERS]; /* DNS name server IP address */ + NXD_ADDRESS nx_dhcpv6_time_server_address[NX_DHCPV6_NUM_TIME_SERVERS]; /* time server IP address */ + NXD_ADDRESS nx_dhcpv6_client_destination_address; /* The destination address where DHCP message should be sent, by default All_DHCP_Relay_Agents_and_Servers(FF02::1:2). */ + UCHAR nx_dhcpv6_domain_name[NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE]; /* Buffer for holding domain name. */ + UCHAR nx_dhcpv6_time_zone[NX_DHCPV6_TIME_ZONE_BUFFER_SIZE]; /* Buffer for holding time zone. */ + ULONG nx_dhcpv6_solicitations_sent; /* The number of Solicit messages sent */ + ULONG nx_dhcpv6_solicitation_responses; /* The number of solicitations server responded to */ + ULONG nx_dhcpv6_requests_sent; /* The number of Request messages sent */ + ULONG nx_dhcpv6_request_responses; /* The number of requests server responded to */ + ULONG nx_dhcpv6_renews_sent; /* The number of renew messages sent */ + ULONG nx_dhcpv6_renew_responses; /* The number of renews server responded to */ + ULONG nx_dhcpv6_rebinds_sent; /* The number of Rebind messages sent */ + ULONG nx_dhcpv6_rebind_responses; /* The number of Rebind requests Server responded to */ + ULONG nx_dhcpv6_releases_sent; /* The number of Release messages sent */ + ULONG nx_dhcpv6_release_responses; /* The number of Releases server responded to */ + ULONG nx_dhcpv6_confirms_sent; /* The number of confirmations sent */ + ULONG nx_dhcpv6_confirm_responses; /* The number of confirmations server responded to */ + ULONG nx_dhcpv6_declines_sent; /* The number of declines sent */ + ULONG nx_dhcpv6_decline_responses; /* The number of declines server responded to */ + ULONG nx_dhcpv6_inform_req_sent; /* The number of Inform (option requests) sent */ + ULONG nx_dhcpv6_inform_req_responses; /* The number of Inform server responsed to */ + ULONG nx_dhcpv6_transmission_timeout; /* Timeout on Client messages before resending a request to the server. */ + ULONG nx_dhcpv6_retransmission_count; /* The number of request retransmissions to the server. */ + ULONG nx_dhcpv6_init_retransmission_timeout; /* The initial retransmission time. */ + ULONG nx_dhcpv6_max_retransmission_count; /* The maximum retransmission count. */ + ULONG nx_dhcpv6_max_retransmission_timeout; /* The maximum retransmission time. */ + ULONG nx_dhcpv6_max_retransmission_duration; /* The maximum retransmissions duration. */ + UINT nx_dhcpv6_request_solicit_mode; /* The mode of sending the solicit message with rapid commit option. */ + UINT nx_dhcpv6_reply_option_flags; /* The flags indicate options the reply messages included. */ + USHORT nx_dhcpv6_reply_option_current_pref_value; /* The preference value of current advertise message. */ + UCHAR nx_dhcpv6_received_message_type; /* The type of received message */ + UCHAR nx_dhcpv6_reserved; /* Reserved. */ + + /* Define the callback function for DHCP state change notification. If specified + by the application, this function is called whenever a state change occurs for + the DHCP associated with this IP instance. */ + VOID (*nx_dhcpv6_state_change_callback)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT old_state, UINT new_state); + + /* Define the callback function for receiving a non successful status from the Server. The + context of the status/error is defined by the message type is was received in and what + option the status is referring to e.g. IA Address. */ + VOID (*nx_dhcpv6_server_error_handler)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type); + +} NX_DHCPV6; + + + +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +/* Define the DHCPv6 Client record structure for restore the DHCPv6 Client state from non volatile memory/across reboots. */ + +typedef struct NX_DHCPV6_CLIENT_RECORD_STRUCT +{ + UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ + UCHAR nx_dhcpv6_reserved[3]; /* Reserved. */ + UINT nx_dhcpv6_client_interface_index; /* DHCPv6 outgoing network interface index */ + UINT nx_dhcpv6_client_address_index[NX_DHCPV6_MAX_IA_ADDRESS]; + /* Index in IP address table where the Client assigned address is located. */ + ULONG nx_dhcpv6_IP_lifetime_time_accrued; /* Time since Client set received or renewed its IP address with the DHCPv6 server. */ + NX_DHCPV6_DUID nx_dhcpv6_client_duid; /* Client DUID; ID by which Client and Server identify each other's DUID */ + NX_DHCPV6_DUID nx_dhcpv6_server_duid; /* Server DUID; ID by which Client and Server identify each other's DUID */ + NX_DHCPV6_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ + NX_DHCPV6_IA_ADDRESS nx_dhcpv6_ia[NX_DHCPV6_MAX_IA_ADDRESS]; /* Client internet address option */ + NX_DHCPV6_OPTIONREQUEST nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ + NX_DHCPV6_CLIENT_FQDN nx_dhcpv6_client_FQDN; /* Set of Client options in Solicit, Request, Renew, or Rebind message types. */ + NXD_ADDRESS nx_dhcpv6_DNS_name_server_address[NX_DHCPV6_NUM_DNS_SERVERS]; /* DNS name server IP address */ + NXD_ADDRESS nx_dhcpv6_time_server_address[NX_DHCPV6_NUM_TIME_SERVERS]; /* time server IP address */ + UCHAR nx_dhcpv6_domain_name[NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE]; /* Buffer for holding domain name. */ + UCHAR nx_dhcpv6_time_zone[NX_DHCPV6_TIME_ZONE_BUFFER_SIZE]; /* Buffer for holding time zone. */ +} NX_DHCPV6_CLIENT_RECORD; +#endif + +#ifndef NX_DHCPV6_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map DHCP API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_dhcpv6_client_create _nx_dhcpv6_client_create +#define nx_dhcpv6_client_delete _nx_dhcpv6_client_delete +#define nx_dhcpv6_create_client_duid _nx_dhcpv6_create_client_duid +#define nx_dhcpv6_create_client_iana _nx_dhcpv6_create_client_iana +#define nx_dhcpv6_create_client_ia _nx_dhcpv6_add_client_ia +#define nx_dhcpv6_add_client_ia _nx_dhcpv6_add_client_ia +#define nx_dhcpv6_client_set_interface _nx_dhcpv6_client_set_interface +#define nx_dhcpv6_client_set_destination_address _nx_dhcpv6_client_set_destination_address +#define nx_dhcpv6_set_time_accrued _nx_dhcpv6_set_time_accrued +#define nx_dhcpv6_get_client_duid_time_id _nx_dhcpv6_get_client_duid_time_id +#define nx_dhcpv6_get_IP_address _nx_dhcpv6_get_IP_address +#define nx_dhcpv6_get_lease_time_data _nx_dhcpv6_get_lease_time_data +#define nx_dhcpv6_get_other_option_data _nx_dhcpv6_get_other_option_data +#define nx_dhcpv6_get_DNS_server_address _nx_dhcpv6_get_DNS_server_address +#define nx_dhcpv6_get_time_server_address _nx_dhcpv6_get_time_server_address +#define nx_dhcpv6_get_time_accrued _nx_dhcpv6_get_time_accrued +#define nx_dhcpv6_get_iana_lease_time _nx_dhcpv6_get_iana_lease_time +#define nx_dhcpv6_get_valid_ip_address_count _nx_dhcpv6_get_valid_ip_address_count +#define nx_dhcpv6_get_valid_ip_address_lease_time _nx_dhcpv6_get_valid_ip_address_lease_time +#define nx_dhcpv6_reinitialize _nx_dhcpv6_reinitialize +#define nx_dhcpv6_request_solicit _nx_dhcpv6_request_solicit +#define nx_dhcpv6_request_solicit_rapid _nx_dhcpv6_request_solicit_rapid +#define nx_dhcpv6_request_confirm _nx_dhcpv6_request_confirm +#define nx_dhcpv6_request_release _nx_dhcpv6_request_release +#define nx_dhcpv6_request_inform_request _nx_dhcpv6_request_inform_request +#define nx_dhcpv6_request_option_DNS_server _nx_dhcpv6_request_option_DNS_server +#define nx_dhcpv6_request_option_domain_name _nx_dhcpv6_request_option_domain_name +#define nx_dhcpv6_request_option_time_server _nx_dhcpv6_request_option_time_server +#define nx_dhcpv6_request_option_timezone _nx_dhcpv6_request_option_timezone +#define nx_dhcpv6_request_option_FQDN _nx_dhcpv6_request_option_FQDN +#define nx_dhcpv6_start _nx_dhcpv6_start +#define nx_dhcpv6_stop _nx_dhcpv6_stop +#define nx_dhcpv6_suspend _nx_dhcpv6_suspend +#define nx_dhcpv6_resume _nx_dhcpv6_resume +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +#define nx_dhcpv6_client_get_record _nx_dhcpv6_client_get_record +#define nx_dhcpv6_client_restore_record _nx_dhcpv6_client_restore_record +#endif + +#else + +/* Services with error checking. */ + +#define nx_dhcpv6_client_create _nxe_dhcpv6_client_create +#define nx_dhcpv6_client_delete _nxe_dhcpv6_client_delete +#define nx_dhcpv6_create_client_duid _nxe_dhcpv6_create_client_duid +#define nx_dhcpv6_create_client_iana _nxe_dhcpv6_create_client_iana +#define nx_dhcpv6_create_client_ia _nxe_dhcpv6_add_client_ia +#define nx_dhcpv6_add_client_ia _nxe_dhcpv6_add_client_ia +#define nx_dhcpv6_client_set_interface _nxe_dhcpv6_client_set_interface +#define nx_dhcpv6_client_set_destination_address _nxe_dhcpv6_client_set_destination_address +#define nx_dhcpv6_set_time_accrued _nxe_dhcpv6_set_time_accrued +#define nx_dhcpv6_get_client_duid_time_id _nxe_dhcpv6_get_client_duid_time_id +#define nx_dhcpv6_get_IP_address _nxe_dhcpv6_get_IP_address +#define nx_dhcpv6_get_lease_time_data _nxe_dhcpv6_get_lease_time_data +#define nx_dhcpv6_get_other_option_data _nxe_dhcpv6_get_other_option_data +#define nx_dhcpv6_get_DNS_server_address _nxe_dhcpv6_get_DNS_server_address +#define nx_dhcpv6_get_time_server_address _nxe_dhcpv6_get_time_server_address +#define nx_dhcpv6_get_time_accrued _nxe_dhcpv6_get_time_accrued +#define nx_dhcpv6_get_iana_lease_time _nxe_dhcpv6_get_iana_lease_time +#define nx_dhcpv6_get_valid_ip_address_count _nxe_dhcpv6_get_valid_ip_address_count +#define nx_dhcpv6_get_valid_ip_address_lease_time _nxe_dhcpv6_get_valid_ip_address_lease_time +#define nx_dhcpv6_reinitialize _nxe_dhcpv6_reinitialize +#define nx_dhcpv6_request_solicit _nxe_dhcpv6_request_solicit +#define nx_dhcpv6_request_solicit_rapid _nxe_dhcpv6_request_solicit_rapid +#define nx_dhcpv6_request_confirm _nxe_dhcpv6_request_confirm +#define nx_dhcpv6_request_release _nxe_dhcpv6_request_release +#define nx_dhcpv6_request_inform_request _nxe_dhcpv6_request_inform_request +#define nx_dhcpv6_request_option_DNS_server _nxe_dhcpv6_request_option_DNS_server +#define nx_dhcpv6_request_option_domain_name _nxe_dhcpv6_request_option_domain_name +#define nx_dhcpv6_request_option_time_server _nxe_dhcpv6_request_option_time_server +#define nx_dhcpv6_request_option_timezone _nxe_dhcpv6_request_option_timezone +#define nx_dhcpv6_request_option_FQDN _nxe_dhcpv6_request_option_FQDN +#define nx_dhcpv6_start _nxe_dhcpv6_start +#define nx_dhcpv6_stop _nxe_dhcpv6_stop +#define nx_dhcpv6_suspend _nxe_dhcpv6_suspend +#define nx_dhcpv6_resume _nxe_dhcpv6_resume +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +#define nx_dhcpv6_client_get_record _nxe_dhcpv6_client_get_record +#define nx_dhcpv6_client_restore_record _nxe_dhcpv6_client_restore_record +#endif + +#endif + +/* Define the prototypes accessible to the application software. */ +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 nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); +UINT nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); +UINT nx_dhcpv6_create_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); +UINT nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); +UINT nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); +UINT nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); +UINT nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); +UINT nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); +UINT nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); +UINT nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); +UINT nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); +UINT nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); +UINT nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); +UINT nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); +UINT nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); +UINT nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +UINT nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); +UINT nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); +#endif + + +#else + +/* DHCP source code is being compiled, do not perform any API mapping. */ + +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 _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 _nxe_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); +UINT _nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); +UINT _nxe_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); +UINT _nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); +UINT _nxe_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); +UINT _nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); +UINT _nxe_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); +UINT _nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); +UINT _nxe_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); +UINT _nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); +UINT _nxe_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); +UINT _nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); +UINT _nxe_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); +UINT _nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); +UINT _nxe_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); +UINT _nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); +UINT _nxe_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT _nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT _nxe_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); +UINT _nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); +UINT _nxe_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT _nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT _nxe_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT _nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); +UINT _nxe_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); +UINT _nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); +UINT _nxe_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); +UINT _nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); +UINT _nxe_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); +UINT _nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); +UINT _nxe_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT _nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); +UINT _nxe_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nxe_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nxe_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nxe_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); +UINT _nxe_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); +UINT _nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); +UINT _nxe_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); +UINT _nxe_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); +#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE +UINT _nxe_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); +UINT _nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); +UINT _nxe_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); +UINT _nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); +#endif + +#endif + + +/* Define DHCPv6 Client internal functions. */ + +VOID _nx_dhcpv6_thread_entry(ULONG info); +VOID _nx_dhcpv6_process(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request(NX_DHCPV6 *dhcpv6_ptr, UINT dhcpv6_state); +UINT _nx_dhcpv6_request_renew(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_rebind(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_request_decline(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_send_request(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_add_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_elapsed_time(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_option_request(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_ia_address(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index, UINT ia_index); +UINT _nx_dhcpv6_add_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_client_FQDN(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_waiting_on_reply(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_packet_process(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); +UINT _nx_dhcpv6_scan_packet_options(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); +UINT _nx_dhcpv6_preprocess_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); +UINT _nx_dhcpv6_extract_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); +VOID _nx_dhcpv6_flush_queue_packets(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_process_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_domain_name(NX_DHCPV6 *dhcpv6_ptr, UCHAR *packet_start, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_ia(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length, UINT ia_index); +UINT _nx_dhcpv6_process_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_preference(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_status(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_time_zone(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_time_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); +VOID _nx_dhcpv6_IP_lifetime_timeout_entry(ULONG dhcpv6_ptr_value); +VOID _nx_dhcpv6_session_timeout_entry(ULONG dhcpv6_ptr_value); +UINT _nx_dhcpv6_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length); +UINT _nx_dhcpv6_utility_get_data(UCHAR *buffer, UINT size, ULONG *value); +INT _nx_dhcpv6_utility_time_randomize(void); +UINT _nx_dhcpv6_update_retransmit_info(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_register_IP_address(NX_DHCPV6 *dhcpv6_ptr); +UINT _nx_dhcpv6_remove_assigned_address(NX_DHCPV6 *dhcpv6_ptr, UINT ia_index); +UINT _nx_dhcpv6_name_string_encode(UCHAR *ptr, UCHAR *name); +UINT _nx_dhcpv6_name_string_unencode(UCHAR *data, UINT start, UCHAR *buffer, UINT size); +#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) +VOID _nx_dhcpv6_ipv6_address_DAD_notify(NX_IP *ip_ptr, UINT status, UINT interface_index, UINT ipv6_addr_index, ULONG *ipv6_address); +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_DHCPV6_CLIENT_H */ + + diff --git a/addons/dhcp/nxd_dhcpv6_server.c b/addons/dhcp/nxd_dhcpv6_server.c new file mode 100644 index 00000000..49fc0be7 --- /dev/null +++ b/addons/dhcp/nxd_dhcpv6_server.c @@ -0,0 +1,7281 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6 Server) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_DHCPV6_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include +#include "nx_api.h" +#include "nx_system.h" +#include "nx_ip.h" +#include "nx_ipv6.h" +#include "nx_udp.h" +#include "nxd_dhcpv6_server.h" +#include "tx_timer.h" + +#ifdef FEATURE_NX_IPV6 + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX create dhcpv6 */ +/* server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* ip_ptr Pointer to server IP instance */ +/* name_ptr DHCPV6 name pointer */ +/* packet_pool_ptr Pointer to server packet pool */ +/* stack_ptr Pointer to free memory */ +/* stack_size Size of server stack memory */ +/* dhcpv6_address_declined_handler Declined address request handler*/ +/* dhcpv6_option_request_handler Option request handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_create DHCPV6 server create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, + NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, + VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), + VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_server_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 server create service. */ + status = _nx_dhcpv6_server_create(dhcpv6_server_ptr, ip_ptr, name_ptr, packet_pool_ptr, stack_ptr, stack_size, + dhcpv6_address_declined_handler, dhcpv6_option_request_handler); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the DHCPv6 Client instance with a Netx packet */ +/* pool, processing thread, and various flag event queues, timers and */ +/* mutexes necessary for DHCPv6 Client operations. */ +/* */ +/* Note: User is encouraged to call nx_dhcpv6_server_option_request */ +/* _handler_set to set the option request handler. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* ip_ptr Pointer to Server IP instance */ +/* name_ptr DHCPV6 name pointer */ +/* packet_pool_ptr Pointer to Server packet pool */ +/* stack_ptr Pointer to free memory */ +/* stack_size Size of server stack memory */ +/* dhcpv6_address_declined_handler Declined address request handler*/ +/* dhcpv6_option_request_handler Option request handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create ThreadX flag event queue*/ +/* tx_mutex_create Create mutex lock on resource */ +/* nx_packet_pool_delete Delete the DHCPV6 packet pool */ +/* nx_udp_socket_create Create the DHCPV6 UDP socket */ +/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ +/* tx_mutex_create Create DHCPV6 mutex */ +/* tx_mutex_delete Delete DHCPV6 mutex */ +/* tx_thread_create Create DHCPV6 processing thread*/ +/* tx_thread_delete Delete DHCPV6 processing thread*/ +/* tx_timer_create Create DHCPV6 timer */ +/* tx_timer_delete Delete DHCPV6 timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, + NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, + VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), + VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)) +{ + +UINT i, status; +NX_DHCPV6_CLIENT *dhcpv6_client_ptr; + + + /* Initialize the DHCPV6 control block to zero. */ + memset((void *) dhcpv6_server_ptr, 0, sizeof(NX_DHCPV6_SERVER)); + + /* Default the server global index to index 1. If otherwise, the host + application must set the DHCPv6 interface before it can start + the Server (nx_dhcpv6_server_interface_set). */ + dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = 1; + + /* Link the DHCPv6 server with the IP instance. */ + dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr = ip_ptr; + + /* Set the DHCPV6 name. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_name = name_ptr; + + /* Set the server packet pool. */ + dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr = packet_pool_ptr; + + /* Create the IP timer event flag instance. */ + status = tx_event_flags_create(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, "DHCPv6 Server Timer Events Queue"); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + return status; + } + + /* Create the DHCPV6 mutex for the Server instance. */ + status = tx_mutex_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), "DHCPV6 Server Mutex", TX_NO_INHERIT); + + /* Determine if the mutexes creation was successful. */ + if (status) + { + + /* Delete the flag queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + + /* No, return error status. */ + return status; + } + + /* Create the DHCPV6 processing thread. */ + status = tx_thread_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), "NetX DHCPV6 Server", _nx_dhcpv6_server_thread_entry, + (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, stack_ptr, stack_size, + NX_DHCPV6_SERVER_THREAD_PRIORITY, NX_DHCPV6_SERVER_THREAD_PRIORITY, 1, TX_DONT_START); + + NX_THREAD_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), dhcpv6_server_ptr) + + /* Determine if the thread creation was successful. */ + if (status) + { + + /* Delete the server protection mutex. */ + tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Delete the flag queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + + /* No, return error status. */ + return status; + } + + /* Create the DHCPV6 timer for keeping track of IP lease time expiration. */ + status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), "NetX DHCPV6 Server Lease timer", + _nx_dhcpv6_server_lease_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, + (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND) , + (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), + TX_NO_ACTIVATE); + + NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), dhcpv6_server_ptr) + + if (status != NX_SUCCESS) + { + + /* Delete the DHCPv6 Server thread. */ + tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Delete the server protection mutex. */ + tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Delete the flag queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + } + + /* Create the DHCPV6 timer for keeping track of the DHCPv6 Client session time. */ + status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), "NetX DHCPV6 Session Duration timer", + _nx_dhcpv6_server_session_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, + (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), + (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), + TX_NO_ACTIVATE); + + NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), dhcpv6_server_ptr) + + if (status != NX_SUCCESS) + { + + /* Delete the server lease timer. */ + tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); + + /* Delete the DHCPv6 Server thread. */ + tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Delete the server protection mutex. */ + tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Delete the flag queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + } + + /* Initialize the DHCPv6 client control blocks */ + for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) + { + + /* Set a local pointer for convenience. */ + dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; + + /* Clear the client record. */ + memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT)); + } + + /* Determine if the timers creation were successful. */ + if (status) + { + + /* Delete the server lease timer. */ + tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); + + /* Delete the server serssion timer. */ + tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); + + /* Delete the DHCPv6 Server thread. */ + tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Delete the server protection mutex. */ + tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Delete the flag queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + + /* Return error status. */ + return status; + } + + /* Save the DHCPV6 instance pointer in the socket. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr; + + /* Set the DHCPv6 Client ID. */ + dhcpv6_server_ptr -> nx_dhcpv6_id = NX_DHCPV6_SERVER_ID; + + /* Set the server preference for clients using multicast only for all request message types. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_multicast_only = NX_TRUE; + + /* Assign the various handlers (server error messages, state change and expired/deprecated addresses). */ + dhcpv6_server_ptr -> nx_dhcpv6_IP_address_declined_handler = dhcpv6_address_declined_handler; + dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler = dhcpv6_option_request_handler; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_option_request_handler_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX set dhcpv6 server */ +/* option request callback service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* dhcpv6_option_request_handler_extended */ +/* Extended option request handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_option_request_handler_set */ +/* DHCPV6 server create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, + UCHAR *buffer_ptr, UINT *index, UINT available_payload)) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((!dhcpv6_server_ptr) || (!dhcpv6_option_request_handler_extended)) + { + return NX_PTR_ERROR; + } + + /* Call actual DHCPV6 server option request handler set service. */ + status = _nx_dhcpv6_server_option_request_handler_set(dhcpv6_server_ptr, dhcpv6_option_request_handler_extended); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_option_request_handler_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DHCPv6 option request handler. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* dhcpv6_option_request_handler_extended */ +/* Extended option request handler */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, + UCHAR *buffer_ptr, UINT *index, UINT available_payload)) +{ + + + /* Set the extended handler callback. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended = dhcpv6_option_request_handler_extended; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_add_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the copy client data */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store client data */ +/* message_xid Client transaction ID */ +/* client_address IP address leased to client */ +/* client_state Client DHCPv6 state e.g. bound */ +/* IP_lease_time_accrued Time expired on current IP lease */ +/* valid_lifetime When address becomes invalid */ +/* duid_type Type of Client DUID */ +/* duid_hardware DUID hardware (usually ethernet) */ +/* physical_address_msw MSB of client mac address */ +/* physical_address_lsw LSB of client mac address */ +/* duid_time Time for link layer time DUID */ +/* duid_vendor_number Enterprise ID for Vendor DUID */ +/* duid_vendor_private Pointer to private ID for DUID */ +/* duid_private_length Vendor Duid private ID length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* NX_DHCPV6_TABLE_FULL No empty slot for client data */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_add_client_record Actual copy client data service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, + ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, + ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if ((dhcpv6_server_ptr == NX_NULL) || (client_address == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + /* Check for missing transaction ID or DUID type. */ + if ((message_xid == 0) || (duid_type == 0)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for missing time expired on the lease (if client in a bound state). */ + if ((IP_lease_time_accrued == 0) && (client_state == NX_DHCPV6_STATE_BOUND)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for invalid enterprise DUID data if type is enterprise. */ + if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) + { + + if ((duid_private_length == 0) || (duid_vendor_private == NX_NULL)) + { + + return NX_INVALID_PARAMETERS; + } + } + /* Check for invalid LINK LAYER duid data. */ + else if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) || (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY)) + { + + if ((physical_address_msw == 0) && (physical_address_lsw == 0)) + { + return NX_INVALID_PARAMETERS; + } + + if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) && (duid_time == 0)) + { + return NX_INVALID_PARAMETERS; + } + } + + /* Call the actual service and return completion status. */ + status = _nx_dhcpv6_add_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state, + IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw, physical_address_lsw, + duid_time, duid_vendor_number, duid_vendor_private, duid_private_length); + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies the input data into a DHCPv6 Client record and */ +/* stored in the server's Client table. It then uses the Client IP */ +/* address to find the matching record in the server IP lease table to */ +/* cross link the tables. */ +/* */ +/* This is intended to satisfy the DHCPv6 protocol requirement that a */ +/* DHPCv6 Server be able to store and retrieve lease data from */ +/* nonvolatile memory e..g between reboots. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store client data */ +/* message_xid Client transaction ID */ +/* client_address IP address leased to client */ +/* client_state Client DHCPv6 state e.g. bound */ +/* IP_lease_time_accrued Time expired on current IP lease */ +/* valid_lifetime When address becomes invalid */ +/* duid_type Type of Client DUID */ +/* duid_hardware DUID hardware (usually ethernet) */ +/* physical_address_msw MSB of client mac address */ +/* physical_address_lsw LSB of client mac address */ +/* duid_time Time for link layer time DUID */ +/* duid_vendor_number Enterprise ID for Vendor DUID */ +/* duid_vendor_private Pointer to private ID for DUID */ +/* duid_private_length Vendor Duid private ID length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* NX_DHCPV6_TABLE_FULL No empty slot for client data */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copy data to specified memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, + ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, + ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length) +{ + +UINT i; +UINT found = NX_FALSE; +NX_DHCPV6_CLIENT *dhcpv6_client_ptr; + + + /* Check if a table index was specified. */ + if (table_index != 0xFFFFFFFF) + { + + /* Check if it is a valid index. */ + if (table_index >= NX_DHCPV6_MAX_CLIENTS) + { + + /* No, return a parameter error. */ + return NX_INVALID_PARAMETERS; + } + + /* Check if it is actually empty. */ + if (dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index].nx_dhcpv6_message_xid != 0) + { + + /* Not empty. Indicate we'll have to find an empty slot. */ + table_index = 0xFFFFFFFF; + } + } + + /* Check if we still need to find a slot. */ + if (table_index == 0xFFFFFFFF) + { + + /* We do, so loop through client records to find one. */ + for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) + { + + /* Is this an empty slot? */ + if (dhcpv6_server_ptr -> nx_dhcpv6_clients[i].nx_dhcpv6_message_xid == 0) + { + + /* This is available. */ + table_index = i; + break; + } + } + + /* Do we have a slot? */ + if (i == NX_DHCPV6_MAX_CLIENTS) + { + + /* No, Indicate the table is full. */ + return NX_DHCPV6_TABLE_FULL; + } + } + + /* Create the table entry. */ + + /* Fill in the generic client information. */ + dhcpv6_client_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index]); + dhcpv6_client_ptr -> nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID; + dhcpv6_client_ptr -> nx_dhcpv6_message_xid = message_xid; + dhcpv6_client_ptr -> nx_dhcpv6_state = (UCHAR)client_state; + dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued = IP_lease_time_accrued; + memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_server_duid), &(dhcpv6_server_ptr -> nx_dhcpv6_server_duid), sizeof(NX_DHCPV6_SVR_DUID)); + + /*Fill in the Client DUID information. */ + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code = NX_DHCPV6_OP_DUID_CLIENT; + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type = (USHORT)duid_hardware; + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type = (USHORT)duid_type; + + /* Determine DUID type to fill in the rest of the DUID fields. */ + if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) + { + + /* Validate the DUID private length. */ + if (duid_private_length > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH) + { + return NX_DHCPV6_INVALID_DUID; + } + + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number = duid_vendor_number; + memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), duid_vendor_private, duid_private_length); + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = (USHORT)(duid_private_length + 6); + } + else + { + + /* Either link layer or link layer plus time. */ + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw = (USHORT)physical_address_msw; + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw = physical_address_lsw; + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 10; + + if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 14; + dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_time = duid_time; + } + } + + /* Fill in the necessary IA-NA and IA Address option fields. */ + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = 24; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = valid_lifetime; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; /* Don't care */ + COPY_NXD_ADDRESS(client_address, &(dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address)); + + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_op_code = NX_DHCPV6_OP_OPTION_STATUS; + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_option_length = 2; /* No message */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; + + /* Now access the server lease table to find this client's lease. */ + for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) + { + + /* Compare our client's assigned IP address with this lease table entry. */ + if(CHECK_IPV6_ADDRESSES_SAME(&(client_address -> nxd_ip_address.v6[0]), + &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0]))) + { + + /* They match! Cross link the tables. */ + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; + found = NX_TRUE; + break; + } + } + + if (!found) + { + + /* This client apparently does not have a valid IP lease. Ok to keep in the tables, + but they will need to request an IP address! */ + return NX_DHCPV6_ADDRESS_NOT_FOUND; + } + + return NX_SUCCESS; + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_retrieve_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the retrieve DHCPv6 Client */ +/* record service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store client data */ +/* message_xid Client transaction ID */ +/* client_address IP address leased to client */ +/* client_state Client DHCPv6 state e.g. bound */ +/* IP_lease_time_accrued Time expired on current IP lease */ +/* valid_lifetime When address becomes invalid */ +/* duid_type Type of Client DUID */ +/* duid_hardware DUID hardware (usually ethernet) */ +/* physical_address_msw MSB of client mac address */ +/* physical_address_lsw LSB of client mac address */ +/* duid_time Time for link layer time DUID */ +/* duid_vendor_number Enterprise ID for Vendor DUID */ +/* duid_vendor_private Pointer to private ID for DUID */ +/* duid_private_length Vendor Duid private ID length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_retrieve_client_record Actual retrieve client data */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, + ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, + ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length) +{ + +UINT status; + + + /* Check for invalid parameters. */ + if (table_index >= NX_DHCPV6_MAX_CLIENTS) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for invalid pointer input. */ + if ((dhcpv6_server_ptr == NX_NULL) || (message_xid == NX_NULL) || (client_address == NX_NULL) || (client_state == NX_NULL) || + (IP_lease_time_accrued == NX_NULL) || (valid_lifetime == NX_NULL) || (duid_type == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + + /* Call the actual service. */ + status = _nx_dhcpv6_retrieve_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state, + IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw, + physical_address_lsw, duid_time, duid_vendor_number, duid_vendor_private, duid_private_length); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_retrieve_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns DHCPv6 Client record data at the specified */ +/* index into the server table to the caller. Note that if a slot in */ +/* the server's client table is empty, evidenced by a zero transaction */ +/* ID, the service returns null data in all parameters with a successful*/ +/* completion status. */ +/* */ +/* This is intended to satisfy the DHCPv6 protocol requirement that a */ +/* DHPCv6 Server be able to store and retrieve IP lease data from */ +/* nonvolatile memory e..g between reboots. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store client data */ +/* message_xid Client transaction ID */ +/* client_address IP address leased to client */ +/* client_state Client DHCPv6 state e.g. bound */ +/* IP_lease_time_accrued Time expired on current IP lease */ +/* valid_lifetime When address becomes invalid */ +/* duid_type Type of Client DUID */ +/* duid_hardware DUID hardware (usually ethernet) */ +/* physical_address_msw MSB of client mac address */ +/* physical_address_lsw LSB of client mac address */ +/* duid_time Time for link layer time DUID */ +/* duid_vendor_number Enterprise ID for Vendor DUID */ +/* duid_vendor_private Pointer to private ID for DUID */ +/* duid_private_length Vendor Duid private ID length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* NX_DHCPV6_INVALID_DUID Malformed DUID retrieved */ +/* */ +/* CALLS */ +/* */ +/* COPY_NXD_ADDRESS Copy IPv6 address to specified */ +/* memory (holding an IPv6 address*/ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, + ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, + ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length) +{ + +NX_DHCPV6_CLIENT *client_ptr; +INT length; + + + /* Get a local pointer for convenience. */ + client_ptr = &(dhcpv6_server_ptr ->nx_dhcpv6_clients[table_index]); + + /* Load the generic client data. */ + *message_xid = client_ptr -> nx_dhcpv6_message_xid; + + /* Is this an empty record? */ + if (*message_xid == 0) + { + + /* Yes so return null data. */ + memset(client_address, 0, sizeof(NXD_ADDRESS)); + *client_state = 0; + *IP_lease_time_accrued = 0; + *valid_lifetime = 0; + *duid_type = 0; + if (duid_hardware) + *duid_hardware = 0; + if (physical_address_msw) + *physical_address_msw = 0; + if (physical_address_lsw) + *physical_address_lsw = 0; + if (duid_time) + *duid_time = 0; + if (duid_vendor_number) + *duid_vendor_number = 0; + if (duid_private_length) + *duid_private_length = 0; + + return NX_SUCCESS; + } + + /* Not an empty record. Extract the data! */ + COPY_NXD_ADDRESS(&(client_ptr -> nx_dhcpv6_ia.nx_global_address), client_address); + *client_state = client_ptr -> nx_dhcpv6_state; + *IP_lease_time_accrued = client_ptr -> nx_dhcpv6_IP_lease_time_accrued; + *valid_lifetime = client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime; + *duid_type = client_ptr -> nx_dhcpv6_client_duid.nx_duid_type; + + /* If this is a LINK LAYER Duid type, load the appropriate data. */ + if ((*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY) || (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)) + { + + /* Check for invalid pointer input for DUID of the link layer type. */ + if ((duid_hardware == NX_NULL) || (physical_address_msw == NX_NULL) || (physical_address_lsw == NX_NULL)) + { + return NX_PTR_ERROR; + } + + *duid_hardware = client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type; + *physical_address_msw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw; + *physical_address_lsw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw; + + if (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + if (duid_time == NX_NULL) + { + return NX_PTR_ERROR; + } + + *duid_time = client_ptr -> nx_dhcpv6_client_duid.nx_duid_time; + } + } + else + { + + /* Client DUID type is vendor assigned. */ + + /* Check for valid pointer input for enterprise ID data */ + if ((duid_vendor_number == NX_NULL) || (duid_vendor_private == NX_NULL) || (duid_private_length == NX_NULL)) + { + return NX_PTR_ERROR; + } + + *duid_vendor_number = client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number; + length = client_ptr -> nx_dhcpv6_client_duid.nx_option_length - 4; + if (length < 0) + { + + return NX_DHCPV6_INVALID_DUID; + } + + memcpy(duid_vendor_private, &(client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), (UINT)length); + *duid_private_length = (UINT)length; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_add_ip_address_lease PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the copy lease service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store data */ +/* lease_IP_address Lease IP address */ +/* T1 T1 lifetime (when to renew) */ +/* T2 T2 lifetime (when to rebind) */ +/* preferred_lifetime When address becomes deprecated */ +/* valid_lifetime When address becomes invalid */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ +/* Address not onlink with Server */ +/* DHCPv6 network interface */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_add_ip_address_lease Actual copy lease data service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, + ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + /* Check for invalid non pointer input. */ + if (CHECK_UNSPECIFIED_ADDRESS(&(lease_IP_address -> nxd_ip_address.v6[0]))) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + /* Check for invalid lease time data. */ + if ((T1 == 0) || (T2 == 0) || (valid_lifetime == 0) || (preferred_lifetime == 0)) + { + + return NX_DHCPV6_PARAM_ERROR; + } + + /* Call the actual service and return completion status. */ + status = _nx_dhcpv6_add_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address, + T1, T2, valid_lifetime, preferred_lifetime); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_ip_address_lease PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies lease data into the Server IP lease table. */ +/* The caller can specify which slot with a index value up to the size */ +/* of the lease table, (NX_DHCPV6_MAX_LEASES - 1), or the DHCPv6 server */ +/* will find an empty slot to store the lease data if the table index is*/ +/* set to 'infinity' e.g. 0xFFFFFFFF. */ +/* */ +/* This is intended to satisfy the DHCPv6 protocol requirement that a */ +/* DHPCv6 Server be able to store and retrieve IP lease data from */ +/* nonvolatile memory e..g between reboots. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to store data */ +/* lease_IP_address Lease IP address */ +/* T1 T1 lifetime (when to renew) */ +/* T2 T2 lifetime (when to rebind) */ +/* preferred_lifetime When address becomes deprecated */ +/* valid_lifetime When address becomes invalid */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_DHCPV6_PARAM_ERROR Invalid table index */ +/* NX_DHCPV6_TABLE_FULL No empty entries for lease data */ +/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ +/* Address not onlink with Server */ +/* DHCPv6 network interface */ +/* CALLS */ +/* */ +/* memcpy Copy memory to specified area */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, + ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime) +{ + +UINT i; +NX_DHCPV6_ADDRESS_LEASE *lease_ptr; +UINT ga_address_index; +UINT prefix_length; + + + /* Get the DHCPv6 server address interface index. */ + ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; + + prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; + + /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the + network masked addresses should be equal). */ + + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &lease_IP_address -> nxd_ip_address.v6[0], prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + /* Is there a table index specified? */ + if (table_index == 0xFFFFFFFF) + { + + /* No, so lets search the server table and find an available slot. */ + for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) + { + + /* Get a local pointer for convenience. */ + lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]); + + /* Does this slot have an address already? */ + if (CHECK_UNSPECIFIED_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0]))) + { + + /* This one looks empty. */ + table_index = i; + break; + } + } + + if (table_index == 0xFFFFFFFF) + { + return NX_DHCPV6_TABLE_FULL; + } + } + else + { + /* Check for valid table index. */ + if (table_index >= NX_DHCPV6_MAX_LEASES) + { + + /* No good. Exceeds the size of the table. */ + return NX_DHCPV6_PARAM_ERROR; + } + } + + /* Copy the supplied IP data into the lease entry. */ + lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]); + + COPY_NXD_ADDRESS(lease_IP_address, &(lease_ptr -> nx_dhcpv6_lease_IP_address)); + lease_ptr -> nx_dhcpv6_lease_T1_lifetime = T1; + lease_ptr -> nx_dhcpv6_lease_T2_lifetime = T2; + lease_ptr -> nx_dhcpv6_lease_valid_lifetime = valid_lifetime; + lease_ptr -> nx_dhcpv6_lease_preferred_lifetime =preferred_lifetime; + + dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses++; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_retrieve_ip_address_lease PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the actual retrieve lease */ +/* service. */ +/* */ +/* This is intended to satisfy the DHCPv6 protocol requirement that a */ +/* DHPCv6 Server be able to store and retrieve lease data from */ +/* nonvolatile memory e..g between reboots. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to obtain data */ +/* lease_IP_address Lease IP address */ +/* T1 T1 lifetime (when to renew) */ +/* T2 T2 lifetime (when to rebind) */ +/* preferred_lifetime When address becomes deprecated */ +/* valid_lifetime When address becomes invalid */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_retrieve_ip_address_lease */ +/* Actual retrieve data service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, + ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL) || (T1 == NX_NULL) || + (T2 == NX_NULL) || (valid_lifetime == NX_NULL) || (preferred_lifetime == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + status = _nx_dhcpv6_retrieve_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address, + T1, T2, valid_lifetime, preferred_lifetime); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_retrieve_ip_address_lease PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves lease data from the Server IP lease table. */ +/* The caller must specify which slot with a index value up to the size */ +/* of the lease table, (NX_DHCPV6_MAX_LEASES - 1). */ +/* */ +/* This is intended to satisfy the DHCPv6 protocol requirement that a */ +/* DHPCv6 Server be able to store and retrieve lease data from */ +/* nonvolatile memory e..g between reboots. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* table_index Table index to obtain data */ +/* lease_IP_address Lease IP address */ +/* T1 T1 lifetime (when to renew) */ +/* T2 T2 lifetime (when to rebind) */ +/* preferred_lifetime When address becomes deprecated */ +/* valid_lifetime When address becomes invalid */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address copy */ +/* NX_DHCPV6_PARAM_ERROR Invalid table index */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copy memory to specified area */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, + ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime) +{ + +NX_DHCPV6_ADDRESS_LEASE *lease_ptr; + + + /* Check for valid table index. */ + if (table_index >= NX_DHCPV6_MAX_LEASES) + { + + /* No good. Exceeds the size of the table. */ + return NX_DHCPV6_PARAM_ERROR; + } + + /* Get a local pointer for convenience. */ + lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]); + + /* Copy the lease data into the input pointer buffers. */ + COPY_NXD_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address), lease_IP_address); + *T1 = lease_ptr -> nx_dhcpv6_lease_T1_lifetime; + *T2 = lease_ptr -> nx_dhcpv6_lease_T2_lifetime; + *valid_lifetime = lease_ptr -> nx_dhcpv6_lease_valid_lifetime; + *preferred_lifetime = lease_ptr -> nx_dhcpv6_lease_preferred_lifetime; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX delete dhcpv6 */ +/* server service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* */ +/* OUTPUT */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_delete Actual DHCPV6 delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 server delete service. */ + status = _nx_dhcpv6_server_delete(dhcpv6_server_ptr); + + /* Return commpletion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DHCPV6 Client instance and releases all of*/ +/* NetX and ThreadX resources. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Release DHCPV6 UDP socket port*/ +/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ +/* tx_thread_terminate Terminate DHCPV6 thread */ +/* tx_thread_delete Delete DHCPV6 thread */ +/* tx_timer_delete Delete DHCPV6 timers */ +/* tx_mutex_delete Delete DHCPV6 mutexes */ +/* tx_event_flags_delete Delete DHCPV6 flag queue */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + + /* Terminate the DHCPV6 processing thread. */ + tx_thread_terminate(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Delete the DHCPV6 processing thread. */ + tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Delete the flag event queue. */ + tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); + + /* Delete the timers */ + tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_lease_timer)); + tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_session_timer)); + + /* Delete the mutexes. */ + tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Release the UDP socket port. */ + nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Clear the dhcpv6 structure ID. */ + dhcpv6_server_ptr -> nx_dhcpv6_id = 0; + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_create_ip_address_range PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create address list */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* start_ipv6_address Start of IP address in list. */ +/* end_ipv6_address End of IP address in list. */ +/* addresses_added Number of addresses added to list*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP list creation */ +/* */ +/* CALLS */ +/* */ +/* nx_dhcpv6_create_ip_address_range Actual list create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, + UINT *addresses_added) +{ + +UINT status; + + + /* Check for invalid input. */ + if ((dhcpv6_server_ptr == NX_NULL) || + (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) || + (addresses_added == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) || + (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0]))) + { + + return(NX_DHCPV6_INVALID_IP_ADDRESS); + } + + /* Check for an invalid address range. */ + if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3]) + { + + return(NX_DHCPV6_INVALID_IP_ADDRESS); + } + + status = _nx_dhcpv6_create_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_added); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_create_ip_address_range PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a list of IPv6 addresses the DHCPv6 server */ +/* may assign to clients, using a start and end address. It returns the*/ +/* number of addresses actually added, which may be limited by the size */ +/* of the server address table. */ +/* */ +/* Note: The NetX Duo DHCPv6 server accomodates up to 256 assignable */ +/* address ranges in the current release. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* start_ipv6_address Start of IP address in list. */ +/* end_ipv6_address End of IP address in list. */ +/* addresses_added Number of addresses added to list*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP list creation */ +/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ +/* Supplied address not reachable */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, + UINT *addresses_added) +{ + +UINT i; +NX_IP *ip_ptr; +UINT prefix_length; +NXD_ADDRESS next_ipv6_address; +UINT ga_address_index; + + + *addresses_added = 0; + + COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address); + + /* Set up a local variable for convenience. */ + ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; + ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; + prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; + + /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the + network masked addresses should be equal). */ + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + /* Set the server ip address based on the specified interface. */ + + /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ + i = 0; + + /* Fit as many IP addresses in the specified range as will fit in the table. */ + while (i < NX_DHCPV6_MAX_LEASES) + { + + NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr; + + /* Set local pointer to the next entry for convenience. */ + ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; + + /* Initialize each entry before adding data. */ + memset(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i], 0, sizeof(NX_DHCPV6_ADDRESS_LEASE)); + + /* Add the IP address into this slot. */ + COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address); + + /* Update the number of addresses added. */ + (*addresses_added)++; + + /* Increase the address low word by one. */ + next_ipv6_address.nxd_ip_address.v6[3]++; + + /* Check if we are overflowing the last word. */ + if (next_ipv6_address.nxd_ip_address.v6[3] == 0xFFFFFFFF) + { + + /* We are. Let's stop here. */ + break; + } + + if (CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0])) + { + break; + } + + i++; + } + + /* Indicate how many addresses were actually added to the server list. */ + dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses = *addresses_added; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_reserve_ip_address_range PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the reserve address list */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* start_ipv6_address Start of IP address to reserve */ +/* end_ipv6_address End of IP address to reserve */ +/* addresses_reserved Number of addresses reserved */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP list creation */ +/* NX_DHCPV6_INVALID_IP_ADDRESS Invalid address supplied */ +/* */ +/* CALLS */ +/* */ +/* nx_dhcpv6_reserve_ip_address_range Actual list create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, + UINT *addresses_reserved) +{ + +UINT status; + + + /* Check for invalid input. */ + if ((dhcpv6_server_ptr == NX_NULL) || + (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) || + (addresses_reserved == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3]) + { + + return(NX_DHCPV6_INVALID_IP_ADDRESS); + } + + if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) || + (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0]))) + { + return(NX_DHCPV6_INVALID_IP_ADDRESS); + } + + status = _nx_dhcpv6_reserve_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_reserved); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_reserve_ip_address_range PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reserves a range of IPv6 addresses not to assign to */ +/* Clients, using a start and end address. It returns the number of */ +/* addresses actually reserved, depending on the size of the server */ +/* address table. To reserve a single address, start and end address */ +/* are the same. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* start_ipv6_address Start of IP address in list. */ +/* end_ipv6_address End of IP address in list. */ +/* addresses_reserved Number of addresses reserved */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful IP address reservation*/ +/* NX_DHCPV6_INVALID_IP_ADDRESS Reserved addresses out of range */ +/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ +/* Supplied address is unreachable */ +/* */ +/* CALLS */ +/* */ +/* CHECK_IP_ADDRESSES_BY_PREFIX Confirm addresses match the */ +/* server domain by matching prefix*/ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, + UINT *addresses_reserved) +{ + +UINT i; +NX_IP *ip_ptr; +UINT prefix_length; +NXD_ADDRESS next_ipv6_address; +NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr = NX_NULL; +UINT ga_address_index; + + + /* Initialize local and input variables. */ + *addresses_reserved = 0; + + COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address); + + /* Set up a local variable for convenience. */ + ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; + ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; + prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; + + /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the + network masked addresses should be equal). */ + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ + i = 0; + + /* Match on start-end addresses for which leases to reserve. */ + while (i < NX_DHCPV6_MAX_LEASES) + { + + /* Set local pointer to the entry for convenience. */ + ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; + + /* Add the IP address into this slot. */ + COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address); + + /* Check if we found the starting address. */ + if (CHECK_IPV6_ADDRESSES_SAME(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], &start_ipv6_address -> nxd_ip_address.v6[0])) + { + break; + } + } + + if (i == NX_DHCPV6_MAX_LEASES) + { + + /* No starting address found in the server IP address list. */ + return NX_DHCPV6_INVALID_IP_ADDRESS; + } + + /* Set the lease times of this entry to infinity. */ + ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF; + + /* Update the number of addresses reserved. */ + (*addresses_reserved)++; + + /* Process the next entry. */ + + /* We found the starting address, so start reserving the rest of the address(es). */ + while ((!CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0])) && + (i < NX_DHCPV6_MAX_LEASES)) + { + + i++; + + /* Set local pointer to the next entry for convenience. */ + ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; + + /* Set the lease times of this entry to infinity. */ + ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE; + ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE; + + /* Set the number of addresses actually reserved. */ + (*addresses_reserved)++; + + /* Return a pointer to the beginning of non reserved addresses.*/ + COPY_NXD_ADDRESS(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address, &next_ipv6_address); + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_create_dns_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function does error checking for the add dns address service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* dns_ipv6_address DNS server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCPV6_PARAM_ERROR Invalid input */ +/* status Actual add dns address status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_create_dns_address */ +/* Add DNS server address service */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (!dhcpv6_server_ptr || !dns_ipv6_address) + { + return NX_PTR_ERROR; + } + + /* Check for invalid parameters and null address. */ + if ((dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID) || + (CHECK_UNSPECIFIED_ADDRESS(&dns_ipv6_address -> nxd_ip_address.v6[0]))) + + { + return NX_DHCPV6_PARAM_ERROR; + } + + status = _nx_dhcpv6_create_dns_address(dhcpv6_server_ptr, dns_ipv6_address); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_create_dns_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function the DNS server address to the DHCPv6 server for when */ +/* clients request the DNS server address. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* dns_ipv6_address DNS server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successfully added dns address */ +/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ +/* DNS prefix does not match */ +/* DHCPv6 server interface */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address) +{ + +NX_IP *ip_ptr; +UINT prefix_length; +UINT ga_address_index; + + + /* Set up local variables for convenience. */ + ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; + ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; + prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; + + /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the + network masked addresses should be equal). */ + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &dns_ipv6_address -> nxd_ip_address.v6[0], + prefix_length)) + { + + return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; + } + + /* Set the dns server for this interface. */ + COPY_NXD_ADDRESS(dns_ipv6_address, &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_set_server_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the create server DUID */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server instance */ +/* duid_type Type of DUID, e.g. LL or LLT */ +/* hardware_type Network hardware type e.g IEEE 802*/ +/* mac_address_msw Mac address most significant bit */ +/* mac_address_lsw Mac address least significant bit */ +/* time Time data for link layer DUIDs */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_set_server_duid Actual create server duid service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, + ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time) +{ +UINT status; + + + /* Check for invalid pointer input. */ + if (dhcpv6_server_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* For link layer time DUIDs, the time input must be non zero. */ + if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + if (time == 0) + { + return NX_PTR_ERROR; + + } + } + + /* Check for invalid non pointer input. */ + if ((duid_type == 0) || (hardware_type == 0) || (mac_address_msw == 0) || (mac_address_lsw == 0)) + { + return NX_INVALID_PARAMETERS; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_set_server_duid(dhcpv6_server_ptr, duid_type, hardware_type, mac_address_msw, mac_address_lsw, time); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_set_server_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the server DUID with the input data. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server instance */ +/* duid_type Type of DUID, e.g. LL or LLT */ +/* hardware_type Network hardware type e.g IEEE 802*/ +/* mac_address_msw Mac address most significant bit */ +/* mac_address_lsw Mac address least significant bit */ +/* time Time data for link layer DUIDs */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_BAD_SERVER_DUID Unknown or invalid DUID type */ +/* NX_DHCPV6_INVALID_VENDOR_DATA Invalid Vendor ID supplied */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* memcpy Copy data to specified location */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, + ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time) +{ + +NX_DHCPV6_SVR_DUID *duid_ptr; + + + duid_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_server_duid; + + /* Initialize the DUID to null. */ + memset(duid_ptr, 0, sizeof(NX_DHCPV6_SVR_DUID)); + + /* Assign the DUID op code. */ + duid_ptr -> nx_op_code = NX_DHCPV6_OP_DUID_SERVER; + + /* Set the DUID type. */ + duid_ptr -> nx_duid_type = (USHORT)duid_type; + + /* Set the DUID data for a non vendor DUID. */ + if (duid_ptr -> nx_duid_type != NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) + { + + /* Server has a valid link local address. Add this to the server DUID fields + if not a vendor assigned DUID type. */ + duid_ptr-> nx_link_layer_address_msw = (USHORT)mac_address_msw; + duid_ptr -> nx_link_layer_address_lsw = mac_address_lsw; + + /* Set the hardware type. */ + duid_ptr -> nx_hardware_type = (USHORT)hardware_type; + } + else + { + /* This is a private vendor DUID with private vendor ID. */ + duid_ptr -> nx_duid_enterprise_number = NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID; + + /* Check that the server vendor ID size. */ + if (sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID) > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH) + { + return NX_DHCPV6_INVALID_VENDOR_DATA; + } + + memcpy(&duid_ptr -> nx_duid_private_identifier[0], NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID, sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID)); + } + + /* Now set the server DUID length. This will depend on DUID type. */ + if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY) + { + + /* Set the length to include the duid type, hardware type, msw and lsw fields. */ + duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + sizeof(ULONG); + } + else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + /* Set the length to include the duid type, hardware type, time, and msw and lsw fields. */ + duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + 2 * sizeof(ULONG); + + /* Set the DUID time. */ + duid_ptr -> nx_duid_time = time; + + } + else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) + { + + /* Set the length to include the duid type, hardware type, enterprise number and + variable length private identifier. */ + duid_ptr -> nx_option_length = sizeof(USHORT) + sizeof(ULONG) + sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID); + } + else + { + + /* Undefined or unknown DUID type. Return error status. */ + return NX_DHCPV6_BAD_SERVER_DUID; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_prepare_iana_status PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the IANA status option. If the flag input is */ +/* set, the standard server status message is added to the */ +/* message buffer, and the option length updated. If the flag is false,*/ +/* no message is sent with the status option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_status_ptr Pointer to IANA status to add */ +/* flag 0 to clear; 1 to add message */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copy specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_response_to_client Send server response to client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS *dhcpv6_status_ptr, UINT flag) +{ + + + /* Make sure the basic header fields are filled in. No need to check the status code has been set; it is + part of the decision to send a response. */ + dhcpv6_status_ptr -> nx_op_code = NX_DHCPV6_OP_OPTION_STATUS; + dhcpv6_status_ptr -> nx_option_length = sizeof(USHORT); + + /* Check if we are adding or clearing a message. */ + if (flag == NX_FALSE) + { + + /* Clear the message. */ + memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX); + + /*We're done! */ + return NX_SUCCESS; + } + + /* Flag is set so we are adding a message into the packet. */ + + /* Clear the message before adding anything into the message buffer. */ + memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX); + + /* Fill in message according to status code. */ + switch (dhcpv6_status_ptr -> nx_status_code) + { + + case NX_DHCPV6_STATUS_SUCCESS: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_SUCCESS, sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS)); + + /* We're done! */ + break; + + case NX_DHCPV6_STATUS_UNSPECIFIED: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED, sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED)); + + /* We're done! */ + break; + + case NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE)); + + /* We're done! */ + break; + + case NX_DHCPV6_STATUS_NO_BINDING: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_BINDING, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING)); + + /* We're done! */ + break; + + case NX_DHCPV6_STATUS_NOT_ON_LINK: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK, sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK)); + + /* We're done! */ + break; + + case NX_DHCPV6_STATUS_USE_MULTICAST: + + /* Copy the standard server reply to message buffer. */ + memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST, sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST)); + + /* Update the option length. */ + dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST)); + + /* We're done! */ + break; + + + default: + break; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_preference PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a DHCPv6 preference option to the server reply. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 Server instance */ +/* dhcpv6_client_ptr Pointer to DHCPv6 Client instance */ +/* index Location where to write the data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Data too large for packet payload */ +/* */ +/* CALLS */ +/* */ +/* memcpy Copy specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_response_to_client Send server response to client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_preference(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +UINT available_payload; +ULONG message_word; + + + /* Fill in option code and length. */ + dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code = NX_DHCPV6_OP_PREFERENCE; + dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length = 1; + dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value = NX_DHCPV6_PREFERENCE_VALUE; + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + /* Check if the DUID will fit in the packet buffer. */ + if (available_payload < (UINT)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length + 4)) + { + + /* It won't! */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Create the word to write to the buffer. */ + message_word = (ULONG)dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code << 16; + message_word |= dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy first half of the DUID option to packet buffer. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); + + *index += (ULONG)sizeof(ULONG); + + /* Set the preference value. */ + *(buffer_ptr + *index) = (UCHAR)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value); + + (*index)++; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_option_requests PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the 'option request' option to the server reply */ +/* packet based on the options requested from the client, and what */ +/* options the DHCPv6 server is configured to supply. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ +/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ +/* buffer_ptr Pointer to packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Not enough room for the option */ +/* request in the packet payload */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the server */ +/* DHCPv6 response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, + UCHAR *buffer_ptr, UINT *index) +{ + +USHORT i, j; +ULONG message_word; +UINT available_payload; +NXD_ADDRESS *dns_server_address; +NX_DHCPV6_SERVER_OPTIONREQUEST *dhcpv6_option_ptr; + + + dhcpv6_option_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_option_request; + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + /* Process up to the maximum allowed options. */ + for(i = 0; i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS; i++) + { + + /* Check for the end of the list. */ + if (dhcpv6_option_ptr -> nx_op_request[i] == 0) + { + + /* No more options. */ + break; + } + + /* Is this the DNS server option? */ + if (dhcpv6_option_ptr -> nx_op_request[i] == NX_DHCPV6_RFC_DNS_SERVER_OPTION) + { + + /* Create an option containing a single DNS server address. */ + dhcpv6_option_ptr -> nx_option_length = 4 * sizeof(ULONG); + + /* Check if the option request option will fit in the packet buffer. */ + if (available_payload < (UINT)(dhcpv6_option_ptr -> nx_option_length + 4)) + { + + /* It won't. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + message_word = (ULONG)dhcpv6_option_ptr -> nx_op_request[i] << 16; + message_word |= dhcpv6_option_ptr -> nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the option request option header to the packet. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + dns_server_address = &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address; + for (j = 0; j < 4; j++) + { + + message_word = dns_server_address -> nxd_ip_address.v6[j]; + + NX_CHANGE_ULONG_ENDIAN(message_word); + + memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); + + *index += (ULONG)sizeof(ULONG); + } + + /* Update the available payload. */ + available_payload = (UINT)(available_payload - (UINT)(dhcpv6_option_ptr -> nx_option_length + 4)); + } + /* Does the DHCPv6 server have an extended option handler? */ + else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended) + { + + /* Yes, so call it. This handler shall fill the buffer with the requested + option data (if available). + + Note: The handler must update the index pointing to the end of data in the buffer + after it inserts the data. This is done for the DNS server option above. */ + (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index, available_payload); + + /* Check if exceed the payload. */ + if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size) + { + + /* Update the available payload. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + } + else + { + return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); + } + } + /* Does the DHCPv6 server have an option handler? */ + else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler) + { + + /* Yes, so call it. This handler shall fill the buffer with the requested + option data (if available). + + Note: The handler must update the index pointing to the end of data in the buffer + after it inserts the data. This is done for the DNS server option above. */ + (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index); + + /* Check if exceed the payload. */ + if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size) + { + + /* Update the available payload. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + } + else + { + return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); + } + + } + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_interface_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the set interface service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to the DHCPV6 Server */ +/* iface_index Physical interface index for */ +/* DHCP communication */ +/* ga_address_index Global address index on DHCPv6*/ +/* interface */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index */ +/* NX_NO_INTERFACE_ADDRESS Invalid global address index */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_interface_set Actual set interfaces service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (dhcpv6_server_ptr == NX_NULL) + { + + return NX_PTR_ERROR; + } + + /* Check for invalid parameters. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + if (ga_address_index >= NX_MAX_IPV6_ADDRESSES) + { + return NX_NO_INTERFACE_ADDRESS; + } + + /* Call the actual service. */ + status = _nx_dhcpv6_server_interface_set(dhcpv6_server_ptr, iface_index, ga_address_index); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_interface_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the physical network interface for DHCPv6 */ +/* communications and the address index of the IP instance for the */ +/* primary global address on that interface. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to the DHCPV6 Server */ +/* iface_index Physical interface index for */ +/* DHCP communication */ +/* ga_address_index Global address index on DHCPv6*/ +/* interface */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Indexes successfully set */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index) +{ + + dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index = iface_index; + dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = ga_address_index; + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_lease_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is scheduled by the ThreadX scheduler on a user */ +/* configurable time interval. It sets a flag for the DHCPv6 server */ +/* thread task to check the lease expiration on its leased IP address. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr_value Pointer to the DHCPV6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Adds a periodic event to the */ +/* ThreadX event queue */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value) +{ + +NX_DHCPV6_SERVER *dhcpv6_server_ptr; + + + /* Setup DHCPv6 Server pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value) + + /* Signal the DHCPv6 Server it is time to do check the lease time remaining on + clients it has leased IP addresses to. */ + tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the resume NetX DHCPv6 */ +/* server task service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_resume Actual DHCPV6 resume function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 stop service. */ + status = _nx_dhcpv6_server_resume(dhcpv6_server_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes DHCPV6 processing thread, activates the */ +/* timers, and sets the running status of the DHCPv6 Server back to */ +/* running. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_ALREADY_STARTED DHPCv6 Server already running */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_resume Resumes DHCPV6 thread task */ +/* tx_timer_activate Activates DHCPv6 timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; + + + /* Is the DHCPv6 Client already running? */ + if (dhcpv6_server_ptr -> nx_dhcpv6_server_running) + { + + /* Return a (benign) error status. */ + return NX_DHCPV6_ALREADY_STARTED; + } + + /* Set the DHCPV6 running flag to indicate DHCPV6 is running. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE; + + /* Start the lease timer. */ + status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); + + /* Check for invalid activate status. */ + if (status != TX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Start the session timer. */ + status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); + + /* Check for invalid activate status. */ + if (status != TX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Resume the Server thread as well. */ + status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Check for invalid resume status. */ + if (status != TX_SUCCESS && status != TX_SUSPEND_LIFTED) + { + + /* Return threadx error status. */ + return status; + } + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_session_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is scheduled by the ThreadX scheduler on a user */ +/* configurable time interval. It sets a flag which the DHCPv6 server */ +/* thread task updates all active client session times and checks if */ +/* any have exceeded the session timeout without sending a response */ +/* back to the server. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr_value Pointer to the DHCPV6 server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Adds a periodic event to the */ +/* ThreadX event queue */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value) +{ + +NX_DHCPV6_SERVER *dhcpv6_server_ptr; + + + /* Setup DHCPv6 Server pointer. */ + NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value) + + /* Signal the DHCPv6 server it's time to do more session time keeping! */ + tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the NetX start the dhcpv6 */ +/* client service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_start Actual DHCPV6 start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 start service. */ + status = _nx_dhcpv6_server_start(dhcpv6_server_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the DHCPV6 processing thread and prepares the */ +/* DHCPv6 Server to receive DHCPv6 client requests. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCPV6_ALREADY_STARTED DHCPv6 server already started */ +/* NX_DHCPV6_MISSING_REQUIRED_OPTIONS Server missing required options */ +/* NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES No addresses available to assign*/ +/* */ +/* CALLS */ +/* */ +/* nxd_ipv6_linklocal_address_set Obtain MAC address for DUID */ +/* nx_udp_socket_create Create the Server UDP socket */ +/* nx_udp_socket_bind Bind the Server socket */ +/* nx_udp_socket_unbind Unbind the Server socket */ +/* tx_timer_activate Activate Server lease timer */ +/* tx_timer_deactivate Deactivate Server lease timer */ +/* tx_thread_resume Resume Server thread task */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; +#ifdef NETXDUO_MULTI_HOME +UINT if_index; +#endif + + + /* Determine if the DHCPV6 server has already started. */ + if (dhcpv6_server_ptr -> nx_dhcpv6_server_running) + { + + /* Yes, it has. */ + return(NX_DHCPV6_ALREADY_STARTED); + } + + /* Check if the server has assignable addresses. */ + if (dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses == 0) + { + return NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES; + } + + /* Check that the global address is valid. */ + if (dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index >= NX_MAX_IPV6_ADDRESSES) + { + return NX_DHCPV6_INVALID_GLOBAL_INDEX; + } + + /* Create the Socket and check the status */ + status = nx_udp_socket_create(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr, + &(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), (CHAR *)"NetX DHCPV6 Server", + NX_DHCPV6_TYPE_OF_SERVICE, NX_DHCPV6_FRAGMENT_OPTION, + NX_DHCPV6_TIME_TO_LIVE, NX_DHCPV6_QUEUE_DEPTH); + + /* Was the socket creation successful? */ + if (status != NX_SUCCESS) + { + + /* No, return error status. */ + return status; + } + + /* Save the DHCP instance pointer in the socket. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr; + + /* Set the DHCPv6 request handler for packets received on the DHCPv6 server socket. */ + status = nx_udp_socket_receive_notify(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), _nx_dhcpv6_server_socket_receive_notify); + + /* Was the socket receive_notify set successful? */ + if (status != NX_SUCCESS) + { + + /* No, return error status. */ + return status; + } + + /* Check if the host application has created or retrieved a previously created server DUID. */ + if (dhcpv6_server_ptr -> nx_dhcpv6_server_duid.nx_duid_type == 0) + { + + /* No valid server DUID detected. Server cannot run yet!*/ + return NX_DHCPV6_NO_SERVER_DUID; + } + + /* Bind the UDP socket to the DHCPV6 Server port. */ + status = nx_udp_socket_bind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), NX_DHCPV6_SERVER_UDP_PORT, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + return status; + } + + /* Activate the DHCPv6 timers. */ + status = tx_timer_activate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer); + + /* Determine if the timer activate call was successful. */ + if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR)) + { + + /* No it was not; unbind the DHCPV6 socket. */ + nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Return the error status. */ + return status; + } + + /* Start the session timer. */ + status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); + + /* Check for invalid activate status. */ + if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR)) + { + + /* No it was not; unbind the DHCPV6 socket. */ + nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Return error status. */ + return status; + } + + /* Ready to resume the DHCPV6 server thread. */ + status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Determine if the resume was successful. */ + if (status != NX_SUCCESS) + { + + /* Deactivate the timer. */ + tx_timer_deactivate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer); + + /* Unbind the DHCPV6 socket. */ + nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); + + return status; + } + + /* Set the DHCPV6 started flag to indicate the DHCPV6 server is now running. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE; + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is notified by NetX Duo when a packet arrives in the */ +/* server socket. It sets a flag which the DHCPv6 server thread */ +/* detect so it will know to process the incoming packet . */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to Server Socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Threads */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + +NX_DHCPV6_SERVER *dhcpv6_server_ptr; + + + /* Get a pointer to the DHCPv6 server. */ + dhcpv6_server_ptr = (NX_DHCPV6_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr; + + /* Signal the DHCPv6 Server it has a UDP packet on its socket receive queue. */ + tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_SERVER_RECEIVE_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dhcpv6_server_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the suspend NetX DHCPv6 */ +/* Server task service. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_suspend Actual DHCPV6 suspend function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DHCPV6 stop service. */ + status = _nx_dhcpv6_server_suspend(dhcpv6_server_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends DHCPV6 processing thread, deactivates the */ +/* timers, and sets the running status of the DHCPv6 Server to not */ +/* running. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ +/* suspended */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend DHCPV6 thread task */ +/* tx_timer_deactivate Deactivate timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + + + /* Determine if the DHCPV6 server thread is running. */ + if (!dhcpv6_server_ptr -> nx_dhcpv6_server_running) + { + + /* DHCPV6 has not been started so we cannot 'suspend' it. */ + return(NX_DHCPV6_NOT_STARTED); + } + + /* Clear the DHCPV6 running flag to indicate DHCPV6 is not running. */ + dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_FALSE; + + /* Stop the timer. */ + tx_timer_deactivate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); + + /* Suspend the Server thread as well. */ + tx_thread_suspend(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the background processing thread for the DHCPV6 */ +/* Client. It waits to be notified by ThreadX event flags when to */ +/* perform certain actions. These include updating the time remaining */ +/* on the Client IP address lease time, and maintaining the duration of*/ +/* the current Client Server session (if Client has made a request). */ +/* It will terminate if a host application handler is called and */ +/* indicates the Client should abort. */ +/* */ +/* INPUT */ +/* */ +/* info Pointer to DHCPV6 Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Receive notice of event flags set */ +/* tx_mutex_get Obtain lock on Client resource */ +/* tx_mutex_put Release lock on Client resource */ +/* nx_dhcpv6_deprecated_IP_address_handler */ +/* Callback function for handling an */ +/* IP address at the end of its */ +/* preferred life time */ +/* nx_dhcpv6_expired_IP_address_handler */ +/* Callback function for handling an */ +/* IP address at the end of its */ +/* valid life time */ +/* _nx_dhcpv6_request_renew Initiate the RENEW request */ +/* _nx_dhcpv6_request_rebind Initiate the REBIND request */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_dhcpv6_server_thread_entry(ULONG info) +{ + +UINT i; +NX_DHCPV6_SERVER *dhcpv6_server_ptr; +NX_DHCPV6_CLIENT *dhcpv6_client_ptr; +ULONG dhcpv6_events; +NXD_ADDRESS client_address; + + + /* Setup the DHCPV6 server pointer. */ + NX_THREAD_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, info) + + /* Continue processing periodic tasks till this internal flag is cleared. */ + while (1) + { + + + /* Pick up IP event flags. */ + tx_event_flags_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, NX_DHCPV6_ALL_EVENTS, + TX_OR_CLEAR, &dhcpv6_events, TX_WAIT_FOREVER); + + if (dhcpv6_events & NX_DHCPV6_SERVER_RECEIVE_EVENT) + { + + /* Listen for new Client DHCP service request e.g. DISCOVERY messages. */ + _nx_dhcpv6_listen_for_messages(dhcpv6_server_ptr); + } + + if (dhcpv6_events & NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT) + { + /* Check the active clients whose sessions that have timed out. */ + for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) + { + + /* Set a local pointer for convenience. */ + dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; + + tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); + + /* Is this client in session with the server? */ + if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time) + { + + /* Update the Client session time. */ + dhcpv6_client_ptr -> nx_dhcpv6_client_session_time += NX_DHCPV6_SESSION_TIMER_INTERVAL; + + if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time >= NX_DHCPV6_SESSION_TIMEOUT) + { + + /* The session has timed out without a response from the Client. Invalidate + the client entry. */ + + /* First get the assigned address. */ + COPY_IPV6_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], + &client_address.nxd_ip_address.v6[0]); + + /* Clear the client record. */ + _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); + } + } + + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + } + } + + /* Check for a periodic DHCP server task. */ + if (dhcpv6_events & NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT) + { + + /* Check the active clients for the time remaining in their leased IP address. */ + for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) + { + + /* Set a local pointer for convenience. */ + dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; + + tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); + + /* Skip those clients who do not have a lease assigned yet. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued == 0) + { + + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + continue; + } + + /* Update the time accrued on the client's current IP address lease. */ + dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued += NX_DHCPV6_IP_LEASE_TIMER_INTERVAL; + + /* Has this address become obsolete? */ + if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >= dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime) + { + + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + /* Clear the client record. */ + _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); + } + else if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >= + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime) + { + + /* Address is deprecated! Client *should* not use it but no action taken by the server yet. */ + } + + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + } + } + + /* Relinquish control before another cycle.*/ + tx_thread_sleep(1); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts data from DHCPv6 Client request packets. A */ +/* request is checked for valid message type and required DHCPv6 data. */ +/* A client record is created if one does not exist for the client and */ +/* the data updated into it. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* dhcpv6_client_ptr Pointer to DHCPv6 client */ +/* packet_ptr Pointer to received packet */ +/* iface_index Interface packet received on */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal */ +/* NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up */ +/* NX_DHCPV6_PROCESSING_ERROR Packet length is different than */ +/* expected */ +/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ +/* NX_DHCPV6_INVALID_HW_ADDRESS Missing or invalid MAC address */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data Extract data from reply packet */ +/* _nx_dhcpv6_server_utility_get_block_option_length */ +/* Extract option header data */ +/* _nx_dhcpv6_process_duid Extract DUID from Client message*/ +/* _nx_dhcpv6_process_DNS_server Extract DNS server from message */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Waits to receive client message*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, + UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address) +{ + +UINT status; +UINT add_on; +UINT record_index; +ULONG op_code; +ULONG option_length; +UCHAR *buffer_ptr; +UINT index; +ULONG returned_xid; +NX_DHCPV6_SVR_DUID client_duid, server_duid; +UINT client_duid_received; +UINT server_duid_received; +NX_DHCPV6_CLIENT temp_client_rec; +ULONG received_message_type; +UINT matching; + + NX_PARAMETER_NOT_USED(iface_index); + + *dhcpv6_client_ptr = NX_NULL; + + /* Create a scratch record for this client so we can qualify it before adding it to the server table. */ + memset(&temp_client_rec, 0, sizeof(NX_DHCPV6_CLIENT)); + + /* Initialize the record with the DHCPv6 Client ID. */ + temp_client_rec.nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID; + + /* Assume the Client is not bound to an IP address yet. */ + temp_client_rec.nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; + + /* Set a pointer to the start of DHCPv6 data. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Initialize local variables. */ + index = 0; + client_duid_received = NX_FALSE; + server_duid_received = NX_FALSE; + + /* Extract the message type which should be the first byte. */ + _nx_dhcpv6_server_utility_get_data(buffer_ptr, 1, &received_message_type); + + /* Check for an illegal message type. */ + if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) || + (received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) || + (received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) || + (received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) + { + + /* These should only be sent to DHCPv6 clients! The Inform Request is actually + legal to receive but should NOT be used to add clients to the server table. */ + return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; + } + + /* Copy the source address to the Client record. */ + COPY_IPV6_ADDRESS(&source_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); + temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* Copy the destination address to the Client record. */ + COPY_IPV6_ADDRESS(&destination_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); + temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* Advance to the data pointer. */ + buffer_ptr++; + + /* Parse the transaction ID. */ + _nx_dhcpv6_server_utility_get_data(buffer_ptr, 3, &returned_xid); + + temp_client_rec.nx_dhcpv6_message_type = received_message_type; + + /* Set the message ID. The server will need this to reply to the Client. */ + temp_client_rec.nx_dhcpv6_message_xid = returned_xid; + + buffer_ptr += 3; + + /* Now parse all the DHCPv6 option blocks in the packet buffer. */ + /* 4 bytes is data pointer offset, and 4 bytes for option code and option length. */ + while (index <= packet_ptr -> nx_packet_length - 4 - 4) + { + + /* Get the option code and length of data of the current option block. */ + status = _nx_dhcpv6_server_utility_get_block_option_length(buffer_ptr, &op_code, &option_length); + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + + /* This is a double check to verify we haven't gone off the end of the packet buffer. */ + if (index > packet_ptr -> nx_packet_length - 4) + { + + /* Reported length of the packet may be incorrect. At any rate, we don't know + exactly what the end of the message is, so abort. */ + return NX_DHCPV6_PROCESSING_ERROR; + } + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Process the option code with an option specific API. */ + switch (op_code) + { + /* Note - these 'process' functions will not move the buffer pointer. */ + + case NX_DHCPV6_OP_DUID_CLIENT: + + client_duid.nx_op_code = (USHORT)op_code; + client_duid.nx_option_length = (USHORT)option_length; + + status = _nx_dhcpv6_process_duid(&client_duid, NX_DHCPV6_CLIENT_DUID_TYPE, buffer_ptr, option_length); + + if (status != NX_SUCCESS) + { + + return status; + } + + /* Copy to the temporary client record. */ + memcpy(&temp_client_rec.nx_dhcpv6_client_duid, &client_duid, sizeof(NX_DHCPV6_SVR_DUID)); + + /* Indicate the message contained the required Client DUID. */ + client_duid_received = NX_TRUE; + + break; + + case NX_DHCPV6_OP_DUID_SERVER: + + server_duid.nx_op_code = (USHORT)op_code; + server_duid.nx_option_length = (USHORT)option_length; + + status = _nx_dhcpv6_process_duid(&server_duid, NX_DHCPV6_SERVER_DUID_TYPE, buffer_ptr, option_length); + + if (status != NX_SUCCESS) + { + + return status; + } + + /* Copy to the temporary client record. */ + memcpy(&temp_client_rec.nx_dhcpv6_server_duid, &server_duid, sizeof(NX_DHCPV6_SVR_DUID)); + + /* Indicate the message contained the required Server DUID. */ + server_duid_received = NX_TRUE; + + break; + + + case NX_DHCPV6_OP_IA_NA: + + status = _nx_dhcpv6_server_process_iana(&temp_client_rec, buffer_ptr, option_length); + + if (status != NX_SUCCESS) + { + return status; + } + + break; + + /* This should not happen. The IA address option must be embedded in the IANA option. */ + case NX_DHCPV6_OP_IA_ADDRESS: + + /* Don't process an IA address option outside of an address association (IANA). */ + status = NX_DHCPV6_IANA_OPTION_MISSING; + + break; + + case NX_DHCPV6_OP_OPTION_REQUEST: + + /* Option request option contains request usually for network configuration parameters + such as the DNS server. */ + status = _nx_dhcpv6_process_option_request(&temp_client_rec, buffer_ptr, option_length); + + if (status != NX_SUCCESS) + { + + return status; + } + + break; + + case NX_DHCPV6_OP_ELAPSED_TIME: + + /* The elapsed time is time elapsed since the client initiated the IP lease request. */ + status = _nx_dhcpv6_process_elapsed_time(&temp_client_rec, buffer_ptr, option_length); + + if (status != NX_SUCCESS) + { + + return status; + } + + break; + + + default: + break; + } + + /* Check for errors from option block processing. */ + if (status != NX_SUCCESS) + { + + + return status; + } + + /* Move to the next top level option. */ + buffer_ptr += option_length + 4; + + } + + /* Check for an improperly formatted packet. */ + if (index != packet_ptr -> nx_packet_length - 4) + { + + /* If we get here if we are not at the expected end of the buffer. Oops */ + return NX_DHCPV6_PROCESSING_ERROR; + } + + /* Check if the message is missing the required DUID(s). */ + if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) + { + + if (!client_duid_received) + { + + return NX_DHCPV6_MESSAGE_DUID_MISSING; + } + } + /* The following message types must include a client and server DUID. */ + else if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) + { + + if (!server_duid_received || !client_duid_received) + { + + return NX_DHCPV6_MESSAGE_DUID_MISSING; + } + } + /* An inform request only requires a server DUID. */ + else if (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) + { + + /* The Inform request message should NOT include an IA. */ + if (temp_client_rec.nx_dhcpv6_ia.nx_op_code != 0) + { + return NX_DHCPV6_INVALID_IA_DATA; + } + } + + /* Validate the client message, and determine how (if) the server should respond to it. */ + status = _nx_dhcpv6_validate_client_message(dhcpv6_server_ptr, &temp_client_rec); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Return all other errors as completion status. Do not send a message to the client. */ + return(status); + } + + if (temp_client_rec.nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) + { + + /* Not responding to client. So do not assign an IP address or update + the client record with invalid message. */ + return NX_SUCCESS; + } + + /* Look up the client record in the server table. If not found, or this is + a new request e.g. a SOLICIT message, create a new client entry in the table and + fill in the extracted information. */ + add_on = NX_FALSE; + + if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || + (received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) + { + + /* Check first if the validation process indicates we do not reply to this message. */ + if (temp_client_rec.nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) + { + + /* Ok to update or create a new record. */ + add_on = NX_TRUE; + } + } + + /* Check if the client is already in the server table. */ + status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &client_duid, &record_index, + add_on, temp_client_rec.nx_dhcpv6_message_xid, &matching); + + /* Check for error during search. */ + if (status != NX_SUCCESS) + { + + return(status); + } + + /* Set a local pointer to the client record in the server table. */ + *dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[record_index]; + + /* Was a match was found? */ + if (!matching) + { + + /* No, this is a new record. Create a new client record. */ + status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr); + } + else + { + + /* A match was found. Check if this is a different message request than the previous client request. */ + if ((temp_client_rec.nx_dhcpv6_message_type != (*dhcpv6_client_ptr) -> nx_dhcpv6_message_type) && + (received_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) + { + + /* This is a different message from the Client. Before updating the record check the client global address + to be the same as what the server assigned or is offering to assign. */ + if (!CHECK_IPV6_ADDRESSES_SAME(&temp_client_rec.nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], + &(*dhcpv6_client_ptr )-> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) + { + + /* This is a different address. Disregard this message. */ + (*dhcpv6_client_ptr) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return NX_SUCCESS; + } + + /* This is a valid request. Update the client record with the new data. */ + status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr); + } + } + + /* Yes we're done with no processing errors detected. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_validate_client_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function validates the client DHCPv6 request, determines if an */ +/* IP address need to be assigned, what state the DHCPv6 Client */ +/* should be advanced to, and what the server response type should be. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 server */ +/* dhcpv6_client_ptr Pointer to DHCPv6 client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Table searched successfully */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ +/* the server database */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Listen for, process and respond*/ +/* to DHCPV6 Client messages */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) +{ + +UINT status; +UINT matching_clients; +UINT matching_server_duids; +UINT record_index; +UINT dest_address_type; +UINT ga_address_index; +UINT if_index; +UINT prefix_length; + + + /* Clear the Server response to the Client. We will decide that below. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = 0; + + ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; + + /* Initialize the response to the client. If the client request is invalid, ignore the request (no response + from server) or indicate the problem in the IANA status option. */ + + /* Initialize the IANA status for the SOLICIT request as successfully granted. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) + { + + /* Respond to a valid Solicit request with an Advertise message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_ADVERTISE; + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; + } + else + { + + /* Respond to a valid Request request with a Reply message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY; + + /* Set the expected IANA status. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) + { + + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; + } + } + + /* Never accept a packet without a DHCP ID. */ + if (!dhcpv6_client_ptr -> nx_dhcpv6_message_xid) + { + + /* Don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return(NX_SUCCESS); + } + + /* Determine if destination address type (unicast or multicast). */ + dest_address_type = IPv6_Address_Type(&dhcpv6_client_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); + + /* Do validation specific for message type. This section will also + advance the DHCPv6 Client state and set the server response message type. */ + switch (dhcpv6_client_ptr -> nx_dhcpv6_message_type) + { + + case NX_DHCPV6_MESSAGE_TYPE_SOLICIT: + { + + /* Check for missing required fields. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0)) + { + + /* Don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return(NX_SUCCESS); + } + + /* Check for presence of a server DUID. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != 0) + { + + /* Don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return(NX_SUCCESS); + } + + /* The Solicit message should never be unicast. Check if the destination is unicast. */ + if (IPV6_ADDRESS_UNICAST & dest_address_type) + { + + /* Don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return NX_SUCCESS; + } + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_REQUEST: + case NX_DHCPV6_MESSAGE_TYPE_RENEW: + case NX_DHCPV6_MESSAGE_TYPE_REBIND: + case NX_DHCPV6_MESSAGE_TYPE_RELEASE: + case NX_DHCPV6_MESSAGE_TYPE_DECLINE: + { + + /* Check for missing required fields. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0)) + { + + /* Don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return(NX_SUCCESS); + } + + /* Check for an invalid unicast destination address type. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_REBIND) + { + + /* The DHCPv6 server does not support unicast. Check for unicast client destination. */ + if (IPV6_ADDRESS_UNICAST & dest_address_type) + { + + /* It is unicast. Set the use multicast error status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_USE_MULTICAST; + + return NX_SUCCESS; + } + } + + /* This client message is not valid if an matching client record does not exist with the server. */ + status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, + &record_index, NX_FALSE, + dhcpv6_client_ptr -> nx_dhcpv6_message_xid, + &matching_clients); + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Check for matching client record. */ + if (!matching_clients) + { + + /* No matching client record found. */ + + /* For Release and Decline messages let the client know using the IANA status code that + the server has no record of the assigned or requested address for this client. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) + { + + /* Set the non-binding error status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; + + /* Set the lifetimes to zero. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + } + else + { + + /* Otherwise don't respond, just discard the message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return(NX_SUCCESS); + } + } + + /* Handle Rebind a little differently. It should not specify a server DUID. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) + { + /* Is there a server DUID in the client message? */ + if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_option_length > 0) + { + + /* Yes; don't respond, just discard the message. . */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + } + + break; + } + else + { + + /* With all other IA addresses the server DUID must match the server DUID. */ + status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid, + &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, &matching_server_duids); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return status; + } + + /* Do the two server DUIDs match? */ + if (!matching_server_duids) + { + + /* No; don't respond, just discard the message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return NX_SUCCESS; + } + } + break; + } + /* The Client wished to confirm its IP address is on link. */ + case NX_DHCPV6_MESSAGE_TYPE_CONFIRM: + { + + /* Check for missing IA option. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length == 0) + { + + /* No IA option, so don't respond, just discard the message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return NX_SUCCESS; + } + + /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the + network masked addresses should be equal). */ + prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; + + if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), + &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], + prefix_length)) + { + + + /* Inform the client their IA address is not on link. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY; + + /* Set the IA-NA error status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NOT_ON_LINK; + + return(NX_SUCCESS); + } + + /* More checks will be done when the client rebind address is searched in the server + address table. For now we are ok. */ + + break; + } + + case NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST: + { + + /* Verify Client's server duid matches the server DUID. Note that if the server DUID type is a + link layer time type (LLT), this comparison should ignore the time field because this is an 'asynchronous' request + from the client, so just match on the LL data. */ + + /* Temporarily set the server DUID type to LL if it was LLT. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) || + (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY)) + { + + /* Now verify the physical address matches what the server has for this client. */ + if_index = dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index; + if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != + dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_msw) + { + + /* Inform the client their physical address is not on record. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + } + else if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw != + dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_lsw) + { + /* Inform the client their physical address is not on record. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + } + } + else + { + + /* Verify the client inform request was intended for this server. If the Client did not + include a server DUID, which is acceptable in DHCPv6 protocol, it will 'pass' this check. */ + status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid, + &dhcpv6_client_ptr -> nx_dhcpv6_server_duid, &matching_server_duids); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return status; + } + + /* Do the two server DUIDs match? */ + if (!matching_server_duids) + { + + /* Don't respond, just discard the message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return NX_SUCCESS; + } + } + + /* Check for missing options request. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length == 0) + { + + /* Don't respond, just discard the message. */ + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + return NX_SUCCESS; + } + + break; + } + + default: + { + + dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; + + /* Clear the success status. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; + + return(NX_SUCCESS); + + /* No further processing to do. Leave the client state unchanged, whatever it was/is. */ + } + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_utility_get_block_option_length PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the input buffer (assuming to be an option */ +/* block in a server reply) for option code and length. It assumes the */ +/* buffer pointer is pointed to the first byte of the option buffer. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ Pointer to DHCPv6 Client */ +/* option Option code of requested data */ +/* buffer_ptr Buffer to copy data to */ +/* length Size of buffer */ +/* valid */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_DHCPV6_OPTION_BLOCK_INCOMPLETE Unknown option specified */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data Parses a specific data from the */ +/* DHCPv6 option */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_utility_get_block_option_length */ +/* Parses option code and length */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Parses each option from server */ +/* reply and updates Client record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length) +{ + + /* Initialize to zero. */ + *option = 0; + *length = 0; + + /* First byte should be the op code. */ + _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, option); + + buffer_ptr += 2; + + /* Next byte should be the option length. */ + _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, length); + + /* Buffer is now pointed at the data (past the length field). */ + buffer_ptr += 2; + + /* Check for null data. */ + if (*option == 0 || *length == 0) + { + + return NX_DHCPV6_OPTION_BLOCK_INCOMPLETE; + } + + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_utility_get_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the input buffer and returns numeric data */ +/* specified by the size argument, up to 4 bytes long. Note that if */ +/* caller is using this utility to extract bytes from a DHCPv6 packet */ +/* there is no need for byte swapping, as compared to using memcpy in */ +/* which case there is for little endian processors. */ +/* */ +/* INPUT */ +/* */ +/* buffer Pointer to data buffer */ +/* value Pointer to data parsed from buffer*/ +/* size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DHCPV6_INVALID_DATA_SIZE Requested data size too large */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* _nx_dhcpv6_process_server_duid Process server duid in server reply*/ +/* _nx_dhcpv6_process_client_duid Process server duid in server reply*/ +/* _nx_dhcpv6_server_utility_get_block_option_length */ +/* Parses option code and length */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Parses each option from server */ +/* reply and updates Client record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_utility_get_data(UCHAR *buffer, UINT size, ULONG *value) +{ + + + /* Check that the size of the data fits in a ULONG. */ + if (size > sizeof(ULONG)) + { + return NX_DHCPV6_INVALID_DATA_SIZE; + } + + *value = 0; + + /* Process the data retrieval request. */ + while (size-- > 0) + { + + /* Build return value. */ + *value = (*value << 8) | *buffer++; + } + + /* Return value. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_utility_time_randomize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns a value of between -1 seconds and 1 second */ +/* in system ticks. It is used to randomize timeouts as required by */ +/* the RFC's so as to not overload a network server after power out. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* ticks Number of ticks between 1 & -1*/ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_convert_delay_to_ticks Convert seconds to ticks */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +INT _nx_dhcpv6_server_utility_time_randomize(void) +{ + +INT temp; +UINT sign; + + + temp = (INT)(NX_RAND() & 0x001F); + sign = temp & 0x8; + + /* Try for a number between 0 and 0x1F. */ + if (sign) + { + temp = -temp; + } + + return temp; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_listen_for_messages PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function listens for DHCPv6 client messages. It validates and */ +/* extracts information for creating or updating the client record. It */ +/* also responds to the Client pending valid request is received, and */ +/* updates its client records. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPv6 Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Message handled successfully */ +/* NO_PACKET No packet received */ +/* NX_DHCP_BAD_INTERFACE_INDEX Packet interface not recognized*/ +/* status Actual completion outcome */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release DHCP packet */ +/* nx_udp_socket_receive Receive DHCP packet */ +/* _nx_dhcpv6_extract_information Extract DHCP packet info */ +/* _nx_dhcpv6_validate_client_message Process the Client message */ +/* _nx_dhcpv6_server_assign_ip_address Assign IP address to Client */ +/* _nx_dhcpv6_respond_to_client_message Create and send response back */ +/* _nx_dhcpv6_clear_client_session Clears client session data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_thread_entry DHCPv6 Server thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER *dhcpv6_server_ptr) +{ + +UINT status; +UINT iface_index; +NXD_ADDRESS source_address; +NXD_ADDRESS destination_address; +NX_IPV6_HEADER *ipv6_header_ptr; +NX_PACKET *packet_ptr; +NX_DHCPV6_CLIENT *dhcpv6_client_ptr; +NX_DHCPV6_ADDRESS_LEASE *dhcpv6_interface_list_ptr; +NX_PACKET *new_packet_ptr; +ULONG bytes_copied = 0; + + + /* Check for an incoming DHCPv6 packet with non blocking option. */ + status = nx_udp_socket_receive(&dhcpv6_server_ptr -> nx_dhcpv6_server_socket, &packet_ptr, NX_DHCPV6_PACKET_WAIT_OPTION); + + /* Check for packet receive errors. */ + if (status != NX_SUCCESS) + { + + /* Return the packet receive status. */ + return(status); + } + + /* Check for valid packet length (message type and ID). */ + if (packet_ptr -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_DHCPV6_INVALID_DATA_SIZE); + } + + /* Get the interface index. */ + nxd_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index); + + /* Does the DHCP server have a table for this packet interface? */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + /* No; Release the packet. */ + nx_packet_release(packet_ptr); + + /* No, return the error status. */ + return(NX_DHCPV6_INVALID_INTERFACE_INDEX); + } + + /* Set a pointer to the IPv6 header to obtain source and destination address. */ + ipv6_header_ptr = (NX_IPV6_HEADER*)(packet_ptr -> nx_packet_ip_header); + + /* Get the source address. */ + COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_source_ip[0], &source_address.nxd_ip_address.v6[0]); + source_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* Get the destination address. */ + COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_destination_ip[0], &destination_address.nxd_ip_address.v6[0]); + destination_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release + the packet from the receive packet pool as soon as possible. */ + status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &new_packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Error allocating packet, return error status. */ + return(status); + } + + /* Verify the incoming packet does not exceed our DHCP Server packet payload. */ + if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length)) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the newly allocated packet and return an error. */ + nx_packet_release(new_packet_ptr); + + return(NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); + } + + /* Use a packet from the DHCP Server as a buffer to store the received packet data. + Then we can release the received packet back to its packet pool. */ + status = nx_packet_data_extract_offset(packet_ptr, 0, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); + + /* Check status. */ + if ((status != NX_SUCCESS) || (bytes_copied == 0)) + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the allocated packet we'll never send. */ + nx_packet_release(new_packet_ptr); + + /* Error extracting packet buffer, return error status. */ + return(status); + } + + /* Update the new packet with the bytes copied. For chained packets, this will reflect the total + 'datagram' length. */ + new_packet_ptr -> nx_packet_length = bytes_copied; + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + bytes_copied; + + /* Now we can release the original packet. */ + nx_packet_release(packet_ptr); + + /* Get the DHCPv6 Server Mutex. */ + tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); + + /* Extract the DHCPv6 specific information from the packet. This will create new Client record or update existing + client record in the server table. */ + status = _nx_dhcpv6_server_extract_packet_information(dhcpv6_server_ptr, &dhcpv6_client_ptr, new_packet_ptr, iface_index, source_address, destination_address); + + /* We are done with this packet now regardless of the success of the above operations. */ + nx_packet_release(new_packet_ptr); + + /* Check if we have extracted a valid client record. */ + if (status != NX_SUCCESS) + { + + /* Not valid; is there a client record we need to clean up? */ + if (dhcpv6_client_ptr) + { + + /* Yes; clear the client record completely. */ + _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); + } + else + { + + /* No record created; return the error status and abort. */ + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + /* Return the error from extracting packet data. */ + return(status); + } + } + + /* Determine if the server will respond to the message. */ + if ((dhcpv6_client_ptr == NX_NULL) || + (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)) + { + + /* Release the mutex. */ + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + /* No, no further processing necessary. */ + return NX_SUCCESS; + } + + /* Check if the server status indicates it will grant the client request. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS) + { + + /* Yes it will. Check if the client is requesting an IP address, or renewing or rebinding a + previously assigned one. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) + { + + /* Yes, it is. This will (re)assign an IP address. */ + status = _nx_dhcpv6_assign_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &dhcpv6_interface_list_ptr); + + /* Check for errors or no address assigned. */ + if (status != NX_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + /* Return all other errors as completion status. Do not send a message to the client. + The server will otherwise wait for the client to try again. Do not clear client record. */ + return(status); + } + + /* Check if a valid IP address is available. */ + if (dhcpv6_interface_list_ptr) + { + + /* There is. DHCPv6 client has been assigned an IP address. */ + + /* Now ensure we are sending valid lease time parameters with the IP address. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) + { + + /* Ignore invalid preferred or valid lifetimes from the client by setting to zero. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + } + /* Check for invalid T1 or T2 values; if out of range, set to zero). */ + + if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime && + (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime)) + { + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + } + else if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime && + (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime)) + { + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + } + else if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) + { + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + } + } + /* For a solicit message, ignore the preferred and valid lifetimes and check for + valid T1 and T2 times. */ + else if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) + { + + if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) + { + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + } + } + + /* If lifetime values are zero, or exceed the server default time, set to the default lease times. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > NX_DHCPV6_DEFAULT_PREFERRED_TIME)) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME; + } + if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime > NX_DHCPV6_DEFAULT_VALID_TIME)) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = NX_DHCPV6_DEFAULT_VALID_TIME; + } + + if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > NX_DHCPV6_DEFAULT_T1_TIME)) + { + + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = NX_DHCPV6_DEFAULT_T1_TIME; + } + + if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 == 0) || + (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > NX_DHCPV6_DEFAULT_T2_TIME)) + { + + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = NX_DHCPV6_DEFAULT_T2_TIME; + } + + /* Update the lease length in the server lease table. */ + dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_preferred_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime; + dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_valid_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime; + dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T1_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1; + dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T2_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2; + + /* Ok to copy this address into the client record. */ + COPY_NXD_ADDRESS(&dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_IP_address, + &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address); + } + } + } + + /* Send the server reply back to the client. */ + status = _nx_dhcpv6_send_response_to_client(dhcpv6_server_ptr, dhcpv6_client_ptr); + + /* Check if we need to remove the client record e.g. if the Client sent a Decline message. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) + { + + /* This will clear the client record and in the case of + a release message, return the IP address lease status to available. */ + status = _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); + + } + + tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); + + /* Return actual outcome status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_send_response_to_client PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function prepares DHCPv6 messages to send back to the Client. */ +/* Most of the information is obtained from the client session record. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ +/* dhcpv6_client_ptr Pointer to DHCPv6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a DHCPv6 packet */ +/* nx_packet_release Release DHCPv6 packet */ +/* nxd_udp_socket_send Send DHCPv6 packets */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer; +UINT status; +UINT buffer_index; +ULONG message_word; + + + /* Allocate a UDP packet from the DHCPv6 server packet pool. */ + status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Indicate this is an IPv6 packet. */ + packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6; + + /* Setup the packet buffer pointer. */ + buffer = packet_ptr -> nx_packet_prepend_ptr; + + /* Clear the payload and packet interface field before preparing the packet for transmission. */ + memset(buffer, 0, (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)); + + /* Now reduce it to three bytes. */ + dhcpv6_client_ptr -> nx_dhcpv6_message_xid = dhcpv6_client_ptr -> nx_dhcpv6_message_xid & 0x0ffffff; + + /* Clear memory to make the message header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Add the server message type and matching client transaction ID as the DHCPv6 header fields. */ + message_word = (ULONG)((dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server << 24) | + (0x0FFFFFF & dhcpv6_client_ptr -> nx_dhcpv6_message_xid)); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the message header to the packet buffer. */ + memcpy(buffer, &message_word, sizeof(ULONG)); + + /* Update the buffer 'pointer'. */ + buffer_index = sizeof(ULONG); + + /* Handle the special case of an Inform Request which does not include a Client identifier. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) + { + + status = NX_SUCCESS; + + /* Only add the Client DUID if the client included one. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code != 0) + { + + /* Add the Client DUID to the packet buffer. */ + status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer, + &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE); + } + } + else + { + + /* Add the Client DUID to the packet buffer. */ + status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer, + &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE); + } + + /* Check for error. */ + if (status != NX_SUCCESS) + { + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + return status; + } + + /* Now add to the server DUID to the message. */ + status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, buffer, + &buffer_index, NX_DHCPV6_SERVER_DUID_TYPE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + return status; + } + + /* Handle the special case of the Confirm request where we need only + send a status option. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) + { + + /* Update the IANA status message. */ + status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE); + + if (status != NX_SUCCESS) + { + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + return status; + } + + /* Ok to just send a status option without the IANA option. */ + status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer, &buffer_index); + + /* Update the IANA status message. */ + status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE); + + if (status != NX_SUCCESS) + { + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + return status; + } + } + + /* Exclude IANA options from Confirm and Inform Request messages. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) && + (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) + { + + /* Add the client IANA to the packet buffer. */ + status = _nx_dhcpv6_server_add_iana(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + return status; + } + } + + /* Only an Advertise response should include a preference. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) + + { + + status = _nx_dhcpv6_add_preference(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); + } + + /* Check if the message type requires the server to add option request data. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) + { + + /* It does. Did the Client ask for a requested option? Only provide information + if there are no status errors from the server. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request) && + (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS)) + { + + /* Add the option request. */ + status = _nx_dhcpv6_add_option_requests(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); + + /* Check for internal error. */ + if (status != NX_SUCCESS) + { + + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + + /* Return the error status and abort. */ + return status; + } + } + } + + /* Adjust the packet length for the DHCPv6 data. */ + packet_ptr -> nx_packet_length = buffer_index; + + /* Update the packet pointer marking the end of the payload (DHCP) data. */ + packet_ptr -> nx_packet_append_ptr += buffer_index; + + /* Send the response packet to the client. */ + status = nxd_udp_socket_interface_send(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), packet_ptr, + &dhcpv6_client_ptr -> nx_dhcp_source_ip_address, NX_DHCPV6_CLIENT_UDP_PORT, + dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + /* Release the allocated back to the DHCPv6 Server packet pool. */ + nx_packet_release(packet_ptr); + } + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpc6_server_assign_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service finds an available IP address for the client if none is */ +/* provided, and updates the client's record with the new IP address. It */ +/* updates the server IP address lease table with the assigned lease */ +/* status */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* dhcpv6_client_ptr Pointer to DHCPV6client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* NX_DHCPV6_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_find_interface_table_ip_address */ +/* Look up IP address in */ +/* server interface table */ +/* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/ +/* in server interfce table */ +/* _nx_dhcp_record_ip_address_owner Set the client as IP address */ +/* owner in interface table */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, + NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr) +{ +UINT status; +UINT i; +NX_DHCPV6_ADDRESS_LEASE *temp_interface_address_ptr; +UINT matching; + + + /* Initialize outcome to no address assigned. */ + *interface_address_ptr = NX_NULL; + + /* Does the Client have a IP address already assigned? */ + if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) + { + + /* Yes; The client has an IP address. */ + + /* Check if this address exists in the Server IP address list. */ + status = _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &temp_interface_address_ptr); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Was the address found in the server table? */ + if (temp_interface_address_ptr) + { + + matching = NX_FALSE; + + /* Verify the server has assigned this address. */ + if (temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to) + { + /* It has; now werify it is assigned to this client. */ + status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_client_duid, + &(temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to -> nx_dhcpv6_client_duid), + &matching); + + /* Check for internal errors. */ + if (status != NX_SUCCESS) + { + + return status; + } + } + else + { + /* It has not (so it is available). Assign it to this client. */ + + /* Set the lease address entry in the server table. */ + *interface_address_ptr = temp_interface_address_ptr; + + /* Mark the owner of the lease as this client. */ + temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; + + /* We are all done. */ + return NX_SUCCESS; + } + + /* Was the address assigned to this client previously? */ + if (matching) + { + + /* Yes, return a pointer to the IP lease in the server table. */ + *interface_address_ptr = temp_interface_address_ptr; + + /* We will (re)assign this IP address to the client. */ + return NX_SUCCESS; + } + else + { + /* No this address is not available. */ + + /* Is it Ok to assign another IP address only if this is a Solicit request? */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT) + { + + /* No; Reply back the client request can not be granted. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; + + /* Because the server can not validate the IP address to assign, + set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + + dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; + + return NX_SUCCESS; + } + } + } + else + { + + /* Client address not found in table. */ + + /* Ok to assign another IP address only if this is a Solicit request? */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT) + { + + /* No; reply backthe client request can not be granted. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; + + /* Because the server can not validate the IP address to assign, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + + dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; + + return NX_SUCCESS; + } + } + } + + /* If we reach this point, we need to find an available address for the client. */ + for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) + { + + if (!dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to) + { + break; + } + } + + /* Check if we found anything. */ + if (i == NX_DHCPV6_MAX_LEASES) + { + + /* No; reply back there are no addresses available. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE; + + /* Because the server can not assign the IP address, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + + dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; + } + else + { + + /* Found an empty slot; assign it to this client. */ + + /* Mark the owner of the lease as this client. */ + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; + + /* Return the lease address entry in the server table. */ + *interface_address_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]); + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks up a client record by the client hardware mac */ +/* address. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ +/* dhcpv6_duid _ptr Pointer to client DUID */ +/* record_index Index of client record found */ +/* in server table */ +/* add_on Option to add if not found */ +/* message_xid Message transaction ID */ +/* matching Indicates if client existed in*/ +/* server records already */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Message handled successfully */ +/* NX_DHCPV6_TABLE_FULL Client record table is full */ +/* */ +/* CALLS */ +/* _nx_dhcpv6_check_duids_same Checks if DUIDs are the same */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Extract DHCPv6 info from */ +/* Client message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *duid_ptr, + UINT *record_index, UINT add_on, ULONG message_xid, UINT *matching) +{ + +UINT i; +UINT status; +UINT available_index; +NX_DHCPV6_CLIENT *client_record_ptr; + + + /* Initialize result to not found. */ + *matching = NX_FALSE; + + /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */ + available_index = NX_DHCPV6_MAX_CLIENTS; + + /* Records are not necessarily added and deleted sequentially, + so search the whole table until a match is found. */ + i = 0; + status = NX_SUCCESS; + + while (i < NX_DHCPV6_MAX_CLIENTS) + { + + /* Set local pointer for convenience. */ + client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; + + /* Skip empty records. */ + if (!client_record_ptr -> nx_dhcpv6_id) + { + + /* Flag the first empty record in case we need to add the current client to the table. */ + if (i < available_index) + available_index = i; + + i++; + + continue; + } + + status = _nx_dhcpv6_check_duids_same(&client_record_ptr -> nx_dhcpv6_client_duid, duid_ptr, matching); + + /* Check the DUID in the received client request against the server record. */ + if ((status == NX_SUCCESS) && *matching) + { + + client_record_ptr -> nx_dhcpv6_message_xid = message_xid; + + + /* Reset the client session time every time we hear from a client. */ + client_record_ptr -> nx_dhcpv6_client_session_time = 1; + + /* Got a match! Return the client record location. */ + *record_index = i; + + /* Set the result to client located. */ + *matching = NX_TRUE; + + return(NX_SUCCESS); + } + + /* No match. Check the next client in the server table. */ + i++; + } + + /* Not found. Create a record for this client? */ + if (!add_on) + { + + /* Do not create a record and handle as an error. */ + return(NX_DHCPV6_CLIENT_RECORD_NOT_FOUND); + } + + /* Check if there is available room in the table for a new client. */ + if (available_index >= NX_DHCPV6_MAX_CLIENTS) + { + + /* No, we cannot add this client so the server's table. */ + return(NX_DHCPV6_TABLE_FULL); + } + + /* Set local pointer to an available slot. */ + client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[available_index]; + + /* Return the location of the newly created client record. */ + *record_index = available_index; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_find_ip_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks up a client DHCPv6 message IP address in the */ +/* appropriate server IP address table, based on the client network */ +/* interface index. For single homed hosts, this defaults to zero. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ +/* dhcpv6_client_ptr Pointer to DHCPv6 client */ +/* interface_address_ptr Pointer to matching entry */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Search completes successfully */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcp_clear_client_record Removes client record from */ +/* server table */ +/* */ +/* CALLED BY */ +/* */ +/* CHECK_IPV6_ADDRESSES_SAME Does IPv6 address comparison */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, + NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr) +{ + +UINT i; +NXD_ADDRESS server_table_address; + + + /* Initialize to not found. */ + *interface_address_ptr = NX_NULL; + + /* Search through the interface specific address table. For single homed hosts, there is only one address table. */ + for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) + { + + /* Get a pointer to the address, using the client's interface index to access the correct IP address table. */ + server_table_address = dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address; + + /* Check for a match. */ + if (CHECK_IPV6_ADDRESSES_SAME(&server_table_address.nxd_ip_address.v6[0], + &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) + { + + /* Set the location of the matching server entry, to indicate we found a match. */ + *interface_address_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; + break; + } + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_clear_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the entire client record from the server table.*/ +/* It also frees up the client's IP address in the server IP address */ +/* table. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_ptr Pointer to DHCPV6 Server */ +/* dhcpv6_client_ptr Pointer to DHCPV6 Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful outcome */ +/* NX_DHCP_BAD_INTERFACE_INDEX Invalid client interface index */ +/* CALLS */ +/* */ +/* tx_mutex_get Get server protection mutex */ +/* tx_mutex_put Release server protection mutex*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Listen for client requests */ +/* _nx_dhcpv6_find_client_record_by_chaddr */ +/* Find client in server table */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) +{ + +UINT i; + + + if (!dhcpv6_client_ptr) + { + + /* Benign error. Return success. */ + return(NX_SUCCESS); + } + + i = 0; + + /* Does the client have an assigned IP address? */ + if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) + { + + /* Yes, We need to free up the Client's assigned IP address in the server database. */ + while (i < NX_DHCPV6_MAX_LEASES) + { + + tx_mutex_get(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), NX_WAIT_FOREVER); + + /* Find the interface table entry by matching IP address. */ + if (CHECK_IPV6_ADDRESSES_SAME(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], + &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) + { + + /* Clear the IP address list item properties. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) + { + + /* Apparently another client has this address so do not clear the assignment status. */ + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF; + } + else + { + + /* Restore availability by clearing the owner. */ + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = NX_NULL; + } + + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T1_lifetime = 0; + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T2_lifetime = 0; + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_valid_lifetime = 0; + dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_preferred_lifetime = 0; + + tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + /* Address now available for DHCP client. */ + break; + } + i++; + + tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); + + } + } + + /* Ok to clear the Client record. */ + memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT)); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_update_client_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the client record based on the most recent */ +/* message received from the client. A typical example is after a */ +/* Solicit message is received the server gets a Request message which */ +/* it will add to the client record it has in its table. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ +/* to_server_ptr Pointer to client to update */ +/* from_client_ptr Pointer to client updated from */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful outcome */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Process DHCPv6 data in packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + NX_DHCPV6_CLIENT *from_extracted_client_data_ptr, + NX_DHCPV6_CLIENT *to_client_data_on_record_ptr) +{ + + NX_PARAMETER_NOT_USED(dhcpv6_server_ptr); + + /* If this is a solicit message update the entire copy into the specified record. */ + if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) + { + + /* Ok to copy the whole record over. */ + memcpy(to_client_data_on_record_ptr, from_extracted_client_data_ptr, sizeof(NX_DHCPV6_CLIENT)); + + /* Update various fields now that the client is in a DHCPv6 session with the server. */ + to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 1; + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); + } + else if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) + { + + /* Update selected fields for an INFORM REQUEST. */ + to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id; + to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid; + to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type; + to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server; + + COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0], + &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); + to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0], + &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); + to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); + + } + /* If this is not a solicit message, update the selected fields into the specified record. */ + else if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) + { + + + /* Ok to update the existing client record. + + Note: if this is a duplicate client request we update the client record just + the same. */ + to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id; + to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid; + to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type; + to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server; + + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_elapsed_time, &from_extracted_client_data_ptr -> nx_dhcpv6_elapsed_time, sizeof(NX_DHCPV6_SERVER_ELAPSED_TIME)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_iana, &from_extracted_client_data_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_SERVER_IA_NA)); + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_ia, &from_extracted_client_data_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_SERVER_IA_ADDRESS)); + + /* Update the IANA status option code, length and status message. The DHCPv6 server + will figure out the actual lenght with the status message text added in later. */ + to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_status_code = from_extracted_client_data_ptr -> nx_dhcpv6_iana_status.nx_status_code; + to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_option_length = sizeof(USHORT); + + COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0], + &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); + + to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0], + &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); + + to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); + + /* Update fields based on the state of the client. At this point the client is bound to a + valid IP address to the session is 'over'. Set timeout fields to stop the session timer + and begin the lease life timer. */ + to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 0; + + /* Start the lease timer if we have just (re)assigned an IP lease. */ + if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || + (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) + { + + to_client_data_on_record_ptr -> nx_dhcpv6_IP_lease_time_accrued = 1; + to_client_data_on_record_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND; + } + + /* No need to set the client state to unbound. We will remove the client record and restore the + IP address status back to available after sending the server reply. */ + } + /* else + Confirm, Inform Request and other messages should not change the client record. */ + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_process_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the IANA option from a client DHCPv6 message.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */ +/* received_buffer Pointer to client packet buffer */ +/* length Size of client packet buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_INVALID_IANA_DATA IANA option is missing data or */ +/* improperly formatted */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data */ +/* Parses data from packet buffer */ +/* _nx_dhcpv6_server_utility_get_block_option_length */ +/* Parses option header from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Extracts DHCPV6 data from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) +{ + +UINT status; +ULONG data; +UINT index; +ULONG opcode, option_length; +UINT process_ia_option; + + + /* Initialize local variables. */ + process_ia_option = NX_TRUE; + index = 0; + + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(USHORT), &data); + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_op_code = (USHORT)data; + + index = 2; + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(USHORT), &data); + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_option_length = (USHORT)data; + + /* Set up the location of the read pointer past option header. */ + index = 4; + + /* The first word should contain the IANA ID. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + + /* Process the IANA ID. */ + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_IA_NA_id = data; + + /* Update the write location index. */ + index += 4; + + /* Copy T1 and T2 from the buffer into IANA. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = data; + + index += (ULONG)sizeof(ULONG); + + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + index += (ULONG)sizeof(ULONG); + + dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = data; + + /* Check for invalid T1/T2 lifetimes. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) + { + + /* Reject the server DHCPv6 response. */ + return NX_DHCPV6_INVALID_IANA_TIME; + } + + /* Check if we're at the end of option data yet. */ + if ((index - 4) == length) + { + + /* Yes, all done. */ + return NX_SUCCESS; + } + + /* Now we recurse into the options embedded in the IANA option. We do it here + because this is part of the IANA option data length. */ + do + { + + /* Get the next option code and length. */ + status = _nx_dhcpv6_server_utility_get_block_option_length(received_buffer + index, &opcode, &option_length); + + /* Check that the block data is valid. */ + if (status != NX_SUCCESS) + { + + /* No, return the error status. */ + return status; + } + + /* Check if this is an IA address option request, and if we have already + processed an IA in this message (the DHCPv6 server is limited to + one IA per client message). */ + if (opcode == NX_DHCPV6_OP_IA_ADDRESS) + { + + /* Yes it is, so process it. */ + status = _nx_dhcpv6_server_process_ia(dhcpv6_client_ptr, (received_buffer + index), option_length, process_ia_option); + + /* Check for errors processing the DHCPv6 message. */ + if (status != NX_SUCCESS) + { + + /* Abort further processing. Return error status. */ + return status; + } + + /* Indicate we already have an IA option if the client request contains multiple IAs. */ + process_ia_option = NX_FALSE; + + /* Keep track of how far into the packet we have parsed. */ + index += option_length + 4; + } + + + } while (index - 4 < length); + + /* Check if we went past the reported size of IA-NA data. */ + if (index - 4 > length) + { + + /* Yes return an error status. */ + return NX_DHCPV6_INVALID_IANA_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_option_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the option request from the client packet. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ +/* received_buffer Pointer to packet buffer */ +/* length Size of packet buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data */ +/* Parses data from specified buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Extracts DHCPv6 data from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) +{ + +ULONG data; +UINT i; +UINT index; +UINT option_length; + + NX_PARAMETER_NOT_USED(length); + + index = 0; + + /* Extract the option code which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + + dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_code = (USHORT)data; + + index += 2; + + /* Extract the option length which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length = (USHORT)data; + + index += 2; + + option_length = dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length; + + i = 0; + + while (option_length && (i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS)) + { + + /* Clear out existing data. */ + dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request[i] = 0; + + /* Extract the option request which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + + dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request[i] = (USHORT)data; + + /* Update all the length and index counters.*/ + option_length -= 2; + index += 2; + i++; + + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_elapsed_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the elapsed time option in the client packet.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ +/* received_buffer Pointer to packet buffer */ +/* length Size of packet buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_OPTION_DATA Elapsed time is missing data */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data */ +/* Parses data from specified buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Extracts DHCPv6 data from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) +{ + +ULONG data; +UINT index; + + index = 0; + + /* Extract the option code which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_op_code = (USHORT)data; + + index += 2; + + /* Extract the option length which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_option_length = (USHORT)data; + + index += 2; + + /* Extract the elapsed session time which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = (USHORT)data; + + index += 2; + + /* Are we past the end of the buffer, subtracting for the toplevel opcode and + length of the IANA option? */ + if ((index - 4) > length || (index - 4) < length) + { + + /* Yes, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_OPTION_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_process_ia PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the IA address option from the client packet.*/ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */ +/* buffer_ptr Pointer to client packet buffer */ +/* length Size of client packet buffer */ +/* process_ia If true, write IA to client record*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_IA_DATA IA option is missing data or */ +/* improperly formatted */ +/* NX_DHCPV6_INVALID_IA_TIME IA option lifetime data is invalid*/ +/* */ +/* CALLS */ +/* */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_process_iana Processes IANA in client request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length, UINT process_ia) +{ + +UINT index, k; +ULONG data; + + + /* Fill in the IA address code and length. Client might already have one on + record, but use the server's data instead. */ + if (process_ia) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (USHORT)length; + } + + /* Set the index for the read pointer past the option header. */ + index = 4; + + for (k = 0; k < sizeof(ULONG); k++) + { + + /* Copy each IPv6 address word into the IA address. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + + if (process_ia) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[k] = data; + } + + /* Move to the next IPv6 address word. */ + index += (ULONG)sizeof(ULONG); + + /* Check if we're going past the end of the option data. */ + if (index - sizeof(ULONG) > length) + { + /* Yes, return an error status.*/ + return NX_DHCPV6_INVALID_IA_DATA; + } + } + + /* Copy the preferred lifetime data from the client buffer to IA.*/ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + + if (process_ia) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = data; + + } + + index += (ULONG)sizeof(ULONG); + + /* Copy the valid lifetime data from the client buffer to IA.*/ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); + + if (process_ia) + { + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = data; + + } + + index += (ULONG)sizeof(ULONG); + + /* Check if we went past the reported size of IA address data. */ + if (index - 4 > length || index - 4 < length) + { + + /* Return an error status. Cannot accept this reply. */ + return NX_DHCPV6_INVALID_IA_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_process_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the DUID from the client packet. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ +/* duid_type Denotes client or server DUID */ +/* received_buffer Pointer to packet buffer */ +/* length Size of packet buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INVALID_DUID DUID is missing data or does not */ +/* match the DUID on record */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_server_utility_get_data */ +/* Parses data from specified buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_extract_packet_information */ +/* Extracts DHCPv6 data from packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID *duid_ptr, UINT duid_type, UCHAR *received_buffer, UINT length) +{ + +ULONG data; +UINT index; + + NX_PARAMETER_NOT_USED(duid_type); + + /* Set an index past the option code and data length. */ + index = 4; + + /* Extract the DUID type which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + duid_ptr -> nx_duid_type = (USHORT)data; + + index += 2; + + /* Extract the hardware type which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + + duid_ptr -> nx_hardware_type = (USHORT)data; + + index += 2; + + /* IS this a link layer plus time DUID type? */ + if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + /* Yes; Extract the time which should be the next 4 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 4, &data); + + duid_ptr -> nx_duid_time = data; + + index += 4; + } + + /* Extract the link local address msw which should be the next 2 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); + + index += 2; + + duid_ptr -> nx_link_layer_address_msw = (USHORT)data; + + /* Extract the link local address lsw which should be the next 4 bytes. */ + _nx_dhcpv6_server_utility_get_data(received_buffer + index, 4, &data); + + index += 4; + + duid_ptr -> nx_link_layer_address_lsw = data; + + + /* Are we past the end of the buffer, subtracting for the toplevel opcode and + length of the IANA option? */ + if ((index - 4) > length || (index - 4) < length) + { + + /* Yes, return the error status to reject this packet. */ + return NX_DHCPV6_INVALID_OPTION_DATA; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_check_duids_same PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares the two input DUIDs to match field by field. */ +/* if they match, the match status is returned NX_TRUE. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_duid1_ptr Pointer to first DHCPV6 DUID */ +/* dhcpv6_duid1_ptr Pointer to 2nd DHCPV6 DUID */ +/* matching Flag indicating if DUIDs match */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS No errors doing comparison */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get server protection mutex */ +/* tx_mutex_put Release server protection mutex*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_listen_for_messages Listen for client requests */ +/* _nx_dhcpv6_find_client_record_by_chaddr */ +/* Find client in server table */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID *dhcpv6_duid1_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid2_ptr, UINT *matching) +{ + + + /* Check for invalid input. */ + if (!dhcpv6_duid1_ptr || !dhcpv6_duid2_ptr || !matching) + { + + /* Return invalid input. */ + return(NX_PTR_ERROR); + } + + /* Initialize result to no match. */ + *matching = NX_FALSE; + + /* CHeck field by field starting with the ones most likely to miss. */ + if (dhcpv6_duid1_ptr -> nx_link_layer_address_msw != dhcpv6_duid2_ptr -> nx_link_layer_address_msw) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_link_layer_address_lsw != dhcpv6_duid2_ptr -> nx_link_layer_address_lsw) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_duid_type != dhcpv6_duid2_ptr -> nx_duid_type) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_hardware_type != dhcpv6_duid2_ptr -> nx_hardware_type) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_op_code != dhcpv6_duid2_ptr -> nx_op_code) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_option_length != dhcpv6_duid2_ptr -> nx_option_length) + { + return NX_SUCCESS; + } + else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + if (dhcpv6_duid1_ptr -> nx_duid_time != dhcpv6_duid2_ptr -> nx_duid_time) + { + return NX_SUCCESS; + } + } + else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) + { + + /* First compare the enterprise ID. */ + if (dhcpv6_duid1_ptr -> nx_duid_enterprise_number != dhcpv6_duid2_ptr -> nx_duid_enterprise_number) + { + return NX_SUCCESS; + } + + /* Then compare the private ID. */ + if (memcmp(dhcpv6_duid1_ptr -> nx_duid_private_identifier, dhcpv6_duid2_ptr -> nx_duid_private_identifier, + dhcpv6_duid1_ptr -> nx_option_length - sizeof(ULONG))) + { + + /* No match. */ + return NX_SUCCESS; + } + } + + /* It's match! */ + *matching = NX_TRUE; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_duid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a DHCPv6 DUID to the server response packet */ +/* based on the input DUID and the DUID type (client or server). */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ +/* dhcpv6_duid_ptr Pointer to DHCPV6 DUID instance */ +/* buffer Pointer to packet buffer */ +/* index Location where to add DUID */ +/* duid_type Indicate client or serve DUID */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet buffer too small for DUID */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Compiles and sends the Server */ +/* DHCPv6 response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid_ptr, UCHAR *buffer_ptr, UINT *index, UINT duid_type) +{ + +ULONG message_word; +UINT available_payload; + + NX_PARAMETER_NOT_USED(duid_type); + + /* Clear memory to make the message header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Compile the header from the DUID. */ + message_word = (ULONG)(dhcpv6_duid_ptr -> nx_op_code << 16); + message_word |= (dhcpv6_duid_ptr -> nx_option_length); + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + /* Check if the DUID will fit in the packet buffer. */ + if (available_payload < (UINT)(dhcpv6_duid_ptr -> nx_option_length + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy first half of the DUID option to packet buffer. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); + *index += (ULONG)sizeof(UINT); + + memset(&message_word, 0, sizeof(ULONG)); + + /* Set up the rest of the Client DUID header. */ + message_word = (ULONG)(dhcpv6_duid_ptr -> nx_duid_type << 16); + message_word |= dhcpv6_duid_ptr -> nx_hardware_type; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Set up the DUID option. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); + *index += (ULONG)sizeof(UINT); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw); + + /* Include the 'time' field if this is a Link layer time DUID type. */ + if (dhcpv6_duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) + { + + memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_duid_time), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + } + + /* Copy the rest of the DUID header. */ + memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_msw), sizeof(USHORT)); + *index += (ULONG)sizeof(USHORT); + + memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_lsw), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Swap bytes back to original endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw); + NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_server_add_iana PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the IANA option to the server response packet */ +/* using the Client IANA on record. It will also add any 'nested' */ +/* options such as the Client IA(s) and IANA status option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ +/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ +/* buffer_ptr Pointer to response packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Buffer too small for IANA option */ +/* CALLS */ +/* */ +/* _nx_dhcpv6_add_ia Adds the IA option to buffer */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_send_request Sends server DHCPv6 response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +UINT status; +UINT add_ia; +UINT temp; +UINT temp_index; +ULONG message_word; +UINT available_payload; +NX_DHCPV6_SERVER_IA_NA *iana_ptr; + + + /* Initialize the completion status variable. */ + status = NX_SUCCESS; + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + iana_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_iana; + + /* Check if the client IANA will fit in the packet buffer. */ + if (available_payload < (UINT)(iana_ptr -> nx_option_length + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* For release or decline messages, or a server status indicating no IP address can be + assigned yet, set the IANA IP lease times to expired. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || + (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code != NX_DHCPV6_STATUS_SUCCESS)) + { + + iana_ptr -> nx_T1 = 0; + iana_ptr -> nx_T2 = 0; + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; + } + + /* Clear memory to make the first word of the IA-NA header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Save this location in the buffer. */ + temp_index = *index; + + /* Write the IANA opcode and data length into one word. */ + message_word = (ULONG)((iana_ptr -> nx_op_code) << 16); + + /* Reset the IANA length to just the IANA option fields, (not IA or status options). */ + iana_ptr -> nx_option_length = 3 * sizeof(ULONG); + + message_word |= iana_ptr -> nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the word into the packet buffer going to the server. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); + + /* Update the buffer pointer. */ + *index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id); + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1); + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2); + + memcpy(buffer_ptr + *index, &(iana_ptr -> nx_IA_NA_id), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T1), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T2), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Swap bytes back. */ + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id); + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1); + NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2); + + /* Determine if we include an IA address option. This requires a successful IANA status + and applies only if the client is requesting or confirming an address including renew/rebinding one. */ + add_ia = NX_FALSE; + + /* We include an IA if we intend to assign or confirm an IP address. */ + if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS) + { + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type >= NX_DHCPV6_MESSAGE_TYPE_SOLICIT) && + (dhcpv6_client_ptr -> nx_dhcpv6_message_type <= NX_DHCPV6_MESSAGE_TYPE_DECLINE)) + { + + add_ia = NX_TRUE; + } + } + + /* Or if we are confirming the IP address a client is releasing or declining, regardless + if our records show this IP address is bound to this client. Sect 18.2.6-7 RFC 3315. */ + if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || + (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) + { + add_ia = NX_TRUE; + } + + if (add_ia) + { + + temp = *index; + + /* Check for a missing IA option (as in the Solicit message did not have one). */ + if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code == 0) + { + + NX_DHCPV6_ADDRESS_LEASE *client_address_lease; + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; + + /* Set the length to include option code, lenght (one word), IPv6 address (4 words), and lifetime data (2 words). */ + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (2 * sizeof(ULONG))+ (4 * sizeof(ULONG)); + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME; + + dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime= NX_DHCPV6_DEFAULT_VALID_TIME; + + /* Find the Client's tentatively assigned address in the Server IP address list. */ + _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &client_address_lease); + + if ((status != NX_SUCCESS) || (client_address_lease == NX_NULL)) + { + + return status; + } + + COPY_IPV6_ADDRESS(&client_address_lease -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], + &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]); + } + + status = _nx_dhcpv6_add_ia(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_ia, buffer_ptr, &temp); + + if (status != NX_SUCCESS) + { + + return status; + } + + + /* Add the size of the IA(s) to the client IANA. Note that we include the option code + and length field of any nested options. */ + iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr-> nx_dhcpv6_ia.nx_option_length + 4); + + /* Update the index into packet buffer from our temporary variable. */ + *index = temp; + } + + /* Update the IANA status message. */ + status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE); + + if (status != NX_SUCCESS) + { + + return status; + } + + temp = *index; + + /* Ok to add one to server reply.*/ + status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer_ptr, &temp); + + if (status != NX_SUCCESS) + { + + return status; + } + + /* Update the index into packet buffer from our temporary variable. */ + *index = temp; + + /* Update the IANA option length with the iana status option size. */ + iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr->nx_dhcpv6_iana_status.nx_option_length + 4); + + /* Rewrite the IANA opcode and update the changed IANA data length with the additional IA address option. */ + message_word = (ULONG)((iana_ptr -> nx_op_code) << 16); + message_word |= (ULONG)(iana_ptr -> nx_option_length); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the updated word into the packet buffer at the saved location. */ + memcpy(buffer_ptr + temp_index, &message_word, sizeof(ULONG)); + + /* Erase the IANA status message. We will add another message on the next (if any) IANA option for the client. */ + status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_ia PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the IA address option to the server response */ +/* packet using the input IA option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ +/* dhcpv6_ia_ptr Pointer to IA to add */ +/* buffer_ptr Pointer to response packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Buffer to small for IA option */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_add_iana Adds the IANA to server response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_ia(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IA_ADDRESS *dhcpv6_ia_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG message_word; +UINT available_payload; + + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + /* Check if the client IA address option will fit in the packet buffer. */ + if (available_payload < (UINT)(dhcpv6_ia_ptr -> nx_option_length + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* If the client has created an address option, apply it to the message. */ + + /* Clear memory to make the first word of the IA-Address header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Compile the header from the IA option on the client record. */ + message_word = (ULONG)(dhcpv6_ia_ptr -> nx_op_code << 16); + message_word |= dhcpv6_ia_ptr -> nx_option_length; + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy option header into the packet and update the index into the buffer. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime); + + /* Copy the IPv6 address to the packet. */ + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Copy the Client's preference for lifetimes to packet. */ + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_preferred_lifetime), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_valid_lifetime), sizeof(ULONG)); + *index += (ULONG)sizeof(ULONG); + + /* Swap bytes back. */ + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime); + NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dhcpv6_add_iana_status PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the IANA status option to the server response */ +/* packet using the input IANA status option. */ +/* */ +/* INPUT */ +/* */ +/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ +/* iana_status_ptr Pointer to IANA status option */ +/* buffer_ptr Pointer to response packet buffer */ +/* index Location into buffer to write data*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ +/* Buffer to small for IA option */ +/* CALLS */ +/* */ +/* memset Clears specified area of memory */ +/* memcpy Copies specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dhcpv6_server_add_iana Add IANA status to server response*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IANA_STATUS *iana_status_ptr, UCHAR *buffer_ptr, UINT *index) +{ + +ULONG message_word; +USHORT message_short; +UINT available_payload; +UINT message_length; + + + /* Compute the available payload in the packet buffer. */ + available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - + NX_IPv6_UDP_PACKET - *index; + + /* Check if the status option will fit in the packet buffer. */ + if (available_payload < (UINT)(iana_status_ptr -> nx_option_length + 4)) + { + + /* Hmmm... not enough! Can't do it. */ + return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Clear memory to make the message header. */ + memset(&message_word, 0, sizeof(ULONG)); + + /* Compile the header for the status option. */ + message_word = (ULONG)(iana_status_ptr -> nx_op_code << 16); + message_word |= (iana_status_ptr -> nx_option_length); + + /* Adjust for endianness. */ + NX_CHANGE_ULONG_ENDIAN(message_word); + + /* Copy the word to packet buffer. */ + memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); + *index += (ULONG)sizeof(UINT); + + memset(&message_word, 0, sizeof(ULONG)); + + /* Set up the status option code. */ + message_short = iana_status_ptr -> nx_status_code; + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(message_short); + + /* Set up the DUID option. */ + memcpy(buffer_ptr + *index, &message_short, sizeof(USHORT)); + *index += (ULONG)sizeof(USHORT); + + message_length = iana_status_ptr -> nx_option_length - (ULONG)(sizeof(USHORT)); + memcpy(buffer_ptr + *index, &iana_status_ptr -> nx_status_message[0], message_length); + + *index += message_length; + + /* No need to swap the last byte. */ + return NX_SUCCESS; +} +#endif /* FEATURE_NX_IPV6 */ diff --git a/addons/dhcp/nxd_dhcpv6_server.h b/addons/dhcp/nxd_dhcpv6_server.h new file mode 100644 index 00000000..ee01ba0e --- /dev/null +++ b/addons/dhcp/nxd_dhcpv6_server.h @@ -0,0 +1,825 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_dhcpv6_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Dynamic Host Configuration Protocol over */ +/* IPv6 (DHCPv6) component, including all data types and external */ +/* references. It is assumed that nx_api.h and nx_port.h have already */ +/* been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_DHCPV6_SERVER_H +#define NXD_DHCPV6_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the DHCPv6 ID to mark the DHCPV6_CLIENT and DHCPV6_SERVER structures as created. */ + +#define NX_DHCPV6_CLIENT_ID 0x44484336UL +#define NX_DHCPV6_SERVER_ID 0x44484337UL + + +/* Define the conversion between timer ticks and seconds (processor dependent). */ + +#define NX_DHCPV6_SERVER_TICKS_PER_SECOND NX_IP_PERIODIC_RATE + + +/* Set up interface defines for NetX Duo. */ + +#define LINK_LOCAL_INTERFACE 0 +#define GLOBAL_IP_INTERFACE 1 + + +/* Set the Client lease time. An infinate lease time is not recommended by the RFC + unless the Client requires a permanent IP address. Most servers will likely not + grant an infinite IP address lease. */ + +#define NX_DHCPV6_INFINITE_LEASE 0xffffffffUL +#define NX_DHCPV6_MULTICAST_MASK 0xff000000UL + + +/* Define RFC mandated (draft only) option codes. */ + +#define NX_DHCPV6_RFC_DNS_SERVER_OPTION 0x00000017UL /* RFC Option code for requesting DNS server IP address */ +#define NX_DHCPV6_RFC_TIME_SERVER_OPTION 0x0000001FUL /* RFC Option code for requesting tme server IP address. */ +#define NX_DHCPV6_RFC_TIME_ZONE_OPTION 0x00000029UL /* RFC Option code for requesting Time zone. */ +#define NX_DHCPV6_RFC_DOMAIN_NAME 0x00000018UL /* RFC Option code for requesting domain name. */ + + +/* Define the DHCPv6 DUID types supported by the NetX DHCPv6 Server. */ + +typedef enum +{ +NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME = 1, +NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED, +NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY + +} NX_DHCPV6_DUID_TYPE_SERVER; + +/* Define constants for denoting server vs client DUIDs. */ + +#define NX_DHCPV6_SERVER_DUID_TYPE 1 +#define NX_DHCPV6_CLIENT_DUID_TYPE 2 + +/* Define approximate time since Jan 1, 2000 for computing DUID time. This will form the + basis for the DUID time ID field. */ + +#define SECONDS_SINCE_JAN_1_2000_MOD_32 2563729999UL + + +/* Define the Hardware types. */ +#define NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET 1 +#define NX_DHCPV6_SERVER_HARDWARE_TYPE_EUI_64 27 + +/* NX_DHCPV6_HW_TYPE_IEEE_802 is defined as 1 to indicate Ethernet hardware type in old releases, for backward compatibility. + + Note: NX_DHCPV6_HW_TYPE_IEEE_802 will be deprecated by NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET + in future releases, should use above symbols to define hardware types. +*/ +#define NX_DHCPV6_HW_TYPE_IEEE_802 1 + + +/* Define the symbol for a static IP address lease, e.g. infinity. */ + +#define NX_DHCPV6_INFINTY_LEASE 0xFFFFFFFF + + +/* Define the DHCPv6 Message Types. */ + +#define NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT 0 +#define NX_DHCPV6_MESSAGE_TYPE_SOLICIT 1 +#define NX_DHCPV6_MESSAGE_TYPE_ADVERTISE 2 +#define NX_DHCPV6_MESSAGE_TYPE_REQUEST 3 +#define NX_DHCPV6_MESSAGE_TYPE_CONFIRM 4 +#define NX_DHCPV6_MESSAGE_TYPE_RENEW 5 +#define NX_DHCPV6_MESSAGE_TYPE_REBIND 6 +#define NX_DHCPV6_MESSAGE_TYPE_REPLY 7 +#define NX_DHCPV6_MESSAGE_TYPE_RELEASE 8 +#define NX_DHCPV6_MESSAGE_TYPE_DECLINE 9 +#define NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE 10 +#define NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST 11 + + +/* Define the DHCPv6 Options. */ + +#define NX_DHCPV6_OP_DUID_CLIENT 1 /* Client DUID (DHCP unique identifier) */ +#define NX_DHCPV6_OP_DUID_SERVER 2 /* Server DUID (DHCP unique identifier) */ +#define NX_DHCPV6_OP_IA_NA 3 /* Identity association for non temporary addresses */ +#define NX_DHCPV6_OP_IA_TA 4 /* Identity association for temporary addresses */ +#define NX_DHCPV6_OP_IA_ADDRESS 5 /* Address associated with IA_NA or IA_TA */ +#define NX_DHCPV6_OP_OPTION_REQUEST 6 /* Identifies a list of options */ +#define NX_DHCPV6_OP_PREFERENCE 7 /* Server's means of affecting Client choice of servers. */ +#define NX_DHCPV6_OP_ELAPSED_TIME 8 /* Duration of Client exchange with DHCPv6 server */ +#define NX_DHCPV6_OP_RELAY_MESSAGE 9 /* Not in use in NetX DHCPV6 */ +#define NX_DHCPV6_OP_AUTHENTICATION 11 /* Not in use in NetX DHCPV6 */ +#define NX_DHCPV6_OP_SERVER_UNICAST 12 /* Server ok's allowing the client to address it in Unicast */ +#define NX_DHCPV6_OP_OPTION_STATUS 13 /* Option request status. */ +#define NX_DHCPV6_OP_RAPID_COMMIT 14 /* Option requesting exchange of two DHCPv6 packets to assign address */ + + +/* Define the DHCPv6 Client states */ + +#define NX_DHCPV6_STATE_BOUND 1 /* Client not known to be bound to an IP address. */ +#define NX_DHCPV6_STATE_UNBOUND 2 /* Client is bound to an IP address (not necessarily by this server). */ + + +/* Define DHCPv6 event flags. These events are processed by the Server DHCPv6 thread. */ + +#define NX_DHCPV6_ALL_EVENTS 0xFFFFFFFFUL /* All Server DHCPv6 event flags */ +#define NX_DHCPV6_SERVER_RECEIVE_EVENT 0x00000001UL /* Packet received on the DHCPv6 server queue. */ +#define NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT 0x00000008UL /* Time keeper to check for expiration on leased IP addresses. */ +#define NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT 0x00000004UL /* Time keeper to check if each session with active client has timed out. */ + + +/* Define DHCPv6 client and server ports. */ + +#define NX_DHCPV6_SERVER_UDP_PORT 547 +#define NX_DHCPV6_CLIENT_UDP_PORT 546 + + +/* Define error codes from DHCPv6 API. */ + +#define NX_DHCPV6_ALREADY_STARTED 0xE91 /* DHCPv6 already started when API called to start it. */ +#define NX_DHCPV6_NOT_STARTED 0xE92 /* DHCPv6 was not started when API was called */ +#define NX_DHCPV6_PARAM_ERROR 0xE93 /* Invalid non pointer input to API */ +#define NX_DHCPV6_INVALID_DEVICE_MAC_ADDRESS 0xE94 /* DHCPv6 server device mac address unknown or undefined */ +#define NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS 0xE95 /* DHCPv6 server interface global IP address unknown or undefined */ +#define NX_DHCPV6_INVALID_INTERFACE_LL_ADDRESS 0xE96 /* DHCPv6 server interface link local address unknown or undefined */ +#define NX_DHCPV6_INVALID_GLOBAL_INDEX 0xE97 /* DHCPv6 global address index not set */ +#define NX_DHCPV6_BAD_SERVER_DUID 0xE98 /* Invalid or inappropriate server DUID (Should not be in some DHCPv6 message types). */ +#define NX_DHCPV6_MESSAGE_DUID_MISSING 0xE99 /* Received a message type missing server or client DUID. */ +#define NX_DHCPV6_INVALID_INTERFACE_INDEX 0xEBC /* Specified interface does not exist for the DHCPv6 server instance */ +#define NX_DHCPV6_INVALID_IANA_TIME 0xEA0 /* Client IA-NA option T1 vs T2 address lease time is invalid. */ +#define NX_DHCPV6_IANA_OPTION_MISSING 0xEA1 /* Received IA address option not belonging to an IA block */ +#define NX_DHCPV6_NO_SERVER_DUID 0xEA2 /* No server DUID detected; DHCPv6 server cannot start without one */ +#define NX_DHCPV6_INVALID_IANA_DATA 0xEA3 /* Client IA-NA option block has bad syntax or missing data */ +#define NX_DHCPV6_INVALID_IA_DATA 0xEA5 /* Server IA address option block has bad syntax or missing data */ +#define NX_DHCPV6_INVALID_IA_TIME 0xEA6 /* Server IA option preferred vs valid lease time is invalid. */ +#define NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES 0xEA7 /* Server created with no assignable addresses. */ +#define NX_DHCPV6_ADDRESS_NOT_FOUND 0xEA8 /* Client address not found in server lease table. */ +#define NX_DHCPV6_OPTION_BLOCK_INCOMPLETE 0xEA9 /* Empty option block data; either zero length or zero option parsed. */ +#define NX_DHCPV6_INVALID_OPTION_DATA 0xEAA /* Server received option data with missing data or bad syntax */ +#define NX_DHCPV6_ILLEGAL_MESSAGE_TYPE 0xEB1 /* Received invalid message request e.g. RENEW (server should discard), */ +#define NX_DHCPV6_PROCESSING_ERROR 0xEB5 /* Invalid Client packet with DHCPv6 format or packet size */ +#define NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD 0xEB6 /* Server DHCPv6 reply will not fit in packet pool packet buffer. */ +#define NX_DHCPV6_INVALID_DATA_SIZE 0xEB7 /* Attempting to parse too large a data object from DHCPv6 request. */ +#define NX_DHCPV6_TABLE_FULL 0xEC4 /* Server table (e.g. Client records or IP address leases) is full. */ +#define NX_DHCPV6_INVALID_IP_ADDRESS 0xECB /* Invalid IP address e.g. null address received or obtained from client record. */ +#define NX_DHCPV6_INVALID_DUID 0xECC /* Invalid DUID received from client or retrieved from memory. */ +#define NX_DHCPV6_CLIENT_RECORD_NOT_FOUND 0xECF /* Unable to find client in Client records table. */ +#define NX_DHCPV6_TIMER_INTERNAL_ERROR 0xED4 /* Problem setting or accessing real time clock server for DUID time field. */ +#define NX_DHCPV6_INVALID_VENDOR_DATA 0xED5 /* Vendor data invalid (ID is too long, null data etc). */ + + +/* Define the DHCPv6 status codes. */ + +#define NX_DHCPV6_STATUS_SUCCESS 0 /* Client request granted. */ +#define NX_DHCPV6_STATUS_UNSPECIFIED 1 /* Failure, reason unspecified; */ +#define NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE 2 /* Server has no addresses available to assign to the IA(s) */ +#define NX_DHCPV6_STATUS_NO_BINDING 3 /* Client record (binding) unavailable or not possible */ +#define NX_DHCPV6_STATUS_NOT_ON_LINK 4 /* Address prefix not appropriate for client domain */ +#define NX_DHCPV6_STATUS_USE_MULTICAST 5 /* Server informs client to use the All_DHCP_Relay_Agents_and_Servers address. */ + + +/* Define the server messages for IANA status codes. Note that these + messages must be shorter than the NX_DHCPV6_STATUS_MESSAGE_MAX + option defined for the client IANA status option. +*/ +#ifndef NX_DHCPV6_STATUS_MESSAGE_SUCCESS +#define NX_DHCPV6_STATUS_MESSAGE_SUCCESS "IA OPTION GRANTED" +#endif + +#ifndef NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED +#define NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED "IA OPTION NOT GRANTED-FAILURE UNSPECIFIED" +#endif + +#ifndef NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE +#define NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE "IA OPTION NOT GRANTED-NO ADDRESSES AVAILABLE" +#endif + + +#ifndef NX_DHCPV6_STATUS_MESSAGE_NO_BINDING +#define NX_DHCPV6_STATUS_MESSAGE_NO_BINDING "IA OPTION NOT GRANTED-INVALID CLIENT REQUEST" +#endif + + +#ifndef NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK +#define NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK "IA OPTION NOT GRANTED-CLIENT NOT ON LINK" +#endif + + +#ifndef NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST +#define NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST "IA OPTION NOT GRANTED-CLIENT MUST USE MULTICAST" +#endif + + +/* Define the wait option on receiving packets on the DHCPv6 server queue. This + is on a receive notify callback, so there need not be any wait involved. */ + +#ifndef NX_DHCPV6_PACKET_WAIT_OPTION +#define NX_DHCPV6_PACKET_WAIT_OPTION NX_IP_PERIODIC_RATE +#endif + +/* Note the DHCPv6 server only supports the DNS server option in the current release. */ + + + +/* Define the DHCPv6 Server application stack size. This is more than enough + for most DHCPv6 Server applications. */ + +#ifndef NX_DHCPV6_SERVER_THREAD_STACK_SIZE +#define NX_DHCPV6_SERVER_THREAD_STACK_SIZE 4096 +#endif + + +/* Define the DHCPv6 Server thread priority. */ + +#ifndef NX_DHCPV6_SERVER_THREAD_PRIORITY +#define NX_DHCPV6_SERVER_THREAD_PRIORITY 2 +#endif + + +/* Define the timer interval in seconds for checking Client lease time expirations. */ + +#ifndef NX_DHCPV6_IP_LEASE_TIMER_INTERVAL +#define NX_DHCPV6_IP_LEASE_TIMER_INTERVAL (60) +#endif + + +/* Define the timer interval in seconds for the session duration timer. */ + +#ifndef NX_DHCPV6_SESSION_TIMER_INTERVAL +#define NX_DHCPV6_SESSION_TIMER_INTERVAL (3) +#endif + + +/* Define the session time out in seconds. This is the timer for how long the server has not + received a client response. */ + +#ifndef NX_DHCPV6_SESSION_TIMEOUT +#define NX_DHCPV6_SESSION_TIMEOUT (20) +#endif + +/* Define the private ID of the vendor DUID tuple. This is a 32 bit word. */ + +#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID +#define NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID 0x12345678 +#endif + + +/* Define the size limit on the Vendor ID buffer. */ + +#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH +#define NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH 48 +#endif + + +/* Define the vendor ID. The server must have this data to create its DUID required for sending + responses to the DHCPv6 client. */ + +#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID +#define NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID "abcdeffghijklmnopqrstuvwxyz" +#endif + + +/* Define parameters for the server DUID */ + +/* Define the server DUID type. The most common are link layer, based on mac address, + and link layer-time which is based on mac address and current time. */ + +#ifndef NX_DHCPV6_SERVER_DUID_TYPE +#define NX_DHCPV6_SERVER_DUID_TYPE NX_DHCPV6_DUID_TYPE_LINK_TIME +#endif + + +/* Default DUID hardware type to Ethernet */ + +#ifndef NX_DHCPV6_SERVER_HW_TYPE +#define NX_DHCPV6_SERVER_HW_TYPE NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET +#endif + + +/* Define the preference option pref-value. When multiple DHCPv6 servers exist, this + enables a server to tell the client which preference to place on this server. The higher + the value the greater the preference. A value of 255 received by a DHCPv6 + client will instruct the client to choose this DHPCv6 server immediately, rather + than wait for the full round trip time out option specified in RFC 3315. RFC 3315 + sect 17.2.2 requires the server set this value to zero by default*/ + +#ifndef NX_DHCPV6_PREFERENCE_VALUE +#define NX_DHCPV6_PREFERENCE_VALUE 0 +#endif + + +/* Define the maximum options to extract from a client message. This makes + no assumptions about the packet size limitations which the host application + must ensure can handle both the client request and the server reply. */ + +#ifndef NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS +#define NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS 6 +#endif + + +/* Set the default T1 time, which is when the Client should begin renewing its IP address, + for leased IP addresses in seconds. RFC 3315 recommends + T1 is 0.5 the value of the preferred lifetime. */ + +#ifndef NX_DHCPV6_DEFAULT_T1_TIME +#define NX_DHCPV6_DEFAULT_T1_TIME (2000) +#endif + + +/* Set the default T2 time, which is when the Client should begin renewing its IP address, + assuming renewal attempts failed, for leased IP addresses in seconds. + T2 must be greater than T2 and less than the value of the preferred lifetime. */ + +#ifndef NX_DHCPV6_DEFAULT_T2_TIME +#define NX_DHCPV6_DEFAULT_T2_TIME (3000) +#endif + + +/* Set the default preferred lifetime for leased IP addresses in seconds, which is + when the Client IP address becomes deprecated. A value of zero in + this field indicates that the server leaves it to the + client discretion to renew its IP address lease. */ + +#ifndef NX_DHCPV6_DEFAULT_PREFERRED_TIME +#define NX_DHCPV6_DEFAULT_PREFERRED_TIME (2 * NX_DHCPV6_DEFAULT_T1_TIME) +#endif + + +/* Set the default valid lifetime in seconds for leased IP addresses in secs, which is when + the Client IP address becomes obsolete. A value of zero in this field indicates + that the server leaves it to the client discretion to renew its IP address lease. + The valid time must be greater than the preferred time. */ + +#ifndef NX_DHCPV6_DEFAULT_VALID_TIME +#define NX_DHCPV6_DEFAULT_VALID_TIME (2 * NX_DHCPV6_DEFAULT_PREFERRED_TIME) +#endif + + + +/* Define maximum size for server messages in status option. */ + +#ifndef NX_DHCPV6_STATUS_MESSAGE_MAX +#define NX_DHCPV6_STATUS_MESSAGE_MAX 100 +#endif + + +/* Define the max number of IPv6 address leases available to lease. */ + +#ifndef NX_DHCPV6_MAX_LEASES +#define NX_DHCPV6_MAX_LEASES 100 +#endif + + +/* Define the max number of clients the server can assign leases to at any given time. + These are clients either already leasing an IPv6 address or currently requesting one. + Note: there are more addresses than clients in the event the client declines an address + or one assigned is already in use. The NetX DHCPv6 server currently only supports + one IP address leased to each client. */ + +#ifndef NX_DHCPV6_MAX_CLIENTS +#define NX_DHCPV6_MAX_CLIENTS 120 +#endif + +/* Define the wait option in timer ticks for DHCPv6 server packet allocations. */ + +#ifndef NX_DHCPV6_PACKET_TIME_OUT +#define NX_DHCPV6_PACKET_TIME_OUT (3 * NX_DHCPV6_SERVER_TICKS_PER_SECOND) +#endif + + +/* Define the DHCPv6 packet size. Should be large enough to hold IP and UDP headers, + plus DHCPv6 data runs about 200 - 300 bytes for a typical exchange. */ + +#ifndef NX_DHCPV6_PACKET_SIZE +#define NX_DHCPV6_PACKET_SIZE 500 +#endif + + +/* Define the DHCPv6 packet memory area. Packet pool size depends on client traffic and + available network bandwidth. */ + +#ifndef NX_DHCPV6_PACKET_POOL_SIZE +#define NX_DHCPV6_PACKET_POOL_SIZE (10 * NX_DHCPV6_PACKET_SIZE) +#endif + + +/* Define UDP socket type of service. */ + +#ifndef NX_DHCPV6_TYPE_OF_SERVICE +#define NX_DHCPV6_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + + +/* Define the UDP socket fragment option. */ + +#ifndef NX_DHCPV6_FRAGMENT_OPTION +#define NX_DHCPV6_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +/* Define the number of routers a UDP packet passes before it is discarded. */ + +#ifndef NX_DHCPV6_TIME_TO_LIVE +#define NX_DHCPV6_TIME_TO_LIVE 0x80 +#endif + +/* Define the stored packets in the UDP server socket queue. */ + +#ifndef NX_DHCPV6_QUEUE_DEPTH +#define NX_DHCPV6_QUEUE_DEPTH 5 +#endif + + +/* Define the Identity Association Internet Address option structure */ +typedef struct NX_DHCPV6_SERVER_IA_ADDRESS_STRUCT +{ + + USHORT nx_op_code; /* IA internet address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ + NXD_ADDRESS nx_global_address; /* Assigned Host IPv6 address */ + ULONG nx_preferred_lifetime; /* Server's preference for IPv6 address T1 life time for itself */ + ULONG nx_valid_lifetime; /* Server's assigned valid time for T2 for any server */ + +} NX_DHCPV6_SERVER_IA_ADDRESS; + +/* Define the Option status structure */ +typedef struct NX_DHCPV6_SERVER_IANA_STATUS_STRUCT +{ + + USHORT nx_op_code; /* IA address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ + USHORT nx_status_code; /* Server status (reply) to client request */ + CHAR nx_status_message[NX_DHCPV6_STATUS_MESSAGE_MAX]; + /* Buffer containing server status messages */ +} NX_DHCPV6_SERVER_IANA_STATUS; + + +/* Define the Preference Option structure */ +typedef struct NX_DHCPV6_SERVER_PREFERENCE_STRUCT +{ + + USHORT nx_op_code; /* IA address option code is 5 */ + USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ + USHORT nx_pref_value; /* Assigned Host IPv6 address */ + +} NX_DHCPV6_SERVER_PREFERENCE; + + +/* Define the Identity Association for Permanent ("Non Temporary" in RFC) address */ + +typedef struct NX_DHCPV6_SERVER_IA_NA_STRUCT +{ + + USHORT nx_op_code; /* IA NA address option code is 3 */ + USHORT nx_option_length; /* 12 + length of variable length fields in IA_NA option . */ + ULONG nx_IA_NA_id; /* IANA identifier; must be unique among all client IANA's. Must be the same on restart per IANA */ + ULONG nx_T1; /* Time client can extend time before address lifetime expires from the server it got it from; applies to all addresses in IA_NA. */ + ULONG nx_T2; /* Same as T1 except this is when the client will request REBIND from another server. */ + +} NX_DHCPV6_SERVER_IA_NA; + + +/* Define DHCPv6 Unique Identifier (DUID); both Client and Server must send messages with their own DUID. */ + +typedef struct NX_DHCPV6_SVR_DUID_STRUCT +{ + + USHORT nx_op_code; /* Client DUID option code is 1; Server DUID code is 2 */ + USHORT nx_option_length; /* Option length = 14 not including length and op code field; */ + USHORT nx_duid_type; /* 3 main types: hw; hw + time; vendor assigned ID (not supported here); requires DUID be stored in non volatile storage */ + USHORT nx_hardware_type; /* Only if LL/LLT type. Hardware type specified by IANA/RFC 826 e.g. IEEE 802; network byte order */ + ULONG nx_duid_time; /* Only if LLT type. Time based on when DUID generated; network byte order. */ + ULONG nx_duid_enterprise_number; /* Only if vendor assigned (enterprise) DUID */ + UCHAR nx_duid_private_identifier[NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH]; + USHORT nx_link_layer_address_msw; /* Only if LL/LLT type. Pointer to Unique link layer address - most significant word (2 bytes)*/ + ULONG nx_link_layer_address_lsw; /* Only if LL/LLT type. Pointer to Unique link layer address - least significant word (4 bytes) */ + +} NX_DHCPV6_SVR_DUID; + + +/* Define the elapsed time option structure. This contains the length of the Client Server session. */ + +typedef struct NX_DHCPV6_SERVER_ELAPSED_TIME_STRUCT +{ + + USHORT nx_op_code; /* Elapsed time option code = 8 not including length and op code field. */ + USHORT nx_option_length; /* Length of time data = 2. */ + USHORT nx_session_time; /* Time of DHCP session e.g. first msg elapsed time is zero. */ + +} NX_DHCPV6_SERVER_ELAPSED_TIME; + + +/* Define the option request structure. This is how the Client requests information other than global IP address. + It can ask for domain name, DNS server, time zone, time server and other options. */ + +typedef struct NX_DHCPV6_SERVER_OPTIONREQUEST_STRUCT +{ + USHORT nx_op_code; /* Option Request code = 6*/ + USHORT nx_option_length; /* Length in bytes of option data = 2 * number of requests */ + USHORT nx_op_request[NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS]; + /* List of option request options e.g. DNS server */ + +} NX_DHCPV6_SERVER_OPTIONREQUEST; + +/* Define the Client DHCPv6 structure containing the DHCPv6 Client record (DHCPv6 status, server DUID etc). */ + +typedef struct NX_DHCPV6_CLIENT_STRUCT +{ + + ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ + ULONG nx_dhcpv6_message_xid; /* Message transaction ID (3 bytes)*/ + UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ + UINT nx_dhcpv6_message_type; /* DHCPv6 message type most recently received from client. */ + UINT nx_dhcpv6_response_back_from_server; /* Response server will send back to client based on previous client message */ + NX_DHCPV6_SVR_DUID nx_dhcpv6_client_duid; /* Client DUID parsed from client DHCPv6 requests */ + NX_DHCPV6_SVR_DUID nx_dhcpv6_server_duid; /* Server DUID parsed from client DHCPv6 requests */ + ULONG nx_dhcpv6_client_session_time; /* Duration of client server session. Used to determine if client quit on the session. */ + UINT nx_dhcpv6_rapid_commit_status; /* Client status on rapid commit (set to true if requests and server approves). */ + NX_DHCPV6_SERVER_ELAPSED_TIME + nx_dhcpv6_elapsed_time; /* Time duration of the current DHCP msg exchange between Client and Server. */ + NX_DHCPV6_SERVER_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ + NX_DHCPV6_SERVER_IA_ADDRESS + nx_dhcpv6_ia; /* Client internet address option */ + NX_DHCPV6_SERVER_OPTIONREQUEST + nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ + NX_DHCPV6_SERVER_IANA_STATUS + nx_dhcpv6_iana_status; /* Status option set by the server for client IANA */ + NX_DHCPV6_SERVER_PREFERENCE + nx_dhcpv6_preference; /* Preference option set by the server */ + ULONG nx_dhcpv6_IP_lease_time_accrued ; /* Time remaining on the Client IP address lease. */ + NXD_ADDRESS nx_dhcp_source_ip_address; /* Source IP of the client DHCP message. */ + NXD_ADDRESS nx_dhcp_destination_ip_address; /* Destination IP of the client DHCP message. */ + +} NX_DHCPV6_CLIENT; + +/* Define the DHCPv6 server interface IP address table. */ + +typedef struct NX_DHCPV6_ADDRESS_LEASE_STRUCT +{ + + NXD_ADDRESS nx_dhcpv6_lease_IP_address; /* Address to assign */ + ULONG nx_dhcpv6_lease_T1_lifetime; /* T1 value set if assigned to client */ + ULONG nx_dhcpv6_lease_T2_lifetime; /* T2 value set if assigned to client */ + ULONG nx_dhcpv6_lease_valid_lifetime; /* valid lifetime set if assigned to client */ + ULONG nx_dhcpv6_lease_preferred_lifetime; /* preferred lifetime set if assigned to client */ + NX_DHCPV6_CLIENT *nx_dhcpv6_lease_assigned_to; /* Client DUID assigned the address */ + +}NX_DHCPV6_ADDRESS_LEASE; + + +/* Define the Server DHCPv6 structure containing the Client tables and assignable IP address tables. */ + +typedef struct NX_DHCPV6_SERVER_STRUCT +{ + ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ + CHAR *nx_dhcpv6_server_name; /* DHCPv6 name supplied at create */ + NX_IP *nx_dhcpv6_ip_ptr; /* The associated IP pointer for this DHCPV6 instance */ + UINT nx_dhcpv6_server_interface_index; /* Index indicating interface DHCPv6 requests accepted */ + UINT nx_dhcpv6_server_ga_address_index; /* Global address index of the DHCPv6 server*/ + NX_DHCPV6_SVR_DUID nx_dhcpv6_server_duid; /* DUID by which server identifies itself to clients */ + NX_DHCPV6_CLIENT nx_dhcpv6_clients[NX_DHCPV6_MAX_CLIENTS]; /* list of clients leased an IPv6 address */ + NX_DHCPV6_ADDRESS_LEASE nx_dhcpv6_lease_list[NX_DHCPV6_MAX_LEASES]; /* List of IP addresses available for DHCPv6 Clients */ + UINT nx_dhcpv6_assignable_addresses; /* Number of assignable addresses the server starts with. */ + UINT nx_dhcpv6_server_multicast_only; /* Indicate if the client should send requests using all servers multicast address */ + NX_UDP_SOCKET nx_dhcpv6_server_socket; /* UDP socket for communicating with DHCPv6 clients */ + TX_MUTEX nx_dhcpv6_server_mutex; /* Mutex protection of server control block */ + TX_TIMER nx_dhcpv6_lease_timer; /* Timer for tracking IP lease expiration */ + TX_TIMER nx_dhcpv6_session_timer; /* Server session duration timer */ + TX_THREAD nx_dhcpv6_server_thread; /* DHCPv6 Server processing thread */ + NX_PACKET_POOL *nx_dhcpv6_packet_pool_ptr; /* Pointer to packet pool for sending DHCPV6 messages */ + TX_EVENT_FLAGS_GROUP nx_dhcpv6_server_timer_events; /* Message queue for IP lease and session timer events. */ + UINT nx_dhcpv6_server_running; /* Status of dhcpv6 server; idle (NX_FALSE) or running (NX_TRUE) */ + NXD_ADDRESS nx_dhcpv6_dns_ip_address; /* DHCP server DNS Server Address in message to DHCP Client */ + + /* Define a handler for receiving a DECLINE or RELEASE message. */ + VOID (*nx_dhcpv6_IP_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message_type); + /* Define a handler for Option Request options. */ + VOID (*nx_dhcpv6_server_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index); + + /* Define a extended handler for Option Request options. */ + VOID (*nx_dhcpv6_server_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index, UINT available_payload); + +} NX_DHCPV6_SERVER; + +#ifndef NX_DHCPV6_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map DHCP API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + + +#define nx_dhcpv6_set_server_duid _nx_dhcpv6_set_server_duid +#define nx_dhcpv6_create_dns_address _nx_dhcpv6_create_dns_address +#define nx_dhcpv6_create_ip_address_range _nx_dhcpv6_create_ip_address_range +#define nx_dhcpv6_add_ip_address_lease _nx_dhcpv6_add_ip_address_lease +#define nx_dhcpv6_add_client_record _nx_dhcpv6_add_client_record +#define nx_dhcpv6_retrieve_client_record _nx_dhcpv6_retrieve_client_record +#define nx_dhcpv6_retrieve_ip_address_lease _nx_dhcpv6_retrieve_ip_address_lease +#define nx_dhcpv6_reserve_ip_address_range _nx_dhcpv6_reserve_ip_address_range +#define nx_dhcpv6_server_create _nx_dhcpv6_server_create +#define nx_dhcpv6_server_delete _nx_dhcpv6_server_delete +#define nx_dhcpv6_server_resume _nx_dhcpv6_server_resume +#define nx_dhcpv6_server_suspend _nx_dhcpv6_server_suspend +#define nx_dhcpv6_server_start _nx_dhcpv6_server_start +#define nx_dhcpv6_server_interface_set _nx_dhcpv6_server_interface_set +#define nx_dhcpv6_server_option_request_handler_set _nx_dhcpv6_server_option_request_handler_set + +#else + +/* Services with error checking. */ + +#define nx_dhcpv6_set_server_duid _nxe_dhcpv6_set_server_duid +#define nx_dhcpv6_create_dns_address _nxe_dhcpv6_create_dns_address +#define nx_dhcpv6_create_ip_address_range _nxe_dhcpv6_create_ip_address_range +#define nx_dhcpv6_add_ip_address_lease _nxe_dhcpv6_add_ip_address_lease +#define nx_dhcpv6_add_client_record _nxe_dhcpv6_add_client_record +#define nx_dhcpv6_retrieve_client_record _nxe_dhcpv6_retrieve_client_record +#define nx_dhcpv6_retrieve_ip_address_lease _nxe_dhcpv6_retrieve_ip_address_lease +#define nx_dhcpv6_reserve_ip_address_range _nxe_dhcpv6_reserve_ip_address_range +#define nx_dhcpv6_server_create _nxe_dhcpv6_server_create +#define nx_dhcpv6_server_delete _nxe_dhcpv6_server_delete +#define nx_dhcpv6_server_resume _nxe_dhcpv6_server_resume +#define nx_dhcpv6_server_suspend _nxe_dhcpv6_server_suspend +#define nx_dhcpv6_server_start _nxe_dhcpv6_server_start +#define nx_dhcpv6_server_interface_set _nxe_dhcpv6_server_interface_set +#define nx_dhcpv6_server_option_request_handler_set _nxe_dhcpv6_server_option_request_handler_set +#endif /* NX_DISABLE_ERROR_CHECKING */ + + +/* Define the prototypes accessible to the application software. */ +UINT nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); +UINT nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); +UINT nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); +UINT nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetimeo); +UINT nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, + ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, + ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); +UINT nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, + ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, + ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); +UINT nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); +UINT nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); +UINT nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, + VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), + VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); +UINT nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); +UINT nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, + UCHAR *buffer_ptr, UINT *index, UINT available_payload)); + +#else + +/* DHCP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); +UINT _nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); +UINT _nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); +UINT _nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); +UINT _nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); +UINT _nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); +UINT _nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); +UINT _nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); +UINT _nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime); +UINT _nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime); +UINT _nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, + ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, + ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); +UINT _nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, + ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, + ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); +UINT _nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, + ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, + ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); +UINT _nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, + ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, + ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); +UINT _nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); +UINT _nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); +UINT _nxe_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, + VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), + VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); +UINT _nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, + VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), + VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); +UINT _nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nxe_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); +UINT _nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); +UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); +UINT _nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, + UCHAR *buffer_ptr, UINT *index, UINT available_payload)); +UINT _nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, + VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, + UCHAR *buffer_ptr, UINT *index, UINT available_payload)); + + +#endif /* NX_DHCPV6_SOURCE_CODE */ + + +UINT _nx_dhcpv6_add_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid_ptr, UCHAR *buffer_ptr, UINT *index, UINT duid_type); +UINT _nx_dhcpv6_add_ia(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IA_ADDRESS *dhcpv6_ia_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IANA_STATUS *iana_status_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_add_preference(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); +UINT _nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr); +UINT _nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID *dhcpv6_duid1_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid2_ptr, UINT *matching); +UINT _nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); +UINT _nx_dhcpv6_create_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw); +UINT _nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *duid_ptr, UINT *record_index, UINT add_on, ULONG message_xid, UINT *matching); +UINT _nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr); +UINT _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, + UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address); +UINT _nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER *dhcpv6_ptr); +UINT _nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS *dhcpv6_status_ptr, UINT flag); +UINT _nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID *duid_ptr, UINT duid_type, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length, UINT process_ia); +UINT _nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT *client_ptr, UCHAR *received_buffer, UINT length); +UINT _nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); +VOID _nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value); +VOID _nx_dhcpv6_server_thread_entry(ULONG ip_instance); +VOID _nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr); +VOID _nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value); +UINT _nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *from_client_ptr, NX_DHCPV6_CLIENT *to_client_ptr); +UINT _nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); +UINT _nx_dhcpv6_server_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length); +UINT _nx_dhcpv6_server_utility_get_data(UCHAR *data, UINT size, ULONG *value); +INT _nx_dhcpv6_server_utility_time_randomize(void); + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_DHCPV6_SERVER_H */ + + diff --git a/addons/dns/nxd_dns.c b/addons/dns/nxd_dns.c new file mode 100644 index 00000000..d5866bd2 --- /dev/null +++ b/addons/dns/nxd_dns.c @@ -0,0 +1,9907 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Domain Name System (DNS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_DNS_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_dns.h" +#include "stdio.h" +#include "string.h" +#include "nx_system.h" + +/* Define the resource record section. */ +#define NX_DNS_RR_ANSWER_SECTION 1 +#define NX_DNS_RR_AUTHORITY_SECTION 2 +#define NX_DNS_RR_ADDITIONAL_SECTION 3 + +/* Internal DNS functions. */ +static UINT _nx_dns_header_create(UCHAR *buffer_ptr, USHORT id, USHORT flags); +static UINT _nx_dns_new_packet_create(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, USHORT id, UCHAR *name, USHORT type); +static UINT _nx_dns_name_size_calculate(UCHAR *name); +static UINT _nx_dns_name_string_encode(UCHAR *ptr, UCHAR *name); +static UINT _nx_dns_name_string_unencode(NX_PACKET *packet_ptr, UCHAR *data, UCHAR *buffer, UINT buffer_size); +static USHORT _nx_dns_network_to_short_convert(UCHAR *ptr); +static ULONG _nx_dns_network_to_long_convert(UCHAR *ptr); +static UINT _nx_dns_question_add(NX_PACKET *packet_ptr, UCHAR *name, USHORT type); +static UCHAR * _nx_dns_resource_data_address_get(UCHAR *resource); +static UINT _nx_dns_resource_data_length_get(UCHAR *resource); +static UINT _nx_dns_resource_type_get(UCHAR *resource); +static UINT _nx_dns_resource_size_get(UCHAR *resource); +static VOID _nx_dns_short_to_network_convert(UCHAR *ptr, USHORT value); +#ifndef NX_DISABLE_IPV4 +static UINT _nx_dns_number_to_ascii_convert(UINT number, CHAR *buffstring); +#endif /* NX_DISABLE_IPV4 */ +static UINT _nx_dns_host_resource_data_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, + UINT *record_count, UINT lookup_type, ULONG wait_option); +static UINT _nx_dns_response_process(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); +static UINT _nx_dns_process_a_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count, UINT rr_location); +static UINT _nx_dns_process_aaaa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count, UINT rr_location); + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +static UINT _nx_dns_resource_name_real_size_calculate(UCHAR *data, UINT start); +static UINT _nx_dns_process_cname_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); +static UINT _nx_dns_process_txt_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); +static UINT _nx_dns_process_ns_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); +static UINT _nx_dns_process_mx_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); +static UINT _nx_dns_process_srv_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); +static UINT _nx_dns_process_soa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); +#endif + +#ifdef NX_DNS_CACHE_ENABLE +static UINT _nx_dns_name_match(UCHAR *src, UCHAR *dst, UINT length); +static UINT _nx_dns_cache_add_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr, NX_DNS_RR **insert_ptr); +static UINT _nx_dns_cache_find_answer(NX_DNS *dns_ptr, VOID *cache_ptr, UCHAR *query_name, USHORT query_type, UCHAR *buffer, UINT buffer_size, UINT *record_count); +static UINT _nx_dns_cache_delete_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr); +static UINT _nx_dns_cache_delete_rr_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr); +static UINT _nx_dns_cache_add_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_size, VOID **insert_ptr); +static UINT _nx_dns_cache_delete_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_len); +static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource); +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef FEATURE_NX_IPV6 +static VOID _nxd_dns_build_an_ipv6_question_string(NXD_ADDRESS *ip_address, UCHAR *buffer, UINT len); +#endif +static UINT _nx_dns_server_add_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +static UINT _nx_dns_server_remove_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +static UINT _nx_dns_server_get_internal(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *server_address); +static UINT _nx_dns_host_by_address_get_internal(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, + UINT host_name_buffer_size, ULONG wait_option); +static UINT _nx_dns_send_query_by_address(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server, UCHAR *ip_question, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +static UINT _nx_dns_send_query_get_rdata_by_name(NX_DNS *dns_ptr, NXD_ADDRESS *server_address, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, UINT *record_count, UINT dns_record_type, ULONG wait_option); + +/* static VOID _nx_dns_long_to_network_convert(UCHAR *ptr, ULONG value); */ +/* static UINT _nx_dns_resource_class_get(UCHAR *resource); */ +/* static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource); */ +/* static UINT _nx_dns_resource_name_get(UCHAR *buffer, UINT start, UCHAR *destination, UINT size); */ + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +UCHAR lookup_end[] = "IN-ADDR.ARPA"; + +#ifdef NX_DNS_CACHE_ENABLE +static NX_DNS_RR temp_rr; +#endif /* NX_DNS_CACHE_ENABLE */ + +#if defined(NX_DNS_ENABLE_EXTENDED_RR_TYPES) || defined(NX_DNS_CACHE_ENABLE) +static UCHAR temp_string_buffer[NX_DNS_NAME_MAX + 1]; +#endif + +/* Record the temp host name,*/ +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +#define TEMP_SRV_BUFFER_SIZE (NX_DNS_NAME_MAX + 1 + sizeof (NX_DNS_SRV_ENTRY)) +#endif + +NX_DNS *_nx_dns_instance_ptr; + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS create function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* ip_ptr Pointer to IP instance */ +/* domain_name DNS name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_create Actual DNS create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id == NX_DNS_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS create service. */ + status = _nx_dns_create(dns_ptr, ip_ptr, domain_name); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a DNS instance for the specified IP. This */ +/* involves creating a UDP DNS socket, and a mutex for mutual exclusion*/ +/* of DNS requests, and binding the DNS socket to the appropriate port.*/ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* ip_ptr Pointer to IP instance */ +/* domain_name DNS name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_create Create DNS UDP socket */ +/* nx_udp_socket_delete Delete DNS UDP socket */ +/* nx_udp_socket_bind Bind DNS UDP socket to port */ +/* nx_udp_socket_unbind Unbind DNS UDP socket */ +/* tx_mutex_create Create a ThreadX mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name) +{ + +UINT status; + + /* If the host does intend to supply their own packet pool, create one here. */ +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Create the DNS packet pool. */ + status = nx_packet_pool_create(&(dns_ptr -> nx_dns_pool), "DNS Pool", NX_DNS_PACKET_PAYLOAD, + dns_ptr -> nx_dns_pool_area, NX_DNS_PACKET_POOL_SIZE); + + /* Check status of packet pool create. */ + if (status != NX_SUCCESS) + { + + /* Return an error. */ + return(NX_DNS_ERROR); + } + + /* Set an internal packet pool pointer to the newly created packet pool. */ + dns_ptr -> nx_dns_packet_pool_ptr = &dns_ptr -> nx_dns_pool; + +#endif + + /* Create the DNS UDP socket. */ + status = nx_udp_socket_create(ip_ptr, &(dns_ptr -> nx_dns_socket), "DNS Socket", + NX_DNS_TYPE_OF_SERVICE, NX_DNS_FRAGMENT_OPTION, NX_DNS_TIME_TO_LIVE, NX_DNS_QUEUE_DEPTH); + + /* Check status of socket create. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Delete the packet pool. */ + nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); +#endif + + /* Return the NetX error. */ + return(status); + } + + /* Bind the UDP socket to the DNS Client port. */ + status = nx_udp_socket_bind(&(dns_ptr -> nx_dns_socket), NX_ANY_PORT, TX_WAIT_FOREVER); + + /* Check status of socket bind. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Delete the packet pool. */ + nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); +#endif + + /* Delete the socket. */ + nx_udp_socket_delete(&(dns_ptr -> nx_dns_socket)); + + /* Return the NetX error. */ + return(status); + } + + /* Create a DNS mutex for multi-thread access protection. */ + status = tx_mutex_create(&dns_ptr -> nx_dns_mutex, "DNS Mutex", TX_NO_INHERIT); + + /* Check status of mutex create. */ + if (status != TX_SUCCESS) + { + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Delete the packet pool. */ + nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); +#endif + + /* Unbind the socket. */ + nx_udp_socket_unbind(&(dns_ptr -> nx_dns_socket)); + + /* Delete the socket. */ + nx_udp_socket_delete(&(dns_ptr -> nx_dns_socket)); + + /* Return the threadx error. */ + return(status); + } + + /* Save the IP structure pointer. */ + dns_ptr -> nx_dns_ip_ptr = ip_ptr; + dns_ptr -> nx_dns_domain = domain_name; + + /* Initialize the rest of the DNS structure. */ + dns_ptr -> nx_dns_id = NX_DNS_ID; + + /* Clear memory except for client DNS server array. */ + memset(&dns_ptr -> nx_dns_server_ip_array[0], 0, NX_DNS_MAX_SERVERS * sizeof(NXD_ADDRESS)); + + /* Setup the maximum retry. */ + dns_ptr -> nx_dns_retries = NX_DNS_MAX_RETRIES; + + /* Is the client's network gateway also the primary DNS server? */ +#if defined(NX_DNS_IP_GATEWAY_AND_DNS_SERVER) && !defined(NX_DISABLE_IPV4) + + /* Verify we have a non zero gateway IP address. */ + if(ip_ptr -> nx_ip_gateway_address != 0) + { + + /* Yes; Assign the IP's gateway address to the first entry in the Client DNS server list. */ + dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version = NX_IP_VERSION_V4; + dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_address.v4 = ip_ptr -> nx_ip_gateway_address; + } + +#endif /* defined(NX_DNS_IP_GATEWAY_AND_DNS_SERVER) && !defined(NX_DISABLE_IPV4) */ + + _nx_dns_instance_ptr = dns_ptr; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the set the DNS Client */ +/* packet pool service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_NOT_ENABLED DNS client not enabled for */ +/* user create packet pool */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_packet_pool_set Actual set packet pool service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr) +{ + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + + /* Client not configured for the user creating the packet pool. Return an error status. */ + return NX_NOT_ENABLED; +#else + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dns_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + status = _nx_dns_packet_pool_set(dns_ptr, packet_pool_ptr); + + return status; +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DNS Client packet pool by passing in a */ +/* packet pool pointer to packet pool already create. The */ +/* NX_DNS_CLIENT_USER_CREATE_PACKET_POOL must be set. For guidelines on*/ +/* packet payload and packet pool size, see the */ +/* nx_packet_pool_create call in nx_dns_create. */ +/* */ +/* Note that the DNS Client nx_dns_delete service will delete this */ +/* packet pool when the DNS Client is deleted. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NOT_ENABLED Setting DNS Client packet */ +/* pool not enabled */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr) +{ + + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + + /* No, return the error status. */ + return NX_NOT_ENABLED; +#else + /* Check the payload size. */ + if (packet_pool_ptr -> nx_packet_pool_payload_size < NX_DNS_PACKET_PAYLOAD) + return(NX_DNS_PARAM_ERROR); + + /* Set the Client packet pool to the supplied packet pool. */ + dns_ptr -> nx_dns_packet_pool_ptr = packet_pool_ptr; + + return NX_SUCCESS; +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS delete function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_delete Actual DNS delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_delete(NX_DNS *dns_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS delete service. */ + status = _nx_dns_delete(dns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created DNS instance for the */ +/* specified IP. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_delete Delete DNS UDP socket */ +/* nx_udp_socket_unbind Unbind DNS UDP socket */ +/* tx_mutex_delete Delete DNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_delete(NX_DNS *dns_ptr) +{ + +UINT status; + + + /* Unbind the UDP socket. */ + status = nx_udp_socket_unbind(&dns_ptr -> nx_dns_socket); + + if (status != NX_SUCCESS) + { + /* Return the socket unbind error. */ + return status; + } + /* Delete the DNS UDP socket. */ + status = nx_udp_socket_delete(&dns_ptr -> nx_dns_socket); + + if (status != NX_SUCCESS) + { + /* Return the socket delete error. */ + return status; + } + +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Delete the DNS packet pool. */ + status = nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); + + if (status != NX_SUCCESS) + { + /* Return the packet pool delete error. */ + return status; + } +#endif + + /* Delete the DNS mutex. */ + status = tx_mutex_delete(&dns_ptr -> nx_dns_mutex); + + if (status != NX_SUCCESS) + { + /* Return the mutex delete error. */ + return status; + } + + /* Cleanup entries in the DNS structure. */ + dns_ptr -> nx_dns_id = 0; + dns_ptr -> nx_dns_ip_ptr = NX_NULL; + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_server_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS add server function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_add Actual DNS add server function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_server_add(NX_DNS *dns_ptr, ULONG server_address) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + { + + return(NX_PTR_ERROR); + } + + /* Check for invalid server IP address. */ + if (server_address == 0) + { + + return(NX_DNS_BAD_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS server add service. */ + status = _nx_dns_server_add(dns_ptr, server_address); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls the actual service to add DNS server address. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_add_internal Actual add DNS server service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address) +{ + +#ifndef NX_DISABLE_IPV4 +NXD_ADDRESS dns_server_address; + + + memset(&dns_server_address, 0, sizeof(NXD_ADDRESS)); + + /* Construct an IP address structure, and fill in IPv4 address information. */ + dns_server_address.nxd_ip_version = NX_IP_VERSION_V4; + dns_server_address.nxd_ip_address.v4 = server_address; + + /* Invoke the real function. */ + return (_nx_dns_server_add_internal(dns_ptr, &dns_server_address)); +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_server_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS add server function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_dns_server_add Actual DNS add server function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((dns_ptr == NX_NULL)|| (server_address == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input or invalid server attributes. */ + if ((dns_ptr -> nx_dns_id != NX_DNS_ID) || (server_address -> nxd_ip_version == NX_NULL)) + { + + return NX_DNS_PARAM_ERROR; + } + + /* Check for an invalid address type. */ + if ((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && + (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) + { + + return NX_DNS_INVALID_ADDRESS_TYPE; + } + + /* Check if the server address is unspecified (::). */ + if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + + /* Check for invalid or null address input*/ +#ifdef FEATURE_NX_IPV6 + if(CHECK_UNSPECIFIED_ADDRESS(&server_address -> nxd_ip_address.v6[0])) + { + + /* Null address input. */ + return NX_DNS_BAD_ADDRESS_ERROR; + } +#else + + /* Unsupported address type. */ + return NX_DNS_INVALID_ADDRESS_TYPE; +#endif + + } + else if (server_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* Check for null address. */ + if(server_address -> nxd_ip_address.v4 == 0) + { + + return NX_DNS_BAD_ADDRESS_ERROR; + } +#else + + /* Unsupported address type. */ + return NX_DNS_INVALID_ADDRESS_TYPE; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS add server service. */ + status = _nxd_dns_server_add(dns_ptr, server_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_server_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the specified DNS server to this DNS (client) */ +/* instance's list of DNS server. DNS servers can be IPv4 or IPv6 */ +/* servers. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* dns_server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_add_internal Actual add DNS server service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address) +{ + + + /* Invoke the real function. */ + return (_nx_dns_server_add_internal(dns_ptr, dns_server_address)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_add_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the specified DNS server to this DNS (client) */ +/* instance's list of DNS server. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* dns_server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_server_add_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) +{ + +UINT status; +UINT i; + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Determine if there was an error getting the mutex. */ + if (status != TX_SUCCESS) + { + + /* Return the completion status error. */ + return(status); + } + + /* Check for a duplicate entry. */ + i = 0; + + /* Check all entries for a either a matching entry or an empty slot is found. */ + while (i < NX_DNS_MAX_SERVERS) + { + + /* The dns server IP is IPv4 address. */ + if (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* Is there a match? */ + if ((server_address -> nxd_ip_version == NX_IP_VERSION_V4) && + (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v4 == server_address -> nxd_ip_address.v4)) + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Yes, no need to add to the table, just return the 'error' status. */ + return NX_DNS_DUPLICATE_ENTRY; + } +#else + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_PARAM_ERROR; +#endif /* NX_DISABLE_IPV4 */ + } + + /* The dns server IP is IPv6 address. */ + else if (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifdef FEATURE_NX_IPV6 + /* Is there a match? */ + if ((server_address -> nxd_ip_version == NX_IP_VERSION_V6) && + CHECK_IPV6_ADDRESSES_SAME(&dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v6[0], + &(server_address -> nxd_ip_address.v6[0]))) + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Yes, no need to add to the table, just return the 'error' status. */ + return NX_DNS_DUPLICATE_ENTRY; + } +#else + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_PARAM_ERROR; +#endif + } + + else + { + /* Yes, find one empty slot in the DNS server array. */ + break; + } + + i++; + } + + if(i == NX_DNS_MAX_SERVERS) + { + + /* Can not find one empty slot. Release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return(NX_NO_MORE_ENTRIES); + } + + /* Add the new entry here. */ + if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifdef FEATURE_NX_IPV6 + COPY_NXD_ADDRESS(server_address, &dns_ptr -> nx_dns_server_ip_array[i]); +#else + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_IPV6_NOT_SUPPORTED; +#endif + } + else + { + +#ifndef NX_DISABLE_IPV4 + dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v4 = server_address -> nxd_ip_address.v4; + dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version = NX_IP_VERSION_V4; +#else + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_INVALID_ADDRESS_TYPE; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Success, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_server_remove PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS remove server function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_remove Actual DNS remove server */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server IP address. */ + if (server_address == 0) + { + return(NX_DNS_BAD_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS remove server service. */ + status = _nx_dns_server_remove(dns_ptr, server_address); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_remove PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls actual service to remove specified DNS Server. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_remove_internal Actual DNS server remove */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address) +{ + +#ifndef NX_DISABLE_IPV4 +NXD_ADDRESS dns_server_address; + + /* Construct an IP address structure, and fill in IPv4 address information. */ + dns_server_address.nxd_ip_version = NX_IP_VERSION_V4; + dns_server_address.nxd_ip_address.v4 = server_address; + + /* Invoke the real function. */ + return (_nx_dns_server_remove_internal(dns_ptr, &dns_server_address)); +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_server_remove PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS remove server function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* server_address DNS Server NXD_ADDRESS instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_remove Actual DNS remove server */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (server_address == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid address type. */ + if ((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && + (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) + { + + return NX_DNS_INVALID_ADDRESS_TYPE; + } + + /* Check if the server address is unspecified (::). */ + if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + + /* Check for invalid or null address input*/ +#ifdef FEATURE_NX_IPV6 + if(CHECK_UNSPECIFIED_ADDRESS(&server_address -> nxd_ip_address.v6[0])) + { + + /* Null address input. */ + return NX_DNS_BAD_ADDRESS_ERROR; + } +#else + + /* Unsupported address type. */ + return NX_DNS_INVALID_ADDRESS_TYPE; +#endif + + } + else if (server_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* Check for null address. */ + if(server_address -> nxd_ip_address.v4 == 0) + { + + return NX_DNS_BAD_ADDRESS_ERROR; + } +#else + + /* Unsupported address type. */ + return NX_DNS_INVALID_ADDRESS_TYPE; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS remove server service. */ + status = _nxd_dns_server_remove(dns_ptr, server_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_server_remove PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the specified DNS server to this DNS */ +/* instance. If the server is not found among the client list of DNS */ +/* servers, the function returns an error. When a server is removed, */ +/* the servers above the removed server's index are moved down one to */ +/* fill the empty slot. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* server_address DNS Server NXD_ADDRESS isntance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) +{ + + + /* Invoke the real function. */ + return (_nx_dns_server_remove_internal(dns_ptr, server_address)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_remove_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the specified DNS server to this DNS */ +/* instance. If the server is not found among the client list of DNS */ +/* servers, the function returns an error. When a server is removed, */ +/* the servers above the removed server's index are moved down one to */ +/* fill the empty slot. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* server_address DNS Server address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_server_remove_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) +{ + +NXD_ADDRESS *DNSserver_array; +UINT status; +UINT i; +UINT found_match; + + /* Initialize local variables. */ + found_match = NX_FALSE; + i = 0; + + /* Calculate the start of the DNS server array. */ + DNSserver_array = dns_ptr -> nx_dns_server_ip_array; + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Determine if there was an error getting the mutex. */ + if (status != TX_SUCCESS) + { + + /* Return an error. */ + return(status); + } + + /* Search through the array to see if we can find the server address. */ + do + { + + /* Is there an IPv6 address in this slot? */ + if (DNSserver_array[i].nxd_ip_version == NX_IP_VERSION_V6) +#ifndef FEATURE_NX_IPV6 + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_IPV6_NOT_SUPPORTED; + } +#else + { + /* Check for a null address. */ + if (!CHECK_UNSPECIFIED_ADDRESS(&DNSserver_array[i].nxd_ip_address.v6[0])) + { + + /* No null; Determine if this entry matches the specified DNS server. */ + if (CHECK_IPV6_ADDRESSES_SAME(&DNSserver_array[i].nxd_ip_address.v6[0], &(server_address -> nxd_ip_address.v6[0]))) + { + + found_match = NX_TRUE; + break; + } + } + /* Check for a null address. */ + else + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + return NX_DNS_BAD_ADDRESS_ERROR; + } + } +#endif + else if (DNSserver_array[i].nxd_ip_version == NX_IP_VERSION_V4) +#ifndef NX_DISABLE_IPV4 + { + + /* Check for a null address. */ + if (DNSserver_array[i].nxd_ip_address.v4 != IP_ADDRESS(0, 0, 0, 0)) + { + + /* Determine if this entry matches the specified DNS server. */ + if (DNSserver_array[i].nxd_ip_address.v4 == server_address -> nxd_ip_address.v4) + { + + found_match = NX_TRUE; + break; + } + } + else + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + return NX_DNS_INVALID_ADDRESS_TYPE; + } + } +#else + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_IPV6_NOT_SUPPORTED; + } +#endif /* NX_DISABLE_IPV4 */ + + /* Check the next slot. */ + i++; + + } while (i < NX_DNS_MAX_SERVERS); + + if (!found_match) + { + + /* Release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Return the error. */ + return(NX_DNS_SERVER_NOT_FOUND); + } + + /* We found the DNS server entry. Remove it from the table. */ + while (i < NX_DNS_MAX_SERVERS - 1) + { + + /* Move them up one slot. */ + +#ifdef FEATURE_NX_IPV6 + /* This will handle IPv6 and IPv4 addresses if IPv6 enabled in NetX Duo. */ + COPY_NXD_ADDRESS(&DNSserver_array[i+1], &DNSserver_array[i]); +#else + /* IPv6 is not enabled, so first verify this is not an IPv6 address. */ + if (DNSserver_array[i+1].nxd_ip_version == NX_IP_VERSION_V6) + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* This should not happen. return an error. */ + return NX_DNS_IPV6_NOT_SUPPORTED; + } + + /* This is an IPv4 address. Copy to the slot above directly. */ + DNSserver_array[i].nxd_ip_version = DNSserver_array[i+1].nxd_ip_version; + DNSserver_array[i].nxd_ip_address.v4 = DNSserver_array[i+1].nxd_ip_address.v4; +#endif + + i++; + } + + /* Terminate the last slot. */ + memset(&dns_ptr -> nx_dns_server_ip_array[NX_DNS_MAX_SERVERS - 1], 0, sizeof(NXD_ADDRESS)); + + /* Release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_server_remove_all PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS remove all */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_remove_all Actual DNS remove all function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_server_remove_all(NX_DNS *dns_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS remove server service. */ + status = _nx_dns_server_remove_all(dns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_remove_all PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes all DNS servers. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_server_remove_all(NX_DNS *dns_ptr) +{ + +UINT status; + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Determine if there was an error getting the mutex. */ + if (status != TX_SUCCESS) + { + /* Return an error. */ + return(NX_DNS_ERROR); + } + + /* Remove all DNS servers. */ + memset(&dns_ptr -> nx_dns_server_ip_array[0], 0, NX_DNS_MAX_SERVERS * sizeof(NXD_ADDRESS)); + + /* Release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_get_serverlist_size PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the get DNS server list size */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* size Pointer to server size */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_get_serverlist_size Actual get DNS server list size*/ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *size) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || (size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get server size service. */ + status = _nx_dns_get_serverlist_size(dns_ptr, size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_get_serverlist_size PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the number of DNS servers in the Client list. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* size Pointer to server list size */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *size) +{ + + /* Initialize the list size to zero. */ + *size = 0; + + /* Loop through the list till we hit the first empty slot. */ + while (*size < NX_DNS_MAX_SERVERS) + { + + /* Is this a valid IP address entry in this slot? */ + if (dns_ptr -> nx_dns_server_ip_array[*size].nxd_ip_version == 0) + { + + /* This is an empty slot, so we're at the end of the list. */ + break; + } + + (*size)++; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the get DNS server service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* index Index into server list */ +/* dns_server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_get Actual get DNS server service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || (dns_server_address == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual get DNS server service. */ + status = _nx_dns_server_get(dns_ptr, index, dns_server_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls actual service to get the DNS Server address. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* index Index into server list */ +/* dns_server_address DNS Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_get Get DNS server service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_address; + + + /* Initialize to not found. */ + *dns_server_address = 0x0; + + /* Invoke the real function. */ + status = _nx_dns_server_get_internal(dns_ptr, index, &server_address); + + if (status != NX_SUCCESS) + { + return status; + } + + /* Verify this is an IPv4 address. */ + if (server_address.nxd_ip_version != NX_IP_VERSION_V4) + { + return NX_DNS_INVALID_ADDRESS_TYPE; + } + + /* Return the IPv4 address information. */ + *dns_server_address = server_address.nxd_ip_address.v4; + + return NX_SUCCESS; +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(index); + NX_PARAMETER_NOT_USED(dns_server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the get DNS server service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* index Index into server list */ +/* dns_server_address Pointer to Server address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_server_remove Actual DNS return server */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_server_address == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual get DNS server service. */ + status = _nxd_dns_server_get(dns_ptr, index, dns_server_address); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retreives the DNS server at the specified index into */ +/* the DNS server list. If the index exceeds the size of the list or */ +/* an empty slot is at that index, the function returns an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* index Index into server list */ +/* dns_server_address Pointer to Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address) +{ + + /* Invoke the real function. */ + return(_nx_dns_server_get_internal(dns_ptr, index, dns_server_address)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_server_get_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retreives the DNS server at the specified index into */ +/* the DNS server list. If the index exceeds the size of the list or */ +/* an empty slot is at that index, the function returns an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS client */ +/* index Index into server list */ +/* dns_server_address Pointer to Server IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_server_get_internal(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *server_address) +{ + +UINT status; + + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Determine if there was an error getting the mutex. */ + if (status != TX_SUCCESS) + { + + /* Return an error. */ + return(status); + } + + /* Check for an invalid index. The max list size is NX_DNS_MAX_SERVERS. */ + if (index >= NX_DNS_MAX_SERVERS) + { + + return NX_DNS_PARAM_ERROR; + } + + /* Is there a valid IP address entry in this slot? */ + if (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == 0) + { + + /* No, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_SERVER_NOT_FOUND; + } +#ifndef NX_DISABLE_IPV4 + /* Check for a null IPv4 address if this is an IPv4 type. */ + else if ((dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == NX_IP_VERSION_V4) && + (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_address.v4 == 0)) + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_BAD_ADDRESS_ERROR; + } +#endif /* NX_DISABLE_IPV4 */ + else if (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == NX_IP_VERSION_V6) +#ifndef FEATURE_NX_IPV6 + { + + /* IPv6 not enabled, return an error status. */ + + /* Release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_INVALID_ADDRESS_TYPE; + } +#else + { + + /* Check for unspecified (null) IPv6 address. */ + if (CHECK_UNSPECIFIED_ADDRESS(&(dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_address.v6[0]))) + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_BAD_ADDRESS_ERROR; + } + } +#endif + + /* Set a pointer to the DNS server in the list. */ + *server_address = (dns_ptr -> nx_dns_server_ip_array[index]); + + /* Release the mutex. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_host_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up host IP address */ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to DNS host IP address*/ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_by_name_get Actual DNS host IP address */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (host_name == NX_NULL) || (host_address_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host by name service. */ + status = _nx_dns_host_by_name_get(dns_ptr, host_name, host_address_ptr, wait_option); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_host_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls service to get the host address by name service */ +/* as an A record (IPv4) lookup query. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to DNS host IP address*/ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get host address */ +/* by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option) +{ + +UINT status; +UINT record_count = 0; + + /* Keep the API consistency. Invoke the real DNS query call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (VOID*)host_address_ptr, sizeof(ULONG), &record_count, NX_DNS_RR_TYPE_A, wait_option); + + /* Record_count set to 1 indicates the call is successful. */ + if(record_count == 1) + { + /* Set the return value. */ + status = NX_SUCCESS; + } + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_host_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS get host by name */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to destination of */ +/* host IP address */ +/* wait_option Timeout value */ +/* lookup_type Lookup for which IP version */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_dns_host_by_name_get Actual DNS get host by name */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, + ULONG wait_option, UINT lookup_type) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if ((dns_ptr == NX_NULL) || (host_name == NX_NULL) || (host_address_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if ((dns_ptr -> nx_dns_id != NX_DNS_ID) || (lookup_type == 0)) + { + return NX_DNS_PARAM_ERROR; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host by name service. */ + status = _nxd_dns_host_by_name_get(dns_ptr, host_name, host_address_ptr, wait_option, lookup_type); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_host_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS get host by name */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to host IP address */ +/* wait_option Timeout value */ +/* lookup_type Lookup for which IP version */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get host by name */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, + ULONG wait_option, UINT lookup_type) +{ + +UINT status; +UINT record_count = 0; + + + /* Is this a AAAA record lookup (e.g. expect an IPv6 address)? If no type is specified default to AAAA type. */ + if((lookup_type == NX_IP_VERSION_V6) || (lookup_type == 0)) + { + +#ifdef FEATURE_NX_IPV6 + /* Send AAAA type message, and keep the API consistency. Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (UCHAR *)&host_address_ptr -> nxd_ip_address.v6[0], 16, &record_count, NX_DNS_RR_TYPE_AAAA, wait_option); + + /* Record_count being set indicates the query gets a valid answer. */ + if (record_count) + { + + /* Have recorded the IPv6 address, set the IP version. */ + host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V6; + + /* Modify the return status.*/ + status = NX_SUCCESS; + } +#else + return NX_DNS_IPV6_NOT_SUPPORTED; +#endif + } + else if(lookup_type == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* Keep the API consistency. Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (UCHAR *)&host_address_ptr -> nxd_ip_address.v4, sizeof(ULONG), &record_count, NX_DNS_RR_TYPE_A, wait_option); + + /* Record_count being set indicates the query gets a valid answer. */ + if (record_count) + { + + /* Have recorded the IPv4 address, set the IP version. */ + host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V4; + + /* Modify the return status.*/ + status = NX_SUCCESS; + } +#else + return NX_DNS_BAD_ADDRESS_ERROR; +#endif + } + + else + { + return NX_DNS_BAD_ADDRESS_ERROR; + } + + /* Return status. */ + return(status); +} + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_info_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS get info by name */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to destination of */ +/* host IP address */ +/* host_port_ptr Pointer to destination of host*/ +/* source port */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_info_by_name_get Actual DNS get info by name */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT *host_port_ptr, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || + (host_name == NX_NULL) || (host_address_ptr == NX_NULL) || (host_port_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host by name service. */ + status = _nx_dns_info_by_name_get(dns_ptr, host_name, host_address_ptr, host_port_ptr, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_info_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the Service record associated with the*/ +/* specified host name. If a service rec cannot be found, this */ +/* routine returns a zero IP address in the input address pointer and a*/ +/* non zero error status return to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* host_address_ptr Pointer to destination of */ +/* host IP address */ +/* host_port_ptr Pointer to destination of */ +/* host port */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, + USHORT *host_port_ptr, ULONG wait_option) +{ + +NX_DNS_SRV_ENTRY *dns_srv_entry; +UINT record_count; +UINT status; +UCHAR temp_buffer[TEMP_SRV_BUFFER_SIZE]; + + /* Call the service get function to get information. */ + status = _nx_dns_domain_service_get(dns_ptr, host_name, (VOID *)temp_buffer, TEMP_SRV_BUFFER_SIZE, &record_count, wait_option); + + /* Check erros. */ + if(status) + { + return status; + } + + /* Set the srv pointer. */ + dns_srv_entry = (NX_DNS_SRV_ENTRY *)temp_buffer; + + /* record the info returned to user. */ + *host_address_ptr = dns_srv_entry -> nx_dns_srv_ipv4_address; + *host_port_ptr = dns_srv_entry -> nx_dns_srv_port_number; + + return NX_SUCCESS; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_ipv4_address_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up host IP address */ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name_ptr Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* IPv4 addresses */ +/* buffer_size Size of the record_buffer */ +/* record_count The count of IPv4 addresses */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_ipv4_address_by_name_get Actual DNS host IP address */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!dns_ptr) || (!host_name_ptr) || (!record_buffer) || (!record_count)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host ipv4 address by name service. */ + status = _nx_dns_ipv4_address_by_name_get(dns_ptr, host_name_ptr, record_buffer, buffer_size, record_count, wait_option); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_ipv4_address_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calls service to get the host address by name service */ +/* as an A record (IPv4) lookup query. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing */ +/* IPv4 addresses */ +/* buffer_size Size of the record_buffer */ +/* record_count The count of IPv4 addresses */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get host rdata */ +/* by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name_ptr, buffer, buffer_size, record_count, NX_DNS_RR_TYPE_A, wait_option); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_ipv6_address_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up host IPv6 address*/ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name_ptr Name of host to search on */ +/* record_buffer Buffer space for storing IPv6 */ +/* addresses. */ +/* buffer_size Size of record_buffer */ +/* record_count The count of IPv6 addresses */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_ipv6_address_by_name_get Actual DNS host IPv6 address */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!dns_ptr) || (!host_name_ptr) || (!record_buffer) || (!record_count)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host ipv6 address by name service. */ + status = _nxd_dns_ipv6_address_by_name_get(dns_ptr, host_name_ptr, record_buffer, buffer_size, record_count, wait_option); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_ipv6_address_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an NXD_ADDRESS instance from the specified */ +/* IPv6 address and submits it to the actual get host by name service */ +/* as an AAAA record (IPv6) lookup query. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing IPv6 */ +/* addresses. */ +/* buffer_size Size of record_buffer */ +/* record_count The count of IPv6 addresses */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual NetX Duo DNS get */ +/* host rdata by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name_ptr, buffer, buffer_size, record_count, NX_DNS_RR_TYPE_AAAA, wait_option); + + /* Return completion status. */ + return status; +} + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_cname_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up host cname */ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* cname response. */ +/* buffer_size Size of record_buffer */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_cname_get Actual DNS host cname */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_cname_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if (!dns_ptr || !host_name || !record_buffer) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host by name service. */ + status = _nx_dns_cname_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cname_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the host cname associated with */ +/* the specified host name. If host cname cannot be found, this */ +/* routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing */ +/* cname response. */ +/* buffer_size Size of record_buffer */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get host cname */ +/* by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_cname_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; +UINT record_count = 0; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, + &record_count, NX_DNS_RR_TYPE_CNAME, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_domain_name_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up the authoritative*/ +/* name servers in a given domain. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* the data structure that */ +/* holds name server information*/ +/* buffer_size Size of the record_buffer */ +/* record_count The number of records stored */ +/* in the record_buffer */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_domain_name_server_get Actual DNS host NS */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get the authoritative name server by name service. */ + status = _nx_dns_domain_name_server_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_domain_name_server_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the authoritative name server */ +/* associated with the specified host name. If host cname cannot */ +/* be found, this routine returns zero for the string size to */ +/* signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* the data structure that */ +/* holds name server information*/ +/* buffer_size Size of the record_buffer */ +/* record_count The number of records stored */ +/* in the record_buffer */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get the */ +/* authoritaive name server */ +/* by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, NX_DNS_RR_TYPE_NS, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_host_text_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up the text strings */ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* the host text string */ +/* buffer_size Size of record_buffer. */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* _nx_dns_host_text_get Actual DNS host text strings */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if (!dns_ptr || !host_name || !record_buffer) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get the text strings by name service. */ + status = _nx_dns_host_text_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_host_text_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the text strings associated with */ +/* the specified host name. If host cname cannot be found, */ +/* this routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing */ +/* the host text string */ +/* buffer_size Size of record_buffer. */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get the text */ +/* strings by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; +UINT record_count = 0; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, &record_count, NX_DNS_RR_TYPE_TXT, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_domain_mail_exchange_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up the mail */ +/* exchange by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for recording */ +/* data structure that holds */ +/* the mail exchange information*/ +/* buffer_size Size of record_buffer. */ +/* record_count The count of mail exchange */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_domain_mail_exchange_get */ +/* Actual DNS host MX lookup */ +/* by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get the mail exchange by name service. */ + status = _nx_dns_domain_mail_exchange_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_domain_mail_exchange_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the mail exchange associated with */ +/* the specified host name. If host cname cannot be found, */ +/* this routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for recording */ +/* data structure that holds */ +/* the mail exchange information*/ +/* buffer_size Size of record_buffer. */ +/* record_count The count of mail exchange */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_get */ +/* Actual DNS get the mail */ +/* exchange by name service */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, + record_count, NX_DNS_RR_TYPE_MX, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_domain_service_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up the service */ +/* by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing the */ +/* the data structures that */ +/* hold the service information */ +/* buffer_size size of record_buffer */ +/* record_count The count of services stored */ +/* in record_buffer */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_domain_service_get */ +/* Actual DNS host SRV */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get the service by name service. */ + status = _nx_dns_domain_service_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_domain_service_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the service associated with */ +/* the specified host name. If host cname cannot be found, */ +/* this routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing the */ +/* the data structures that */ +/* hold the service information */ +/* buffer_size size of record_buffer */ +/* record_count The count of services stored */ +/* in record_buffer */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Route that sends out the */ +/* query and process response. */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, + UINT buffer_size, UINT *record_count, ULONG wait_option) +{ + +UINT status; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, + record_count, NX_DNS_RR_TYPE_SRV, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_authority_zone_start_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS look up the start of */ +/* a zone of authority by name service. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to search on */ +/* record_buffer Buffer space for storing */ +/* the data structures that */ +/* hold the SOA information */ +/* buffer_size Size of record_buffer. */ +/* wait_option Time to wait on server response*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* _nx_dns_authority_zone_start_get Actual DNS host text strings */ +/* lookup by host name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_authority_zone_start_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if (!dns_ptr || !host_name || !record_buffer) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if(((ALIGN_TYPE)record_buffer & 0x3) != 0) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get the start of zone authority by name service. */ + status = _nx_dns_authority_zone_start_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); + + /* Return status. */ + return(status); +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_authority_zone_start_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the start of a zone of authority */ +/* associated with the specified host name. If it cannot be found, */ +/* this routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer space for storing */ +/* the data structures that */ +/* hold the SOA information */ +/* buffer_size Size of record_buffer. */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Actual DNS get the authority */ +/* zone by name service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_authority_zone_start_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, + UINT buffer_size, ULONG wait_option) +{ + +UINT status; +UINT record_count = 0; + + /* Invoke the real connection call. */ + status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, &record_count, NX_DNS_RR_TYPE_SOA, wait_option); + + /* Return completion status. */ + return status; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_host_resource_data_by_name_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to find the IP address associated with the */ +/* specified host name. If a DNS server responds but does not have */ +/* the IP address, this function skips to the next server in the */ +/* DNS client list. Otherwise it will resend the same query up to the */ +/* DNS client's max retry times before skipping to the next server. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_name Name of host to resolve */ +/* record_buffer Buffer for record ipv4 address*/ +/* buffer_size Buffer size for ipv4 adress */ +/* record_count The count of ipv4 address */ +/* wait_option Timeout value */ +/* lookup_type Lookup for which IP version */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_send_query_get_rdata_by_name */ +/* Creates and transmits a DNS */ +/* query on supplied host name */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_host_resource_data_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, + UCHAR *buffer, UINT buffer_size, + UINT *record_count, UINT lookup_type, ULONG wait_option) +{ + +UINT status; +UINT retries; +UINT i; + + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), wait_option); + + /* Check status. */ + if (status != TX_SUCCESS) + { + + /* The mutex was not granted in the time specified. Return the threadx error. */ + return(status); + } + + /* Clear the record name buffer and record count. This way + if the query fails, the API returns zero record. */ + memset(buffer, 0, buffer_size); + + /* Initialize the record count. */ + *record_count = 0; + +#ifdef NX_DNS_CACHE_ENABLE + + /* Find the answer in local cache. */ + if(_nx_dns_cache_find_answer(dns_ptr, dns_ptr -> nx_dns_cache, host_name, (USHORT)lookup_type, buffer, buffer_size, record_count) == NX_DNS_SUCCESS) + { + + /* Put the DNS mutex. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + return (NX_DNS_SUCCESS); + } +#endif /*NX_DNS_CACHE_ENABLE. */ + + /* Determine if there is at least one DNS server. Is there anything in the first slot? */ + if (dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version == 0) + { + + /* No, this means the list is empty. Release the DNS Client lock. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + /* At least one DNS server is required - return an error. */ + return(NX_DNS_NO_SERVER); + } + + /* Keep sending queries to all DNS Servers till the retry count expires. */ + for (retries = 0; retries < dns_ptr -> nx_dns_retries; retries++) + { + + /* The client should try other servers and server addresses before repeating a query to a specific address of a server. + RFC1035, Section4.2.1 UDP usage, Page32. */ + /* Attempt host name resolution from each DNS server till one if found. */ + for (i = 0; (i < NX_DNS_MAX_SERVERS) && (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version != 0); i ++) + { + + /* Send the DNS query. */ + status = _nx_dns_send_query_get_rdata_by_name(dns_ptr, &dns_ptr -> nx_dns_server_ip_array[i], host_name, + buffer, buffer_size, record_count, lookup_type, wait_option); + + /* Check the status. */ + if (status == NX_SUCCESS) + { + + /* Release the mutex */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + /* Yes, have done, just return success. */ + return NX_SUCCESS; + } + } + + /* Timed out for querying all DNS servers in this cycle, double the timeout, limited to NX_DNS_MAX_RETRANS_TIMEOUT. */ + if ((2 * wait_option) <= NX_DNS_MAX_RETRANS_TIMEOUT) + wait_option = wait_option * 2; + else + wait_option = NX_DNS_MAX_RETRANS_TIMEOUT; + } + + /* Release protection. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + /* Failed on all servers, return DNS lookup failed status. */ + return(NX_DNS_QUERY_FAILED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_send_query_by_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the name of a host from the specified */ +/* IP address associated. If the IP address cannot be found, this */ +/* routine returns a NULL host name . */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* dns_server Pointer to DNS server to use */ +/* ip_question Buffer pointer to IP address */ +/* in ascii to lookup */ +/* host_name_ptr Buffer pointer to host name */ +/* host_name_buffer_size Buffer size for host name */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* _nx_dns_network_to_long_convert Convert to unsigned long */ +/* _nx_dns_network_to_short_convert Convert to unsigned short */ +/* _nx_dns_new_packet_create Create new DNS packet */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_resource_data_length_get Get length of resource */ +/* _nx_dns_resource_type_get Get resource type */ +/* nx_packet_copy Copy packet */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_receive Receive DNS UDP packet */ +/* nxd_udp_socket_send Send DNS UDP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_send_query_by_address(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server, UCHAR *ip_question, UCHAR *host_name_ptr, + UINT host_name_buffer_size, ULONG wait_option) +{ + +UINT status; +USHORT answerCount; +UCHAR *data_ptr; +NX_PACKET *packet_ptr; +NX_PACKET *receive_packet_ptr; +USHORT id; +UINT ip_question_size; +UINT name_size; +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE +ULONG start_time; +ULONG current_time; +ULONG elapsed_time; +ULONG time_remaining; +#endif +#ifdef NX_DNS_CACHE_ENABLE +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + + + + /* Check for IP question. */ + if (_nx_utility_string_length_check((CHAR *)ip_question, &ip_question_size, NX_DNS_IP_LOOKUP_SIZE)) + { + return(NX_DNS_SIZE_ERROR); + } + + /* Create a random DNS query ID based on the first word of an IP address (or only + word for IPv4 addresses). */ + if (dns_server -> nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifdef FEATURE_NX_IPV6 + id = (USHORT)(dns_server -> nxd_ip_address.v6[0] ^ tx_time_get()); +#else + return NX_DNS_IPV6_NOT_SUPPORTED; +#endif + } + else + { +#ifndef NX_DISABLE_IPV4 + id = (USHORT)(dns_server -> nxd_ip_address.v4 ^ tx_time_get()); +#else + return NX_DNS_BAD_ADDRESS_ERROR; +#endif + } + + /* Allocate a packet. */ + status = nx_packet_allocate(dns_ptr -> nx_dns_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_DNS_PACKET_ALLOCATE_TIMEOUT); + + /* Check the allocate status. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Create a request */ + status = _nx_dns_new_packet_create(dns_ptr, packet_ptr, id, ip_question, NX_DNS_RR_TYPE_PTR); + + /* Check the DNS packet create status. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return(status); + } + + /* First clear off any 'old' DNS packets. */ + +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE + + /* We will use the time spent sleeping to clear broadcast DNS packets from a previous query + from the DNS receive queue. This will prevent ensure the most recent DNS response is + processed and avoid the situation of valid DNS response packets overflowing the DNS socket + queue. */ + + receive_packet_ptr = NX_NULL; + + + /* Remove all packets from the DNS Client receive queue. */ + status = NX_SUCCESS;; + do + { + + /* Is there any packets on the queue? */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, 1 ); + + /* Yes, we received a packet on the DNS port! */ + if (status == NX_SUCCESS) + { + + /* But we don't want it. Release it! */ + nx_packet_release(receive_packet_ptr); + } + + /* Keep checking till the queue becomes empty. */ + + } while(status == NX_SUCCESS); + +#endif + + /* Send the DNS packet out. */ + status = nxd_udp_socket_send(&dns_ptr -> nx_dns_socket, packet_ptr, dns_server, NX_DNS_PORT); + + + /* Check the completion of the send. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful, release the packet. */ + nx_packet_release(packet_ptr); + + return status; + } + +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE + + /* Initialize the value. */ + elapsed_time = 0; + time_remaining = wait_option; + + /* If waiting for the DNS 'sleep' interval, check for packets arriving on the queue. */ + while(time_remaining > 0) + { + + start_time = tx_time_get(); + + /* Check if some of these packet are intended for other hosts. */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, time_remaining); + + /* Determine if this one is for us. */ + if (status == NX_SUCCESS) + { + + /* Check the ID from the Client query matches the ID in the received DNS packet. */ + if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) == id) + { + /* They do. We can stop receiving packets and process this one. */ + break; + } + else + { + /* They do not. Discard the packet! */ + nx_packet_release(receive_packet_ptr); + } + } + + /* Get the current time. */ + current_time = tx_time_get(); + + /* Has the time wrapped? */ + if (current_time >= start_time) + { + /* No, simply subtract to get the elapsed time. */ + elapsed_time = current_time - start_time; + } + else + { + /* Yes it has. Time has rolled over the 32-bit boundary. */ + elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; + } + + /* Update the time remaining by subtracting the elapsed time. */ + if (time_remaining > elapsed_time) + { + time_remaining -= elapsed_time; + } + else + { + time_remaining = 0; + } + } + +#else + + /* Otherwise, wait for a DNS response UDP packet. */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, wait_option); +#endif + + /* Check status. */ + if (status == NX_SUCCESS) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + if (receive_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(receive_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We received a response. First, check that there is a valid header. */ + if (receive_packet_ptr -> nx_packet_length <= NX_DNS_QDSECT_OFFSET) + { + /* No; Release the new packet. */ + nx_packet_release(receive_packet_ptr); + + /* Return error status. */ + return NX_DNS_MALFORMED_PACKET; + } + + /* Packet is long enough. Check the IDs in the DNS header match. */ + if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) != id) + { + + /* No; Release the packet. */ + nx_packet_release(receive_packet_ptr); + + /* Return error status. */ + return NX_DNS_BAD_ID_ERROR; + } + + /* We have a response with matching ID, check that it is a response + and is successful and has a response record. */ + status = _nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_FLAGS_OFFSET); + + /* Check for indication of DNS server error (cannot authenticate answer or authority portion + of the DNS data. */ + if ((status & NX_DNS_ERROR_MASK) == NX_DNS_ERROR_MASK) + { + + /* No; Release the packet. */ + nx_packet_release(receive_packet_ptr); + + return NX_DNS_SERVER_AUTH_ERROR; + } + + answerCount = _nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ANCOUNT_OFFSET); + + /* Is it for our question? */ + if (((status & NX_DNS_QUERY_MASK) == NX_DNS_RESPONSE_FLAG) + && ((status & NX_DNS_RCODE_MASK) == NX_DNS_RCODE_SUCCESS) + && (answerCount >= 1)) + { + + /* Yes, set a point to the start of the question to find the response record. */ + data_ptr = receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDSECT_OFFSET; + + /* Determine if there is a question still in the server's response. */ + if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET) == 1) + { + + /* Yes, the question is present in the response, skip it! */ + data_ptr += _nx_dns_name_size_calculate(data_ptr) + 4; + } + + /* Check all the response records */ + while (answerCount-- > 0) + { + + /* Check for valid data_ptr. */ + if (data_ptr >= receive_packet_ptr -> nx_packet_append_ptr) + { + + /* Release the packet. */ + nx_packet_release(receive_packet_ptr); + + /* NULL-terminate the host name string. */ + *host_name_ptr = NX_NULL; + + /* Return an error! */ + return(NX_DNS_SIZE_ERROR); + } + + /* Check that the answer has a name and there is space for it. */ + if (_nx_dns_resource_type_get(data_ptr) == NX_DNS_RR_TYPE_PTR) + { + +#ifdef NX_DNS_CACHE_ENABLE + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Update the pointer to point at the response data and get the name. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Determine if there is room for the name - one less for NULL termination. */ + name_size = _nx_dns_name_string_unencode(receive_packet_ptr, data_ptr, host_name_ptr, host_name_buffer_size - 1); + if (name_size) + { + + /* Yes; We're done! */ + + /* Need to release the packet. */ + nx_packet_release(receive_packet_ptr); + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_PTR; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, ip_question, ip_question_size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the PTR string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, host_name_ptr, name_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Return success! */ + return(NX_SUCCESS); + } + else + { + + /* Nope, Our destination string is too small. Release the packet. */ + nx_packet_release(receive_packet_ptr); + + /* NULL-terminate the host name string. */ + *host_name_ptr = NX_NULL; + + /* Return an error! */ + return(NX_DNS_SIZE_ERROR); + } + } + else + { + /* This response isn't a name, just skip it. */ + data_ptr += _nx_dns_resource_size_get(data_ptr); + } + + } /* and check the next answer record */ + } + + /* We got a packet, but did it supply name resolution? */ + if (answerCount == 0) + { + + /* No, set the failed query status. */ + status = NX_DNS_QUERY_FAILED; + } + + /* Release the packet. */ + nx_packet_release(receive_packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_send_query_get_rdata_by_name PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates and sends a new DNS query on the specific */ +/* information. On receiving a response, this function also invokes */ +/* a process function to parse the resposne. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* server_address The DNS server address */ +/* record_buffer Buffer for resource data */ +/* buffer_size Buffer size for resource data */ +/* record_count The count of resource data */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a new packet */ +/* _nx_dns_new_packet_create Create new DNS packet */ +/* nx_packet_release Release packet */ +/* nxd_udp_socket_send Send DNS UDP packet */ +/* nx_udp_socket_receive Receive DNS UDP packet */ +/* _nx_dns_response_process Process the DNS respondse */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_resource_data_by_name_get */ +/* Get the resource data by name */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_send_query_get_rdata_by_name(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address, + UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, + UINT *record_count, UINT dns_record_type, ULONG wait_option) +{ + +UINT status; +NX_PACKET *packet_ptr; +NX_PACKET *receive_packet_ptr; +USHORT id; +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE +ULONG start_time; +ULONG current_time; +ULONG elapsed_time; +ULONG time_remaining; +#endif + + /* Generate a random ID based on host name. */ + id = (USHORT)((ALIGN_TYPE) host_name ^ tx_time_get()); + + /* Allocate a packet. */ + status = nx_packet_allocate(dns_ptr -> nx_dns_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_DNS_PACKET_ALLOCATE_TIMEOUT); + + /* Check the allocate status. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Create a request */ + status = _nx_dns_new_packet_create(dns_ptr, packet_ptr, id, host_name, (USHORT)dns_record_type); + + /* Check the DNS packet create status. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return error status. */ + return(status); + } + + /* First clear off any 'old' DNS packets. */ +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE + + /* Initialize the value */ + receive_packet_ptr = NX_NULL; + + /* Remove all packets from the DNS Client receive queue. */ + status = NX_SUCCESS;; + do + { + + start_time = tx_time_get(); + + /* Is there any packets on the queue? */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, 1 ); + + /* Yes, we received a packet on the DNS port! */ + if (status == NX_SUCCESS) + { + + /* But we don't want it. Release it! */ + nx_packet_release(receive_packet_ptr); + } + + /* Keep checking till the queue becomes empty. */ + + } while(status == NX_SUCCESS); +#endif + + /* Send the DNS packet out. */ + status = nxd_udp_socket_send(&dns_ptr -> nx_dns_socket, packet_ptr, dns_server_address, NX_DNS_PORT); + + /* Check the completion of the send. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful, release the packet. */ + nx_packet_release(packet_ptr); + + return status; + } + +#ifdef NX_DNS_CLIENT_CLEAR_QUEUE + + /* Initialize the value. */ + elapsed_time = 0; + time_remaining = wait_option; + + /* If waiting for the DNS 'sleep' interval, check for packets arriving on the queue. */ + while(time_remaining > 0) + { + + start_time = tx_time_get(); + + /* Check if some of these packet are intended for other hosts. */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, time_remaining); + + /* Determine if this one is for us. */ + if (status == NX_SUCCESS) + { + + /* Check the IDs in the DNS header match. */ + if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) == id) + { + + /* They do. We can stop receiving packets and process this one. */ + break; + } + else + { + + /* They do not. Discard the packet! */ + nx_packet_release(receive_packet_ptr); + } + } + + /* Get the current time. */ + current_time = tx_time_get(); + + /* Has the time wrapped? */ + if (current_time >= start_time) + { + /* No, simply subtract to get the elapsed time. */ + elapsed_time = current_time - start_time; + } + else + { + + /* Yes it has. Time has rolled over the 32-bit boundary. */ + elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; + } + + /* Update the time remaining with the elapsed time. */ + if (time_remaining > elapsed_time) + { + time_remaining -= elapsed_time; + } + else + time_remaining = 0; + + } + +#else + + /* Otherwise, wait for a DNS response UDP packet. */ + status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, wait_option); +#endif + + /* Check status. */ + if (status == NX_SUCCESS) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + if (receive_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(receive_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Call the function to process the DNS packet. */ + status = _nx_dns_response_process(dns_ptr, receive_packet_ptr, record_buffer, buffer_size, record_count); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_response_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a DNS respond packet. If the reply packet */ +/* includes multiple answers. this service records as many answers */ +/* into the record_buffer. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* record_buffer Buffer for resource data */ +/* buffer_size Buffer size for resource data */ +/* record_count The count of resource data */ +/* lookup_type The DNS query type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* _nx_dns_network_to_short_convert Convert to unsigned short */ +/* _nx_dns_resource_type_get Get the value of the resource */ +/* type. */ +/* _nx_dns_process_cname_type Process the CNAME type record */ +/* _nx_dns_process_txt_type Process the TXT type record */ +/* _nx_dns_process_ns_type Process the NS type record */ +/* _nx_dns_process_mx_type Process the MX type record */ +/* _nx_dns_process_srv_type Process the SRV type record */ +/* _nx_dns_process_a_type Process the A type record */ +/* _nx_dns_process_aaaa_type Process the AAAA type record */ +/* _nx_dns_process_soa_type Process the SOA type record */ +/* nx_packet_release Release the packet. */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_response_process(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *record_buffer, + UINT buffer_size, UINT *record_count) +{ + +UINT status; +USHORT answerCount; +USHORT answerRRCount; +USHORT authorityRRCount; +USHORT additionalRRCount; +UCHAR *data_ptr; +UINT response_type; +UCHAR *buffer_prepend_ptr; +UCHAR *buffer_append_ptr; +UINT rrIndex; +UINT rr_location; +UINT answer_found = NX_FALSE; + + /* Set the buffer pointer. */ + buffer_prepend_ptr = record_buffer; + buffer_append_ptr = record_buffer + buffer_size; + + /* We received a response. Is there a valid header? */ + if (packet_ptr -> nx_packet_length <= NX_DNS_QDSECT_OFFSET) + { + + /* No; Release the new packet. */ + nx_packet_release(packet_ptr); + + /* Return error status. */ + return NX_DNS_MALFORMED_PACKET; + } + + /* Does the incoming DNS header ID match the query ID we sent out? */ + if (_nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) != dns_ptr -> nx_dns_transmit_id) + { + + /* No; Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error status. */ + return NX_DNS_BAD_ID_ERROR; + } + + /* Check that the packet has a valid response record. */ + status = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_FLAGS_OFFSET); + + /* Check for indication of DNS server error (cannot authenticate answer or authority portion + of the DNS data. */ + if ((status & NX_DNS_ERROR_MASK) == NX_DNS_ERROR_MASK) + { + + /* Release the source packet. */ + nx_packet_release(packet_ptr); + + return NX_DNS_SERVER_AUTH_ERROR; + } + + /* Determine if we have any 'answers' to our DNS query. */ + answerRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ANCOUNT_OFFSET); + answerCount = answerRRCount; + + /* Also check if there are any 'hints' from the Authoritative nameserver. */ + authorityRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_NSCOUNT_OFFSET); + answerCount = (USHORT)(answerCount + authorityRRCount); + + /* Include Additional section as well */ + additionalRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ARCOUNT_OFFSET); + answerCount = (USHORT)(answerCount + additionalRRCount); + + /* Are there answers in this resposne? */ + if (((status & NX_DNS_QUERY_MASK) == NX_DNS_RESPONSE_FLAG) + && ((status & NX_DNS_RCODE_MASK) == NX_DNS_RCODE_SUCCESS) + && (answerCount >= 1)) + { + + + /* This looks like the response to our question, now find the response record. */ + /* Point at the start of the question. */ + data_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDSECT_OFFSET; + + /* Determine if there is a question still in the server's response. */ + if (_nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET) == 1) + { + /* Yes, the question is present in the response, skip it! */ + data_ptr += _nx_dns_name_size_calculate(data_ptr) + 4; + } + + /* Set the status. */ + status = NX_SUCCESS; + + /* Check all the response records */ + for(rrIndex = 0; rrIndex < answerCount; rrIndex++) + { + + /* Set the section class. */ + if(answerRRCount && (rrIndex < answerRRCount)) + rr_location = NX_DNS_RR_ANSWER_SECTION; + else if(authorityRRCount && (rrIndex < (UINT)(answerRRCount + authorityRRCount))) + rr_location = NX_DNS_RR_AUTHORITY_SECTION; + else + rr_location = NX_DNS_RR_ADDITIONAL_SECTION; + + /* Check for valid data_ptr. */ + if (data_ptr >= packet_ptr -> nx_packet_append_ptr) + { + + /* Process error. */ + break; + } + + /* Process the server response. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Is this an A Type? */ + if(response_type == NX_DNS_RR_TYPE_A) + { + + /* Call the function process the A type message. */ + status = _nx_dns_process_a_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count, rr_location); + + } + + /* Is this an AAAA Type? */ + else if(response_type == NX_DNS_RR_TYPE_AAAA) + { + + /* Call the function process the AAAA type message. */ + status = _nx_dns_process_aaaa_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count, rr_location); + + } + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + + /* Is this a Type NX_DNS_RR_TYPE_CNAME? */ + else if(response_type == NX_DNS_RR_TYPE_CNAME) + { + + /* Call the function process the CNAME type message. */ + status = _nx_dns_process_cname_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); + + } + + /* Is this a Type NX_DNS_RR_TYPE_TXT? */ + else if(response_type == NX_DNS_RR_TYPE_TXT) + { + + /* Call the function process the TXT type message. */ + status = _nx_dns_process_txt_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); + } + + /* Is this a Type NX_DNS_RR_TYPE_NS? */ + else if(response_type == NX_DNS_RR_TYPE_NS) + { + + /* Call the function process the NS type message. */ + status = _nx_dns_process_ns_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); + } + + + /* Is this a Type NX_DNS_RR_TYPE_MX? */ + else if(response_type == NX_DNS_RR_TYPE_MX) + { + + /* Call the function process the MX type message. */ + status = _nx_dns_process_mx_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); + } + + /* Is this a Type NX_DNS_RR_TYPE_SRV? */ + else if(response_type == NX_DNS_RR_TYPE_SRV) + { + + /* Call the function process the SRV type message. */ + status = _nx_dns_process_srv_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); + } + + /* Is this a Type NX_DNS_RR_TYPE_SOA? */ + else if(response_type == NX_DNS_RR_TYPE_SOA) + { + + /* Call the function process the SOA type message. */ + status = _nx_dns_process_soa_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); + + } +#endif + + /* Check the process status. */ + if(status != NX_SUCCESS) + { + + /* Process error. */ + break; + } + else + { + + /* Did we get a correct answer? */ + if ((answer_found == NX_FALSE) && + (response_type == dns_ptr -> nx_dns_lookup_type)) + { + answer_found = NX_TRUE; + } + } + + data_ptr += _nx_dns_resource_size_get(data_ptr); + } + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Check the answer found flag. */ + if (answer_found) + status = NX_SUCCESS; + else + status = NX_DNS_QUERY_FAILED; + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_a_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the A record type. If the DNS look up type */ +/* was NS, MX, or SRV type, this function also parses the additional */ +/* section looking for A type information. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* buffer_prepend_ptr Pointer to the starting */ +/* address of available buffer */ +/* buffer_append_ptr Pointer to the ending address */ +/* of available buffer */ +/* record_count The count of the IPv4 address */ +/* rr_location The DNS resource data section */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_a_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, + UINT *record_count, UINT rr_location) +{ + +UINT response_type; +ULONG ipv4_address; + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +UCHAR *buffer_header_ptr; +#endif +#ifdef NX_DNS_CACHE_ENABLE +UINT size; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#if !defined(NX_DNS_CACHE_ENABLE) && !defined(NX_DNS_ENABLE_EXTENDED_RR_TYPES) + NX_PARAMETER_NOT_USED(packet_ptr); +#endif + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Process the A type message in the answer section.*/ + if((rr_location == NX_DNS_RR_ANSWER_SECTION)|| + (rr_location == NX_DNS_RR_AUTHORITY_SECTION)) + { + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Yes, make sure it has the correct data size. */ + if (_nx_dns_resource_data_length_get(data_ptr) == 4) + { + + /* Finally, get the address!!! */ + ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); + + /* Check the buffer space. */ + + if (*buffer_prepend_ptr + 4 > *buffer_append_ptr) + { + + /* The buffer space is not enough. */ + return(NX_DNS_NEED_MORE_RECORD_BUFFER); + } + + /* Set the return IP address. */ + memcpy(*buffer_prepend_ptr,&ipv4_address,4); + + /* Update the record buffer pointer. */ + *buffer_prepend_ptr +=4; + + /* Update the count of ipv4 address. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_A; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the IPv4 address. */ + temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_a.nx_dns_rr_a_address = ipv4_address; + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Success! Return success to caller! */ + return(NX_SUCCESS); + } + else + { + + /* Return.*/ + return(NX_DNS_MALFORMED_PACKET); + } + } + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + /* Process the A type message in the additional section. */ + else if(rr_location == NX_DNS_RR_ADDITIONAL_SECTION) + { + if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_NS) + { + NX_DNS_NS_ENTRY *ns_entry; + UINT entry_index; + UINT name_size; + + /* Processing NS query, and encountered A type in the additional section. */ + /* This means the record_buffer should already contain name server information, + and the name server IP address is in this resource record. */ + + /* First obtain the string. */ + temp_string_buffer[0] = 0; + name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!name_size) + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the first address of record buffer. */ + buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_NS_ENTRY)); + + /* Go through all the records and match the string. */ + for(entry_index = 0; entry_index < *record_count; entry_index++) + { + + /* Set the NS entry. */ + ns_entry = (NX_DNS_NS_ENTRY*)(buffer_header_ptr); + + /* Check the ipv4 address.*/ + if( ns_entry -> nx_dns_ns_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) + { + + /* Update the buffer prepend pointer, and match the next NS entry. */ + buffer_header_ptr += sizeof(NX_DNS_NS_ENTRY); + + continue; + } + + if((memcmp(ns_entry -> nx_dns_ns_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) + { + + /* This A type record contains the IPv4 address for the NS entry. */ + + /* Yes, make sure it has the correct data size. */ + if (_nx_dns_resource_data_length_get(data_ptr) == 4) + { + + /* Finally, get the address!!! */ + ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); + + /* Record the NS entry ipv4 address . */ + ns_entry -> nx_dns_ns_ipv4_address = ipv4_address; + + /* Success! Return success to caller! */ + return(NX_SUCCESS); + } + } + else + { + + /* Update the buffer prepend pointer, and match the next NS entry. */ + buffer_header_ptr += sizeof(NX_DNS_NS_ENTRY); + } + } + } + + else if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_MX) + { + NX_DNS_MX_ENTRY *mx_entry; + UINT entry_index; + UINT name_size; + + /* Processing MX query, and encountered A type in the additional section. */ + /* This means the record_buffer should already contain mail exchange information, + and the mail server IP address is in this resource record. */ + + /* First obtain the string. */ + temp_string_buffer[0] = 0; + name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!name_size) + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Set the record buffer prepend. */ + buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_MX_ENTRY)); + + /* Go through all the records and match the string. */ + for(entry_index = 0; entry_index < *record_count; entry_index++) + { + + /* Set the MX entry pointer. */ + mx_entry = (NX_DNS_MX_ENTRY*)(buffer_header_ptr); + + /* Check the ipv4 address, If the ipv4 address has been set, skip it..*/ + if( mx_entry -> nx_dns_mx_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) + { + + /* Update the buffer prepend pointer, and match the next MX entry. */ + buffer_header_ptr += sizeof(NX_DNS_MX_ENTRY); + continue; + } + + if((memcmp(mx_entry -> nx_dns_mx_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) + { + + /* This A type record contains the IPv4 address for the MX entry. */ + + /* Yes, make sure it has the correct data size. */ + if (_nx_dns_resource_data_length_get(data_ptr) == 4) + { + + /* Finally, get the address!!! */ + ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); + + /* Record the MX entry ipv4 address . */ + mx_entry -> nx_dns_mx_ipv4_address = ipv4_address; + + /* Success! Return success to caller! */ + return(NX_SUCCESS); + } + } + else + { + + /* Update the buffer prepend pointer, and match the next MX entry. */ + buffer_header_ptr += sizeof(NX_DNS_MX_ENTRY); + } + } + } + else if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_SRV) + { + NX_DNS_SRV_ENTRY *srv_entry; + UINT entry_index; + UINT name_size; + + /* Processing SRV query, and encountered A type in the additional section. */ + /* This means the record_buffer should already contain SRV information, + and the mail server IP address is in this resource record. */ + + /* First obtain the string. */ + temp_string_buffer[0] = 0; + name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!name_size) + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Set the record buffer prepend. */ + buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_SRV_ENTRY)); + + /* Go through all the records and match the string. */ + for(entry_index = 0; entry_index < *record_count; entry_index++) + { + + /* Set the MX entry pointer. */ + srv_entry = (NX_DNS_SRV_ENTRY*)(buffer_header_ptr); + + /* Check the ipv4 address, If the ipv4 address has been set, skip it..*/ + if( srv_entry -> nx_dns_srv_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) + { + + /* Update the buffer prepend pointer, and match the next MX entry. */ + buffer_header_ptr += sizeof(NX_DNS_SRV_ENTRY); + continue; + } + + if((memcmp(srv_entry -> nx_dns_srv_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) + { + + /* This A type record contains the IPv4 address for the MX entry. */ + + /* Yes, make sure it has the correct data size. */ + if (_nx_dns_resource_data_length_get(data_ptr) == 4) + { + + /* Finally, get the address!!! */ + ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); + + /* Record the SRV entry ipv4 address . */ + srv_entry -> nx_dns_srv_ipv4_address = ipv4_address; + + /* Success! Return success to caller! */ + return(NX_SUCCESS); + } + } + else + { + + /* Update the buffer prepend pointer, and match the next MX entry. */ + buffer_header_ptr += sizeof(NX_DNS_SRV_ENTRY); + } + } + } + } +#endif + + /* Return.*/ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_aaaa_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the AAAA record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* buffer_prepend_ptr Pointer to the starting */ +/* address of available buffer */ +/* buffer_append_ptr Pointer to the ending address */ +/* of available buffer */ +/* record_count The count of the IPv6 address */ +/* rr_location The DNS resource data section */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_aaaa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, + UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, + UCHAR **buffer_append_ptr, UINT *record_count, + UINT rr_location) +{ + +UINT response_type; +UINT i; +ULONG ipv6_address; +NX_DNS_IPV6_ADDRESS *ipv6_address_ptr; +#ifdef NX_DNS_CACHE_ENABLE +UINT size; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifndef NX_DNS_CACHE_ENABLE + NX_PARAMETER_NOT_USED(packet_ptr); +#endif + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Process the A type message in the answer section.*/ + if((rr_location == NX_DNS_RR_ANSWER_SECTION)|| + (rr_location == NX_DNS_RR_AUTHORITY_SECTION)) + { + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Yes, make sure it has the correct data size. */ + if (_nx_dns_resource_data_length_get(data_ptr) == 16) + { + + /* Check the buffer space. */ + if ((*buffer_prepend_ptr + sizeof(NX_DNS_IPV6_ADDRESS)) > *buffer_append_ptr) + { + + /* The buffer space is not enough. */ + return(NX_DNS_NEED_MORE_RECORD_BUFFER); + } + + /* Update the pointer to the ipv6 address. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + ipv6_address_ptr = (NX_DNS_IPV6_ADDRESS*)(*buffer_prepend_ptr); + + /* Finally, Record the ipv6 address to record buffer. */ + for(i = 0; i < 4; i++) + { + + ipv6_address = _nx_dns_network_to_long_convert(data_ptr); + + ipv6_address_ptr -> ipv6_address[i] = ipv6_address; + + data_ptr +=4; + + } + + *buffer_prepend_ptr = *buffer_prepend_ptr + sizeof(NX_DNS_IPV6_ADDRESS); + + /* Update the count of ipv6 address. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_AAAA; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the IPv6 address string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, ipv6_address_ptr, 16, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Success! */ + return(NX_SUCCESS); + } + else + { + + /* Return.*/ + return(NX_DNS_MALFORMED_PACKET); + } + + } + + /* Return.*/ + return(NX_SUCCESS); + +} + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_cname_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the CNAME record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* record_buffer Buffer space for storing */ +/* the host cname */ +/* buffer_size Size of record_buffer. */ +/* record_count Record count */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_cname_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR *record_buffer, UINT buffer_size, UINT *record_count) +{ +UINT response_type; +UINT name_size; +#ifdef NX_DNS_CACHE_ENABLE +UINT size; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if(response_type == dns_ptr -> nx_dns_lookup_type) + { + + /* Update the pointer to point at the resource data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Determine if there is room for the name - one less for NULL termination. */ + name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, record_buffer, buffer_size - 1); + if (name_size) + { + + /* Yes, got the canonical name successfully,and record the information! */ + + /* Update the count. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_CNAME; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the cname string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, record_buffer, name_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_cname.nx_dns_rr_cname_name))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + return(NX_SUCCESS); + } + else + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + } + + /* If send A type query, should also process the CNAME + A type response. + RFC1034, section3.6.2, page15 and RFC10.5 section 3.3.1, page14. */ + else if (dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_A) + { + + /* Only get the A type message, skip the CNAME answer process, + and return success to process next A type answer. + The CNAME record to be implemented. */ + return(NX_SUCCESS); + } + + /* Error lookup response*/ + else + { + /* Return error status. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_txt_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the TXT DNS type packet and record text string*/ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* record_buffer Buffer space for storing */ +/* the host text string */ +/* buffer_size Size of record_buffer. */ +/* record_count Record count */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_txt_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR *record_buffer, UINT buffer_size, UINT *record_count) +{ +UINT response_type; +UINT text_data_length; +#ifdef NX_DNS_CACHE_ENABLE +UINT size; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#else + NX_PARAMETER_NOT_USED(packet_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Update the pointer to point at the response data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Get the text resource data length. */ + text_data_length = (UINT) (*data_ptr++); + + /* Judge the resource data buffer space. */ + if(text_data_length > buffer_size - 1) + { + + /* Return error, and release the packet in repsonse*/ + return(NX_DNS_MALFORMED_PACKET); + + } + else + { + + /* Record the text string to the buffer. */ + memcpy(&record_buffer[0],data_ptr,text_data_length); + + /* Null terminate text. */ + record_buffer[text_data_length] = '\0'; + + /* Update the count. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_TXT; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the txt string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, record_buffer, text_data_length, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_txt.nx_dns_rr_txt_data))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Yes; We're done! Return success! */ + return(NX_SUCCESS); + } +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_ns_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the NS record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* buffer_prepend_ptr Pointer to the starting */ +/* address of available buffer */ +/* buffer_append_ptr Pointer to the ending address */ +/* of available buffer */ +/* record_count The count of the name server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* _nx_dns_resource_name_real_size_calculate */ +/* Calculate real size of name */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_ns_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, + UINT *record_count) +{ +NX_DNS_NS_ENTRY *nx_dns_ns_entry_ptr; +UINT response_type; +UINT name_buffer_size; +#ifdef NX_DNS_CACHE_ENABLE +UINT size; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Update the pointer to point at the resource data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Get the real size of the name, and set the name buffer size.*/ + name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the buffer space. */ + if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_NS_ENTRY))) + { + + /* The buffer space is not enough. */ + return(NX_DNS_NEED_MORE_RECORD_BUFFER); + } + + /* Set the ns entry pointer. */ + nx_dns_ns_entry_ptr = (NX_DNS_NS_ENTRY *)(*buffer_prepend_ptr); + + /* Initialize the variables to NULL. */ + memset(nx_dns_ns_entry_ptr, 0, sizeof(NX_DNS_NS_ENTRY)); + + /* Update the buffer pointer.*/ + *buffer_prepend_ptr += sizeof(NX_DNS_NS_ENTRY); + + /* Update the store pointer. include the null flag '\0'. */ + *buffer_append_ptr -= (name_buffer_size + 1); + + /* Determine if there is room for the name - one less for NULL termination. */ + if (_nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size)) + { + + /* Yes,record the name server successfully. */ + + /* Update the name server pointer. */ + nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr = *buffer_append_ptr; + + /* Update the count of ns. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_NS; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Add the ns string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr, name_buffer_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + return(NX_SUCCESS); + } + else + { + /* Ruturn. */ + return(NX_DNS_MALFORMED_PACKET); + } +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_mx_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the MX record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* buffer_prepend_ptr Pointer to the starting */ +/* address of available buffer */ +/* buffer_append_ptr Pointer to the ending address */ +/* of available buffer */ +/* record_count The count of the mail exchange*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* _nx_dns_resource_name_real_size_calculate */ +/* Calculate real size of name */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_mx_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, + UINT *record_count) +{ +NX_DNS_MX_ENTRY *nx_dns_mx_entry_ptr; +UINT response_type; +UINT name_buffer_size; +USHORT mx_preference; +UINT name_length; +#ifdef NX_DNS_CACHE_ENABLE +UINT status; +ULONG rr_ttl; +UINT size; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Update the pointer to point at the resource data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Get the preference data of the resource data. */ + mx_preference = _nx_dns_network_to_short_convert(data_ptr); + + /* Skip the MX preference, and update the pointer to point at the mail exchange data. */ + data_ptr += 2; + + /* Get the real size of the name, and set the name buffer size.*/ + name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the buffer space. */ + if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_MX_ENTRY))) + { + + /* The buffer space is not enough. */ + return(NX_DNS_NEED_MORE_RECORD_BUFFER); + } + + /* Set the ns entry pointer. */ + nx_dns_mx_entry_ptr = (NX_DNS_MX_ENTRY *)(*buffer_prepend_ptr); + + /* Initialize the variables to NULL. */ + memset(nx_dns_mx_entry_ptr, 0, sizeof(NX_DNS_MX_ENTRY)); + + /* Record the MX preference. */ + nx_dns_mx_entry_ptr -> nx_dns_mx_preference = mx_preference; + + /* Update the buffer pointer.*/ + *buffer_prepend_ptr += sizeof(NX_DNS_MX_ENTRY); + + /* Update the store pointer. include the null flag '\0'. */ + *buffer_append_ptr -= (name_buffer_size + 1); + + /* Determine if there is room for the name - one less for NULL termination. */ + name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size); + + /* Check the length. */ + if (name_length) + { + + /* Yes,record the name server successfully. */ + + /* Update the name server pointer. */ + nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr = *buffer_append_ptr; + + /* Update the count of mx. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + + /* Check the temp buffer size. */ + if (name_length + 2 > NX_DNS_NAME_MAX + 1) + return (NX_SUCCESS); + + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_MX; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Set the MX rdata preference string. */ + *(USHORT *)(&temp_string_buffer[0]) = mx_preference; + + /* Set the MX rdata string. */ + memcpy((char*)&temp_string_buffer[2], (const char*)nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr, name_length); + + /* Add the MX string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length + 2, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + return(NX_SUCCESS); + } + else + { + + /* Return. */ + return(NX_DNS_MALFORMED_PACKET); + } +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_srv_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the DNS SRV record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* buffer_prepend_ptr Pointer to the starting */ +/* address of available buffer */ +/* buffer_append_ptr Pointer to the ending address */ +/* of available buffer */ +/* record_count The count of the services */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* _nx_dns_resource_name_real_size_calculate */ +/* Calculate real size of name */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_srv_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, + UCHAR **buffer_append_ptr, UINT *record_count) +{ +NX_DNS_SRV_ENTRY *nx_dns_srv_entry_ptr; +UINT response_type; +UINT name_buffer_size; +USHORT srv_priority; +USHORT srv_weight; +USHORT srv_port_number; +UINT name_length; +#ifdef NX_DNS_CACHE_ENABLE +UINT status; +ULONG rr_ttl; +UINT size; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!size) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Update the pointer to point at the resource data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Get the priority data of the resource data. */ + srv_priority = _nx_dns_network_to_short_convert(data_ptr); + + /* Skip the SRV preference, and update the pointer to point at the weight data. */ + data_ptr += 2; + + /* Get the weight data of the resource data. */ + srv_weight = _nx_dns_network_to_short_convert(data_ptr); + + /* Skip the SRV weight, and update the pointer to point at the port data. */ + data_ptr += 2; + + /* Get the port data of the resource data. */ + srv_port_number = _nx_dns_network_to_short_convert(data_ptr); + + /* Skip the SRV port, and update the pointer to point at the target data. */ + data_ptr += 2; + + /* Get the real size of the name, and set the name buffer size.*/ + name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the buffer space. */ + if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_MX_ENTRY))) + { + + /* The buffer space is not enough. */ + return(NX_DNS_NEED_MORE_RECORD_BUFFER); + } + + /* Set the SRV entry pointer. */ + nx_dns_srv_entry_ptr = (NX_DNS_SRV_ENTRY *)(*buffer_prepend_ptr); + + /* Initialize the variables to NULL. */ + memset(nx_dns_srv_entry_ptr, 0, sizeof(NX_DNS_SRV_ENTRY)); + + /* Record the SRV options data. */ + nx_dns_srv_entry_ptr -> nx_dns_srv_priority = srv_priority; + nx_dns_srv_entry_ptr -> nx_dns_srv_weight = srv_weight; + nx_dns_srv_entry_ptr -> nx_dns_srv_port_number = srv_port_number; + + /* Update the buffer pointer.*/ + *buffer_prepend_ptr += sizeof(NX_DNS_SRV_ENTRY); + + /* Update the store pointer. include the null flag '\0'. */ + *buffer_append_ptr -= (name_buffer_size + 1); + + /* Determine if there is room for the name - one less for NULL termination. */ + name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size); + + /* Check the length. */ + if (name_length) + { + + /* Yes,record the name server successfully. */ + + /* Update the name server pointer. */ + nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr = *buffer_append_ptr; + + /* Update the count of srv. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + + /* Check the temp buffer size. */ + if (name_length + 6 > NX_DNS_NAME_MAX + 1) + return (NX_SUCCESS); + + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_SRV; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Set the SRV priority, weight and port number. */ + *(USHORT *)(&temp_string_buffer[0]) = srv_priority; + *(USHORT *)(&temp_string_buffer[2]) = srv_weight; + *(USHORT *)(&temp_string_buffer[4]) = srv_port_number; + + /* Set the SRV rdata string. */ + memcpy((char*)&temp_string_buffer[6], (const char*)nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr, name_length); + + /* Add the srv string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length + 6, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + return(NX_SUCCESS); + } + else + { + + /* Return. */ + return(NX_DNS_MALFORMED_PACKET); + } +} +#endif + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_process_soa_type PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the SOA record type. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Pointer to received packet */ +/* data_ptr Pointer to resource data */ +/* section */ +/* record_buffer Buffer space for storing */ +/* the data structures that */ +/* hold the SOA information */ +/* buffer_size Size of record_buffer. */ +/* record_count Record count */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_resource_type_get Get resource type */ +/* _nx_dns_resource_data_address_get Get address of data */ +/* _nx_dns_name_string_unencode Unencode the name and get it. */ +/* _nx_dns_name_size_calculate Calculate size of name field */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_response_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_process_soa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, + UCHAR *record_buffer, UINT buffer_size, UINT *record_count) +{ +NX_DNS_SOA_ENTRY *nx_dns_soa_entry_ptr; +UINT response_type; +ULONG mname_length; +ULONG rname_length; +UCHAR *buffer_start; +#ifdef NX_DNS_CACHE_ENABLE +ULONG name_length; +UINT status; +ULONG rr_ttl; +#endif /* NX_DNS_CACHE_ENABLE */ + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the value. */ + memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); + memset(&temp_rr, 0, sizeof (NX_DNS_RR)); + + /* First obtain the string. */ + name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); + + /* Check the string correct. */ + if(!name_length) + { + + /* Return! */ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the resource record ttl. */ + rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + + /* Process the server response and get it. */ + response_type = _nx_dns_resource_type_get(data_ptr); + + /* Verify this is what the DNS Client was requesting. */ + if (response_type != dns_ptr -> nx_dns_lookup_type) + { + + /* No, this was not what the Client requested. Return error status. + This should not happen so return error to the host application, + might be a problem with the query or the server. */ + return NX_DNS_MISMATCHED_RESPONSE; + } + + /* Set the SRV entry pointer. */ + nx_dns_soa_entry_ptr = (NX_DNS_SOA_ENTRY *)(record_buffer); + + /* Update the start address of available buffer and the buffer size. */ + buffer_start = record_buffer + sizeof(NX_DNS_SOA_ENTRY); + buffer_size -= sizeof(NX_DNS_SOA_ENTRY); + + /* Update the pointer to point at the resource data. */ + data_ptr = _nx_dns_resource_data_address_get(data_ptr); + + /* Get the primary name server and record it in buffer. */ + mname_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, buffer_start, buffer_size - 1); + + /* Check the name length. */ + if (mname_length) + { + + /* Yes, got the primary name server successfully. set the mname ptr pointer. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr = buffer_start; + + /* Update the pointer to point at the rname data. */ + data_ptr += _nx_dns_name_size_calculate(data_ptr); + + /* Update the start address of available buffer and the buffer size. 1 is the Null terminate. */ + buffer_start += mname_length + 1; + buffer_size -= mname_length + 1; + } + else + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the responsible mail address and record it in buffer. */ + rname_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, buffer_start, buffer_size - 1); + + if (rname_length) + { + + /* Yes, got the primary name server successfully. set the mname ptr pointer. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr = buffer_start; + + /* Update the pointer to point at the rname data. */ + data_ptr += _nx_dns_name_size_calculate(data_ptr); + + /* Update the start address of available buffer and the buffer size.1 is the Null terminate. */ + buffer_start += rname_length + 1; + buffer_size -= rname_length + 1; + } + else + { + + /* Return !*/ + return(NX_DNS_MALFORMED_PACKET); + } + + /* Get the serial number of the resource data. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_serial = _nx_dns_network_to_long_convert(data_ptr); + + /* Skip the serial number, and update the pointer to point at the refresh data. */ + data_ptr += 4; + + /* Get the refresh number of the resource data. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_refresh = _nx_dns_network_to_long_convert(data_ptr); + + /* Skip the refresh number, and update the pointer to point at the retry data. */ + data_ptr += 4; + + /* Get the retry number of the resource data. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_retry = _nx_dns_network_to_long_convert(data_ptr); + + /* Skip the retry number, and update the pointer to point at the expire data. */ + data_ptr += 4; + + /* Get the expire number of the resource data. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_expire = _nx_dns_network_to_long_convert(data_ptr); + + /* Skip the expire number, and update the pointer to point at the minmum data. */ + data_ptr += 4; + + /* Get the minmum number of the resource data. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_minmum = _nx_dns_network_to_long_convert(data_ptr); + + /* Skip the serial number, and update the pointer to point at the refresh data. */ + data_ptr += 4; + + /* Update the count. */ + (*record_count) ++; + +#ifdef NX_DNS_CACHE_ENABLE + + /* Check the temp buffer size. */ + if (mname_length + rname_length + 22 > NX_DNS_NAME_MAX + 1) + return (NX_SUCCESS); + + /* Set the resource record type. */ + temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_SOA; + + /* Set the resource record ttl. */ + temp_rr.nx_dns_rr_ttl = rr_ttl; + + /* Add the name string. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length, (VOID **)(&(temp_rr.nx_dns_rr_name))); + + /* Check the status. */ + if(status) + return (NX_SUCCESS); + + /* Set the SOA MNAME. */ + memcpy((char*)&temp_string_buffer[0], (char*)nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr, mname_length); + temp_string_buffer[mname_length] = '\0'; + + /* Set the SOA RNAME. */ + memcpy((char*)&temp_string_buffer[mname_length + 1], (char*)nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr, rname_length); + temp_string_buffer[mname_length + 1 + rname_length] = '\0'; + + /* Set the SOA Serial, Refresh, Retry, Expire, Minmum. */ + *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 2]) = nx_dns_soa_entry_ptr -> nx_dns_soa_serial; + *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 6]) = nx_dns_soa_entry_ptr -> nx_dns_soa_refresh; + *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 10]) = nx_dns_soa_entry_ptr -> nx_dns_soa_retry; + *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 14]) = nx_dns_soa_entry_ptr -> nx_dns_soa_expire; + *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 18]) = nx_dns_soa_entry_ptr -> nx_dns_soa_minmum; + + /* Add the SOA string, mname length, '\0', rname length, '\0', Refresh, Retry, Expire, Minmum. */ + status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, mname_length + rname_length + 22, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata))); + + /* Check the status. */ + if(status) + { + _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); + return (NX_SUCCESS); + } + + /* Add the resource record. */ + status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); + + /* Check the status. */ + if(status) + { + + /* Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); + } +#endif /* NX_DNS_CACHE_ENABLE */ + + return (NX_SUCCESS); +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_host_by_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS get host by address */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* ip_address IP address to get host name */ +/* host_name Destination for host name */ +/* host_name_buffer_size Buffer size of host name */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_by_address_get Actual DNS get host by address*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG host_address, UCHAR *host_name, UINT host_name_buffer_size, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (host_name == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid non pointer input. */ + if (!host_address || dns_ptr -> nx_dns_id != NX_DNS_ID || (host_name_buffer_size == 0)) + return(NX_DNS_PARAM_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS get host by address service. */ + status = _nx_dns_host_by_address_get(dns_ptr, host_address, host_name, host_name_buffer_size, wait_option); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_host_by_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the host name associated with the */ +/* specified IP address. If a host name cannot be found, this */ +/* routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* dns_address DNS server IP address */ +/* host_name Destination for host name */ +/* host_name_buffer_size Buffer size for host name */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_host_by_address_get_internal Actual host address */ +/* get service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG dns_address, UCHAR *host_name, UINT host_name_buffer_size, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +NXD_ADDRESS host_address; + + + /* Check for null address input. */ + if (dns_address == 0) + { + return NX_DNS_BAD_ADDRESS_ERROR; + } + + /* Construct an IP address structure, and fill in IPv4 address information. */ + host_address.nxd_ip_version = NX_IP_VERSION_V4; + host_address.nxd_ip_address.v4 = dns_address; + + /* Invoke the real function. */ + return(_nx_dns_host_by_address_get_internal(dns_ptr, &host_address, host_name, host_name_buffer_size, wait_option)); +#else + NX_PARAMETER_NOT_USED(dns_ptr); + NX_PARAMETER_NOT_USED(dns_address); + NX_PARAMETER_NOT_USED(host_name); + NX_PARAMETER_NOT_USED(host_name_buffer_size); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_dns_host_by_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the NetX duo compatible DNS get */ +/* host by address function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* ip_address IP address to get host name */ +/* host_name_ptr Destination for host name */ +/* host_name_buffer_size Size of host name buffer */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_dns_host_by_address_get Actual DNS get host by address*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((dns_ptr == NX_NULL) || (host_name_ptr == NX_NULL) || (host_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid host name size. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID || (host_name_buffer_size == 0)) + return(NX_DNS_PARAM_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DNS service get host IP address by host name. */ + status = _nxd_dns_host_by_address_get(dns_ptr, host_address, host_name_ptr, host_name_buffer_size, wait_option); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_host_by_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the host name associated with the */ +/* specified IP address. If a host name cannot be found, this */ +/* routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_address_ptr NXD_ADDRESS instance with the */ +/* IP address to search for */ +/* host name */ +/* host_name_ptr Destination for host name */ +/* host_name_buffer_size Buffer size for host name */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_dns_build_an_ipv6_question_string Create the DNS query */ +/* _nx_dns_send_query_by_address Create and transmit the DNS */ +/* query packet */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, + UINT host_name_buffer_size, ULONG wait_option) +{ + + + /* Invoke the real function. */ + return(_nx_dns_host_by_address_get_internal(dns_ptr, host_address_ptr, host_name_ptr, host_name_buffer_size, wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_host_by_address_get_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses DNS to get the host name associated with the */ +/* specified IP address. If a host name cannot be found, this */ +/* routine returns zero for the string size to signal an error. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* host_address_ptr Pointer to host address */ +/* host_name_ptr Destination for host name */ +/* host_name_buffer_size Buffer size for host name */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_dns_build_an_ipv6_question_string Create the DNS query */ +/* _nx_dns_send_query_by_address Create and transmit the DNS */ +/* query packet */ +/* tx_mutex_get Get DNS protection mutex */ +/* tx_mutex_put Release DNS protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_host_by_address_get_internal(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, + UINT host_name_buffer_size, ULONG wait_option) +{ + +UINT retries; +UINT status; +UCHAR ip_question[NX_DNS_IP_LOOKUP_SIZE + 1]; +UINT i; +#ifndef NX_DISABLE_IPV4 +UCHAR dot = '.'; +UINT value; +UINT length, index; +#endif /* NX_DISABLE_IPV4 */ + + + /* Check for an invalid address type. */ + if ((host_address_ptr -> nxd_ip_version != NX_IP_VERSION_V4) && + (host_address_ptr -> nxd_ip_version != NX_IP_VERSION_V6)) + { + + return NX_DNS_INVALID_ADDRESS_TYPE; + } + + if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V6) +#ifdef FEATURE_NX_IPV6 + { + + /* Check for Null address input. */ + if (CHECK_UNSPECIFIED_ADDRESS(&(host_address_ptr ->nxd_ip_address.v6[0]))) + { + return NX_DNS_BAD_ADDRESS_ERROR; + } + } +#else + { + /* IPv6 not supported. */ + return NX_DNS_INVALID_ADDRESS_TYPE; + } +#endif + else if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* Check for Null address input. */ + if (host_address_ptr -> nxd_ip_address.v4== 0) +#endif /* NX_DISABLE_IPV4 */ + { + + return NX_DNS_BAD_ADDRESS_ERROR; + } + } + else + { + return NX_DNS_INVALID_ADDRESS_TYPE; + } + + /* Check for an invalid buffer size. */ + if (host_name_buffer_size == 0) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Clear the host name buffer. */ + memset(host_name_ptr, 0, sizeof(host_name_buffer_size)); + + /* Get the protection mutex to make sure no other thread interferes. */ + status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), wait_option); + + /* Check status. */ + if (status != TX_SUCCESS) + { + + /* The mutex was not granted in the time specified. Return an error. */ + return(NX_DNS_TIMEOUT); + } + + /* Determine if there is at least one DNS server. Is the first slot empty? */ + if (dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version == 0) + { + + /* No, this means the list is empty. Release the DNS Client lock. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + /* At least one DNS server is required - return an error. */ + return(NX_DNS_NO_SERVER); + } + + /* Is this an IPv6 address we are looking up? */ + if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + /* Release the mutex and return. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + return NX_DNS_IPV6_NOT_SUPPORTED; +#else + /* Yes; build the PTR query string containing an IPv6 address. */ + _nxd_dns_build_an_ipv6_question_string(host_address_ptr, &ip_question[0], NX_DNS_IP_LOOKUP_SIZE); +#endif + } + else + { + +#ifndef NX_DISABLE_IPV4 + memset(ip_question, 0, NX_DNS_IP_LOOKUP_SIZE); + value = host_address_ptr -> nxd_ip_address.v4 & 0xff; + length = _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[0]); + ip_question[length++] = dot; + index = length; + + value = (host_address_ptr -> nxd_ip_address.v4 >> 8) & 0xff; + length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]); + ip_question[length++] = dot; + index = length; + + value = (host_address_ptr -> nxd_ip_address.v4 >> 16) & 0xff; + length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]) ; + ip_question[length++] = dot; + index = length; + + value = (host_address_ptr -> nxd_ip_address.v4 >> 24) & 0xff; + length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]); + ip_question[length++] = dot; + index = length; + + memcpy(&ip_question[length], &lookup_end[0], 12); +#else + /* Release the mutex and return. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + return NX_DNS_BAD_ADDRESS_ERROR; +#endif /* NX_DISABLE_IPV4 */ + } + +#ifdef NX_DNS_CACHE_ENABLE + + /* Find the answer in local cache. */ + if(_nx_dns_cache_find_answer(dns_ptr, dns_ptr -> nx_dns_cache, ip_question, NX_DNS_RR_TYPE_PTR, host_name_ptr, host_name_buffer_size, NX_NULL) == NX_DNS_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + return (NX_DNS_SUCCESS); + } +#endif /*NX_DNS_CACHE_ENABLE. */ + + /* Keep sending queries to all DNS Servers till the retry count expires. */ + for (retries = 0; retries < dns_ptr -> nx_dns_retries; retries++) + { + + /* The client should try other servers and server addresses before repeating a query to a specific address of a server. + RFC1035, Section4.2.1 UDP usage, Page32. */ + /* Attempt host name resolution from each DNS server till one if found. */ + for (i = 0; (i < NX_DNS_MAX_SERVERS) && (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version != 0); i ++) + { + + /* Send the PTR/reverse lookup query. */ + status = _nx_dns_send_query_by_address(dns_ptr, &dns_ptr -> nx_dns_server_ip_array[i], &ip_question[0], + host_name_ptr, host_name_buffer_size, wait_option); + + /* Check the status. */ + if (status == NX_SUCCESS) + { + + /* Release the mutex */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + /* Yes, have done, just return success. */ + return NX_SUCCESS; + } + } + + /* Timed out for querying all DNS servers in this cycle, double the timeout, limited to NX_DNS_MAX_RETRANS_TIMEOUT. */ + if ((2 * wait_option) <= NX_DNS_MAX_RETRANS_TIMEOUT) + wait_option = wait_option * 2; + else + wait_option = NX_DNS_MAX_RETRANS_TIMEOUT; + } + + /* Release protection. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Failed on all servers, return DNS lookup failed status. */ + return(NX_DNS_QUERY_FAILED); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_new_packet_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This routine fills in the header and question in a DNS queyr packet,*/ +/* and updates the size and the question count fields in the header. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* packet_ptr Packet allocated for message */ +/* id DNS Client Identification */ +/* name Question e.g. host name */ +/* type DNS message type e.g. A, AAAA */ +/* */ +/* OUTPUT */ +/* */ +/* NX_DNS_PACKET_CREATE_ERROR Error creating header or query*/ +/* NX_SUCCESS Successful compltion */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_header_create Create a DNS header */ +/* _nx_dns_question_add Add the DNS question to packet*/ +/* nx_packet_allocate Allocate a new DNS packet */ +/* nx_packet_release Release DNS packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_name_get Get IP address with name */ +/* _nx_host_by_address_get Get name from IP address */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_new_packet_create(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, USHORT id, UCHAR *name, USHORT type) +{ + +UINT size; + + /* Add the DNS header. */ + size = _nx_dns_header_create(packet_ptr -> nx_packet_append_ptr, id, NX_DNS_QUERY_FLAGS); + + /* Determine if there was an error. */ + if (size == 0) + { + + /* Return error status. */ + return NX_DNS_PACKET_CREATE_ERROR; + } + + /* Save the DNS transmit id and lookup type. */ + dns_ptr -> nx_dns_transmit_id = id; + dns_ptr -> nx_dns_lookup_type = type; + + /* Setup the packet pointers. */ + packet_ptr -> nx_packet_append_ptr += size; + packet_ptr -> nx_packet_length += size; + + /* Add the DNS question. */ + size = _nx_dns_question_add(packet_ptr, name, type); + + /* Determine if there was an error. */ + if (size == 0) + { + + /* Return the error status. */ + return NX_DNS_PACKET_CREATE_ERROR; + } + + /* Successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_header_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a standard DNS header and returns the size of */ +/* header. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to header area */ +/* id Identification */ +/* flags Flags */ +/* */ +/* OUTPUT */ +/* */ +/* size Size of DNS header */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_short_to_network_convert Convert from short to network */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_new_packet_create Create new DNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_header_create(UCHAR *buffer_ptr, USHORT id, USHORT flags) +{ + + /* Transaction ID. */ + _nx_dns_short_to_network_convert(buffer_ptr + NX_DNS_ID_OFFSET, id); + + /* Flags and Command. */ + _nx_dns_short_to_network_convert(buffer_ptr + NX_DNS_FLAGS_OFFSET, flags); + + /* Initialize counts to 0. */ + memset(buffer_ptr + NX_DNS_QDCOUNT_OFFSET, 0, 8); + + /* Return the size of the DNS header. */ + return(NX_DNS_QDSECT_OFFSET); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_question_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a question to the packet buffer at the end of */ +/* the current data and updates the size and the question count */ +/* (assuming that there is a dns header at the start if the packet */ +/* buffer). The question class is assumed to be INET. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to header area */ +/* name Host name or IP address that */ +/* is target of the DNS query */ +/* type DNS record type (e.g. A, AAAA)*/ +/* */ +/* OUTPUT */ +/* */ +/* size Total size of packet */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_string_encode Encode the supplied string */ +/* _nx_dns_network_to_short_convert Convert from network to short */ +/* _nx_dns_short_to_network_convert Convert from short to network */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_new_packet_create Create new DNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_question_add(NX_PACKET *packet_ptr, UCHAR *name, USHORT type) +{ + +UINT name_size; +UINT size; +USHORT value; + + + /* Check for name. */ + if (_nx_utility_string_length_check((CHAR *)name, &name_size, NX_DNS_NAME_MAX)) + { + + /* Name error, release the packet. */ + nx_packet_release(packet_ptr); + + /* Return a size of 0 to indicate an error. */ + return(0); + } + + /* The question will take the size of the string plus 6 bytes, is there space? */ + if ((name_size + 6) > (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr)) + { + + /* Size error, release the packet. */ + nx_packet_release(packet_ptr); + + /* Return a size of 0 to indicate an error. */ + return(0); + } + + /* Encode and add the name. */ + size = _nx_dns_name_string_encode(packet_ptr -> nx_packet_append_ptr, name); + + /* Add the type and class. */ + _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_append_ptr + size, type); + size += 2; + _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_append_ptr + size, NX_DNS_RR_CLASS_IN); + size += 2; + + /* Update the packet size and end. */ + packet_ptr -> nx_packet_length += size; + packet_ptr -> nx_packet_append_ptr += size; + + /* Get the question count. */ + value = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET); + + /* Increment question count by one. */ + value++; + _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET, value); + + /* Return the size. */ + return(packet_ptr -> nx_packet_length); +} + + +#ifdef FEATURE_NX_IPV6 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_dns_build_an_ipv6_question_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the IP address in text form to go into the DNS*/ +/* lookup query ("Name"), including the ip6.arpa tag on the end. */ +/* */ +/* INPUT */ +/* */ +/* ip_address NXD_ADDRESS instance with the */ +/* IP address to search for */ +/* host name */ +/* buffer Pointer to host name to lookup*/ +/* len Buffer size for host name */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_dns_host_by_address_get Lookup host by address service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_dns_build_an_ipv6_question_string(NXD_ADDRESS *ip_address, UCHAR *buffer, UINT len) +{ +INT i, j; +ULONG temp; + + memset(buffer, 0, len); + for (j = 3; j >= 0; j--) + { + i = 0; + while (i <= 7) + { + + temp = ip_address -> nxd_ip_address.v6[j]; + temp = temp >> (4 * i++); + temp = (USHORT)temp & 0xf; + if(temp >= 10) + *buffer = (UCHAR)('a' + ((UCHAR)temp - 10)); + else + *buffer = (UCHAR)('0' + (UCHAR)temp); + buffer ++; + *buffer = '.'; + buffer++; + } + } + + memcpy(buffer, "ip6.arpa", sizeof("ip6.arpa")); + + return; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_name_string_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a string containing the name as a list of */ +/* labels separated by dots to the encoded list of labels specified */ +/* in RFC1035 for DNS servers. This conversion doesn't handle */ +/* compression and doesn't check on the lengths of the labels or the */ +/* entire name. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* count Count of characters encoded */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_question_add Add question to DNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_name_string_encode(UCHAR *ptr, UCHAR *name) +{ + +UCHAR *length; +UINT count = 1; + + + /* Point to the first character position in the buffer. This will point + to the length of the following name. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + + /* Move through string, copying bytes and updating length. + Whenever a "." is found, start a new string by updating the + pointer to the length and setting the length to zero. */ + while (*name) + { + + /* Is a dot been found? */ + if (*name == '.') + { + + /* Yes, setup a new length pointer. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + name++; + } + else + { + + /* Copy a character to the destination. */ + *ptr++ = *name++; + + /* Adjust the length of the current segment. */ + (*length)++; + } + + /* Increment the total count here. */ + count++; + } + + /* Add the final zero length, like a NULL terminator. */ + *ptr = 0; + + /* Increment the total count. */ + count++; + + /* Return the count. */ + return(count); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_name_string_unencode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts from the encoded list of labels as specified */ +/* in RFC 1035 to a string containing the name as a list of labels */ +/* separated by dots. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer to decode */ +/* start Location of start of data */ +/* buffer Pointer to decoded data */ +/* buffer_size Size of data buffer to decode */ +/* */ +/* OUTPUT */ +/* */ +/* Size of decoded data */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_send_query_by_address Send reverse lookup query */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_name_string_unencode(NX_PACKET *packet_ptr, UCHAR *data, UCHAR *buffer, UINT buffer_size) +{ + +UCHAR *character; +UCHAR *message_start; +UINT label_size; +UINT offset; +UINT length; + + + /* Initialize the value. */ + character = data; + message_start = packet_ptr -> nx_packet_prepend_ptr; + length = 0; + + /* As long as there is space in the buffer and we haven't + found a zero terminating label */ + while (*character != '\0') + { + + /* Check the buffer size. */ + if (buffer_size > length) + { + + /* Get the label size. */ + label_size = *character++; + + /* Is this a compression pointer or a count. */ + if (label_size <= NX_DNS_LABEL_MAX) + { + + /* Simple count, check for space and copy the label. */ + while ((buffer_size > length) && (label_size > 0)) + { + + *buffer++ = *character++; + length++; + label_size--; + } + + /* Now add the '.' */ + *buffer++ = '.'; + length++; + } + else if ((label_size & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) + { + + /* Message compression. */ + + /* Get the offset. */ + offset = ((label_size & NX_DNS_LABEL_MAX) << 8) + *character; + + /* Check the offset. */ + if (offset >= packet_ptr -> nx_packet_length) + { + + /* This is malformed packet. */ + return(0); + } + else + { + + /* This is a pointer, just adjust the source. */ + character = message_start + offset; + } + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + else + { + + /* Size error , just fail */ + return(0); + } + } + + /* Check for invalid length. */ + if (length == 0) + return(length); + + /* Done copying the data, set the last . to a trailing null */ + if (*(buffer - 1) == '.') + { + + buffer--; + length --; + } + + /* Null terminate name. */ + *buffer = '\0'; + + /* Return name size. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_name_size_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the size of the name. */ +/* */ +/* INPUT */ +/* */ +/* name Pointer to the name */ +/* */ +/* OUTPUT */ +/* */ +/* UINT Size of name */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_name_get Get IP address with name */ +/* _nx_host_by_address_get Get name from IP address */ +/* _nx_dns_resource_type_get Get resource type */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_name_size_calculate(UCHAR *name) +{ + +UINT size = 0; + + + /* As long as we haven't found a zero length terminating label */ + while (*name != '\0') + { + + UINT labelSize = *name++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_DNS_LABEL_MAX) + { + + /* Simple count, adjust size and skip the label. */ + size += labelSize + 1; + name += labelSize; + } + else if ((labelSize & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) + { + + /* This is a pointer size is 2 bytes and this is the end of this name */ + return(size + 2); + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + + /* Adjust size for the final NULL. */ + return(size + 1); +} + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_name_real_size_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the real size of the resouce name. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer to decode */ +/* start Location of start of data */ +/* */ +/* OUTPUT */ +/* */ +/* Real size of a string */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_send_query_by_name Send reverse lookup query */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_resource_name_real_size_calculate(UCHAR *data, UINT start) +{ + +UCHAR *character = data + start; +UINT length = 0; + + + /* As long as there is space in the buffer and we haven't + found a zero terminating label */ + while (*character != '\0') + { + + UINT labelSize = *character++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_DNS_LABEL_MAX) + { + + /* Simple count, check for space and copy the label. */ + while (labelSize > 0) + { + character++; + length++; + labelSize--; + } + + /* Now add the '.' space */ + length++; + } + else if ((labelSize & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) + { + + /* This is a pointer, just adjust the source. */ + character = data + ((labelSize & NX_DNS_LABEL_MAX) << 8) + *character; + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + + /* Reduce the last '.' string, update the length. */ + length --; + + /* Return name size. */ + return(length); +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource type. It is a wrapper for the */ +/* actual internal function that retrieves the name to maintain */ +/* compatibility with the previous version of DNS Client, e.g. NetX DNS*/ +/* Client. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* resource type */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate name's size */ +/* _nx_dns_network_to_short_convert Actual get resource type */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_name_get Get IP address with name */ +/* _nx_host_by_address_get Get name from IP address */ +/* _nx_dns_name_size_calculate Calculate name's size */ +/* _nx_dns_network_to_short_convert Convert network to short */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_resource_type_get(UCHAR *resource) +{ + + return(_nx_dns_network_to_short_convert(resource + _nx_dns_name_size_calculate(resource))); +} + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_time_to_live_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource time to live. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* resource type */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource) +{ + + return(_nx_dns_network_to_long_convert(resource + _nx_dns_name_size_calculate(resource) + 4)); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_data_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource data length. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* data length */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate name's size */ +/* _nx_dns_network_to_short_convert Convert from network to short */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_name_get Get IP address with name */ +/* _nx_host_by_address_get Get name from IP address */ +/* _nx_dns_resource_size_get Get size of resource */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_resource_data_length_get(UCHAR *resource) +{ + + return(_nx_dns_network_to_short_convert(resource + _nx_dns_name_size_calculate(resource) + 8)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_data_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource data address. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* pointer to address */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate name's size */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_name_get Get IP address with name */ +/* _nx_host_by_address_get Get name from IP address */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UCHAR *_nx_dns_resource_data_address_get(UCHAR *resource) +{ + + return(resource + _nx_dns_name_size_calculate(resource) + 10); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_resource_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource data size. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* size of data */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_name_size_calculate Calculate name's size */ +/* _nx_dns_resource_data_length_get Get resource data length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_host_by_address_get Get name from IP address */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_resource_size_get(UCHAR *resource) +{ + + /* Resource size is + name size + data size + 2 bytes for type, 2 for class, 4 for time to live and 2 for data length + i.e. name size + data size + 10 bytes overhead + */ + return(_nx_dns_name_size_calculate(resource) + _nx_dns_resource_data_length_get(resource) + 10); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_short_to_network_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an unsigned short to network byte order, */ +/* which is big endian. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to the destination */ +/* value Source value */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* DNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static void _nx_dns_short_to_network_convert(UCHAR *ptr, USHORT value) +{ + + *ptr++ = (UCHAR)(value >> 8); + *ptr = (UCHAR)value; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_network_to_short_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an unsigned short in network format, which */ +/* big endian, to an unsigned short. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to the source */ +/* */ +/* OUTPUT */ +/* */ +/* return value */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* DNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static USHORT _nx_dns_network_to_short_convert(UCHAR *ptr) +{ + +USHORT value = *ptr++; + + value = (USHORT)((value << 8) | *ptr); + + return(value); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_network_to_long_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an unsigned long in network format, which */ +/* big endian, to an unsigned long. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to the source */ +/* */ +/* OUTPUT */ +/* */ +/* return value */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* DNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_dns_network_to_long_convert(UCHAR *ptr) +{ + +ULONG value = *ptr++; + + value = (value << 8) | *ptr++; + value = (value << 8) | *ptr++; + value = (value << 8) | *ptr; + + return(value); +} + + +#ifndef NX_DISABLE_IPV4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_number_to_ascii_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts single digits into an ASCII character in an */ +/* NULL terminated string. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* buffstring Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_dns_host_by_address_get Send PTR query to DNS server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_number_to_ascii_convert(UINT number, CHAR *buffstring) +{ +UINT value; +UINT digit; +UINT index = 0; + + value = number; + + /* Is the value in the range of 100 and 255? */ + if(value >= 200) + { + buffstring[index++] = '2'; + value -= 200; + } + else if(value >= 100) + { + buffstring[index++] = '1'; + value -= 100; + } + + digit = value % 10; + value = value / 10; + + if(value == 0) + { + /* The 10s is zero. However if we already recorded the hundreds, + we need to insert 0 here. */ + if(index != 0) + buffstring[index++] = '0'; + } + else + buffstring[index++] = (CHAR)('0' + value); + + /* Last print the digit. */ + buffstring[index++] = (CHAR)('0' + digit); + + return index; +} +#endif /* NX_DISABLE_IPV4 */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_cache_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS cache initialize */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* cache_ptr Pointer to cache memory */ +/* cache_size The size of cache */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_cache_initialize Actual cache initialize function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!dns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Check for invalid input pointers. */ + if (!cache_ptr) + { + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure peer cache is 4-byte aligned. */ + if ((((ALIGN_TYPE)cache_ptr & 0x3) != 0) || + ((cache_size & 0x3) != 0)) + { + return(NX_DNS_ERROR); + } + + /* Call actual DNS cache initialize service. */ + status = _nx_dns_cache_initialize(dns_ptr, cache_ptr, cache_size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the DNS cache. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* cache_ptr Pointer to cache memory */ +/* cache_size The size of cache */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DNS mutex */ +/* tx_mutex_put Put the DNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size) +{ + +ALIGN_TYPE *head; +ALIGN_TYPE *tail; + + + /* Get the mutex. */ + tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Zero out the cache. */ + memset(cache_ptr, 0, cache_size); + + /* Set the head. */ + head = (ALIGN_TYPE*)cache_ptr; + *head = (ALIGN_TYPE)((ALIGN_TYPE*)cache_ptr + 1); + + /* Set the tail. */ + tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; + *tail = (ALIGN_TYPE)tail; + + /* Record the info. */ + dns_ptr -> nx_dns_cache = (UCHAR*)cache_ptr; + dns_ptr -> nx_dns_cache_size = cache_size; + + /* Clear the count. */ + dns_ptr -> nx_dns_rr_count = 0; + dns_ptr -> nx_dns_string_count = 0; + dns_ptr -> nx_dns_string_bytes = 0; + + /* Put the DNS mutex. */ + tx_mutex_put(&dns_ptr -> nx_dns_mutex); + + return(NX_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS cache full notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_cache_notify_set Actual cache notify set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!dns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Call actual DNS cache notify set function. */ + status = _nx_dns_cache_notify_set(dns_ptr, cache_full_notify_cb); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the cache full notify function. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DNS mutex */ +/* tx_mutex_put Put the DNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)) +{ + + + /* Get the DNS mutex. */ + tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Set the cache notify. */ + dns_ptr -> nx_dns_cache_full_notify = cache_full_notify_cb; + + /* Release the DNS mutex. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return(NX_DNS_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_dns_cache_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS cache full notify clear */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_dns_cache_notify_clear Actual cache notify clear function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_dns_cache_notify_clear(NX_DNS *dns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!dns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (dns_ptr -> nx_dns_id != NX_DNS_ID) + { + return(NX_DNS_PARAM_ERROR); + } + + /* Call actual DNS cache notify clear function. */ + status = _nx_dns_cache_notify_clear(dns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clear the cache full notify function. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the DNS mutex */ +/* tx_mutex_put Put the DNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_dns_cache_notify_clear(NX_DNS *dns_ptr) +{ + + + /* Get the DNS mutex. */ + tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); + + /* Clear the cache notify. */ + dns_ptr -> nx_dns_cache_full_notify = NX_NULL; + + /* Release the DNS mutex. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return(NX_DNS_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_add_rr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the DNS resource record into record buffer. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_add_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr, NX_DNS_RR **insert_ptr) +{ + +ALIGN_TYPE *tail; +ALIGN_TYPE *head; +NX_DNS_RR *p; +NX_DNS_RR *rr; +ULONG elapsed_time; +ULONG current_time; +ULONG max_elapsed_time; + + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Initialize the parameters. */ + max_elapsed_time = 0; + current_time = tx_time_get(); + + /* Get head and tail. */ + tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; + tail = (ALIGN_TYPE*)(*tail); + head = (ALIGN_TYPE*)cache_ptr; + head = (ALIGN_TYPE*)(*head); + + /* Set the pointer. */ + rr = NX_NULL; + + /* Find an empty entry before head. */ + for(p = (NX_DNS_RR*)((ALIGN_TYPE*)cache_ptr + 1); p < (NX_DNS_RR*)head; p++) + { + if(!p -> nx_dns_rr_type) + { + rr = p; + break; + } + } + + /* Check the record ptr. */ + if (!rr) + { + /* Check whether the cache is full. */ + if((ALIGN_TYPE*)((UCHAR*)head + sizeof(NX_DNS_RR)) > tail) + { + + /* Find an aging resource reocrd and repalce it. */ + for(p = (NX_DNS_RR*)((ALIGN_TYPE*)cache_ptr + 1); p < (NX_DNS_RR*)head; p++) + { + + if (!p -> nx_dns_rr_name) + continue; + + /* Calculate the elapsed time. */ + elapsed_time = current_time - p -> nx_dns_rr_last_used_time; + + /* Step1. Find the expired resource record. */ + if ((elapsed_time / NX_IP_PERIODIC_RATE) >= p ->nx_dns_rr_ttl) + { + + /* Yes, find it. */ + rr = p; + break; + } + + /* Step2. Find the aging resource record. */ + if (elapsed_time >= max_elapsed_time) + { + rr = p; + max_elapsed_time = elapsed_time; + } + } + + /* Check the replacement resource record. */ + if (rr) + { + + /* Delete this record. */ + _nx_dns_cache_delete_rr(dns_ptr, cache_ptr, cache_size, rr); + + /* Update the head. */ + head = (ALIGN_TYPE*)cache_ptr; + head = (ALIGN_TYPE*)(*head); + } + else + { + return(NX_DNS_CACHE_ERROR); + } + } + else + { + rr = (NX_DNS_RR*)head; + } + } + + /* Just copy it to cache_ptr. */ + memcpy(rr, record_ptr, sizeof(NX_DNS_RR)); + + /* Update the resource record count. */ + dns_ptr -> nx_dns_rr_count ++; + + /* Get the current time to set the elapsed time. */ + rr -> nx_dns_rr_last_used_time = current_time; + + /* Set the insert ptr. */ + if(insert_ptr != NX_NULL) + *insert_ptr = rr; + + if((ALIGN_TYPE*)rr >= head) + { + + /* Update HEAD when new record is added. */ + head = (ALIGN_TYPE*)cache_ptr; + *head = (ALIGN_TYPE)(rr + 1); + } + + return(NX_DNS_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_find_answer PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the answer of DNS query in record buffer. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance. */ +/* cache_ptr Pointer to the record buffer */ +/* query_name RR Query name */ +/* query_type RR Query type */ +/* buffer Pointer to buffer */ +/* buffer_size The size of record_buffer */ +/* record_count The count of RR stored */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_find_answer(NX_DNS *dns_ptr, VOID *cache_ptr, UCHAR *query_name, USHORT query_type, UCHAR *buffer, UINT buffer_size, UINT *record_count) +{ + +ALIGN_TYPE *head; +NX_DNS_RR *p; +ULONG current_time; +ULONG elasped_ttl; +UINT old_count; +UINT answer_count; +UCHAR *buffer_prepend_ptr; +UINT query_name_length; +UINT name_string_length; +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +UCHAR *buffer_append_ptr; +NX_DNS_NS_ENTRY *nx_dns_ns_entry_ptr; +NX_DNS_MX_ENTRY *nx_dns_mx_entry_ptr; +NX_DNS_SRV_ENTRY *nx_dns_srv_entry_ptr; +NX_DNS_SOA_ENTRY *nx_dns_soa_entry_ptr; +UINT rname_string_length; +UINT mname_string_length; +#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ + + + /* Check the query name string. */ + if (_nx_utility_string_length_check((CHAR *)query_name, &query_name_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Initialize the value. */ + old_count = 0; + answer_count = 0; + if(record_count) + *record_count = 0; + + /* Set the buffer pointer. */ + buffer_prepend_ptr = buffer; +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + buffer_append_ptr = buffer + buffer_size; +#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ + + /* Get the current time. */ + current_time = tx_time_get(); + + /* Get head. */ + head = (ALIGN_TYPE*)cache_ptr; + head = (ALIGN_TYPE*)(*head); + + /* Lookup the cache to delete the expired resource record and find the answer. */ + for(p = (NX_DNS_RR*)((UCHAR*)cache_ptr + sizeof(ALIGN_TYPE)); (ALIGN_TYPE*)p < head; p++) + { + + /* Check whether the resource record is valid. */ + if (!p -> nx_dns_rr_name) + continue; + + /* Calucate the elapsed time. */ + elasped_ttl = (current_time - p -> nx_dns_rr_last_used_time) / NX_IP_PERIODIC_RATE; + + /* Compare the ttl. */ + if (elasped_ttl >= p -> nx_dns_rr_ttl) + { + + /* The resource record is expired, Delete the resource record. */ + _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, p); + continue; + } + + /* Check the resource record type. */ + if (p -> nx_dns_rr_type != query_type) + continue; + + /* Check the resource record name. */ + if (_nx_dns_name_match(p -> nx_dns_rr_name, query_name, query_name_length)) + continue; + + /* Update the elasped time and ttl. */ + p -> nx_dns_rr_last_used_time = current_time; + p -> nx_dns_rr_ttl -= elasped_ttl; + + /* Yes, get the answer. */ + + /* Check the type. */ + switch (query_type) + { + + case NX_DNS_RR_TYPE_A: + { + + /* Check the buffer size. */ + if (buffer_size < 4) + break; + + /* Set the IPv4 address. */ + *(ULONG *)buffer_prepend_ptr = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_a.nx_dns_rr_a_address; + + /* Update the count and pointer. */ + answer_count++; + buffer_size -= 4; + buffer_prepend_ptr += 4; + + break; + } + case NX_DNS_RR_TYPE_AAAA: + { + + /* Check the buffer size. */ + if (buffer_size < 16) + break; + + /* Set the IPv6 address. */ + *(ULONG *)buffer_prepend_ptr = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[0]; + *(ULONG *)(buffer_prepend_ptr + 4) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[1]; + *(ULONG *)(buffer_prepend_ptr + 8) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[2]; + *(ULONG *)(buffer_prepend_ptr + 12) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[3]; + + /* Update the count and pointer. */ + answer_count++; + buffer_size -= 16; + buffer_prepend_ptr += 16; + + break; + } + case NX_DNS_RR_TYPE_PTR: +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + case NX_DNS_RR_TYPE_CNAME: + case NX_DNS_RR_TYPE_TXT: +#endif + { + + /* PTR, CNAME, TXT record should be only one answer, union: ptr name, cname name, and txt data. */ + /* Check the name string. */ + if (_nx_utility_string_length_check((CHAR *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, &name_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure there is enough room to store the name and null-terminator. */ + if (buffer_size < (name_string_length + 1)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Set the cname string. */ + memcpy((char *)buffer_prepend_ptr, (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, name_string_length); + + /* Return success. */ + return (NX_DNS_SUCCESS); + } +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + case NX_DNS_RR_TYPE_NS: + { + + /* Check the name string. */ + if (_nx_utility_string_length_check((CHAR *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name, &name_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure there is enough room to store the name and null-terminator. */ + if (buffer_size < (sizeof(NX_DNS_NS_ENTRY) + name_string_length + 1)) + break; + + /* Set the ns entry pointer. */ + nx_dns_ns_entry_ptr = (NX_DNS_NS_ENTRY *)(buffer_prepend_ptr); + + /* Update the store pointer. include the null flag '\0'. */ + buffer_append_ptr -= (name_string_length + 1); + + /* Set the ns string. */ + memcpy((char *)buffer_append_ptr, (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name, name_string_length); + nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr = buffer_append_ptr; + + /* Update the count and pointer. */ + answer_count++; + buffer_size -= (sizeof(NX_DNS_NS_ENTRY) + name_string_length + 1); + buffer_prepend_ptr += sizeof(NX_DNS_NS_ENTRY); + + break; + } + case NX_DNS_RR_TYPE_MX: + { + + /* Check the name string. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata + 2), &name_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure there is enough room to store the name and null-terminator. */ + if (buffer_size < (sizeof(NX_DNS_MX_ENTRY) + name_string_length + 1)) + break; + + /* Set the mx entry pointer. */ + nx_dns_mx_entry_ptr = (NX_DNS_MX_ENTRY *)(buffer_prepend_ptr); + + /* Set the mx preference. */ + nx_dns_mx_entry_ptr -> nx_dns_mx_preference = *(USHORT *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata; + + /* Update the store pointer. include the null flag '\0'. */ + buffer_append_ptr -= (name_string_length + 1); + + /* Set the mx string. */ + memcpy((char *)buffer_append_ptr, (char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata + 2), name_string_length); + nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr = buffer_append_ptr; + + /* Update the count and pointer. */ + answer_count++; + buffer_size -= (sizeof(NX_DNS_MX_ENTRY) + name_string_length + 1); + buffer_prepend_ptr += sizeof(NX_DNS_MX_ENTRY); + + break; + } + case NX_DNS_RR_TYPE_SRV: + { + + /* Check the name string. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 6), &name_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure there is enough room to store the name and null-terminator. */ + if (buffer_size < (sizeof(NX_DNS_SRV_ENTRY) + name_string_length + 1)) + break; + + /* Set the srv entry pointer. */ + nx_dns_srv_entry_ptr = (NX_DNS_SRV_ENTRY *)(buffer_prepend_ptr); + + /* Set the priority, weight and port number. */ + nx_dns_srv_entry_ptr -> nx_dns_srv_priority = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata); + nx_dns_srv_entry_ptr -> nx_dns_srv_weight = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 2); + nx_dns_srv_entry_ptr -> nx_dns_srv_port_number = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 4); + + /* Update the store pointer. include the null flag '\0'. */ + buffer_append_ptr -= (name_string_length + 1); + + /* Set the srv string. */ + memcpy((char *)buffer_append_ptr, (char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 6), name_string_length); + nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr = buffer_append_ptr; + + /* Update the count and pointer. */ + answer_count++; + buffer_size -= (sizeof(NX_DNS_SRV_ENTRY) + name_string_length + 1); + buffer_prepend_ptr += sizeof(NX_DNS_SRV_ENTRY); + + break; + } + case NX_DNS_RR_TYPE_SOA: + { + + /* Check the mname string. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata), &mname_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Check the rname string. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + 1), &rname_string_length, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Make sure there is enough room to store the name and null-terminator. */ + if (buffer_size < (sizeof(NX_DNS_SOA_ENTRY) + mname_string_length + rname_string_length + 2)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + + /* Set the soa entry pointer. */ + nx_dns_soa_entry_ptr = (NX_DNS_SOA_ENTRY *)(buffer_prepend_ptr); + + /* Update the store pointer. include the null flag '\0'. */ + buffer_append_ptr -= (mname_string_length + rname_string_length + 2); + + /* Set the soa mname string. */ + memcpy((char *)(buffer_append_ptr), (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata, mname_string_length); + nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr = buffer_append_ptr; + + /* Set the soa rname string. */ + memcpy((char *)(buffer_append_ptr + mname_string_length + 1), (const char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + 1), rname_string_length); + nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr = (buffer_append_ptr + mname_string_length + 1); + + /* Set the SOA Serial, Refresh, Retry, Expire, Minmum. */ + nx_dns_soa_entry_ptr -> nx_dns_soa_serial = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 2); + nx_dns_soa_entry_ptr -> nx_dns_soa_refresh = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 6); + nx_dns_soa_entry_ptr -> nx_dns_soa_retry = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 10); + nx_dns_soa_entry_ptr -> nx_dns_soa_expire = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 14); + nx_dns_soa_entry_ptr -> nx_dns_soa_minmum = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 18); + + /* Return success. */ + return (NX_DNS_SUCCESS); + } +#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ + } + + /* Check if the answer count is updated. */ + if (old_count == answer_count) + { + + /* The answer count is not updated, means the buffer is not enough, stop finding. */ + break; + } + else + { + /* Update the old count. */ + old_count = answer_count; + } + } + + /* Check the answer count. */ + if (answer_count) + { + + /* Update the record count. */ + if (record_count) + *record_count = answer_count; + return (NX_DNS_SUCCESS); + } + else + { + return(NX_DNS_ERROR); + } +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_delete_rr PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DNS resource record from cache. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_delete_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr) +{ + +ALIGN_TYPE *head; + + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Delete the resource record strings. */ + _nx_dns_cache_delete_rr_string(dns_ptr, cache_ptr,cache_size, record_ptr); + + /* Zero out the record. */ + memset(record_ptr, 0, sizeof(NX_DNS_RR)); + + /* Update the resource record count. */ + dns_ptr -> nx_dns_rr_count --; + + /* Get head. */ + head = (ALIGN_TYPE*)cache_ptr; + head = (ALIGN_TYPE*)(*head); + + /* Move HEAD if the last RR is deleted. */ + if(record_ptr == ((NX_DNS_RR*)head - 1)) + { + while(!record_ptr -> nx_dns_rr_type) + { + record_ptr--; + if(record_ptr < (NX_DNS_RR*)cache_ptr) + break; + } + *((ALIGN_TYPE*)cache_ptr) = (ALIGN_TYPE)(record_ptr + 1); + } + + return(NX_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_delete_rr_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DNS entry string from the record cache. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_delete_rr_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr) +{ + +UINT string_len; +UINT size; + + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Compare the resource record type. */ + if((record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_PTR) +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + || + (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_TXT) || + (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_CNAME) || + (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_NS) +#endif + ) + { + + /* Delete the rdata name string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, 0); + } + else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_AAAA) + { + + /* Delete the IPv6 address string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address, 16); + } +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_SRV) + { + + /* Compute the SRV rdata length. */ + if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata), &size, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + string_len = (UINT)(size + 6); + + /* Delete the SRV rdata string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata, string_len); + } + else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_MX) + { + + /* Compute the MX rdata length. */ + if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata), &size, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + string_len = (UINT)(size + 2); + + /* Delete the MX rdata string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata, string_len); + } + else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_SOA) + { + + /* Compute the SOA rdata length. */ + if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata), &size, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + string_len = size; /* MNAME */ + string_len += 1; /* '\0' */ + + if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + string_len), &size, NX_DNS_NAME_MAX)) + { + + /* Return. */ + return(NX_DNS_CACHE_ERROR); + } + string_len += size; /* RNAME */ + string_len += 1; /* '\0' */ + string_len += 20; /* Serial, Refresh, Retry, Expire, Minmum. */ + + /* Delete the SRV rdata string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata, string_len); + } +#endif + + /* Delete the name string. */ + _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_name, 0); + + return(NX_DNS_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_add_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds or finds the DNS string in the cache. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_add_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_size, VOID **insert_ptr) +{ + +ALIGN_TYPE *tail; +ALIGN_TYPE *head; +UINT string_len; +USHORT len, cnt; +USHORT min_len = 0xFFFF; +UCHAR *p, *available, *start; + + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Get head and tail. */ + tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; + p = (UCHAR*)tail; + tail = (ALIGN_TYPE*)(*tail); + head = (ALIGN_TYPE*)cache_ptr; + head = (ALIGN_TYPE*)(*head); + + /* Calculate the amount of memory needed to store this string, including CNT and LEN fields. */ + + /* Make the length 4 bytes align. */ + string_len = string_size; + + /* Add the length of CNT and LEN fields. */ + string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + available = (UCHAR*)tail; + while(p > (UCHAR*)tail) + { + + /* Get len and cnt. */ + len = *((USHORT*)(p - 2)); + cnt = *((USHORT*)(p - 4)); + start = p - len; + + if((len == string_len) && + (!_nx_dns_name_match(start, string_ptr, string_size))) + { + + /* The same string exists in the string table. */ + if(insert_ptr) + *insert_ptr = start; + + /* Increase the use count CNT. */ + cnt++; + *((USHORT*)(p - 4)) = cnt; + + return(NX_SUCCESS); + } + + /* This slot is not being used. The size of the slot is a smaller + fit for this string. */ + if((cnt == 0) && (len >= string_len) && (len < min_len)) + { + + /* This place is better to insert. */ + available = p; + min_len = len; + } + + /* Move to the next string. */ + p = start; + } + + /* If we reach this point, the string needs to be added to the string table. */ + if(available == (UCHAR*)tail) + { + + /* Make sure the service cache still has room to add this string + (without overwriting the RR area.) */ + if(((UCHAR*)tail - string_len) < (UCHAR*)head) + { + + /* This service cache does not have room for the string table to grow. */ + /* Invoke user-installed cache full notify function .*/ + if(dns_ptr -> nx_dns_cache_full_notify) + { + + /* Call the notify function. */ + (dns_ptr -> nx_dns_cache_full_notify)(dns_ptr); + } + + /* The buffer is full. */ + return(NX_DNS_SIZE_ERROR); + } + + /* Update TAIL. */ + *((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1) = (ALIGN_TYPE)(available - string_len); + + } + else if(string_len < min_len) + { + + /* Set the LEN for remaining space. */ + *((USHORT*)(available - 2 - string_len)) = (USHORT)(min_len - string_len); + } + + /* Set LEN and CNT. */ + *((USHORT*)(available - 2)) = (USHORT)string_len; + *((USHORT*)(available - 4)) = 1; + + /* Clear last 4 bytes. */ + *((ULONG*)(available - 8)) = 0; + + /* Insert string to cache. */ + memcpy(available - string_len, string_ptr, string_size); + + /* Set end character 0. */ + *(available - string_len + string_size) = 0; + + /* Update the string length and count . */ + dns_ptr -> nx_dns_string_count ++; + dns_ptr -> nx_dns_string_bytes += string_len; + + if(insert_ptr) + *insert_ptr = available - string_len; + + return(NX_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_cache_delete_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the DNS string from the record buffer. */ +/* */ +/* INPUT */ +/* */ +/* dns_ptr Pointer to DNS instance. */ +/* cache_ptr Pointer to the record buffer */ +/* cache_size The size of buffer. */ +/* string_ptr Pointer to the string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_cache_delete_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_len) +{ + +ALIGN_TYPE *tail; +ALIGN_TYPE *end; +USHORT cnt; + + + /* Check the cache. */ + if (cache_ptr == NX_NULL) + return(NX_DNS_CACHE_ERROR); + + /* Validate input parameter. */ + if (string_ptr == NX_NULL) + return(NX_DNS_PARAM_ERROR); + + /* Validate string. */ + if (_nx_utility_string_length_check((CHAR *)string_ptr, &string_len, NX_DNS_NAME_MAX)) + return(NX_DNS_SIZE_ERROR); + + /* Add the length of CNT and LEN fields. */ + /* Also make the total length 4 bytes align. */ + string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + end = (ALIGN_TYPE*)((UCHAR*)string_ptr + string_len); + + /* Get tail. */ + + /* Validate the string table. */ + tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; + if(end > tail) + { + + /* The end of string exceeds cache_ptr. */ + return(NX_DNS_SIZE_ERROR); + } + tail = (ALIGN_TYPE*)(*tail); + if((UCHAR*)string_ptr < (UCHAR*)tail) + { + + /* The end of string exceeds cache_ptr. */ + return(NX_DNS_SIZE_ERROR); + } + + /* Decrease the usage counter value. */ + cnt = *((USHORT*)((UCHAR*)end - 4)); + cnt--; + *((USHORT*)((UCHAR*)end - 4)) = cnt; + + /* Clear the memory if cnt is zero. */ + if(cnt == 0) + { + memset(string_ptr, 0, string_len - 2); + + /* Update the string length and count . */ + dns_ptr -> nx_dns_string_count --; + dns_ptr -> nx_dns_string_bytes -= string_len; + + /* Update the tail pointer if the string at the tail is deleted. */ + if(string_ptr == tail) + { + tail = end; + + while(end < ((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1)) + { + + /* Set the string pt and string length. */ + string_ptr = end; + + /* Validate string. */ + if (_nx_utility_string_length_check((CHAR *)string_ptr, &string_len, NX_DNS_NAME_MAX)) + return(NX_DNS_SIZE_ERROR); + + /* Check the string length. */ + if(string_len == 0) + { + + /* This slot is cleared. */ + while(*((ULONG*)string_ptr) == 0) + string_ptr = (UCHAR*)string_ptr + 4; + + end = (ALIGN_TYPE*)((UCHAR*)string_ptr + 4); + cnt = *((USHORT*)string_ptr); + } + else + { + + /* Make the length 4 bytes align and add the length of CNT and LEN fields. */ + string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + end = (ALIGN_TYPE*)((UCHAR*)string_ptr + string_len); + cnt = *((USHORT*)((UCHAR*)end - 4)); + } + + /* Check whether this slot is never referenced. */ + if(cnt == 0) + tail = end; + else + break; + } + *((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1) = (ALIGN_TYPE)tail; + } + } + + return(NX_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ + + +#ifdef NX_DNS_CACHE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_dns_name_match PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function name string match, the lowercase letters "a" to "z" */ +/* match their uppercase equivalents "A" to "Z". */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_dns_name_match(UCHAR *src, UCHAR *dst, UINT length) +{ + +UINT index = 0; + + + /* Check the name. */ + while (*dst != '\0') + { + if((*src) != (*dst)) + { + if((((*src) | 0x20) >= 'a') && (((*src) | 0x20) <= 'z')) + { + /* Match the characters, case in-sensitive. */ + if(((*src) | 0x20) != ((*dst) | 0x20)) + return(NX_DNS_NAME_MISMATCH); + } + else + { + return(NX_DNS_NAME_MISMATCH); + } + } + src ++; + dst ++; + index ++; + } + + /* Check the scan length. */ + if (index != length) + { + return (NX_DNS_NAME_MISMATCH); + } + + /* Return success. */ + return(NX_DNS_SUCCESS); +} +#endif /* NX_DNS_CACHE_ENABLE */ diff --git a/addons/dns/nxd_dns.h b/addons/dns/nxd_dns.h new file mode 100644 index 00000000..e646484d --- /dev/null +++ b/addons/dns/nxd_dns.h @@ -0,0 +1,1013 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Domain Name System (DNS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_dns.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Domain Name System Protocol (DNS) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_DNS_H +#define NXD_DNS_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_udp.h" +#include "nx_ipv4.h" +#include "nx_ipv6.h" + +/* Define the DNS ID. */ + +#define NX_DNS_ID 0x444e5320UL + +/* Define message and name limits. */ + +#define NX_DNS_LABEL_MAX 63 /* Maximum Label (between to dots) size */ +#define NX_DNS_NAME_MAX 255 /* Maximum Name size */ +#define NX_DNS_IP_LOOKUP_SIZE 75 /* IPv6 needs 66 characters for the address plus 8 for the ip6.arpa plus null */ + /* IPv4 needs 12 characters max for the address plus 12 for the IN-ADDR.ARPA plus null */ + + +/* Define offsets into the DNS message buffer. */ + +#define NX_DNS_ID_OFFSET 0 /* Offset to ID code in DNS buffer */ +#define NX_DNS_FLAGS_OFFSET 2 /* Offset to flags in DNS buffer */ +#define NX_DNS_QDCOUNT_OFFSET 4 /* Offset to Question Count in DNS buffer */ +#define NX_DNS_ANCOUNT_OFFSET 6 /* Offset to Answer Count in DNS buffer */ +#define NX_DNS_NSCOUNT_OFFSET 8 /* Offset to Authority Count in DNS buffer */ +#define NX_DNS_ARCOUNT_OFFSET 10 /* Offset to Additional Info. Count in DNS buffer */ +#define NX_DNS_QDSECT_OFFSET 12 /* Offset to Question Section in DNS buffer */ + + +/* Define return code constants. */ + +#define NX_DNS_SUCCESS 0x00 /* DNS success */ +#define NX_DNS_ERROR 0xA0 /* DNS internal error */ +#define NX_DNS_NO_SERVER 0xA1 /* No DNS server was specified */ +#define NX_DNS_TIMEOUT 0xA2 /* DNS timeout occurred */ +#define NX_DNS_QUERY_FAILED 0xA3 /* DNS query failed; no DNS server sent an 'answer' */ +#define NX_DNS_BAD_ADDRESS_ERROR 0xA4 /* Improperly formatted IPv4 or IPv6 address */ +#define NX_DNS_SIZE_ERROR 0xA5 /* DNS destination size is too small */ +#define NX_DNS_MALFORMED_PACKET 0xA6 /* Improperly formed or corrupted DNS packet received */ +#define NX_DNS_BAD_ID_ERROR 0xA7 /* DNS packet from server does not match query ID */ +#define NX_DNS_PARAM_ERROR 0xA8 /* Invalid non pointer input to API */ +#define NX_DNS_SERVER_NOT_FOUND 0xA9 /* Server not found in Client list of DNS servers */ +#define NX_DNS_PACKET_CREATE_ERROR 0xAA /* Error creating DNS packet */ +#define NX_DNS_EMPTY_DNS_SERVER_LIST 0xAB /* DNS Client's list of DNS servers is empty */ +#define NX_DNS_SERVER_AUTH_ERROR 0xAC /* Server not able to authenticate answer/authority data*/ +#define NX_DNS_ZERO_GATEWAY_IP_ADDRESS 0xAD /* DNS Client IP instance has a zero gateway IP address */ +#define NX_DNS_MISMATCHED_RESPONSE 0xAE /* Server response type does not match the query request*/ +#define NX_DNS_DUPLICATE_ENTRY 0xAF /* Duplicate entry exists in DNS server table */ +#define NX_DNS_RETRY_A_QUERY 0xB0 /* SOA status returned; web site only exists as IPv4 */ +#define NX_DNS_IPV6_DISABLED_ERROR 0xB1 /* Cannot process AAAA or PTR record with IPv6 disabled */ +#define NX_DNS_INVALID_ADDRESS_TYPE 0xB2 /* IP address type (e.g. IPv6) not supported */ +#define NX_DNS_IPV6_NOT_SUPPORTED 0xB3 /* Cannot process AAAA or PTR record with IPv6 disabled */ +#define NX_DNS_NEED_MORE_RECORD_BUFFER 0xB4 /* The buffer size is not enough. */ +#define NX_DNS_FEATURE_NOT_SUPPORTED 0xB5 /* The requested feature is not supported in this build */ +#define NX_DNS_NAME_MISMATCH 0xB6 /* The name mismatch. */ +#define NX_DNS_CACHE_ERROR 0xB7 /* The Cache size is not enough. */ + + +/* Define constants for the flags word. */ + +#define NX_DNS_QUERY_MASK 0x8000 +#define NX_DNS_RESPONSE_FLAG 0x8000 +#define NX_DNS_ERROR_MASK 0x8002 /* Server response indicates an error or data not authenticated by server */ + + +#define NX_DNS_OPCODE_QUERY (0 << 12) /* Shifted right 12 is still 0 */ +#define NX_DNS_OPCODE_IQUERY (1 << 12) /* 1 shifted right by 12 */ +#define NX_DNS_OPCODE_STATUS (2 << 12) /* 2 shifted right by 12 */ + +#define NX_DNS_AA_FLAG 0x0400 /* Authoritative Answer */ +#define NX_DNS_TC_FLAG 0x0200 /* Truncated */ +#define NX_DNS_RD_FLAG 0x0100 /* Recursive Query */ +#define NX_DNS_RA_FLAG 0x0080 /* Recursion Available */ +#define NX_DNS_FA_FLAG 0x0010 /* Force Authentication */ + +#define NX_DNS_RCODE_MASK 0x000f /* Isolate the Result Code */ +#define NX_DNS_RCODE_SUCCESS 0 +#define NX_DNS_RCODE_FORMAT_ERR 1 +#define NX_DNS_RCODE_SERVER_ERR 2 +#define NX_DNS_RCODE_NAME_ERR 3 +#define NX_DNS_RCODE_NOT_IMPL 4 +#define NX_DNS_RCODE_REFUSED 5 + +#define NX_DNS_QUERY_FLAGS (NX_DNS_OPCODE_QUERY | NX_DNS_RD_FLAG) /* | NX_DNS_FA_FLAG */ + +/* Define name compression masks. */ + +#define NX_DNS_COMPRESS_MASK 0xc0 +#define NX_DNS_COMPRESS_VALUE 0xc0 +#define NX_DNS_POINTER_MASK 0xc000 + +/* Define resource record types. */ + +#define NX_DNS_RR_TYPE_A 1 /* Host address */ +#define NX_DNS_RR_TYPE_NS 2 /* Authoritative name server */ +#define NX_DNS_RR_TYPE_MD 3 /* Mail destination (Obsolete - use MX) */ +#define NX_DNS_RR_TYPE_MF 4 /* Mail forwarder (Obsolete - use MX) */ +#define NX_DNS_RR_TYPE_CNAME 5 /* Canonical name for an alias */ +#define NX_DNS_RR_TYPE_SOA 6 /* Marks the start of a zone of authority */ +#define NX_DNS_RR_TYPE_MB 7 /* Mailbox domain name (EXPERIMENTAL) */ +#define NX_DNS_RR_TYPE_MG 8 /* Mail group member (EXPERIMENTAL) */ +#define NX_DNS_RR_TYPE_MR 9 /* Mail rename domain name (EXPERIMENTAL) */ +#define NX_DNS_RR_TYPE_NULL 10 /* Null RR (EXPERIMENTAL) */ +#define NX_DNS_RR_TYPE_WKS 11 /* Well known service description */ +#define NX_DNS_RR_TYPE_PTR 12 /* Domain name pointer */ +#define NX_DNS_RR_TYPE_HINFO 13 /* Host information */ +#define NX_DNS_RR_TYPE_MINFO 14 /* Mailbox or mail list information */ +#define NX_DNS_RR_TYPE_MX 15 /* Mail exchange */ +#define NX_DNS_RR_TYPE_TXT 16 /* Text strings */ +#define NX_DNS_RR_TYPE_AAAA 28 /* IPv6 Host address */ +#define NX_DNS_RR_TYPE_SRV 33 /* The location of services */ + + +/* Define constants for Qtypes (queries). */ + +#define NX_DNS_RR_TYPE_AXFR 252 /* Request for a transfer of an entire zone */ +#define NX_DNS_RR_TYPE_MAILB 253 /* Request for mailbox-related records (MB, MG or MR) */ +#define NX_DNS_RR_TYPE_MAILA 254 /* Request for mail agent RRs (Obsolete - see MX) */ +#define NX_DNS_RR_TYPE_ALL 255 /* Request for all records */ + +/* Define resource record classes. */ + +#define NX_DNS_RR_CLASS_IN 1 /* Internet */ +#define NX_DNS_RR_CLASS_CS 2 /* CSNET class (Obsolete) */ +#define NX_DNS_RR_CLASS_CH 3 /* CHAOS class */ +#define NX_DNS_RR_CLASS_HS 4 /* Hesiod [Dyer 87] */ + + +/* Define constant valid for Qtypes (queries). */ + +#define NX_DNS_RR_CLASS_ALL 255 /* Any class */ + +/* Define the TCP and UDP port number */ + +#define NX_DNS_PORT 53 /* Port for TX,RX and TCP/UDP */ + + +/* Start of configurable options. */ + +/* Set the IP instance gateway server to be the DNS server if the gateway address is non zero. */ +/* +#define NX_DNS_IP_GATEWAY_AND_DNS_SERVER +*/ + +/* Determine if the Client will create its own packet pool + or let the host application create one. See nx_dns_packet_pool_set + for how to set the DNS packet pool from the host application. */ +/* +#define NX_DNS_CLIENT_USER_CREATE_PACKET_POOL +*/ + +/* Enable the feature to clear off old DNS packets before sending a fresh query. */ +/* +#define NX_DNS_CLIENT_CLEAR_QUEUE +*/ + +/* Enable the feature to send the TXT, CNAME, NS, MX, SRV, SOA DNS types query. */ +/* +#define NX_DNS_ENABLE_EXTENDED_RR_TYPES +*/ + +/* Enable the cache to store the resource record. */ +/* +#define NX_DNS_CACHE_ENABLE +*/ + +/* Define UDP socket create options. */ + +#ifndef NX_DNS_TYPE_OF_SERVICE +#define NX_DNS_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_DNS_FRAGMENT_OPTION +#define NX_DNS_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_DNS_TIME_TO_LIVE +#define NX_DNS_TIME_TO_LIVE 0x80 +#endif + +/* Define the queue depth of the DNS Client socket. */ + +#ifndef NX_DNS_QUEUE_DEPTH +#define NX_DNS_QUEUE_DEPTH 5 +#endif + +/* Define the maximum size of DNS message. 512 is the maximum size defined in RFC 1035 section 2.3.4. */ + +#ifndef NX_DNS_MESSAGE_MAX +#define NX_DNS_MESSAGE_MAX 512 +#endif + +/* Define a payload to include the maximum size DNS message plus the Ethernet, IP and UDP overhead. */ + +#ifndef NX_DNS_PACKET_PAYLOAD_UNALIGNED +#define NX_DNS_PACKET_PAYLOAD_UNALIGNED (NX_UDP_PACKET + NX_DNS_MESSAGE_MAX) +#endif + +/* Round up to a 4 byte aligned packet payload. */ + +#define NX_DNS_PACKET_PAYLOAD (((NX_DNS_PACKET_PAYLOAD_UNALIGNED + sizeof(ULONG) - 1)/sizeof(ULONG)) * sizeof(ULONG)) + +/* Define the size (e.g. number of packets) of the DNS Client + packet pool for sending out DNS messages. */ + +#ifndef NX_DNS_PACKET_POOL_SIZE +#define NX_DNS_PACKET_POOL_SIZE (16 * (NX_DNS_PACKET_PAYLOAD + sizeof(NX_PACKET))) +#endif + + +/* Define the maximum number of retries to a DNS server. */ + +#ifndef NX_DNS_MAX_RETRIES +#define NX_DNS_MAX_RETRIES 3 +#endif + +/* Define size of the DNS server list. Remember to allow for one 'null' terminating + e.g. zero IP address entry for this list. */ + +#ifndef NX_DNS_MAX_SERVERS +#define NX_DNS_MAX_SERVERS 5 +#endif + +/* Define the maximum amount of time to retransmit a DNS query. The default wait time is 64 seconds. + the retransmission policy are recommended in RFC1035 page 32. */ +#ifndef NX_DNS_MAX_RETRANS_TIMEOUT +#define NX_DNS_MAX_RETRANS_TIMEOUT (64 * NX_IP_PERIODIC_RATE) +#endif + +/* Define the timeout option in timer ticks for allocating a packet + from the DNS Client packet pool. */ + +#ifndef NX_DNS_PACKET_ALLOCATE_TIMEOUT +#define NX_DNS_PACKET_ALLOCATE_TIMEOUT NX_IP_PERIODIC_RATE +#endif + + +/* Define the basic DNS data structure. */ + +typedef struct NX_IP_DNS_STRUCT +{ + ULONG nx_dns_id; /* DNS ID */ + UCHAR *nx_dns_domain; /* Pointer to domain name */ + USHORT nx_dns_lookup_type; /* DNS look up type */ + USHORT nx_dns_transmit_id; /* DNS message transmit identifier */ + NX_IP *nx_dns_ip_ptr; /* Pointer to associated IP structure */ + NXD_ADDRESS nx_dns_server_ip_array[NX_DNS_MAX_SERVERS]; /* List of DNS server IP addresses */ + ULONG nx_dns_retries; /* DNS query retries */ +#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + NX_PACKET_POOL nx_dns_pool; /* The pool of UDP data packets for DNS messages */ + UCHAR nx_dns_pool_area[NX_DNS_PACKET_POOL_SIZE]; +#endif + NX_PACKET_POOL *nx_dns_packet_pool_ptr; /* Pointer to DNS Client packet pool */ + NX_UDP_SOCKET nx_dns_socket; /* DNS Socket */ + TX_MUTEX nx_dns_mutex; /* DNS Mutex to protect DNS instance */ +#ifdef NX_DNS_CACHE_ENABLE + UCHAR* nx_dns_cache; /* Pointer to the cache. */ + UINT nx_dns_cache_size; /* The size of cache. */ + ULONG nx_dns_rr_count; /* The number of resource records in the cache. */ + ULONG nx_dns_string_count; /* The number of strings in the cache. */ + ULONG nx_dns_string_bytes; /* The number of total bytes in string table in the cache. */ + VOID (*nx_dns_cache_full_notify)(struct NX_IP_DNS_STRUCT *); +#endif /* NX_DNS_CACHE_ENABLE */ +} NX_DNS; + + +/* Define the RDATA structure. */ +/********************************************************************************/ +/* Type A */ +/********************************************************************************/ + +/* A RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + | ADDRESS | + |-------------------------------------------------------------| +*/ +/* The host name may have multiple addresses,so we need a buffer to record the all addresses. + return_buffer must be 4-byte aligned. This return buffer is used to store IP addresses returned from the server. + record_number stores the number of entries in the buffer. If the server returns more entries than the buffer + can hold, the entries exceeding the buffer size are dropped. */ + +/* Layout of the buffer + |-------------------------------------------------------------------------------------| + |ip.address.0|ip.address.1|ip.address.2|....... |ip.address.n| + |-------------------------------------------------------------------------------------| +*/ + +/********************************************************************************/ +/* Type AAAA */ +/********************************************************************************/ +/* AAAA RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + | ADDRESS | + |-------------------------------------------------------------| + | ADDRESS | + |-------------------------------------------------------------| + | ADDRESS | + |-------------------------------------------------------------| + | ADDRESS | + |-------------------------------------------------------------| +*/ + +typedef struct NX_DNS_IPV6_ADDRESS_STRUCT +{ + ULONG ipv6_address[4]; +} NX_DNS_IPV6_ADDRESS; + + +/* The return_buffer must be 4-byte aligned. This return buffer is used to store IP addresses returned from the server. */ +/* The record_number in the query stores the number of entries in the buffer. If the server returns more entries than the buffer + can hold, the entries exceeding the buffer size are dropped. */ + +/* Layout of the buffer + |---------------------------------------------------------------| + |ip.address.0[0]|ip.address.0[1]|ip.address.0[2]|ip.address.0[3]| + |---------------------------------------------------------------| + |ip.address.1[0]|ip.address.1[1]|ip.address.1[2]|ip.address.1[3]| + |---------------------------------------------------------------| + | | + | .......................................... | + | | + |---------------------------------------------------------------| + |ip.address.n[0]|ip.address.n[1]|ip.address.n[2]|ip.address.n[3]| + |---------------------------------------------------------------| + +*/ + +/********************************************************************************/ +/* PTR */ +/********************************************************************************/ +/* PTR RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + / PTRDNAME / + / / + |-------------------------------------------------------------| +*/ + + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES + +/********************************************************************************/ +/* Type NS */ +/********************************************************************************/ +/* NS RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + / NSDNAME / + / / + |-------------------------------------------------------------| +*/ + +typedef struct NX_DNS_NS_ENTRY_STRUCT +{ + ULONG nx_dns_ns_ipv4_address; /* The name server ipv4 address. */ + UCHAR *nx_dns_ns_hostname_ptr; /* The name server. */ +} NX_DNS_NS_ENTRY; + +/* Store the message in one buffer. Layout of the buffer: + + record_buffer |---------------------------------------------------------------| + entry 0 |xx.xx.xx.xx |Pointer to the host name string | + record_buffer + 8 |---------------------------------------------------------------| + entry 1 |xx.xx.xx.xx |Pointer to the host name string | + record_buffer + 16 |---------------------------------------------------------------| + entry 2 |xx.xx.xx.xx |Pointer to the host name string | + record_buffer + 24 |---------------------------------------------------------------| + entry 3 |xx.xx.xx.xx |Pointer to the host name string | + record_buffer + 32 |---------------------------------------------------------------| + entry 4 |xx.xx.xx.xx |Pointer to the host name string | + record_buffer + 40 |---------------------------------------------------------------| + |xx.xx.xx.xx |Pointer to the host name string | + |---------------------------------------------------------------| + | | ns_hostname 4 | + |ns_hostname 3 | ns_hostname 2 | + |ns_hostname 1 | ns_hostname 0 | + record_buffer + max |---------------------------------------------------------------| + */ + +/********************************************************************************/ +/* CNAME */ +/********************************************************************************/ +/* CNAME RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + / CNAME / + / / + |-------------------------------------------------------------| +*/ + + +/********************************************************************************/ +/* MX */ +/********************************************************************************/ +/* MX RDATA format + 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |-----------------------------| + | PREFERECE | + |-----------------------------| + / EXCHANGE / + / / + |-----------------------------| +*/ + +/* Define the mail exchange record type */ +typedef struct NX_DNS_MAIL_EXCHANGE_ENTRY_STRUCT +{ + ULONG nx_dns_mx_ipv4_address; /* The mail exchange server ipv4 address. */ + USHORT nx_dns_mx_preference; /* The preference given to this RR, Lower values are preferred. */ + USHORT nx_dns_mx_reserved0; /* Keep 4-byte aligned. */ + UCHAR *nx_dns_mx_hostname_ptr; /* The mail exchange server host name. */ +} NX_DNS_MX_ENTRY; + +/* Layout of the buffer + record_buffer |---------------------------------------------------------| + entry 0 |xx.xx.xx.xx|preference|res|pointer to host name string | + record_buffer + 12 |---------------------------------------------------------| + entry 1 |xx.xx.xx.xx|preference|res|pointer to host name string | + record_buffer + 24 |---------------------------------------------------------| + entry 2 |xx.xx.xx.xx|preference|res|pointer to host name string | + record_buffer + 36 |---------------------------------------------------------| + entry 3 |xx.xx.xx.xx|preference|res|pointer to host name string | + record_buffer + 48 |---------------------------------------------------------| + entry 4 |xx.xx.xx.xx|preference|res|pointer to host name string | + record_buffer + 60 |---------------------------------------------------------| + |xx.xx.xx.xx|preference|res|pointer to host name string | + |---------------------------------------------------------| + | | mx_hostname 4 | + |mx_hostname 3 | mx_hostname 2 | + |mx_hostname 1 | mx_hostname 0 | + record_buffer + max |---------------------------------------------------------| +*/ + +/********************************************************************************/ +/* SRV */ +/********************************************************************************/ + +/* Define the service record type. */ +typedef struct NX_DNS_SERVICE_ENTRY_STRUCT +{ + ULONG nx_dns_srv_ipv4_address; + USHORT nx_dns_srv_priority; + USHORT nx_dns_srv_weight; + USHORT nx_dns_srv_port_number; + USHORT nx_dns_srv_reserved0; + UCHAR *nx_dns_srv_hostname_ptr; +} NX_DNS_SRV_ENTRY; + +/* Layout of the buffer: + + record_buffer |-------------------------------------------------------------------| + entry 0 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + record_buffer + 16 |-------------------------------------------------------------------| + entry 1 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + record_buffer + 32 |-------------------------------------------------------------------| + entry 2 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + record_buffer + 48 |-------------------------------------------------------------------| + entry 3 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + record_buffer + 64 |-------------------------------------------------------------------| + entry 4 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + record_buffer + 80 |-------------------------------------------------------------------| + |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | + | | srv_hostname 4 | + |srv_hostname 3 | srv_hostname 2 | + |srv_hostname 1 | srv_hostname 0 | + record_buffer + max |-------------------------------------------------------------------| + +*/ +/********************************************************************************/ +/* TXT */ +/********************************************************************************/ +/* TXT RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + / TXT-DATA / + / / + |-------------------------------------------------------------| +*/ + +/********************************************************************************/ +/* SOA */ +/********************************************************************************/ +/* SOA RDATA format + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + |-------------------------------------------------------------| + / MNAME / + / / + |-------------------------------------------------------------| + / RNAME / + / / + |-------------------------------------------------------------| + | SERIAL | + |-------------------------------------------------------------| + | REFRESH | + |-------------------------------------------------------------| + | RETRY | + |-------------------------------------------------------------| + | EXPIRE | + |-------------------------------------------------------------| + | MINMUM | + |-------------------------------------------------------------| +*/ + +/* Define the service record type. */ + +typedef struct NX_DNS_SOA_ENTRY_STRUCT +{ + + UCHAR *nx_dns_soa_host_mname_ptr; + UCHAR *nx_dns_soa_host_rname_ptr; + ULONG nx_dns_soa_serial; + ULONG nx_dns_soa_refresh; + ULONG nx_dns_soa_retry; + ULONG nx_dns_soa_expire; + ULONG nx_dns_soa_minmum; +} NX_DNS_SOA_ENTRY; + +/* Layout of the buffer + record_buffer + + |-------------------------------------------------------------------| + | pointer to primary name server| pointer to responsible mailbox | + |-------------------------------------------------------------------| + | serial | refresh | retry | expire | minmum | + |-------------------------------------------------------------------| + | soa_host_mname | soa_host_rname | + |-------------------------------------------------------------------| + */ + +/********************************************************************************/ +/* LOC */ +/********************************************************************************/ +/* To be implemented */ + +/********************************************************************************/ +/* NAPTR */ +/********************************************************************************/ +/* To be implemented */ + +/********************************************************************************/ +/* DNAME */ +/********************************************************************************/ +/* To be implemented */ + +#endif + + +/* Define the RDATA structure. */ + +/* A RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | ADDRESS | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_A_STRUCT +{ + ULONG nx_dns_rr_a_address; +} NX_DNS_RR_A; + +/* AAAA RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | | + | | + | | + | IPv6 ADDRESS | + | | + | | + | | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_AAAA_STRUCT +{ + ULONG* nx_dns_rr_aaaa_address; /* Keep the same resource record structure size, store the rdata information into cache with string. */ +} NX_DNS_RR_AAAA; + + +/* PTR RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / PTRDNAME / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_PTR_STRUCT +{ + UCHAR* nx_dns_rr_ptr_name; +} NX_DNS_RR_PTR; + + +/* NS RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / NSDNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_NS_STRUCT +{ + UCHAR* nx_dns_rr_ns_name; +} NX_DNS_RR_NS; + +/* CNMAE RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / CNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_CNAME_STRUCT +{ + UCHAR* nx_dns_rr_cname_name; +} NX_DNS_RR_CNAME; + + +/* MX RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PREFERENCE | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / NEWNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_MX_STRUCT +{ + UCHAR* nx_dns_rr_mx_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string. "preference, newname" */ +} NX_DNS_RR_MX; + +/* TXT RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / TXT-DATA / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_TXT_STRUCT +{ + UCHAR* nx_dns_rr_txt_data; +} NX_DNS_RR_TXT; + +/* SRV RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PRIORITY | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | WEIGHTS | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PORT | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / TARGET / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_SRV_STRUCT +{ + UCHAR* nx_dns_rr_srv_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string, "priority, weights, port,target". */ +} NX_DNS_RR_SRV; + + +/* SOA RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RNAME / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | SERIAL | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | REFRESH | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | RETRY | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | EXPIRE | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | MINMUM | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_DNS_RR_SOA_STRUCT +{ + UCHAR* nx_dns_rr_soa_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string. + "Mname, Rname, Serial, Refresh, Retry, Expire, Minmum" */ +} NX_DNS_RR_SOA; + + +/* The following data structure is used to store the resource records(RRs). */ +typedef struct NX_DNS_RR_STRUCT +{ + + UCHAR* nx_dns_rr_name; /* Owner's name,i.e., the name of the node to which this resource record pertains. */ + + USHORT nx_dns_rr_type; /* RR TYPE. */ + + USHORT nx_dns_rr_class; /* RR CLASS. */ + + ULONG nx_dns_rr_ttl; /* The time interval that the RR may be cached before the source of the information should again be consulted. */ + + ULONG nx_dns_rr_last_used_time; /* Define the last used time for the peer RR. */ + + /* Union that holds resource record data. */ + union nx_dns_rr_rdata_union + { + NX_DNS_RR_A nx_dns_rr_rdata_a; + NX_DNS_RR_AAAA nx_dns_rr_rdata_aaaa; + NX_DNS_RR_PTR nx_dns_rr_rdata_ptr; + NX_DNS_RR_SRV nx_dns_rr_rdata_srv; + NX_DNS_RR_TXT nx_dns_rr_rdata_txt; + NX_DNS_RR_CNAME nx_dns_rr_rdata_cname; + NX_DNS_RR_NS nx_dns_rr_rdata_ns; + NX_DNS_RR_MX nx_dns_rr_rdata_mx; + NX_DNS_RR_SOA nx_dns_rr_rdata_soa; + } nx_dns_rr_rdata; + +}NX_DNS_RR; + + +#ifndef NX_DNS_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_dns_create _nx_dns_create +#define nx_dns_delete _nx_dns_delete +#define nx_dns_packet_pool_set _nx_dns_packet_pool_set +#define nx_dns_host_by_address_get _nx_dns_host_by_address_get +#define nx_dns_host_by_name_get _nx_dns_host_by_name_get +#define nx_dns_ipv4_address_by_name_get _nx_dns_ipv4_address_by_name_get + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +#define nx_dns_cname_get _nx_dns_cname_get +#define nx_dns_domain_name_server_get _nx_dns_domain_name_server_get +#define nx_dns_host_text_get _nx_dns_host_text_get +#define nx_dns_domain_mail_exchange_get _nx_dns_domain_mail_exchange_get +#define nx_dns_domain_service_get _nx_dns_domain_service_get +#define nx_dns_authority_zone_start_get _nx_dns_authority_zone_start_get +#define nx_dns_info_by_name_get _nx_dns_info_by_name_get +#endif + +#define nx_dns_server_add _nx_dns_server_add +#define nx_dns_server_remove _nx_dns_server_remove +#define nx_dns_server_remove_all _nx_dns_server_remove_all +#define nx_dns_server_get _nx_dns_server_get +#define nx_dns_get_serverlist_size _nx_dns_get_serverlist_size + +#define nxd_dns_ipv6_address_by_name_get _nxd_dns_ipv6_address_by_name_get +#define nxd_dns_host_by_address_get _nxd_dns_host_by_address_get +#define nxd_dns_host_by_name_get _nxd_dns_host_by_name_get +#define nxd_dns_server_add _nxd_dns_server_add +#define nxd_dns_server_remove _nxd_dns_server_remove +#define nxd_dns_server_get _nxd_dns_server_get + +#ifdef NX_DNS_CACHE_ENABLE +#define nx_dns_cache_initialize _nx_dns_cache_initialize +#define nx_dns_cache_notify_set _nx_dns_cache_notify_set +#define nx_dns_cache_notify_clear _nx_dns_cache_notify_clear +#endif /* NX_DNS_CACHE_ENABLE */ + +#else + +/* Services with error checking. */ + +#define nx_dns_create _nxe_dns_create +#define nx_dns_delete _nxe_dns_delete +#define nx_dns_packet_pool_set _nxe_dns_packet_pool_set +#define nx_dns_host_by_address_get _nxe_dns_host_by_address_get +#define nx_dns_host_by_name_get _nxe_dns_host_by_name_get +#define nx_dns_ipv4_address_by_name_get _nxe_dns_ipv4_address_by_name_get + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +#define nx_dns_cname_get _nxe_dns_cname_get +#define nx_dns_domain_name_server_get _nxe_dns_domain_name_server_get +#define nx_dns_host_text_get _nxe_dns_host_text_get +#define nx_dns_domain_mail_exchange_get _nxe_dns_domain_mail_exchange_get +#define nx_dns_domain_service_get _nxe_dns_domain_service_get +#define nx_dns_authority_zone_start_get _nxe_dns_authority_zone_start_get +#define nx_dns_info_by_name_get _nxe_dns_info_by_name_get +#endif + +#define nx_dns_server_add _nxe_dns_server_add +#define nx_dns_server_remove _nxe_dns_server_remove +#define nx_dns_server_remove_all _nxe_dns_server_remove_all +#define nx_dns_server_get _nxe_dns_server_get +#define nx_dns_get_serverlist_size _nxe_dns_get_serverlist_size + +#define nxd_dns_ipv6_address_by_name_get _nxde_dns_ipv6_address_by_name_get +#define nxd_dns_host_by_address_get _nxde_dns_host_by_address_get +#define nxd_dns_host_by_name_get _nxde_dns_host_by_name_get +#define nxd_dns_server_add _nxde_dns_server_add +#define nxd_dns_server_remove _nxde_dns_server_remove +#define nxd_dns_server_get _nxde_dns_server_get + +#ifdef NX_DNS_CACHE_ENABLE +#define nx_dns_cache_initialize _nxe_dns_cache_initialize +#define nx_dns_cache_notify_set _nxe_dns_cache_notify_set +#define nx_dns_cache_notify_clear _nxe_dns_cache_notify_clear +#endif /* NX_DNS_CACHE_ENABLE */ + +#endif + +/* Define the prototypes accessible to the application software. */ + +UINT nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); +UINT nx_dns_delete(NX_DNS *dns_ptr); +UINT nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); +UINT nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); +UINT nx_dns_server_remove_all(NX_DNS *dns_ptr); +UINT nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); +UINT nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); +UINT nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); +UINT nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +UINT nx_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT nx_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); +#endif + +UINT nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); +UINT nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address); +UINT nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +UINT nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); + +#ifdef NX_DNS_CACHE_ENABLE +UINT nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); +UINT nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); +UINT nx_dns_cache_notify_clear(NX_DNS *dns_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + +#else + +/* DNS source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); +UINT _nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); +UINT _nxe_dns_delete(NX_DNS *dns_ptr); +UINT _nx_dns_delete(NX_DNS *dns_ptr); +UINT _nxe_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT _nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); +UINT _nxe_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT _nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT _nxe_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); +UINT _nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); +UINT _nxe_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +UINT _nxe_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size,ULONG wait_option); +UINT _nx_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size,ULONG wait_option); +UINT _nxe_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nxe_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT _nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT _nxe_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nxe_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nxe_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT _nx_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); +UINT _nxe_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); +UINT _nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); +#endif + +UINT _nxe_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); +UINT _nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); +UINT _nxe_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); +UINT _nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); +UINT _nxe_dns_server_remove_all(NX_DNS *dns_ptr); +UINT _nx_dns_server_remove_all(NX_DNS *dns_ptr); +UINT _nxe_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); +UINT _nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); +UINT _nxe_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); +UINT _nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); +UINT _nxde_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); +UINT _nxde_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT _nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); +UINT _nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); +UINT _nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); +UINT _nxde_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +UINT _nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +UINT _nxde_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +UINT _nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); +UINT _nxde_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); +UINT _nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); + +#ifdef NX_DNS_CACHE_ENABLE +UINT _nxe_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); +UINT _nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); +UINT _nxe_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); +UINT _nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); +UINT _nxe_dns_cache_notify_clear(NX_DNS *dns_ptr); +UINT _nx_dns_cache_notify_clear(NX_DNS *dns_ptr); +#endif /* NX_DNS_CACHE_ENABLE */ + +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_DNS_H */ + diff --git a/addons/ftp/nxd_ftp_client.c b/addons/ftp/nxd_ftp_client.c new file mode 100644 index 00000000..e85ed09e --- /dev/null +++ b/addons/ftp/nxd_ftp_client.c @@ -0,0 +1,6078 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_FTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* If FileX is not used in your application, define this option. Then define the + services declared in filex_stub.h elsewhere. +#define NX_FTP_NO_FILEX +*/ + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_ipv6.h" +#endif /* FEATURE_NX_IPV6 */ +#include "nxd_ftp_client.h" +#include "stdio.h" +#include "string.h" + + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client connect call. */ +/* */ +/* Note: The string lengths of username and password are limited by */ +/* the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* server_ip FTP server IPv4 address */ +/* username Pointer to login username */ +/* password Pointer to login password */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_ftp_client_connect Actual client connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, + CHAR *password, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid server IP address. */ + if (server_ip == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client connect function. */ + status = _nx_ftp_client_connect(ftp_client_ptr, server_ip, username, password, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(ftp_client_ptr); + NX_PARAMETER_NOT_USED(server_ip); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a previously created FTP instance with the */ +/* FTP server at the specified IP address. */ +/* */ +/* Note: The string lengths of username and password are limited by */ +/* the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* server_ip FTP server IPv4 address */ +/* username Pointer to login username */ +/* password Pointer to login password */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_connect_internal Connect to FTP server using */ +/* IP address */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, + CHAR *password, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +NXD_ADDRESS server_ipduo; + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ipduo.nxd_ip_version = NX_IP_VERSION_V4; + server_ipduo.nxd_ip_address.v4 = server_ip; + + + /* Invoke the real connection call. */ + return (_nx_ftp_client_connect_internal(ftp_client_ptr, &server_ipduo, username, password, wait_option)); +#else + NX_PARAMETER_NOT_USED(ftp_client_ptr); + NX_PARAMETER_NOT_USED(server_ip); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_ftp_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client connect call. */ +/* */ +/* Note: The string lengths of username and password are limited by */ +/* the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* server_ip FTP server IP address */ +/* username Pointer to login username */ +/* password Pointer to login password */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_ftp_client_connect Actual client connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, + CHAR *password, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid server IP address. */ + if (!server_ipduo) + return(NX_IP_ADDRESS_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client connect function. */ + status = _nxd_ftp_client_connect(ftp_client_ptr, server_ipduo, username, password, wait_option); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_ftp_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a previously created FTP instance with the */ +/* FTP server at the specified IP address. */ +/* */ +/* Note: The string lengths of username and password are limited by */ +/* the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* server_ip FTP server IP duo address */ +/* username Pointer to login username */ +/* password Pointer to login password */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_connect_internal Acutal connect service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, + CHAR *password, ULONG wait_option) +{ + + /* Invoke the real connection call. */ + return (_nx_ftp_client_connect_internal(ftp_client_ptr, server_ipduo, username, password, wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_connect_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a previously created FTP instance with the */ +/* FTP server at the specified IP address. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* server_ip FTP server IP address */ +/* username Pointer to login username */ +/* password Pointer to login password */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_bind Bind client socket to port */ +/* nxd_tcp_client_socket_connect Connect to FTP server */ +/* nx_tcp_client_socket_unbind Unbind client socket from port*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive server response */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_connect_internal(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ip, CHAR *username, + CHAR *password, ULONG wait_option) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT length; +UINT i; +UINT status; + + + /* Determine if the client is still in a not connected state. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_NOT_CONNECTED) + { + + /* Already connected, return an error. */ + return(NX_FTP_NOT_DISCONNECTED); + } + + /* Bind the client control socket. */ + status = nx_tcp_client_socket_bind(&(ftp_client_ptr -> nx_ftp_client_control_socket), NX_FTP_CLIENT_SOURCE_PORT, wait_option); + + /* Check for an error. */ + if ((status != NX_SUCCESS) && (status != NX_ALREADY_BOUND)) + { + + /* Unable to bind socket to port. */ + return(status); + } + + /* Connect the socket to the FTP server. */ + status = nxd_tcp_client_socket_connect(&(ftp_client_ptr -> nx_ftp_client_control_socket), server_ip, NX_FTP_SERVER_CONTROL_PORT, wait_option); + + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* Now wait for the "220 " response from the FTP server to indicate the connection has been + established. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Check to see if no packet was received. */ + if (status) + { + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Return. */ + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + length = packet_ptr -> nx_packet_length; + + /* Check for 220 message. */ + if ((length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2')) + { + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(NX_FTP_EXPECTED_22X_CODE); + } + + memset(buffer_ptr, 0, length); + + /* Check if out of boundary. */ + if (((!username) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 11)) || + ((username) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7))) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Now build the user name message. */ + buffer_ptr[0] = 'U'; + buffer_ptr[1] = 'S'; + buffer_ptr[2] = 'E'; + buffer_ptr[3] = 'R'; + buffer_ptr[4] = ' '; + + /* Determine if a user name was supplied. */ + if (username == NX_NULL) + { + + /* No username specified, use "USER". */ + buffer_ptr[5] = 'U'; + buffer_ptr[6] = 'S'; + buffer_ptr[7] = 'E'; + buffer_ptr[8] = 'R'; + buffer_ptr[9] = 13; + buffer_ptr[10]= 10; + + /* Set the length of the packet. */ + packet_ptr -> nx_packet_length = 11; + } + else + { + + /* A username was supplied, copy it into the buffer. */ + for(i = 0; username[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy byte of the username. */ + buffer_ptr[5+i] = (UCHAR)username[i]; + } + + /* Now insert the CR/LF. */ + buffer_ptr[5+i] = 13; + buffer_ptr[5+i+1] = 10; + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = i + 7; + } + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the username to the FTP server. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Check for unsuccessful send. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* There may be multiple 220 responses from FTP server after establishing connection. + Flush mutiple 220 respones and wait for 331 response from the FTP server. */ + while(1) + { + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Return. */ + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 220 message. */ + if ((packet_ptr -> nx_packet_length >= 3) && (buffer_ptr[0] == '2') && (buffer_ptr[1] == '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + continue; + } + + /* Check to make sure the response is proper. */ + + /* Check for 331 message. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '3') || (buffer_ptr[1] != '3')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(NX_FTP_EXPECTED_33X_CODE); + } + else + { + break; + } + } + + memset(buffer_ptr, 0, length); + + /* Check if out of boundary. */ + if (((!password) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 11)) || + ((password) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7))) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Now build the password message. */ + buffer_ptr[0] = 'P'; + buffer_ptr[1] = 'A'; + buffer_ptr[2] = 'S'; + buffer_ptr[3] = 'S'; + buffer_ptr[4] = ' '; + + /* Determine if a password was specified. */ + if (password == NX_NULL) + { + + /* No password was specified, use "PASS". */ + buffer_ptr[5] = 'P'; + buffer_ptr[6] = 'A'; + buffer_ptr[7] = 'S'; + buffer_ptr[8] = 'S'; + buffer_ptr[9] = 13; + buffer_ptr[10]= 10; + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = 11; + } + else + { + + /* Password was specified, copy it into the buffer. */ + for(i = 0; password[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy byte of password. */ + buffer_ptr[5+i] = (UCHAR)password[i]; + } + + /* Now insert the CR/LF. */ + buffer_ptr[5+i] = 13; + buffer_ptr[5+i+1] = 10; + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = i + 7; + } + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the password to the FTP server. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Check for successful send. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 230 message, signaling successful login. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '3')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Close the socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(NX_FTP_EXPECTED_23X_CODE); + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* If we get here, we have a successful connect with the FTP server. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_CONNECTED; + + ftp_client_ptr -> nx_ftp_client_data_port = ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_port; + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* ftp_client_name Name of this FTP client */ +/* ip_ptr Pointer to IP instance */ +/* window_size Size of TCP receive window */ +/* pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, + ULONG window_size, NX_PACKET_POOL *pool_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id == NXD_FTP_CLIENT_ID) || + (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual client create function. */ + status = _nx_ftp_client_create(ftp_client_ptr, ftp_client_name, ip_ptr, window_size, pool_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an FTP client instance. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* ftp_client_name Name of this FTP client */ +/* ip_ptr Pointer to IP instance */ +/* window_size Size of TCP receive window */ +/* pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create TCP socket */ +/* nx_tcp_socket_delete Delete TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, + ULONG window_size, NX_PACKET_POOL *pool_ptr) +{ + +UINT status; + + + /* Clear the client FTP control block. */ + memset((void *) ftp_client_ptr, 0, sizeof(NX_FTP_CLIENT)); + + /* Create the TCP control socket. */ + status = nx_tcp_socket_create(ip_ptr, &(ftp_client_ptr -> nx_ftp_client_control_socket), ftp_client_name, + NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, window_size, + NX_NULL, NX_NULL); + + /* Check for an error. */ + if (status) + { + + /* Return an error. */ + return(status); + } + + /* Create the TCP data socket. */ + status = nx_tcp_socket_create(ip_ptr, &(ftp_client_ptr -> nx_ftp_client_data_socket), ftp_client_name, + NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, window_size, + NX_NULL, _nx_ftp_client_data_disconnect); + + /* Check for an error. */ + if (status) + { + + /* Delete the control socket. */ + nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Return an error. */ + return(status); + } + + /* Save off the remaining information. */ + + /* Save the client name. */ + ftp_client_ptr -> nx_ftp_client_name = ftp_client_name; + + /* Save the IP pointer. */ + ftp_client_ptr -> nx_ftp_client_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + ftp_client_ptr -> nx_ftp_client_packet_pool_ptr = pool_ptr; + + /* Set the initial client state. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_NOT_CONNECTED; + + /* Set the FTP client id. */ + ftp_client_ptr -> nx_ftp_client_id = NXD_FTP_CLIENT_ID; + + /* Default to active transfer mode. */ + ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled = NX_FALSE; + + /* Default to stream mode. */ + ftp_client_ptr -> nx_ftp_client_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_data_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the disconnect from the server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* data_socket_ptr Pointer to FTP client data */ +/* socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_disconnect Disconnect TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ftp_client_data_disconnect(NX_TCP_SOCKET *data_socket_ptr) +{ + + /* Disconnect FTP client data socket. */ + nx_tcp_socket_disconnect(data_socket_ptr, NX_NO_WAIT); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_delete Actual client delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nx_ftp_client_delete(ftp_client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created FTP client instance. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create TCP socket */ +/* nx_tcp_socket_delete Delete TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr) +{ + + /* Determine if the client is still in a not connected state. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_NOT_CONNECTED) + { + + /* Already connected, return an error. */ + return(NX_FTP_NOT_DISCONNECTED); + } + + /* Delete the control and data sockets. */ + nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_data_socket)); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_directory_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client directory */ +/* create call. */ +/* */ +/* Note: The string length of directory_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_name New directory name */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_directory_create Actual client directory */ +/* create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (directory_name == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client directory create function. */ + status = _nx_ftp_client_directory_create(ftp_client_ptr, directory_name, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_directory_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the specified directory name on the FTP */ +/* server. */ +/* */ +/* Note: The string length of directory_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_name New directory name */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive packet from server */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + /* Ensure the client is the proper state for directory create request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Allocate a packet for sending the directory create command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "MKD" message to indicate directory create. */ + buffer_ptr[0] = 'M'; + buffer_ptr[1] = 'K'; + buffer_ptr[2] = 'D'; + buffer_ptr[3] = ' '; + + /* Copy the new directory name into the message. */ + for(i = 0; directory_name[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the directory name. */ + buffer_ptr[4+i] = (UCHAR)directory_name[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+4] = 13; + buffer_ptr[i+5] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+6; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the MKD message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* MKD error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "MKD" was processed successfully. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Create directory error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Yes, the directory was created. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_directory_default_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client directory */ +/* default set. */ +/* */ +/* Note: The string length of directory_path is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_path New default directory path */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_directory_default_set Actual client directory */ +/* default set call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client directory default set function. */ + status = _nx_ftp_client_directory_default_set(ftp_client_ptr, directory_path, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_directory_default_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function changes the default working directory on the FTP */ +/* server. */ +/* */ +/* Note: The string length of directory_path is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_path New default directory path */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive packet from server */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + + /* Ensure the client is the proper state for a default directory request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Allocate a packet for sending the change directory command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "CWD" message to indicate default directory change. */ + buffer_ptr[0] = 'C'; + buffer_ptr[1] = 'W'; + buffer_ptr[2] = 'D'; + buffer_ptr[3] = ' '; + + /* Copy the new default directory into the message. */ + for(i = 0; directory_path[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the directory path. */ + buffer_ptr[4+i] = (UCHAR)directory_path[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+4] = 13; + buffer_ptr[i+5] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+6; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the CWD message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* RNFR file error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "CWD" was processed successfully. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Change directory error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Yes, the default directory was changed. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_directory_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client directory */ +/* delete. */ +/* */ +/* Note: The string length of directory_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_name Directory name to delete */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_directory_delete Actual client directory */ +/* delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client directory delete function. */ + status = _nx_ftp_client_directory_delete(ftp_client_ptr, directory_name, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_directory_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the specified directory on the FTP */ +/* server. */ +/* */ +/* Note: The string length of directory_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_name Directory name to delete */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive packet from server */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + + /* Ensure the client is the proper state for directory delete request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Allocate a packet for sending the directory delete command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "RMD" message to indicate directory delete. */ + buffer_ptr[0] = 'R'; + buffer_ptr[1] = 'M'; + buffer_ptr[2] = 'D'; + buffer_ptr[3] = ' '; + + /* Copy the directory name into the message. */ + for(i = 0; directory_name[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the directory name. */ + buffer_ptr[4+i] = (UCHAR)directory_name[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+4] = 13; + buffer_ptr[i+5] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+6; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the RMD message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* DELE error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "RMD" was processed successfully. */ + if ((packet_ptr -> nx_packet_length < 3) ||(buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Delete directory error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Yes, the directory was deleted. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_directory_listing_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client directory */ +/* listing get. */ +/* */ +/* Note: The string length of directory_path is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_path Directory to get listing for */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* that contains the listing */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_directory_listing_get Actual client directory */ +/* listing get call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, + NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client directory listing get function. */ + status = _nx_ftp_client_directory_listing_get(ftp_client_ptr, directory_path, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_directory_listing_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets a listing for the specified directory on the */ +/* FTP server. */ +/* */ +/* Note: The string length of directory_path is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* directory_path Directory to get listing for */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* that contains the listing */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_packet_allocate Allocate packet */ +/* _nx_ftp_client_active_transfer_setup Setup active transfer */ +/* _nx_ftp_client_passive_transfer_setup Setup passive transfer */ +/* _nx_ftp_client_block_mode_send Send block mode command */ +/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ +/* nx_packet_release Release packet */ +/* nx_tcp_server_socket_accept Connect data socket to server */ +/* nx_tcp_socket_receive Receive response from server */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, + NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *new_packet_ptr; +UINT status; + + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Ensure the client is the proper state for directory listing request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Divert to passive mode operation if passive mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled) + { + + /* Transfer the data in passive transfer mode. */ + status = _nx_ftp_client_passive_transfer_setup(ftp_client_ptr, wait_option); + } + else + { + + /* Transfer the data in active transfer mode. */ + status = _nx_ftp_client_active_transfer_setup(ftp_client_ptr, wait_option); + } + + /* Determine if set up successful. */ + if (status) + { + return(status); + } + + /* Check if enable block mode. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Send MODE B command to FTP server. */ + status = _nx_ftp_client_block_mode_send(ftp_client_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + return(status); + } + } + + /* Allocate a packet for sending the NLST command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &new_packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < 7) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = new_packet_ptr -> nx_packet_prepend_ptr; + + /* Now build the actual NLST request. */ + buffer_ptr[0] = 'N'; + buffer_ptr[1] = 'L'; + buffer_ptr[2] = 'S'; + buffer_ptr[3] = 'T'; + buffer_ptr[4] = ' '; + + /* Copy the directory path into the buffer. */ + for(i = 0; directory_path[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of directory path. */ + buffer_ptr[5+i] = (UCHAR)directory_path[i]; + } + + /* Insert the CR/LF. */ + buffer_ptr[5+i] = 13; + buffer_ptr[5+i+1] = 10; + + /* Setup the length of the packet. */ + new_packet_ptr -> nx_packet_length = i + 7; + + /* Setup the packet append pointer. */ + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + new_packet_ptr -> nx_packet_length; + + /* Send the NLST message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), new_packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Return error. */ + return(status); + } + + /* Check if enable passive mode. */ + if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) + { + + /* Now wait for the data connection to connect. */ + status = nx_tcp_server_socket_accept(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); + + /* Determine if the accept was unsuccessful. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Return error. */ + return(status); + } + } + + /* Now wait for response from the FTP server control port. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &new_packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Error in NLST request to FTP server. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = new_packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 1xx message, signaling the data port was connected properly and ready for + transfer. */ + if ((new_packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '1')) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Error in NLST request to FTP server. */ + return(NX_FTP_EXPECTED_1XX_CODE); + } + + /* Release the last packet. */ + nx_packet_release(new_packet_ptr); + + /* Now read a listing packet from the data socket. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); + + /* Determine if an error occurred. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Map all unsuccessful status to error. */ + return(status); + } + + /* Determine if the block mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Retrieve the block header. */ + status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); + + /* Determine if an error occurred. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + } + } + + /* Return staus to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_directory_listing_continue PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client directory */ +/* listing continue. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* that contains the listing */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_directory_listing_continue Actual client directory */ +/* listing continue call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client directory listing continue function. */ + status = _nx_ftp_client_directory_listing_continue(ftp_client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_directory_listing_continue PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the next listing buffer. It is assumed that */ +/* a successful _nx_ftp_client_directory_listing_get immediately */ +/* preceded this call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* that contains the listing */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_server_socket_unlisten Unlisten on server port */ +/* nx_tcp_socket_receive Receive packet from server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; +NX_PACKET *response_ptr; +UCHAR *buffer_ptr; + + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Ensure the client is the proper state for directory listing request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Now read a listing packet from the data socket. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); + + /* Determine if the block mode is enabled. */ + if ((status == NX_SUCCESS) && + (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)) + { + + /* Retrieve the block header. */ + status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); + } + + /* Determine if an error occurred. */ + if (status) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Wait for response from the FTP server on the control socket. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &response_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Directory listing error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = response_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "NLST" was processed successfully. */ + if ((response_ptr -> nx_packet_length >= 3) && (buffer_ptr[0] == '2')) + { + + /* Release the packet. */ + nx_packet_release(response_ptr); + + /* Appropriate end of listing error. */ + return(NX_FTP_END_OF_LISTING); + } + else + { + + /* Release the packet. */ + nx_packet_release(response_ptr); + + /* Map all other unsuccessful status to error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + } + + /* Return success to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client disconnect. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_disconnect Actual client disconnect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client disconnect function. */ + status = _nx_ftp_client_disconnect(ftp_client_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disconnects a previously established FTP connection. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_client_socket_unbind Unbind a socket */ +/* nx_tcp_socket_disconnect Disconnect a socket */ +/* nx_tcp_socket_receive Receive response from server */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT status; + + + /* Determine if the client is in a not connected state. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + { + + /* Already connected, return an error. */ + return(NX_FTP_NOT_CONNECTED); + } + + /* Enter the not connected state. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_NOT_CONNECTED; + + /* Allocate a packet for sending the port and IP address. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Clean up connection socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) + { + + /* Clean up connection socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Build QUIT message to end the FTP connection. */ + buffer_ptr[0] = 'Q'; + buffer_ptr[1] = 'U'; + buffer_ptr[2] = 'I'; + buffer_ptr[3] = 'T'; + buffer_ptr[4] = 13; + buffer_ptr[5] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 6; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the QUIT message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Clean up connection socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Clean up connection socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the disconnect was processed properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Clean up connection socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Success. Disconnect and unbind the control socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_close PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file close. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_close Actual client file close call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file close function. */ + status = _nx_ftp_client_file_close(ftp_client_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_close PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function closes a previously open client FTP file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ +/* nx_packet_release Release packet */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_server_socket_unlisten Unlisten on server socket */ +/* nx_tcp_socket_disconnect Disconnect a socket */ +/* nx_tcp_socket_receive Receive response from server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT status; + + + /* Ensure the client is in the proper state for closing the socket. */ + if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_NOT_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + else if ((ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_OPEN) && + (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN)) + return(NX_FTP_NOT_OPEN); + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Set the state to connected. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_CONNECTED; + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* Unable to connect socket to server FTP control port. */ + return(status); + } + + /* We have a packet, setup pointer to the packet payload area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the close was processed properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file delete. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_name File name to delete */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_delete Actual client file delete call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (file_name == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file delete function. */ + status = _nx_ftp_client_file_delete(ftp_client_ptr, file_name, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the specified file on the FTP */ +/* server. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_name File name to delete */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive packet from server */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + + /* Ensure the client is the proper state for file delete request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Allocate a packet for sending the file delete command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "DELE" message to indicate file delete. */ + buffer_ptr[0] = 'D'; + buffer_ptr[1] = 'E'; + buffer_ptr[2] = 'L'; + buffer_ptr[3] = 'E'; + buffer_ptr[4] = ' '; + + /* Copy the file name into the message. */ + for(i = 0; file_name[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the file name. */ + buffer_ptr[5+i] = (UCHAR)file_name[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+5] = 13; + buffer_ptr[i+6] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+7; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the DELE message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* DELE error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "DELE" was processed successfully. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* File delete error. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Yes, the file was deleted. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_passive_mode_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the request to passive mode. Once this is set */ +/* the Client will send a PASV command preceding any FTP Client command*/ +/* involving transferring data on the data socket. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* passive_mode_enabled True to enable */ +/* False to disable */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled) +{ + +UINT status; + + if (ftp_client_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + if ((passive_mode_enabled != NX_TRUE) && (passive_mode_enabled != NX_FALSE)) + { + return NX_INVALID_PARAMETERS; + } + + status = _nx_ftp_client_passive_mode_set(ftp_client_ptr, passive_mode_enabled); + + return status; + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_passive_mode_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the request to passive mode. Once this is set */ +/* the Client will send a PASV command preceding any FTP Client command*/ +/* for accessing a server data port. If passive mode is not set, */ +/* the FTP Client will send and receive data via active transfer mode. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* passive_mode_enabled True to enable passive mode */ +/* False to disable passive mode */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled) +{ + + /* Set the transfer status according to the passive mode enabled input. */ + ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled = passive_mode_enabled; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_transfer_mode_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP transfer mode set. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* transfer_mode Transfer mode */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_transfer_mode_set Actual transfer mode set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode) +{ + +UINT status; + + /* Check for valid pointer. */ + if (ftp_client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual transfer mode set function. */ + status = _nx_ftp_client_transfer_mode_set(ftp_client_ptr, transfer_mode); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_transfer_mode_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the transfer mode. */ +/* Note: just support stream mode and block mode yet. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* transfer_mode Transfer mode */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode) +{ + + /* Check for transfer mode. */ + if ((transfer_mode != NX_FTP_TRANSFER_MODE_STREAM) && + (transfer_mode != NX_FTP_TRANSFER_MODE_BLOCK)) + { + return(NX_INVALID_PARAMETERS); + } + + /* Set the transfer mode. */ + ftp_client_ptr -> nx_ftp_client_transfer_mode = transfer_mode; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file open. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_name Client file name */ +/* open_type Open for read or open for */ +/* write */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_open Actual client file open call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (file_name == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for illegal open option type. */ + if ((open_type != NX_FTP_OPEN_FOR_READ) && (open_type != NX_FTP_OPEN_FOR_WRITE)) + return(NX_OPTION_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file open function. */ + status = _nx_ftp_client_file_open(ftp_client_ptr, file_name, open_type, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens a client FTP file. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_name Client file name */ +/* open_type Open for read or open for */ +/* write */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_packet_allocate Allocate packet */ +/* _nx_ftp_client_active_transfer_setup Setup active transfer */ +/* _nx_ftp_client_passive_transfer_setup Setup passive transfer */ +/* _nx_ftp_client_block_mode_send Send block mode command */ +/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ +/* nx_packet_release Release packet */ +/* nx_tcp_server_socket_accept Connect data socket to server */ +/* nx_tcp_socket_receive Receive response from server */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + + /* Ensure the client is the proper state for an open request. */ + if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_NOT_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + else if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_OPEN) + return(NX_FTP_NOT_CLOSED); + else if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_WRITE_OPEN) + return(NX_FTP_NOT_CLOSED); + + /* Flush the control socket queue for any old messages before starting a new file open request. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, 1); + + /* Determine if a packet was received. */ + if (status == NX_SUCCESS) + { + + /* Just discard it. */ + nx_packet_release(packet_ptr); + } + + /* Allocate a packet for sending the TYPE command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status != NX_SUCCESS) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 8) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_INVALID_PACKET); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "TYPE I" message to indicate binary file transfer. */ + buffer_ptr[0] = 'T'; + buffer_ptr[1] = 'Y'; + buffer_ptr[2] = 'P'; + buffer_ptr[3] = 'E'; + buffer_ptr[4] = ' '; + buffer_ptr[5] = 'I'; + + /* Set the CR/LF. */ + buffer_ptr[6] = 13; + buffer_ptr[7] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 8; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the TYPE message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status != NX_SUCCESS) + { + + /* Unable to open file with FTP server. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "TYPE I" was received properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Divert to passive mode operation if passive mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled) + { + + /* Set up the passive transfer mode: + Send PASV request, + Get server IP and port to connect to, + Open data socket based on server info in PASV response. */ + status = _nx_ftp_client_passive_transfer_setup(ftp_client_ptr, wait_option); + } + else + { + + /* Open in active transfer mode. */ + status = _nx_ftp_client_active_transfer_setup(ftp_client_ptr, wait_option); + } + + /* Determine if set up successful. */ + if (status) + { + return(status); + } + + /* Check if enable block mode. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Send MODE B command to FTP server. */ + status = _nx_ftp_client_block_mode_send(ftp_client_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + return(status); + } + } + + /* Allocate a packet for sending the TYPE command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Return error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build the actual open request. */ + if (open_type == NX_FTP_OPEN_FOR_WRITE) + { + + /* File write request, STOR is the command for writing a file. */ + buffer_ptr[0] = 'S'; + buffer_ptr[1] = 'T'; + buffer_ptr[2] = 'O'; + buffer_ptr[3] = 'R'; + buffer_ptr[4] = ' '; + } + else + { + + /* File read request, RETR is the command for reading a file. */ + buffer_ptr[0] = 'R'; + buffer_ptr[1] = 'E'; + buffer_ptr[2] = 'T'; + buffer_ptr[3] = 'R'; + buffer_ptr[4] = ' '; + } + + /* Copy the file name into the buffer. */ + for(i = 0; file_name[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of file name. */ + buffer_ptr[5+i] = (UCHAR)file_name[i]; + } + + /* Insert the CR/LF. */ + buffer_ptr[5+i] = 13; + buffer_ptr[5+i+1] = 10; + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = i + 7; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the STOR/RETR message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Check if enable passive mode. */ + if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) + { + + /* Active mode. Now wait for the data connection to connect. */ + status = nx_tcp_server_socket_accept(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); + + /* Determine if the accept was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Return error. */ + return(status); + } + } + + /* Now wait for response from the FTP server control port. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status != NX_SUCCESS) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Unable to open file with FTP server. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 1xx message, signaling the data port was connected properly and ready for transfer. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '1')) + { + + /* Cleanup data socket. */ + _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_1XX_CODE); + } + + /* Release the last packet. */ + nx_packet_release(packet_ptr); + + /* At this point, the client has successfully opened a FTP connection. */ + if (open_type == NX_FTP_OPEN_FOR_WRITE) + { + + /* Set the client state to open for write. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_WRITE_OPEN; + } + else + { + + /* Set the client state to open for read. */ + ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_OPEN; + } + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file read. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_read Actual client file read call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file read function. */ + status = _nx_ftp_client_file_read(ftp_client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reads a packet of the file from the data connection */ +/* with the FTP server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Destination of for the */ +/* received packet pointer */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive response from server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Determine if the file is open for writing. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_OPEN) + return(NX_FTP_NOT_OPEN); + + /* Default the packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Read the packet from the data connection. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); + + /* Determine if an error occurred. */ + if (status == NX_NOT_CONNECTED) + { + + /* Map not-connected status to end of file. */ + status = NX_FTP_END_OF_FILE; + } + + /* Determine if the block mode is enabled. */ + if ((status == NX_SUCCESS) && + (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)) + { + + /* Retrieve the block header. */ + status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); + } + + /* Return status to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_rename PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file rename. */ +/* */ +/* Note: The string lengths of filename and new_filename are limited */ +/* by the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* filename Current file name */ +/* new_filename New file name */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_ftp_client_file_rename Actual client file rename call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || + (filename == NX_NULL) || (new_filename == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file rename function. */ + status = _nx_ftp_client_file_rename(ftp_client_ptr, filename, new_filename, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_rename PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function renames the specified file with the supplied */ +/* filename. */ +/* */ +/* Note: The string lengths of filename and new_filename are limited */ +/* by the packet payload size. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* filename Current file name */ +/* new_filename New file name */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive packet from server */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option) +{ + +UINT i; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; + + + /* Ensure the client is the proper state for a rename file request. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) + return(NX_FTP_NOT_CONNECTED); + + /* Allocate a packet for sending the file rename command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build "RNFR" message to indicate file rename request. */ + buffer_ptr[0] = 'R'; + buffer_ptr[1] = 'N'; + buffer_ptr[2] = 'F'; + buffer_ptr[3] = 'R'; + buffer_ptr[4] = ' '; + + /* Copy the old file name into the message. */ + for(i = 0; filename[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the file name. */ + buffer_ptr[5+i] = (UCHAR)filename[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+5] = 13; + buffer_ptr[i+6] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+7; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the RNFR message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* RNFR file error. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 3xx message, signaling the "RNFR" was received properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '3')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to rename file with FTP server. */ + return(NX_FTP_EXPECTED_3XX_CODE); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Now build "RNTO" message to specify new file name. */ + buffer_ptr[0] = 'R'; + buffer_ptr[1] = 'N'; + buffer_ptr[2] = 'T'; + buffer_ptr[3] = 'O'; + buffer_ptr[4] = ' '; + + /* Copy the old file name into the message. */ + for(i = 0; new_filename[i]; i++) + { + + /* Check if out of boundary. */ + if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* Copy character of the new file name. */ + buffer_ptr[5+i] = (UCHAR)new_filename[i]; + } + + /* Set the CR/LF. */ + buffer_ptr[i+5] = 13; + buffer_ptr[i+6] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = i+7; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the RNTO message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status) + { + + /* RNTO file error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the "RNTO" was processed properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to rename with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Release packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_size_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file size set. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_size The total size of file */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_size_set Actual file size set call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file size set function. */ + status = _nx_ftp_client_file_size_set(ftp_client_ptr, file_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_size_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the file size for block mode before send packets */ +/* to the file on the data connection with the FTP server. */ +/* */ +/* Note:a. This API is only used for block mode, */ +/* b. Must call this API before call nx_ftp_client_file_write. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* file_size The total size of file */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size) +{ + +UINT status; + + + /* Check for invalid file size. */ + if (file_size == 0) + return(NX_FTP_CLIENT_INVALID_SIZE); + + /* Check if already set the file size. */ + if (ftp_client_ptr -> nx_ftp_client_block_total_size != 0) + return(NX_FTP_CLIENT_FILE_SIZE_ALREADY_SET); + + /* Determine if the block mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode != NX_FTP_TRANSFER_MODE_BLOCK) + return(NX_FTP_CLIENT_NOT_BLOCK_MODE); + + /* Determine if the file is open for writing. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN) + return(NX_FTP_NOT_OPEN); + + /* Send start block header for file size. */ + status = _nx_ftp_client_block_header_send(ftp_client_ptr, file_size); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Store the file size for writing. */ + ftp_client_ptr -> nx_ftp_client_block_total_size = file_size; + ftp_client_ptr -> nx_ftp_client_block_remaining_size = file_size; + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_client_file_write PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP client file write. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Pointer to packet to write */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_file_write Actual client file write call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file write function. */ + status = _nx_ftp_client_file_write(ftp_client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_file_write PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes a packet to the file on the data connection */ +/* with the FTP server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Pointer to packet to write */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; +ULONG file_size = 0; + + + /* Determine if the file is open for writing. */ + if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN) + return(NX_FTP_NOT_OPEN); + + /* Determine if the block mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Record the file size. */ + file_size = packet_ptr -> nx_packet_length; + + /* Check the file size. */ + if (ftp_client_ptr -> nx_ftp_client_block_remaining_size < packet_ptr -> nx_packet_length) + return(NX_FTP_CLIENT_INVALID_SIZE); + } + + /* Write packet payload to the file. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Determine if the block mode is enabled. */ + if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Update the file size. */ + ftp_client_ptr -> nx_ftp_client_block_remaining_size -= file_size; + + /* Check if the file is already sent. */ + if (ftp_client_ptr -> nx_ftp_client_block_remaining_size == 0) + { + + /* Send end block header for file size. */ + status = _nx_ftp_client_block_header_send(ftp_client_ptr, 0); + } + } + + /* Return success to caller. */ + return(status); +} + + +#ifdef FEATURE_NX_IPV6 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_utility_convert_IPv6_to_ascii PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an IP address to ascii e.g. for insertion */ +/* into FTP EPRT or PORT command. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* buffer Pointer to ascii port number string*/ +/* buffer_length Size of buffer */ +/* size IPv6 address string size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful conversion */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_utility_convert_number_ascii */ +/* Converts a single number to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open FTP Client file open service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_ftp_utility_convert_IPv6_to_ascii(NX_TCP_SOCKET *socket_ptr, CHAR *buffer, UINT buffer_length, UINT *size) +{ + + +CHAR *temp; +CHAR number_buf[10]; /* 0x20010000 -> "2001:0000:" */ + + + /* Set a pointer to the start of the buffer. */ + temp = buffer; + + /* Clear the buffer. */ + memset(temp, 0, buffer_length); + + /* Clear the scratch buffer. */ + memset(number_buf, 0, 10); + + _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[0], number_buf); + + /* Append to string buffer. */ + memcpy(temp, number_buf, 10); + + /* Move the pointer past this number. */ + temp += 10; + + /* Clear the scratch buffer. */ + memset(number_buf, 0, 10); + + _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[1], number_buf); + + /* Append to string buffer. */ + memcpy(temp, number_buf, 10); + + /* Move the pointer past this number. */ + temp += 10; + + /* Clear the scratch buffer. */ + memset(number_buf, 0, 10); + + _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[2], number_buf); + + /* Append to string buffer. */ + memcpy(temp, number_buf, 10); + + /* Move the pointer past this number. */ + temp += 10; + + /* Clear the scratch buffer. */ + memset(number_buf, 0, 10); + + _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[3], number_buf); + + /* Append to string buffer. */ + memcpy(temp, number_buf, 10); + + /* Move the pointer past this number. */ + temp += 10; + + /* Remove the trailing ':'. */ + *(temp - 1) = 0x0; + *size = 39; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_utility_convert_number_ascii PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number to ascii text for inserting IP */ +/* address and port numbers into FTP EPRT and PORT commands. It is up */ +/* to the caller to provide a buffer large enough to hold the ascii */ +/* conversion of the input number. */ +/* */ +/* INPUT */ +/* */ +/* number Number to convert to ASCII */ +/* numstring Pointer to ascii string */ +/* */ +/* OUTPUT */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* None */ +/* */ +/* CALLED BY */ +/* _nx_ftp_utility_convert_IPv6_to_ascii */ +/* Convert IPv6 address to ASCII */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_ftp_utility_convert_number_ascii(ULONG number, CHAR *numstring) +{ + +UINT j; +UCHAR c; + + /* Go through each bit of the ULONG to convert. */ + for (j = 0; j <=7 ; j++) + { + + /* Save the bit off the most significant end. */ + c = (UCHAR)((number & 0xF0000000) >> 28); + + /* Make it the most significant byte. */ + number = number << 4; + + /* Convert the digit to an ascii character. */ + if (c < 10) + { + *numstring = (CHAR)('0' + c); + } + else /* Handle HEX digits... */ + { + *numstring = (CHAR)('A' + (c - 10)); + } + + /* Move past the digit. */ + numstring++; + + /* Determine if we need to add a colon. */ + if (j == 3 || j == 7) + { + /* Yes, append the colon and move the pointer past it. */ + *numstring = ':'; + numstring++; + } + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_utility_convert_portnumber_ascii PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number to ascii text e.g. used by */ +/* _nx_nat_utility_convert_portnumber_ULONG_to_ascii for inserting */ +/* changed port numbers back into FTP PORT command . */ +/* */ +/* INPUT */ +/* */ +/* number Port number to convert to ASCII */ +/* numstring Pointer to ascii portnumber string */ +/* numstring_length Portnumber string length */ +/* */ +/* OUTPUT */ +/* */ +/* NX_FTP_ERROR Unable to convert e.g. overflow error*/ +/* NX_SUCCESS Successful conversion */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open Processes the FTP file open service */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_ftp_utility_convert_portnumber_ascii(UINT number, CHAR *numstring, UINT *numstring_length) +{ + +UINT j; +UINT digit; + + + /* Initialize counters. */ + (*numstring_length) = 0; + + /* Loop to convert the number to ASCII. */ + while ((*numstring_length) < 10) + { + + /* Shift the current digits over one. */ + for (j = (*numstring_length); j != 0; j--) + { + + /* Move each digit over one place. */ + numstring[j] = numstring[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + numstring[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + (*numstring_length)++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Make the string NULL terminated. */ + numstring[(*numstring_length)] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + (*numstring_length) = 0; + numstring[0] = '0'; + return NX_FTP_INVALID_NUMBER; + } + + /* Return size to caller. */ + return NX_SUCCESS; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines which IP TCP packet to allocate based on */ +/* the FTP connection address IP type and then allocates the packet. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Allocated packet to return */ +/* wait_option Packet allocate wait option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_NOT_ENABLED IPv6 not enabled */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_packet_allocate(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT packet_type; +UINT status; + + + /* Default to IPv4 TCP packet to allocate. */ + packet_type = NX_IPv4_TCP_PACKET; + + /* Determine IP version by FTP connection type. */ + if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + + return NX_NOT_ENABLED; +#else + + /* Allocate a TCP IPv6 packet. */ + packet_type = NX_IPv6_TCP_PACKET; +#endif + } + + + /* Allocate the actual packet. */ + status = nx_packet_allocate(ftp_client_ptr -> nx_ftp_client_packet_pool_ptr, packet_ptr, packet_type, wait_option); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_active_transfer_setup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the Client data socket for active transfer */ +/* where the Client data socket is the TCP client. */ +/* */ +/* Find free port and listen on it, sends the PORT/EPRT command to */ +/* server, then wait for a connection from server. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_packet_allocate Allocate packet */ +/* _nx_ftp_utility_convert_IPv6_to_ascii Convert IPv6 address to ASCII */ +/* _nx_ftp_utility_convert_portnumber_ascii Convert port to ASCII */ +/* nx_packet_release Release packet */ +/* nx_tcp_free_port_find Find a free port */ +/* nx_tcp_server_socket_listen Listen for TCP data socket */ +/* connection from server */ +/* nx_tcp_server_socket_unlisten Unlisten on server socket */ +/* nx_tcp_socket_receive Receive response from server */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open Open a file for read or write */ +/* _nx_ftp_client_directory_listing_get Get directory list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_active_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +UINT status; +UINT data_port; +#ifndef NX_DISABLE_IPV4 +ULONG ip_address; +#endif /* NX_DISABLE_IPV4 */ +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +#ifdef FEATURE_NX_IPV6 +UINT ipduo_size; +#endif + + + /* Pickup the next free port for the data socket. */ + status = nx_tcp_free_port_find(ftp_client_ptr -> nx_ftp_client_ip_ptr, + ftp_client_ptr -> nx_ftp_client_data_port + 1, &data_port); + + /* Determine if the port find was successful. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Save the data port to the client record. */ + ftp_client_ptr -> nx_ftp_client_data_port = data_port; + + /* Start listening on the data port. */ + status = nx_tcp_server_socket_listen(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port, &(ftp_client_ptr -> nx_ftp_client_data_socket), 5, NX_NULL); + + /* Determine if the listen is successful. */ + if (status != NX_SUCCESS) + { + + /* Return error. */ + return(status); + } + + /* Allocate a packet for sending the PORT/EPRT command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status != NX_SUCCESS) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Return error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build the IP and port number FTP message. */ + if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { +#ifndef FEATURE_NX_IPV6 + return NX_NOT_ENABLED; +#else + CHAR ipduo_buffer[NX_FTP_IPV6_ADDRESS_BUFSIZE]; + UINT index; + + /* EPRT command: EPRT |2|1080::8:800:200C:417A|5282| + RFC2428, Section2, Page3. */ + + /* Check if out of boundary. + Max EPRT command sring: 8 ("EPRT |2|") + 39 (IPv6 address string) + 1 ('|') + 5 (Max port string) + 1 ('|') + 2 ("\r\n") = 56. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 56) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_INVALID_PACKET); + } + + buffer_ptr[0] = 'E'; + buffer_ptr[1] = 'P'; + buffer_ptr[2] = 'R'; + buffer_ptr[3] = 'T'; + buffer_ptr[4] = ' '; + buffer_ptr[5] = '|'; + buffer_ptr[6] = '2'; + buffer_ptr[7] = '|'; + + /* Convert the PORT command ipv6 address and port number format to ascii text. */ + + /* Clear our scratch buffer. */ + memset(&ipduo_buffer[0], 0, NX_FTP_IPV6_ADDRESS_BUFSIZE); + + /* Convert the IPv6 address to text. */ + status = _nx_ftp_utility_convert_IPv6_to_ascii(&(ftp_client_ptr -> nx_ftp_client_control_socket), + &ipduo_buffer[0], NX_FTP_IPV6_ADDRESS_BUFSIZE, &ipduo_size); + + /* Append to the packet buffer . */ + memcpy(buffer_ptr + 8, ipduo_buffer, ipduo_size); + + /* Update the index past the IPv6 address. */ + index = 8 + ipduo_size; + + /* Add the required space character. */ + buffer_ptr[index++] = '|'; + + /* Clear the scratch buffer again. */ + memset(&ipduo_buffer[0], 0, NX_FTP_IPV6_ADDRESS_BUFSIZE); + + /* Convert the preferred port to ascii. */ + status = _nx_ftp_utility_convert_portnumber_ascii(data_port, &ipduo_buffer[0], &ipduo_size); + + /* Append to the packet buffer. */ + memcpy(buffer_ptr + index, ipduo_buffer, ipduo_size); + + /* Update the index past the port. */ + index += ipduo_size; + + /* Add the required space character. */ + buffer_ptr[index++] = '|'; + + /* Set the CR/LF. */ + buffer_ptr[index++] = 13; + buffer_ptr[index++] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = index; +#endif /* FEATURE_NX_IPV6 */ + } + else + { + /* IPv4 FTP connection */ +#ifdef NX_DISABLE_IPV4 + return NX_NOT_ENABLED; +#else + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 30) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_INVALID_PACKET); + } + + /* Pickup the IPv4 address of this IP instance. */ + ip_address = ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address ; + + /* Now build the IP and port number FTP message. */ + buffer_ptr[0] = 'P'; + buffer_ptr[1] = 'O'; + buffer_ptr[2] = 'R'; + buffer_ptr[3] = 'T'; + buffer_ptr[4] = ' '; + + buffer_ptr[5] = (UCHAR)('0' + (ip_address >> 24)/100); + buffer_ptr[6] = (UCHAR)('0' + ((ip_address >> 24)/10)%10); + buffer_ptr[7] = (UCHAR)('0' + (ip_address >> 24)%10); + buffer_ptr[8] = ','; + + buffer_ptr[9] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)/100); + buffer_ptr[10] = (UCHAR)('0' + (((ip_address >> 16) & 0xFF)/10)%10); + buffer_ptr[11] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)%10); + buffer_ptr[12] = ','; + + buffer_ptr[13] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)/100); + buffer_ptr[14] = (UCHAR)('0' + (((ip_address >> 8) & 0xFF)/10)%10); + buffer_ptr[15] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)%10); + buffer_ptr[16] = ','; + + buffer_ptr[17] = (UCHAR)('0' + (ip_address & 0xFF)/100); + buffer_ptr[18] = (UCHAR)('0' + ((ip_address & 0xFF)/10)%10); + buffer_ptr[19] = (UCHAR)('0' + (ip_address & 0xFF)%10); + buffer_ptr[20] = ','; + + buffer_ptr[21] = (UCHAR)('0' + (data_port >> 8)/100); + buffer_ptr[22] = (UCHAR)('0' + ((data_port >> 8)/10)%10); + buffer_ptr[23] = (UCHAR)('0' + ((data_port >> 8)%10)); + buffer_ptr[24] = ','; + + buffer_ptr[25] = (UCHAR)('0' + (data_port & 255)/100); + buffer_ptr[26] = (UCHAR)('0' + ((data_port & 255)/10)%10); + buffer_ptr[27] = (UCHAR)('0' + ((data_port & 255)%10)); + + /* Set the CR/LF. */ + buffer_ptr[28] = 13; + buffer_ptr[29] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 30; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the PORT/EPRT message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status != NX_SUCCESS) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Unable to open file with FTP server. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the IP/port was received properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) + { + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_passive_transfer_setup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the Client data socket for passive transfer */ +/* where the Client data socket is the TCP client. */ +/* */ +/* It sends the PASV command and if the server sends an OK status, it */ +/* extracts the server connection info from the server response and */ +/* opens a connection on the data socket. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_client_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_client_socket_bind Bind the data socket to a port*/ +/* nxd_tcp_client_socket_connect Connect to server data socket */ +/* nx_tcp_socket_receive Receive response from server */ +/* nx_tcp_socket_send Send request to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open Open a file for read or write */ +/* _nx_ftp_client_directory_listing_get Get directory list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_passive_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT status; +UINT i; +UINT data_port; +#ifndef NX_DISABLE_IPV4 +UINT commas = 0; +ULONG ip_address = 0; +ULONG temp = 0; +#endif /* NX_DISABLE_IPV4 */ + + + /* Send the PASV command to switch to passive mode. */ + + /* Allocate a packet for sending the TYPE command. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); + + /* Determine if the packet allocation was successful. */ + if (status != NX_SUCCESS) + { + + /* Return error. */ + return(status); + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Set the error status. */ + return(NX_FTP_FAILED); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { +#ifndef FEATURE_NX_IPV6 + return(NX_NOT_ENABLED); +#else + + /* Now build "EPSV" message. RFC2428. */ + buffer_ptr[0] = 'E'; + buffer_ptr[1] = 'P'; + buffer_ptr[2] = 'S'; + buffer_ptr[3] = 'V'; +#endif /* FEATURE_NX_IPV6 */ + } + else + { +#ifdef NX_DISABLE_IPV4 + return(NX_NOT_ENABLED); +#else + + /* Now build "PASV" message . */ + buffer_ptr[0] = 'P'; + buffer_ptr[1] = 'A'; + buffer_ptr[2] = 'S'; + buffer_ptr[3] = 'V'; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Set the CR/LF. */ + buffer_ptr[4] = 13; + buffer_ptr[5] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 6; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the PASV or EPSV message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Wait for response from the FTP server. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status != NX_SUCCESS) + { + + /* Unable to open file with FTP server. */ + return(status); + } + + /* Setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { +#ifndef FEATURE_NX_IPV6 + return(NX_NOT_ENABLED); +#else + + /* EPSV command, RFC2428. */ + + /* Check for 2xx message, signaling the "EPSV" was received properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2') || (buffer_ptr[2] != '9')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* The text returned in response to the EPSV command MUST be: + \ + () */ + + /* The netowrk address used to establish the data connnection will be the same + network address used for the control connection. + An example response string follows: + Entering Extended Passive Mode (|||6446|) */ + + /* Check the length. command + + passive key word "(|||"*/ + if (packet_ptr -> nx_packet_length < 8) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_INVALID_COMMAND); + } + + /* Set the index. */ + i = 7; + + /* Skip the text to locate the key word "(|||". */ + while (i < packet_ptr -> nx_packet_length) + { + + /* Check if match the key word. */ + if ((buffer_ptr[i - 3] == '(') && + (buffer_ptr[i - 2] == '|') && + (buffer_ptr[i - 1] == '|') && + (buffer_ptr[i] == '|')) + { + break; + } + + /* Move to next character. */ + i++; + } + + /* Check for properly formated address command from server. */ + if (i >= packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_INVALID_COMMAND); + } + + /* Update the index to pickup the port number. */ + data_port = 0; + i++; + while ((i < packet_ptr -> nx_packet_length) && (buffer_ptr[i] != '|')) + { + + /* Is a numeric character present? */ + if ((buffer_ptr[i] < '0') || (buffer_ptr[i] > '9')) + { + + /* Invalid port number. */ + break; + } + + /* Yes, numeric character is present. Update the IP port. */ + data_port = (data_port * 10) + (UINT) (buffer_ptr[i] - '0'); + + /* Move to next character. */ + i++; + } + + /* At this point we are done with the packet. */ + nx_packet_release(packet_ptr); + + /* Determine if an error occurred. */ + if ((buffer_ptr[i] != '|') || (data_port == 0)) + { + + /* Set the error status. */ + return(NX_FTP_INVALID_COMMAND); + } + + /* Save the passive IP address and data port. */ + COPY_NXD_ADDRESS(&(ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip), &(ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip)); + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_port = data_port; +#endif /* FEATURE_NX_IPV6 */ + } + else + { +#ifdef NX_DISABLE_IPV4 + return(NX_NOT_ENABLED); +#else + + /* Check for 2xx message, signaling the "PASV" was received properly. */ + if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2') || (buffer_ptr[2] != '7')) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Now parse the address and port for the Client to connect to on the data socket. + IP address and port are comma delimited and port number is the last two numbers, + PASV port = (p1 * 256) + p2. */ + + /* Skip non numeric text and whitespace. */ + i = 3; + while (((buffer_ptr[i] > '9') || (buffer_ptr[i] < '0')) && (i < packet_ptr -> nx_packet_length)) + { + i++; + } + + /* Check for properly formated command from server. */ + if (i >= packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return NX_FTP_INVALID_COMMAND; + } + + /* First, pickup the IP address. */ + commas = 0; + ip_address = 0; + temp = 0; + status = NX_SUCCESS; + + while (i < packet_ptr -> nx_packet_length) + { + + /* Is a numeric character present? */ + if ((buffer_ptr[i] >= '0') && (buffer_ptr[i] <= '9')) + { + + /* Yes, numeric character is present. Update the IP address. */ + temp = (temp*10) + (ULONG) (buffer_ptr[i] - '0'); + } + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[i] == 0x0D) || (buffer_ptr[i] == 0x0A) || (buffer_ptr[i] == 0)) + { + status = NX_FTP_INVALID_COMMAND; + break; + } + + /* Determine if a comma is present. */ + if (buffer_ptr[i] == ',') + { + + /* Increment the comma count. */ + commas++; + + /* Setup next byte of IP address. */ + ip_address = (ip_address << 8) & 0xFFFFFFFF; + ip_address = ip_address | (temp & 0xFF); + temp = 0; + + /* Have we finished with the IP address? */ + if (commas == 4) + { + + /* Finished with IP address. */ + i++; + break; + } + } + + /* Move to next character. */ + i++; + } + + /* Now pickup the port number. */ + data_port = 0; + temp = 0; + while (i < packet_ptr -> nx_packet_length) + { + + /* Is a numeric character present? */ + if ((buffer_ptr[i] >= '0') && (buffer_ptr[i] <= '9')) + { + + /* Yes, numeric character is present. Update the IP port. */ + temp = (temp*10) + (UINT) (buffer_ptr[i] - '0'); + } + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[i] == 0x0D) || (buffer_ptr[i] == 0x0A) || (buffer_ptr[i] == 0)) + { + /* Good condition on the port number! */ + break; + } + + /* Determine if a comma is present. */ + if (buffer_ptr[i] == ',') + { + + /* Increment the comma count. */ + commas++; + + /* Move the data port number up. */ + data_port = (data_port << 8) & 0xFFFFFFFF; + data_port = data_port | (temp & 0xFF); + temp = 0; + + /* Have we finished with the port? */ + if (commas >= 6) + { + + /* Error, get out of the loop. */ + status = NX_FTP_INVALID_ADDRESS; + break; + } + } + + /* Move to next character. */ + i++; + } + + /* Move port number up. */ + data_port = (data_port << 8) & 0xFFFFFFFF; + data_port = data_port | (temp & 0xFF); + + /* At this point we are done with the packet. */ + nx_packet_release(packet_ptr); + + /* Determine if an error occurred. */ + if ((status != NX_SUCCESS) || (buffer_ptr[i] != 13) || (commas != 5) || (ip_address == 0) || (data_port == 0)) + { + + /* Set the error status. */ + return NX_FTP_INVALID_COMMAND; + } + + /* Save the passive IP address and data port. */ + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4; + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4 = ip_address; + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_port = data_port; + +#endif /* NX_DISABLE_IPV4 */ + } + + /* Bind the client data socket to any port. */ + status = nx_tcp_client_socket_bind((&ftp_client_ptr -> nx_ftp_client_data_socket), NX_ANY_PORT, wait_option); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Unable to bind socket to port. */ + return(status); + } + + /* Now connect to the IP address and port the server asked us to. */ + status = nxd_tcp_client_socket_connect(&(ftp_client_ptr -> nx_ftp_client_data_socket), + &(ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip), + data_port, wait_option); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_data_socket)); + } + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_data_socket_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function cleans up the data socket. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_disconnect Disconnect a socket */ +/* nx_tcp_client_socket_unbind Release the data socket port */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_server_socket_unlisten Unlisten on server socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open Open a file for read or write */ +/* _nx_ftp_client_file_close Actual client file close call */ +/* _nx_ftp_client_directory_listing_get Get directory list */ +/* _nx_ftp_client_directory_listing_continue */ +/* Continue to get directory list*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_client_data_socket_cleanup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + + + /* Disconnect the data socket. */ + nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); + + /* Check if enable passive mode. */ + if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) + { + + /* Unaccept the data socket. */ + nx_tcp_server_socket_unaccept(&(ftp_client_ptr -> nx_ftp_client_data_socket)); + + /* Stop listening on the data port. */ + nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_port); + } + else + { + + /* Release the socket port. */ + nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_data_socket)); + } + + /* Clear the block size. */ + ftp_client_ptr -> nx_ftp_client_block_total_size = 0; + ftp_client_ptr -> nx_ftp_client_block_remaining_size = 0; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_block_mode_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends MODE B command to FTP server for block mode. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_open Open a file for read or write */ +/* _nx_ftp_client_directory_listing_get Get directory list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_block_mode_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) +{ + +UINT status; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; + + + /* Send MODE B command. */ + + /* Allocate the packet. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, NX_NO_WAIT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build the actual MODE B request. */ + buffer_ptr[0] = 'M'; + buffer_ptr[1] = 'O'; + buffer_ptr[2] = 'D'; + buffer_ptr[3] = 'E'; + buffer_ptr[4] = ' '; + buffer_ptr[5] = 'B'; + + /* Insert the CR/LF. */ + buffer_ptr[6] = 13; + buffer_ptr[7] = 10; + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = 8; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the MODE B message. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error. */ + return(status); + } + + /* Now wait for response from the FTP server control port. */ + status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); + + /* Determine if a packet was not received. */ + if (status != NX_SUCCESS) + { + + /* Unable to open file with FTP server. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for 2xx message, signaling the data port was connected properly and ready for transfer. */ + if (buffer_ptr[0] != '2') + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Unable to open file with FTP server. */ + return(NX_FTP_EXPECTED_2XX_CODE); + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_block_header_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the block header for block mode. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* block_size The size of block data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_size_set Set the file size for writing */ +/* _nx_ftp_client_file_write Send data packet to server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_block_header_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG block_size) +{ + +UINT status; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; + + + /* Use block mode to transfer data. RFC959, Section3.4.2, Page21-22. */ + + /* Allocate the packet. */ + status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, NX_NO_WAIT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Set the block header. */ + if (block_size) + { + + /* Descriptor. */ + buffer_ptr[0] = 0; + + /* Byte count. */ + buffer_ptr[1] = (UCHAR)(block_size >> 8); + buffer_ptr[2] = (UCHAR)(block_size); + } + else + { + + /* Descriptor. */ + buffer_ptr[0] = 64; + + /* Byte count. */ + buffer_ptr[1] = 0; + buffer_ptr[2] = 0; + } + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = 3; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Write packet payload to the file. */ + status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, NX_NO_WAIT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Return success to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_client_block_header_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the block header for block mode. */ +/* */ +/* INPUT */ +/* */ +/* ftp_client_ptr Pointer to FTP client */ +/* packet_ptr Pointer to packet to write */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_client_file_read Read data from server */ +/* _nx_ftp_client_directory_listing_get Get directory list */ +/* _nx_ftp_client_directory_listing_continue */ +/* Continue to get directory list*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_client_block_header_retrieve(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr) +{ + +ULONG delta; +UCHAR *buffer_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN +NX_PACKET *before_last_packet; +NX_PACKET *last_packet; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + + /* Check if it is the first packet. */ + if (ftp_client_ptr -> nx_ftp_client_block_total_size == 0) + { + + /* Check the packet length. */ + if ((packet_ptr -> nx_packet_length < 3) || + (packet_ptr -> nx_packet_prepend_ptr + 3 > packet_ptr -> nx_packet_append_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_CLIENT_INVALID_SIZE); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Process block header. */ + ftp_client_ptr -> nx_ftp_client_block_total_size = (ULONG)((buffer_ptr[1] << 8) | buffer_ptr[2]); + ftp_client_ptr -> nx_ftp_client_block_remaining_size = ftp_client_ptr -> nx_ftp_client_block_total_size; + + /* Skip the block header. */ + packet_ptr -> nx_packet_prepend_ptr += 3; + packet_ptr -> nx_packet_length -= 3; + } + + /* Check if have remaining data. */ + if (ftp_client_ptr -> nx_ftp_client_block_remaining_size == 0) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_CLIENT_END_OF_BLOCK); + } + + /* Check the data of current packet. */ + if (ftp_client_ptr -> nx_ftp_client_block_remaining_size < packet_ptr -> nx_packet_length) + { + + /* Remove the extra data, such as: end block header. */ + + /* Calculate the difference in the length. */ + delta = packet_ptr -> nx_packet_length - ftp_client_ptr -> nx_ftp_client_block_remaining_size; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta; + + /* Adjust the append pointer. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Loop to process adjustment that spans multiple packets. */ + while (delta) + { + + /* Determine if the packet is chained (or still chained after the adjustment). */ + if (packet_ptr -> nx_packet_last == NX_NULL) + { + + /* No, packet is not chained, simply adjust the append pointer in the packet. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; + + /* Break out of the loop, since the adjustment is complete. */ + break; + } + + /* Pickup the pointer to the last packet. */ + last_packet = packet_ptr -> nx_packet_last; + + /* Determine if the amount to adjust is less than the payload in the last packet. */ + /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ + if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta) + { + + /* Yes, simply adjust the append pointer of the last packet in the chain. */ + /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ + last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta; + + /* Get out of the loop, since the adjustment is complete. */ + break; + } + else + { + + /* Adjust the delta by the amount in the last packet. */ + delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)); + + /* Find the packet before the last packet. */ + before_last_packet = packet_ptr; + while (before_last_packet -> nx_packet_next != last_packet) + { + + /* Move to the next packet in the chain. */ + before_last_packet = before_last_packet -> nx_packet_next; + } + + /* At this point, we need to release the last packet and adjust the other packet + pointers. */ + + /* Ensure the next packet pointer is NULL in what is now the last packet. */ + before_last_packet -> nx_packet_next = NX_NULL; + + /* Determine if the packet is still chained. */ + if (packet_ptr != before_last_packet) + { + + /* Yes, the packet is still chained, setup the last packet pointer. */ + packet_ptr -> nx_packet_last = before_last_packet; + } + else + { + + /* The packet is no longer chained, set the last packet pointer to NULL. */ + packet_ptr -> nx_packet_last = NX_NULL; + } + + /* Release the last packet. */ + _nx_packet_release(last_packet); + } + } +#else + + /* Simply adjust the append pointer in the packet. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Update the file size. */ + ftp_client_ptr -> nx_ftp_client_block_remaining_size -= packet_ptr -> nx_packet_length; + + /* Return success to caller. */ + return(NX_SUCCESS); +} diff --git a/addons/ftp/nxd_ftp_client.h b/addons/ftp/nxd_ftp_client.h new file mode 100644 index 00000000..c79b8e18 --- /dev/null +++ b/addons/ftp/nxd_ftp_client.h @@ -0,0 +1,373 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_ftp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Duo File Transfer Protocol (FTP over */ +/* IPv6) component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_FTP_CLIENT_H +#define NXD_FTP_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +/* Define the FTP Client ID. */ + + +#define NXD_FTP_CLIENT_ID 0x46545200UL + + +/* Define the maximum number of clients the FTP Server can accommodate. */ + +#ifndef NX_FTP_MAX_CLIENTS +#define NX_FTP_MAX_CLIENTS 4 +#endif + + +/* Define FTP TCP socket create options. Normally any TCP port will do but this + gives the application a means to specify a source port. */ + +#ifndef NX_FTP_CLIENT_SOURCE_PORT +#define NX_FTP_CLIENT_SOURCE_PORT NX_ANY_PORT +#endif + +#ifndef NX_FTP_CONTROL_TOS +#define NX_FTP_CONTROL_TOS NX_IP_NORMAL +#endif + +#ifndef NX_FTP_DATA_TOS +#define NX_FTP_DATA_TOS NX_IP_NORMAL +#endif + +#ifndef NX_FTP_FRAGMENT_OPTION +#define NX_FTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_FTP_CONTROL_WINDOW_SIZE +#define NX_FTP_CONTROL_WINDOW_SIZE 400 +#endif + +#ifndef NX_FTP_DATA_WINDOW_SIZE +#define NX_FTP_DATA_WINDOW_SIZE 2048 +#endif + + +#ifndef NX_FTP_TIME_TO_LIVE +#define NX_FTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_FTP_USERNAME_SIZE +#define NX_FTP_USERNAME_SIZE 20 +#endif + +#ifndef NX_FTP_PASSWORD_SIZE +#define NX_FTP_PASSWORD_SIZE 20 +#endif + +#ifndef NX_FTP_TIMEOUT_PERIOD +#define NX_FTP_TIMEOUT_PERIOD 60 /* Number of seconds to check */ +#endif + + + +/* Define open types. */ + +#define NX_FTP_OPEN_FOR_READ 0x01 /* FTP file open for reading */ +#define NX_FTP_OPEN_FOR_WRITE 0x02 /* FTP file open for writing */ + + +/* Define transfer modes. Note: just support stream mode and block mode yet. */ + +#define NX_FTP_TRANSFER_MODE_STREAM 0 /* FTP stream transmission mode */ +#define NX_FTP_TRANSFER_MODE_BLOCK 1 /* FTP block transmission mode */ +#define NX_FTP_TRANSFER_MODE_COMPRESSED 2 /* FTP compressed transmission mode */ + + +/* Define return code constants. */ + +#define NX_FTP_ERROR 0xD0 /* Generic FTP internal error - deprecated */ +#define NX_FTP_TIMEOUT 0xD1 /* FTP timeout occurred */ +#define NX_FTP_FAILED 0xD2 /* FTP error */ +#define NX_FTP_NOT_CONNECTED 0xD3 /* FTP not connected error */ +#define NX_FTP_NOT_DISCONNECTED 0xD4 /* FTP not disconnected error */ +#define NX_FTP_NOT_OPEN 0xD5 /* FTP not opened error */ +#define NX_FTP_NOT_CLOSED 0xD6 /* FTP not closed error */ +#define NX_FTP_END_OF_FILE 0xD7 /* FTP end of file status */ +#define NX_FTP_END_OF_LISTING 0xD8 /* FTP end of directory listing status */ +#define NX_FTP_EXPECTED_1XX_CODE 0xD9 /* Expected a 1xx response from server */ +#define NX_FTP_EXPECTED_2XX_CODE 0xDA /* Expected a 2xx response from server */ +#define NX_FTP_EXPECTED_22X_CODE 0xDB /* Expected a 22x response from server */ +#define NX_FTP_EXPECTED_23X_CODE 0xDC /* Expected a 23x response from server */ +#define NX_FTP_EXPECTED_3XX_CODE 0xDD /* Expected a 3xx response from server */ +#define NX_FTP_EXPECTED_33X_CODE 0xDE /* Expected a 33x response from server */ +#define NX_FTP_INVALID_NUMBER 0xDF /* Extraced an invalid number from server response */ +#define NX_FTP_INVALID_ADDRESS 0x1D0 /* Invalid IP address parsed from FTP command */ +#define NX_FTP_INVALID_COMMAND 0x1D1 /* Invalid FTP command (bad syntax, unknown command) */ +#define NX_FTP_CLIENT_INVALID_SIZE 0x1D2 /* Invalid FTP file size */ +#define NX_FTP_CLIENT_FILE_SIZE_ALREADY_SET 0x1D3 /* The file size is already set */ +#define NX_FTP_CLIENT_NOT_BLOCK_MODE 0x1D4 /* Block mode is not enabled */ +#define NX_FTP_CLIENT_END_OF_BLOCK 0x1D5 /* FTP end of block */ + + +/* Define FTP connection states. */ + +#define NX_FTP_STATE_NOT_CONNECTED 1 /* FTP not connected */ +#define NX_FTP_STATE_CONNECTED 2 /* FTP connected */ +#define NX_FTP_STATE_OPEN 3 /* FTP file open for reading */ +#define NX_FTP_STATE_WRITE_OPEN 4 /* FTP file open for writing */ + + +/* Define the FTP Server TCP port numbers. */ + +#define NX_FTP_SERVER_CONTROL_PORT 21 /* Control Port for FTP server */ +#define NX_FTP_SERVER_DATA_PORT 20 /* Data Port for FTP server in active transfer mode */ + +/* Define the size for buffer to store an IPv6 address represented in ASCII. */ +#define NX_FTP_IPV6_ADDRESS_BUFSIZE 60 + +/* Define the FTP basic commands. The ASCII command will be parsed and converted to the numerical + representation shown below. */ + +#define NX_FTP_NOOP 0 +#define NX_FTP_USER 1 +#define NX_FTP_PASS 2 +#define NX_FTP_QUIT 3 +#define NX_FTP_RETR 4 +#define NX_FTP_STOR 5 +#define NX_FTP_RNFR 6 +#define NX_FTP_RNTO 7 +#define NX_FTP_DELE 8 +#define NX_FTP_RMD 9 +#define NX_FTP_MKD 10 +#define NX_FTP_NLST 11 +#define NX_FTP_PORT 12 +#define NX_FTP_CWD 13 +#define NX_FTP_PWD 14 +#define NX_FTP_TYPE 15 +#define NX_FTP_LIST 16 +#define NX_FTP_CDUP 17 +#define NX_FTP_INVALID 18 +#define NX_FTP_EPRT 19 +#define NX_FTP_PASV 20 +#define NX_FTP_EPSV 21 +#define NX_FTP_MODE 22 + + + +/* Define the basic FTP Client data structure. */ + +typedef struct NX_FTP_CLIENT_STRUCT +{ + ULONG nx_ftp_client_id; /* FTP Client ID */ + CHAR *nx_ftp_client_name; /* Name of this FTP client */ + NX_IP *nx_ftp_client_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_ftp_client_packet_pool_ptr; /* Pointer to FTP client packet pool */ + ULONG nx_ftp_client_server_ip; /* Server's IP address */ + UINT nx_ftp_client_state; /* State of FTP client */ + NX_TCP_SOCKET nx_ftp_client_control_socket; /* Client FTP control socket */ + NX_TCP_SOCKET nx_ftp_client_data_socket; /* Client FTP data transfer socket */ + UINT nx_ftp_client_data_port; /* Port the Client data socket binds */ + UINT nx_ftp_client_passive_transfer_enabled; /* Client enabled for passive transfer */ + UINT nx_ftp_client_transfer_mode; /* Client transfer mode */ + ULONG nx_ftp_client_block_total_size; /* Total size of data in block mode */ + ULONG nx_ftp_client_block_remaining_size; /* Remaining size of data in block mode*/ +} NX_FTP_CLIENT; + + +#ifndef NX_FTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_ftp_client_connect _nx_ftp_client_connect +#define nxd_ftp_client_connect _nxd_ftp_client_connect +#define nx_ftp_client_create _nx_ftp_client_create +#define nx_ftp_client_delete _nx_ftp_client_delete +#define nx_ftp_client_directory_create _nx_ftp_client_directory_create +#define nx_ftp_client_directory_default_set _nx_ftp_client_directory_default_set +#define nx_ftp_client_directory_delete _nx_ftp_client_directory_delete +#define nx_ftp_client_directory_listing_get _nx_ftp_client_directory_listing_get +#define nx_ftp_client_directory_listing_continue _nx_ftp_client_directory_listing_continue +#define nx_ftp_client_disconnect _nx_ftp_client_disconnect +#define nx_ftp_client_file_close _nx_ftp_client_file_close +#define nx_ftp_client_file_delete _nx_ftp_client_file_delete +#define nx_ftp_client_file_open _nx_ftp_client_file_open +#define nx_ftp_client_file_read _nx_ftp_client_file_read +#define nx_ftp_client_file_rename _nx_ftp_client_file_rename +#define nx_ftp_client_file_write _nx_ftp_client_file_write +#define nx_ftp_client_file_size_set _nx_ftp_client_file_size_set +#define nx_ftp_client_passive_mode_set _nx_ftp_client_passive_mode_set +#define nx_ftp_client_transfer_mode_set _nx_ftp_client_transfer_mode_set + +#else + +/* Services with error checking. */ + +#define nx_ftp_client_connect _nxe_ftp_client_connect +#define nxd_ftp_client_connect _nxde_ftp_client_connect +#define nx_ftp_client_create _nxe_ftp_client_create +#define nx_ftp_client_delete _nxe_ftp_client_delete +#define nx_ftp_client_directory_create _nxe_ftp_client_directory_create +#define nx_ftp_client_directory_default_set _nxe_ftp_client_directory_default_set +#define nx_ftp_client_directory_delete _nxe_ftp_client_directory_delete +#define nx_ftp_client_directory_listing_get _nxe_ftp_client_directory_listing_get +#define nx_ftp_client_directory_listing_continue _nxe_ftp_client_directory_listing_continue +#define nx_ftp_client_disconnect _nxe_ftp_client_disconnect +#define nx_ftp_client_file_close _nxe_ftp_client_file_close +#define nx_ftp_client_file_delete _nxe_ftp_client_file_delete +#define nx_ftp_client_file_open _nxe_ftp_client_file_open +#define nx_ftp_client_file_read _nxe_ftp_client_file_read +#define nx_ftp_client_file_rename _nxe_ftp_client_file_rename +#define nx_ftp_client_file_write _nxe_ftp_client_file_write +#define nx_ftp_client_file_size_set _nxe_ftp_client_file_size_set +#define nx_ftp_client_passive_mode_set _nxe_ftp_client_passive_mode_set +#define nx_ftp_client_transfer_mode_set _nxe_ftp_client_transfer_mode_set + +#endif + +/* Define the prototypes accessible to the application software. */ + +UINT nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); +UINT nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); +UINT nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); +UINT nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); +UINT nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); +UINT nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); +UINT nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); +UINT nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); +UINT nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); +UINT nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); +UINT nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); + +#else + +/* FTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxde_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxe_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); +UINT _nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); +UINT _nxe_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); +UINT _nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); +UINT _nxe_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT _nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT _nxe_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); +UINT _nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); +UINT _nxe_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT _nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); +UINT _nxe_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nxe_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nxe_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); +UINT _nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); +UINT _nxe_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); +UINT _nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); +UINT _nxe_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); +UINT _nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); +UINT _nxe_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nxe_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); +UINT _nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); +UINT _nxe_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); +UINT _nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); +UINT _nxe_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); +UINT _nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); + +#endif /* NX_FTP_SOURCE_CODE */ + +/* Internal functions. */ +VOID _nx_ftp_client_data_disconnect(NX_TCP_SOCKET *data_socket_ptr); +UINT _nx_ftp_client_packet_allocate(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_ftp_client_active_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nx_ftp_client_passive_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +VOID _nx_ftp_client_data_socket_cleanup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nx_ftp_client_block_mode_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); +UINT _nx_ftp_client_block_header_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG block_size); +UINT _nx_ftp_client_block_header_retrieve(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr); +UINT _nx_ftp_client_connect_internal(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ip, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_ftp_utility_convert_IPv6_to_ascii(NX_TCP_SOCKET *tcp_socket_ptr, CHAR *buffer, UINT buffer_length, UINT *size); +UINT _nx_ftp_utility_convert_number_ascii(ULONG number, CHAR *numstring); +UINT _nx_ftp_utility_convert_portnumber_ascii(UINT number, CHAR *numstring, UINT *numstring_length); + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_FTP_CLIENT_H */ diff --git a/addons/ftp/nxd_ftp_server.c b/addons/ftp/nxd_ftp_server.c new file mode 100644 index 00000000..0eb1f635 --- /dev/null +++ b/addons/ftp/nxd_ftp_server.c @@ -0,0 +1,6684 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** File Transfer Protocol */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_FTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* If FileX is not used in this application, define this option and define the FileX services + declared in filex_stub.h elsewhere. +#define NX_FTP_NO_FILEX +*/ + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_ftp_server.h" +#include "stdio.h" +#include "string.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/* Define FTP Error codes. */ + +#define NX_FTP_CODE_RESTART_MARKER "110" /* Restart marker reply. + In this case, the text is exact and not left to the + particular implementation; it must read: + MARK yyyy = mmmm + Where yyyy is User-process data stream marker, and mmmm + server's equivalent marker (note the spaces between markers + and "="). */ +#define NX_FTP_CODE_READY_NNN "120" /* Service ready in nnn minutes. */ +#define NX_FTP_CODE_START_XFER "125" /* Data connection already open; transfer starting. */ +#define NX_FTP_CODE_OPENING "150" /* File status okay; about to open data connection. */ +#define NX_FTP_CODE_CMD_OK "200" /* Command okay. */ +#define NX_FTP_CODE_CONNECTION_OK "220" /* Connection okay. */ +#define NX_FTP_CODE_CLOSE "221" /* Service closing control connection. */ +#define NX_FTP_CODE_LOGOFF "226" /* Closing data connection. */ +#define NX_FTP_CODE_LOGIN "230" /* User logged in, proceed. */ +#define NX_FTP_CODE_COMPLETED "250" /* Requested file action okay, completed. */ +#define NX_FTP_CODE_MADE_DIR "257" /* PATHNAME created. */ +#define NX_FTP_CODE_USER_OK "331" /* User name okay, need password. */ +#define NX_FTP_CODE_NEED_ACCT "332" /* Need account for login. */ +#define NX_FTP_CODE_FILE_PEND "350" /* Requested file action pending further information. */ +#define NX_FTP_CODE_CMD_FAIL "501" /* Syntax error in parameters or arguments. */ +#define NX_FTP_CODE_NOT_IMPLEMENTED "502" /* Command not implemented. */ +#define NX_FTP_CODE_UNAUTHORIZED "530" /* Not logged in. */ +#define NX_FTP_CODE_NO_ACCT "532" /* Need account for storing files. */ +#define NX_FTP_CODE_BAD_TYPE "504" /* Invalid TYPE. */ +#define NX_FTP_CODE_BAD_FILE "550" /* Requested action not taken. File unavailable (e.g., file not found, no access). */ +#define NX_FTP_CODE_BAD_PAGE_TYPE "551" /* Requested action aborted: page type unknown. */ +#define NX_FTP_CODE_NO_SPACE "552" /* Requested file action aborted, no space. */ +#define NX_FTP_CODE_BAD_NAME "553" /* Requested action not taken, File name not allowed. */ + +static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number); + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* ftp_server_name Name of FTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* ftp_login Pointer to user's login */ +/* function */ +/* ftp_logout Pointer to user's logout */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (ftp_server_ptr == NX_NULL) || (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) || + (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server create function. */ + status = _nx_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(ftp_server_ptr); + NX_PARAMETER_NOT_USED(ftp_server_name); + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(media_ptr); + NX_PARAMETER_NOT_USED(stack_ptr); + NX_PARAMETER_NOT_USED(stack_size); + NX_PARAMETER_NOT_USED(pool_ptr); + NX_PARAMETER_NOT_USED(ftp_login); + NX_PARAMETER_NOT_USED(ftp_logout); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an FTP server on the specified IP. */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* ftp_server_name Name of FTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* ftp_login Pointer to user's login */ +/* function */ +/* ftp_logout Pointer to user's logout */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_create_internal Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Call actual server create function but set the ftp login and logout arguments to NULL. */ + status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, NX_NULL, NX_NULL); + + /* Set the FTP server to accept login functions having IPv4 address arguments. */ + ftp_server_ptr -> nx_ftp_login_ipv4 = ftp_login_ipv4; + ftp_server_ptr -> nx_ftp_logout_ipv4 = ftp_logout_ipv4; + + /* Return status. */ + return status; +#else + NX_PARAMETER_NOT_USED(ftp_server_ptr); + NX_PARAMETER_NOT_USED(ftp_server_name); + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(media_ptr); + NX_PARAMETER_NOT_USED(stack_ptr); + NX_PARAMETER_NOT_USED(stack_size); + NX_PARAMETER_NOT_USED(pool_ptr); + NX_PARAMETER_NOT_USED(ftp_login_ipv4); + NX_PARAMETER_NOT_USED(ftp_logout_ipv4); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_ftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP duo (IPv4 and IPv6) */ +/* server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* ftp_server_name Name of FTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* ftp_login Pointer to user's login */ +/* function */ +/* ftp_logout Pointer to user's logout */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_ftp_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id == NXD_FTP_SERVER_ID) || + (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) || + (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server create function. */ + status = _nxd_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_ftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a "duo" FTP server on the specified IP for */ +/* IPv4 or IPv6 networks. */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* ftp_server_name Name of FTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* ftp_login Pointer to user's login */ +/* function */ +/* ftp_logout Pointer to user's logout */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_create_internal Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) +{ + + +UINT status; + + + /* Call actual server create function. */ + status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); + + /* Return status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_create_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a FTP server on the specified IP. */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* ftp_server_name Name of FTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* ftp_login Pointer to user's login */ +/* function */ +/* ftp_logout Pointer to user's logout */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_FTP_INSUFFICIENT_PACKET_PAYLOAD Packet payload too small */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create control sockets */ +/* nx_tcp_socket_delete Delete control sockets */ +/* nx_tcp_socket_receive_notify Register receive notify */ +/* callback */ +/* tx_event_flags_create Create event flags */ +/* tx_event_flags_delete Delete event flags */ +/* tx_thread_create Create FTP server thread */ +/* tx_thread_delete Delete FTP server thread */ +/* tx_timer_create Create FTP server timer */ +/* tx_timer_delete Delete FTP server timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_create_internal(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) +{ + +UINT i; +UINT status; + + + /* Clear the FTP server structure. */ + memset((void *) ftp_server_ptr, 0, sizeof(NX_FTP_SERVER)); + + /* Check the supplied packet pool for minimum required payload length (NX_FTP_SERVER_MIN_PACKET_PAYLOAD). This configurable + option is explained in more detail in the header file. */ + if (pool_ptr -> nx_packet_pool_payload_size < NX_FTP_SERVER_MIN_PACKET_PAYLOAD) + { + + return NX_FTP_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Save the packet pool pointer. */ + ftp_server_ptr -> nx_ftp_server_packet_pool_ptr = pool_ptr; + + /* Create the FTP Server thread. */ + status = tx_thread_create(&(ftp_server_ptr -> nx_ftp_server_thread), "FTP Server Thread", _nx_ftp_server_thread_entry, + (ULONG) ftp_server_ptr, stack_ptr, stack_size, NX_FTP_SERVER_PRIORITY, NX_FTP_SERVER_PRIORITY, + NX_FTP_SERVER_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred creating the thread. */ + if (status) + { + + /* Error creating the server thread. */ + return(status); + } + + /* Create the ThreadX event flags. These will be used to driver the FTP server thread. */ + status = tx_event_flags_create(&(ftp_server_ptr -> nx_ftp_server_event_flags), + "FTP Server Thread Events"); + + /* Determine if an error occurred creating the event flags. */ + if (status) + { + + + /* Delete the server thread. */ + tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Error creating the server event flags. */ + return(status); + } + + /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if + a client connection has gone silent and needs to be terminated. */ + status = tx_timer_create(&(ftp_server_ptr -> nx_ftp_server_timer), "FTP Server Timer", _nx_ftp_server_timeout, + (ULONG) ftp_server_ptr, (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD), + (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD), TX_NO_ACTIVATE); + + /* Determine if an error occurred creating the timer. */ + if (status) + { + + /* Delete the server thread. */ + tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Delete the server event flags. */ + tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); + + /* Error creating the server timer. */ + return(status); + } + + /* Loop to create all the FTP client control sockets. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Create an FTP client control socket. */ + status += nx_tcp_socket_create(ip_ptr, &(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket), + "FTP Server Control Socket", NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, + NX_FTP_TIME_TO_LIVE, NX_FTP_CONTROL_WINDOW_SIZE, NX_NULL, _nx_ftp_server_control_disconnect); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Register the receive function. */ + nx_tcp_socket_receive_notify(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket), + _nx_ftp_server_command_present); + } + + /* Make sure each socket points to the FTP server. */ + ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + } + + /* Determine if an error has occurred. */ + if (status) + { + + /* Loop to delete any created sockets. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Delete the FTP socket. */ + nx_tcp_socket_delete(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket)); + } + + /* Delete the server thread. */ + tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); + + /* Delete the timer. */ + tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer)); + + /* Return an error. */ + return(status); + } + + /* Initialize the data port. */ + ftp_server_ptr -> nx_ftp_server_data_port = NX_SEARCH_PORT_START; + + /* Save the Server name. */ + ftp_server_ptr -> nx_ftp_server_name = ftp_server_name; + + /* Save the IP pointer address. */ + ftp_server_ptr -> nx_ftp_server_ip_ptr = ip_ptr; + + /* Set the FTP media pointer address. */ + ftp_server_ptr -> nx_ftp_server_media_ptr = media_ptr; + + /* Save the user-supplied login and logout functions. */ + ftp_server_ptr -> nx_ftp_login = ftp_login; + ftp_server_ptr -> nx_ftp_logout = ftp_logout; + + /* Set the server ID to indicate the FTP server thread is ready. */ + ftp_server_ptr -> nx_ftp_server_id = NXD_FTP_SERVER_ID; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP server delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_delete Actual server delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_ftp_server_delete(ftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created FTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_server_socket_unaccept Unaccept server socket */ +/* nx_tcp_server_socket_unlisten Unlisten on server */ +/* nx_tcp_socket_delete Delete socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* tx_event_flags_delete Delete event flags */ +/* tx_thread_delete Delete thread */ +/* tx_thread_suspend Suspend thread */ +/* tx_thread_terminate Terminate thread */ +/* tx_timer_deactivate Deactivate timer */ +/* tx_timer_delete Delete timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +NX_FTP_CLIENT_REQUEST *client_request_ptr; + + + /* Clear the server ID to indicate the FTP server is no longer ready. */ + ftp_server_ptr -> nx_ftp_server_id = 0; + + /* Suspend the FTP server thread. */ + tx_thread_suspend(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Terminate server thread. */ + tx_thread_terminate(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Delete server thread. */ + tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); + + /* Deactivate and delete timer. */ + tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer)); + tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer)); + + /* Walk through the server structure to close any remaining open files. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++) + { + + /* Set the client request. */ + client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* If created, cleanup the data socket. */ + if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) + { + + /* Disconnect data socket. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Unbind/unaccept the data socket. */ + if (client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + } + + /* Delete data socket. */ + nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + + /* Close file. */ + fx_file_close(&(client_request_ptr -> nx_ftp_client_request_file)); + } + + /* Clear the passive transfer enabled flag. */ + client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Reset the transfer mode as stream mode. */ + client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Reset the block bytes. */ + client_request_ptr -> nx_ftp_client_request_block_bytes = 0; + + /* Disconnect the control and data ports. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); + + /* Unaccept the control socket. */ + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket)); + + /* Delete both the control and data sockets. */ + nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_control_socket)); + } + + /* Unlisten on the FTP control port. */ + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP server start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_start Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nx_ftp_server_start(ftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts a previously created FTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_listen Listen of FTP clients */ +/* tx_thread_resume Resume the FTP server thread */ +/* tx_timer_activate Activate FTP server timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT status; +ULONG events; + + + /* Start listening on the FTP control socket. */ + status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, + &(ftp_server_ptr -> nx_ftp_server_client_list[0].nx_ftp_client_request_control_socket), + NX_FTP_MAX_CLIENTS, _nx_ftp_server_connection_present); + + /* Determine if an error is present. */ + if (status) + { + + /* Error, return to caller. */ + return(status); + } + + /* Activate FTP server timer. */ + tx_timer_activate(&(ftp_server_ptr -> nx_ftp_server_timer)); + + /* Clear stop event. */ + tx_event_flags_get(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR_CLEAR, &events, TX_NO_WAIT); + + /* Start the FTP server thread. */ + tx_thread_resume(&(ftp_server_ptr -> nx_ftp_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ftp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the FTP server stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_stop Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_ftp_server_stop(ftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops a previously started FTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend the FTP server thread */ +/* tx_timer_deactivate Deactivate FTP server timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +NX_FTP_CLIENT_REQUEST *client_request_ptr; + + /* Deactivate FTP server timer. */ + tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer)); + + /* Suspend the FTP server thread. */ + tx_event_flags_set(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR); + + /* Walk through the server structure to close any remaining open files. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++) + { + + /* Set the client request. */ + client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* If created, cleanup the data socket. */ + if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) + { + + /* Disconnect data socket. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Unbind/unaccept the data socket. */ + if (client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + } + + /* Delete data socket. */ + nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_data_socket)); + + /* Close file. */ + fx_file_close(&(client_request_ptr -> nx_ftp_client_request_file)); + } + + /* Clear the passive transfer enabled flag. */ + client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Reset the transfer mode as stream mode. */ + client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Reset the block bytes. */ + client_request_ptr -> nx_ftp_client_request_block_bytes = 0; + + /* Disconnect the control and data ports. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); + + /* Unaccept the control socket. */ + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket)); + + /* Delete both the control and data sockets. */ + nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_control_socket)); + } + + /* Unlisten on the FTP control port. */ + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an FTP Server response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket FTP socket */ +/* packet_ptr Response packet pointer */ +/* reply_code Reply code string */ +/* message Optional message */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Packet release */ +/* nx_tcp_socket_send Send TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX FTP Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message) +{ + +UCHAR *buffer_ptr; +UINT status; + + + /* Set the packet prepend pointer. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; + packet_ptr -> nx_packet_length = 0; + + /* Now setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Copy reply code to the packet. */ + while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) + { + + /* copy the next character */ + *buffer_ptr++ = (UCHAR) *reply_code++; + + /* Update the packet length. */ + packet_ptr -> nx_packet_length++; + } + + /* Add a separating space */ + *buffer_ptr++ = (UCHAR) ' '; + packet_ptr -> nx_packet_length++; + + /* Copy message to the packet */ + while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) + { + + /* copy the next character */ + *buffer_ptr++ = (UCHAR) *message++; + + /* Update the packet length. */ + packet_ptr -> nx_packet_length++; + } + + /* Add a trailing space, CR, LF. */ + *buffer_ptr++ = ' '; + *buffer_ptr++ = 13; + *buffer_ptr = 10; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length += 3; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the failed message back. */ + status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_directory_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an FTP Server directory response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket FTP socket */ +/* packet_ptr Response packet pointer */ +/* reply_code Reply code string */ +/* message Optional message */ +/* directory Directory path */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Packet release */ +/* nx_tcp_socket_send Send TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX FTP Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_directory_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message, CHAR *directory) +{ + +UCHAR *buffer_ptr; +UINT status; + + + /* Set the packet prepend pointer. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; + packet_ptr -> nx_packet_length = 0; + + /* Now setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Copy reply code to the packet. */ + while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) + { + + /* copy the next character. */ + *buffer_ptr++ = (UCHAR) *reply_code++; + + /* Update the packet length. */ + packet_ptr -> nx_packet_length++; + } + + /* Add a separating space and the leading ". */ + *buffer_ptr++ = (UCHAR) ' '; + packet_ptr -> nx_packet_length++; + + *buffer_ptr++ = (UCHAR) '"'; + packet_ptr -> nx_packet_length++; + + /* Is there a valid directory. */ + if ((directory != NULL) && (*directory)) + { + + /* If the directory doesn't start with a / then make sure it does. */ + if ((*directory != '/') && (*directory != '\\')) + { + + /* Add / to message. */ + *buffer_ptr++ = (UCHAR) '/'; + packet_ptr -> nx_packet_length++; + } + + /* Copy directory to the packet. */ + while ((*directory) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) + { + + /* Copy the next character , doubling any " characters. */ + if (*directory == '"') + { + + /* Double the character. */ + *buffer_ptr++ = (UCHAR) *directory; + packet_ptr -> nx_packet_length++; + } + + /* Copy the directory character, converting backslashes to slashes. */ + if (*directory == '\\') + { + + /* Convert to slash for consistency. */ + *buffer_ptr++ = (UCHAR) '/'; + directory++; + } + else + { + + /* Copy regular directory character. */ + *buffer_ptr++ = (UCHAR) *directory++; + } + + /* Update the packet length. */ + packet_ptr -> nx_packet_length++; + } + } + else + { + + /* No valid directory, simply assume root. */ + *buffer_ptr++ = (UCHAR) '/'; + packet_ptr -> nx_packet_length++; + } + + /* Add the trailing " and a separating space. */ + *buffer_ptr++ = (UCHAR) '"'; + packet_ptr -> nx_packet_length++; + + *buffer_ptr++ = (UCHAR) ' '; + packet_ptr -> nx_packet_length++; + + /* Copy message to the packet. */ + while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) + { + + /* Copy the next character. */ + *buffer_ptr++ = (UCHAR) *message++; + + /* Update the packet length. */ + packet_ptr -> nx_packet_length++; + } + + /* Add a trailing space, CR, LF. */ + *buffer_ptr++ = (UCHAR) ' '; + *buffer_ptr++ = (UCHAR) 13; + *buffer_ptr = (UCHAR) 10; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length += 3; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the failed message back. */ + status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry of the FTP server. All basic */ +/* processing is initiated by this function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_address Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_command_process Process client FTP command */ +/* _nx_ftp_server_connect_process Process connection requests */ +/* _nx_ftp_server_control_disconnect_processing */ +/* Process control disconnect */ +/* _nx_ftp_server_data_disconnect_process Process data disconnection */ +/* requests */ +/* _nx_ftp_server_data_process Process client write data */ +/* _nx_ftp_server_timeout_processing Process activity timeout */ +/* tx_event_flags_get Get FTP event(s) */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_thread_entry(ULONG ftp_server_address) +{ + +NX_FTP_SERVER *server_ptr; +UINT status; +ULONG events; + + + /* Setup the server pointer. */ + server_ptr = (NX_FTP_SERVER *) ftp_server_address; + + /* Loop to process FTP Server requests. */ + while(1) + { + + /* Wait for an FTP client activity. */ + status = tx_event_flags_get(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_ANY_EVENT, + TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Check the return status. */ + if (status) + { + + /* If an error occurs, simply continue the loop. */ + continue; + } + + /* Check whether service is started. */ + if (events & NX_FTP_STOP_EVENT) + { + + /* Suspend thread here. */ + tx_thread_suspend(&server_ptr -> nx_ftp_server_thread); + continue; + } + + /* Otherwise, an event is present. Process according to the event. */ + + /* Check for a client connection event. */ + if (events & NX_FTP_SERVER_CONNECT) + { + + /* Call the connect processing. */ + _nx_ftp_server_connect_process(server_ptr); + } + + /* Check for an FTP client write data event. */ + if (events & NX_FTP_SERVER_DATA) + { + + /* Call processing to handle client file write data. */ + _nx_ftp_server_data_process(server_ptr); + } + + /* Check for a FTP client command event. */ + if (events & NX_FTP_SERVER_COMMAND) + { + + /* Call the command processing. */ + _nx_ftp_server_command_process(server_ptr); + } + + /* Check for a client disconnect event. */ + if (events & NX_FTP_SERVER_DATA_DISCONNECT) + { + + /* Call the data disconnect processing. */ + _nx_ftp_server_data_disconnect_process(server_ptr); + } + + /* Check for a control disconnect event. */ + if (events & NX_FTP_SERVER_CONTROL_DISCONNECT) + { + + /* Call the control disconnect processing. */ + _nx_ftp_server_control_disconnect_processing(server_ptr); + } + + + /* Check for a client activity timeout event. */ + if (events & NX_FTP_SERVER_ACTIVITY_TIMEOUT) + { + + /* Call the activity timeout processing. */ + _nx_ftp_server_timeout_processing(server_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_command_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all FTP client commands received on all */ +/* client connections. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_parse_command Parse FTP client command */ +/* _nx_ftp_server_response Send FTP response */ +/* _nx_ftp_server_directory_response Send FTP response for dir */ +/* _nx_ftp_server_number_to_ascii Converts number to ascii text */ +/* fx_file_attributes_read Read file attributes */ +/* fx_file_close Close file */ +/* fx_file_delete Delete file */ +/* fx_file_open Open file */ +/* fx_file_read Read from file */ +/* fx_file_rename Rename file */ +/* fx_file_truncate Truncate file */ +/* fx_directory_attributes_read Read directory attributes */ +/* fx_directory_create Create directory */ +/* fx_directory_delete Delete directory */ +/* fx_directory_first_entry_find Find first directory entry */ +/* fx_directory_local_path_restore Restore directory path */ +/* fx_directory_local_path_set Set directory path */ +/* fx_directory_next_entry_find Find next directory entry */ +/* fx_media_flush Flush cached media sectors */ +/* nx_ftp_packet_allocate Allocate a packet */ +/* nx_packet_release Release a packet */ +/* nx_tcp_client_socket_bind Bind client socket */ +/* nx_tcp_client_socket_connect Connect client socket */ +/* nxd_tcp_client_socket_connect Connect client socket in IPv6 */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_server_socket_relisten Relisten on server socket */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_socket_create Create data socket */ +/* nx_tcp_socket_delete Delete data socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* nx_tcp_socket_receive Receive from command socket */ +/* nx_tcp_socket_send Send packet */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_socket_delete Delete socket */ +/* nx_tcp_socket_receive Receive packet */ +/* nx_tcp_socket_receive_notify Register notification routine */ +/* nx_tcp_socket_transmit_configure Configure data transer socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr) +{ + + +#ifdef FEATURE_NX_IPV6 +NXD_ADDRESS ipduo_address; +UINT port_size; +#endif +#ifndef NX_DISABLE_IPV4 +ULONG connect_ip4_address = 0; +UINT commas; +ULONG ip_address; +UINT temp; +#endif /* NX_DISABLE_IPV4 */ +UINT i, j; +INT k; +UINT port; +ULONG length; +ULONG remaining_length; +UINT status; +UINT ftp_command; +UINT single_file; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +FX_LOCAL_PATH temp_path; +NX_FTP_CLIENT_REQUEST *client_req_ptr; +UINT attributes; +ULONG size; +UINT year, month, day; +UINT hour, minute, second; +CHAR filename[FX_MAX_LONG_NAME_LEN]; +const char *months[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; +UINT no_more_ftp_entries = NX_FALSE; +ULONG block_size; + + year = 1900; + month = 1; + day = 1; + hour = 1; + minute = 1; + second = 1; + attributes = 1; + size = 1; + + /* Now look for a socket that has receive data. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + +#ifndef NX_DISABLE_IPV4 + if(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + connect_ip4_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4; + } +#endif /* NX_DISABLE_IPV4 */ + + /* Now see if this socket has data. */ + if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_receive_queue_count) + { + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; + + /* Attempt to read a packet from this socket. */ + status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_control_socket), &packet_ptr, NX_NO_WAIT); + + /* Check for not data present. */ + if (status != NX_SUCCESS) + { + + /* Just continue the loop and look at the next socket. */ + continue; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* And continue looking at other client requests. */ + continue; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Now, parse the command in the packet. Note that the parse command adjusts the packet pointer + such that it is positioned at the next token in the buffer. */ + ftp_command = _nx_ftp_server_parse_command(packet_ptr); + + /* Check to make sure the client request is authenticated. */ + if ((client_req_ptr -> nx_ftp_client_request_authenticated == NX_FALSE) && + (ftp_command != NX_FTP_USER) && (ftp_command != NX_FTP_PASS)) + { + + /* Unauthorized request. */ + + /* Increment the access error count. */ + ftp_server_ptr -> nx_ftp_server_authentication_errors++; + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_UNAUTHORIZED, "Not logged in"); + + /* And continue looking at other client requests. */ + continue; + } + + /* Check to make sure the client has write access if requesting a write. */ + else if ((client_req_ptr -> nx_ftp_client_request_read_only == NX_TRUE) && + ((ftp_command == NX_FTP_STOR) || (ftp_command == NX_FTP_RNFR) || (ftp_command == NX_FTP_RNTO) || + (ftp_command == NX_FTP_DELE) || (ftp_command == NX_FTP_RMD ) || (ftp_command == NX_FTP_MKD ))) + { + + /* Unauthorized request. */ + + /* Increment the access error count. */ + ftp_server_ptr -> nx_ftp_server_authentication_errors++; + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_NO_ACCT, "Need account for storing files"); + + /* And continue looking at other client requests. */ + continue; + } + + /* Switch on the command received. */ + switch(ftp_command) + { + + case NX_FTP_USER: + { + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First, save the username in the request structure. */ + for (j = 0; j < (NX_FTP_USERNAME_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++) + { + + /* Copy a character. */ + client_req_ptr -> nx_ftp_client_request_username[j] = (CHAR) buffer_ptr[j]; + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + } + + /* Ensure the username is NULL terminated. */ + client_req_ptr -> nx_ftp_client_request_username[j] = NX_NULL; + + /* Now send an intermediate response to the username. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_USER_OK, "Enter password"); + break; + } + + case NX_FTP_PASS: + { + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First, save the password in the request structure. */ + for (j = 0; j < (NX_FTP_PASSWORD_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++) + { + + /* Copy a character. */ + client_req_ptr -> nx_ftp_client_request_password[j] = (CHAR) buffer_ptr[j]; + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + } + + /* Ensure the password is NULL terminated. */ + client_req_ptr -> nx_ftp_client_request_password[j] = NX_NULL; + + /* Initially assume client will have read-write access. */ + client_req_ptr -> nx_ftp_client_request_read_only = NX_FALSE; + + /* Initialize the login status as unsuccessful. */ + status = NX_FTP_INVALID_LOGIN; + + /* Does this FTP server have an login handler? */ + if (ftp_server_ptr -> nx_ftp_login) + { + + /* Now call the user's login callback routine to see if the username,password is valid. */ + status = (ftp_server_ptr -> nx_ftp_login)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, + &client_req_ptr -> nx_ftp_client_request_read_only); + } +#ifndef NX_DISABLE_IPV4 + else + { + + /* No duo handler. Check if this is an IPv4 connection. */ + if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4) + { + + /* This is an IPv4 connection. */ + + /* Does this server have an IPv4 login function? */ + if (ftp_server_ptr -> nx_ftp_login_ipv4) + { + + /* Yes; Now call the user's login callback routine to see if the username,password is valid. */ + status = (ftp_server_ptr -> nx_ftp_login_ipv4) + (ftp_server_ptr, + (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4), + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, + &client_req_ptr -> nx_ftp_client_request_read_only); + } + } + } +#endif /* NX_DISABLE_IPV4 */ + + /* Set the login as TRUE. */ + client_req_ptr -> nx_ftp_client_request_login = NX_TRUE; + + if (status == NX_SUCCESS) + { + + /* Successful connection. */ + + /* Mark as authenticated. */ + client_req_ptr -> nx_ftp_client_request_authenticated = NX_TRUE; + + /* Default transfer type is ASCII image. */ + client_req_ptr -> nx_ftp_client_request_transfer_type = 'A'; + + /* Now build a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_LOGIN, "Logged in"); + } + else + { + + /* Unsuccessful login. */ + + /* Increment the number of login errors. */ + ftp_server_ptr -> nx_ftp_server_login_errors++; + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_UNAUTHORIZED, "Login Fail"); + } + + break; + } + + case NX_FTP_QUIT: + { + + /* Increment the number of disconnection requests. */ + ftp_server_ptr -> nx_ftp_server_disconnection_requests++; + + /* Check if this client login. */ + if (client_req_ptr -> nx_ftp_client_request_login) + { + + /* Call the logout function. */ + +#ifndef NX_DISABLE_IPV4 + /* Does this server have an IPv4 login function? */ + if (ftp_server_ptr -> nx_ftp_logout_ipv4) + { + + /* Call the logout which takes IPv4 address input. */ + (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr, + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4, + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, NX_NULL); + } +#endif /* NX_DISABLE_IPV4 */ + if (ftp_server_ptr -> nx_ftp_logout) + { + + /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */ + (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, NX_NULL); + } + + /* Set the login as FALSE. */ + client_req_ptr -> nx_ftp_client_request_login = NX_FALSE; + } + + /* Clear authentication. */ + client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CLOSE, "Logging Off"); + + /* Now disconnect the command socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); + + /* Unaccept the server socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); + + /* Relisten on this socket. This will probably fail, but it is needed just in case all available + clients were in use at the time of the last relisten. */ + nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, + &(client_req_ptr -> nx_ftp_client_request_control_socket)); + + /* Check to see if a packet is queued up. */ + if (client_req_ptr -> nx_ftp_client_request_packet) + { + + /* Yes, release it! */ + nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); + } + + /* Disable the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; + break; + } + + case NX_FTP_RETR: + { + + /* Check that the transfer type is a Binary Image. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I') + { + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed"); + + /* We are done processing. */ + break; + } + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Attempt to open the file. */ + status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, + &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, + FX_OPEN_FOR_READ); + + /* Determine if the file open was successful. */ + if (status == FX_SUCCESS) + { + + /* Check if passive transfer enabled. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + + /* Now wait for the data connection to connect. */ + status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + else + { + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, + &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, + NX_NULL, NX_NULL); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Bind the socket to the FTP server data port. */ + status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); + + /* Determine if the socket was bound. */ + if (status) + { + + /* FTP server data port is busy, use any data port. */ + nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); + } + + /* Now attempt to connect the data port to the client's data port. */ + status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), + &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + } + } + + /* Now check and see if the open for read has any errors. */ + if (status == NX_SUCCESS) + { + + /* The open for read command is successful! */ + + /* Set the open for read type in the client request structure. */ + client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_READ; + + /* Set the total bytes field to files size. */ + client_req_ptr -> nx_ftp_client_request_total_bytes = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_START_XFER, "File Opened"); + + /* Determine if the block mode is enabled. */ + if ((client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) && + (client_req_ptr -> nx_ftp_client_request_total_bytes)) + { + + /* Send start block header for file size. */ + status = _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, + client_req_ptr -> nx_ftp_client_request_total_bytes); + } + + /* Now read the file and send the contents to the client. */ + while (status == NX_SUCCESS) + { + + /* Allocate a new packet. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Calculate the maximum read size. */ + length = ((ULONG) (packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - NX_PHYSICAL_TRAILER; + + /* Determine if the length is greater than the connected MSS. */ + if (length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) + { + + /* Yes, reduce the length to match the MSS. */ + length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; + } + + /* Read a buffer's worth of the file. */ + status = fx_file_read(&(client_req_ptr -> nx_ftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr, length, &length); + + /* Determine if the file read was successful. */ + if (status == FX_SUCCESS) + { + + /* Now send the packet on the data socket. */ + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = length; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the file data to the client. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), + packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + else + { + + /* Update the remaining bytes in the file. */ + client_req_ptr -> nx_ftp_client_request_total_bytes = client_req_ptr -> nx_ftp_client_request_total_bytes - length; + + /* Increment the number of bytes sent. */ + ftp_server_ptr -> nx_ftp_server_total_bytes_sent += length; + } + } + else + { + + /* Release packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Send end block header for file size. */ + _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); + } + + /* Disconnect the data socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); + + /* Tear down the client data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + + /* Clear the open type in the client request structure. */ + client_req_ptr -> nx_ftp_client_request_open_type = 0; + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Allocate a new packet. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Now determine if the read was a success. */ + if ((status == FX_END_OF_FILE) && (client_req_ptr -> nx_ftp_client_request_total_bytes == 0)) + { + + /* The read command was successful! */ + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "File Sent"); + } + else + { + + /* Read command failed. */ + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Read Fail"); + } + } + else + { + + /* Unsuccessful open for read or read command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "File Open Fail"); + } + + break; + } + + case NX_FTP_STOR: + { + + /* Check that the transfer type is a Binary Image. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I') + { + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed"); + + /* And we are done processing. */ + break; + } + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Attempt to open the file. */ + status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); + + + /* Determine if there was an error. */ + if (status != FX_SUCCESS) + { + + /* Create a new file. */ + status = fx_file_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); + + if (status == FX_SUCCESS) + { + + /* Open the new file. */ + status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); + } + } + + /* Truncate the file to a size of 0. */ + status += fx_file_truncate(&(client_req_ptr -> nx_ftp_client_request_file), 0); + + /* Determine if the file create/open was successful. */ + if (status == FX_SUCCESS) + { + + /* Check if passive transfer enabled. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + + /* Set the disconnect callback. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_disconnect_callback = _nx_ftp_server_data_disconnect; + + /* Register the receive function. */ + nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket), _nx_ftp_server_data_present); + + /* Now wait for the data connection to connect. */ + status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + else + { + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, _nx_ftp_server_data_disconnect); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Register the receive function. */ + nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket), + _nx_ftp_server_data_present); + + /* Bind the socket to the FTP server data port. */ + status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); + + /* Determine if the socket was bound. */ + if (status) + { + + /* FTP server data port is busy, use any data port. */ + nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); + } + /* Now attempt to connect the data port to the client's data port. */ + status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), + &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); + + + /* Check for connect error. */ + if (status) + { + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + } + else + { + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + } + } + + /* Now check and see if the open for write has any errors. */ + if (status == NX_SUCCESS) + { + + /* The open for writing command is successful! */ + + /* Set the open for write type in the client request structure. */ + client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_WRITE; + + /* Set the total bytes field to zero. */ + client_req_ptr -> nx_ftp_client_request_total_bytes = 0; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_START_XFER, "File Open for Write"); + } + else + { + /* Unsuccessful open for writing command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "File Open Failed"); + } + + break; + } + + case NX_FTP_RNFR: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Read the file attributes to see if it is actually there. */ + status = fx_file_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j); + + /* If not a file, read the directory attributes. */ + if (status == FX_NOT_A_FILE) + status = fx_directory_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j); + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + /* Successful start to the file rename. */ + + /* Save the packet in the client request structure. */ + client_req_ptr -> nx_ftp_client_request_packet = packet_ptr; + + /* Allocate a new packet. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_FILE_PEND, "Rename File From"); + } + else + { + + /* Unsuccessful first half of file rename. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Rename File not found"); + } + break; + } + + case NX_FTP_RNTO: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Rename the file. */ + status = fx_file_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr); + + /* If not a file, rename the directory. */ + if (status == FX_NOT_A_FILE) + status = fx_directory_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + + /* Release the packet in the client request structure. */ + nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); + client_req_ptr -> nx_ftp_client_request_packet = NX_NULL; + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + /* Successful file rename. */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "File Renamed"); + } + else + { + + /* Unsuccessful file rename. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Rename failed"); + } + break; + } + + case NX_FTP_DELE: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Remove the specified file. */ + status = fx_file_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + /* Successful delete file. */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "File Deleted"); + } + else + { + + /* Unsuccessful file delete. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Delete Failed"); + } + break; + } + + case NX_FTP_RMD: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Remove the specified directory. */ + status = fx_directory_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + /* Successful delete directory. */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "Directory Deleted"); + } + else + { + + /* Unsuccessful directory delete. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Delete Directory Fail"); + } + break; + } + + case NX_FTP_MKD: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Create the specified directory. */ + status = fx_directory_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + FX_LOCAL_PATH temporary_path; + + + /* Successful create directory. */ + + /* Change the path to the new directory, using a temporary directory structure */ + status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temporary_path, (CHAR *) buffer_ptr); + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + CHAR *local_dir; + + + /* Successful change directory. */ + + /* Get the actual path */ + fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); + + /* Now send a successful response to the client. */ + _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Directory Created", local_dir); + } + else + { + /* Unsuccessful directory change. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Set New Directory Fail"); + } + + /* Restore the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + } + else + { + + /* Unsuccessful directory create. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Directory Create failed"); + } + break; + } + + case NX_FTP_NLST: + { + + /* Assume ASCII and relax restriction. */ + if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') && + (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')) + { + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed"); + + /* And we are done processing. */ + break; + } + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Determine if there is a directory path. */ + if (j) + { + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Set the path to the supplied directory. */ + status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr); + } + else + { + + /* Just set the buffer pointer to NULL since there isn't a string. */ + buffer_ptr = NX_NULL; + + /* Default status to success. */ + status = FX_SUCCESS; + } + + + /* Determine if the path setup was successful. */ + if (status == FX_SUCCESS) + { + + /* Check if passive transfer enabled. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + + /* Now wait for the data connection to connect. */ + status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + else + { + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Bind the socket to the FTP server data port. */ + status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); + + /* Determine if the socket was bound. */ + if (status) + { + + /* FTP server data port is busy, use any data port. */ + nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); + } + /* Now attempt to connect the data port to the client's data port. */ + status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), + &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); + + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + } + } + + /* Now check and see if the directory listing command has any errors. */ + if (status == NX_SUCCESS) + { + + /* The directory listing is successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_START_XFER, "Sending List"); + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Get the directory listing size. */ + _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size); + + /* Send start block header for file size. */ + if (block_size) + _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size); + } + + /* Allocate a new packet. */ + status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Calculate the remaining length. */ + remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); + + /* Determine if the advertised MSS is even less. */ + if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) + { + + /* Reduce the remaining length to the MSS value. */ + remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; + } + + /* Now generate the full directory listing and send the contents to the client. */ + j = 0; + while (status == NX_SUCCESS) + { + + /* Pickup the next directory entry. */ + if (j == 0) + { + + + /* First directory entry. */ + status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + + } + else + { + + /* Not the first entry - pickup the next! */ + status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + + } + + /* Increment the entry count. */ + j++; + + /* Determine if successful. */ + if (status == NX_SUCCESS) + { + + /* Setup pointer to buffer. */ + buffer_ptr = packet_ptr -> nx_packet_append_ptr; + + /* Calculate the size of the name. */ + length = 0; + do + { + if (filename[length]) + length++; + else + break; + } while (length < FX_MAX_LONG_NAME_LEN); + + /* Make sure there is enough space for the file name. */ + if ((length + 2) > remaining_length) + { + + /* Send the current buffer out. */ + + /* Send the directory data to the client. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), + packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Allocate a new packet. */ + status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if the packet allocate was successfull. */ + if (status) + { + + /* Get out of the loop! */ + break; + } + + /* Calculate the remaining length. */ + remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); + + /* Determine if the advertised MSS is even less. */ + if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) + { + + /* Reduce the remaining length to the MSS value. */ + remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; + } + + /* Setup pointer to buffer. */ + buffer_ptr = packet_ptr -> nx_packet_append_ptr; + } + + /* Put the file name and cr/lf in the buffer*/ + memcpy(buffer_ptr, filename, length); + buffer_ptr[length++] = '\r'; + buffer_ptr[length++] = '\n'; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length; + + /* Adjust the remaining length. */ + remaining_length = remaining_length - length; + } + } + + /* Now determine if the directory listing was a success. */ + if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length)) + { + + no_more_ftp_entries = NX_TRUE; + + /* Send the directory data to the client. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), + packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + } + else if (packet_ptr) + { + + /* Release packet just in case! */ + nx_packet_release(packet_ptr); + } + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Send end block header for file size. */ + _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); + } + + /* Disconnect the data socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); + + /* Tear down the client data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Allocate a new packet. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Now determine if the directory listing was a success (e..g runs until no more entries found). */ + if (no_more_ftp_entries) + { + + /* The directory listing was successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "List End"); + } + else + { + + /* Directory listing command failed. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "List fail"); + } + } + else + { + /* Unsuccessful directory listing command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "List bad Directory"); + } + break; + } + + case NX_FTP_LIST: + { + + /* Assume ASCII and relax restriction. */ + if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') && + (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')) + { + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed"); + + /* And we are done processing. */ + break; + } + + /* Change to the default directory of this connection. */ + status = fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Find the end of the message. */ + j = 0; + k = -1; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a slash or backslash is present. */ + if ((buffer_ptr[j] == '/') || (buffer_ptr[j] == '\\')) + k = (INT)j; + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Default the single file specified flag to false. */ + single_file = NX_FALSE; + + /* Determine if there is a directory path. */ + if (j) + { + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + + /* Set the path to the supplied directory. */ + status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr); + + /* Determine if the path setup was unsuccessful. */ + if (status) + { + + /* Pickup the information for the single file. */ + status = fx_directory_information_get(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + + /* Determine if a file is specified as the LIST parameter. */ + if ((status == FX_SUCCESS) && ((attributes & FX_DIRECTORY) == 0)) + { + + /* Yes, a file name was supplied. Set the single file flag for the processing below. */ + single_file = NX_TRUE; + + /* Advance to first character of the filename. */ + k++; + + /* Copy the file name from the last slash into the filename buffer. */ + j = 0; + while ((buffer_ptr[(UINT)k + j]) && (j < FX_MAX_LONG_NAME_LEN-1)) + { + + /* Copy a character of the filename. */ + filename[j] = (CHAR)(buffer_ptr[(UINT)k + j]); + + /* Move to next character. */ + j++; + } + + /* Null terminate the string. */ + filename[j] = NX_NULL; + } + } + } + else + { + + /* Just set the buffer pointer to NULL since there isn't a string. */ + buffer_ptr = NX_NULL; + } + + /* Determine if the path setup was successful. */ + if (status == FX_SUCCESS) + { + + CHAR *local_dir; + + + /* Get the actual path */ + fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); + + /* Check if passive transfer enabled. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + + /* Now wait for the data connection to connect. */ + status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + else + { + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Bind the socket to the FTP server data port. */ + status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); + + /* Determine if the socket was bound. */ + if (status) + { + + /* FTP server data port is busy, use any data port. */ + nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); + } + + /* Now attempt to connect the data port to the client's data port. */ + status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), + &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); + + + /* Check for connect error. */ + if (status) + { + + /* Yes, a connect error is present. Tear everything down. */ + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + } + else + { + + /* Setup the data port with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), + NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_FTP_SERVER_RETRY_MAX, + NX_FTP_SERVER_RETRY_SHIFT); + } + } + } + } + + /* Now check and see if the directory listing command has any errors. */ + if (status == NX_SUCCESS) + { + + /* The directory listing is successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_START_XFER, "Sending List"); + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Get the directory listing size. */ + _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size); + + /* Send start block header for file size. */ + if (block_size) + _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size); + } + + /* Allocate a new packet. */ + status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Calculate the remaining length. */ + remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); + + /* Determine if the advertised MSS is even less. */ + if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) + { + + /* Reduce the remaining length to the MSS value. */ + remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; + } + + /* Now generate the full directory listing and send the contents to the client. */ + j = 0; + while (status == NX_SUCCESS) + { + + /* Determine if a single file was specified. */ + if (single_file == NX_FALSE) + { + + /* Typical case - not a single file. */ + + /* Pickup the next directory entry. */ + if (j == 0) + { + + /* First directory entry. */ + status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + + } + else + { + + /* Not the first entry - pickup the next! */ + status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + + } + } + else + { + + /* The parameter to the LIST command is a single file. Simply return the information + already gathered above for this one file instead of traversing the entire list. */ + + /* Is this the first pass through the loop? */ + if (j) + { + + /* End the loop, since the single file has already been sent. */ + status = FX_NO_MORE_ENTRIES; + } + } + + /* Increment the entry count. */ + j++; + + /* Determine if successful. */ + if (status == NX_SUCCESS) + { + + /* Check if the month is valid before convert it. */ + if ((month < 1) || (month > 12)) + continue; + + /* Setup pointer to buffer. */ + buffer_ptr = packet_ptr -> nx_packet_append_ptr; + + /* Calculate the size of the name. */ + length = 0; + do + { + if (filename[length]) + length++; + else + break; + } while (length < FX_MAX_LONG_NAME_LEN); + + /* Make sure there is enough space for the data plus the file info. + File Info is 10 chars for permissions, 15 chars for owner and group, + 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */ + if ((length + 52) > remaining_length) + { + + /* Send the current buffer out. */ + + /* Send the directory data to the client. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Allocate a new packet. */ + status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if the packet allocate was successfull. */ + if (status) + { + + /* Get out of the loop! */ + break; + } + + /* Calculate the remaining length. */ + remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); + + /* Determine if the advertised MSS is even less. */ + if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) + { + + /* Reduce the remaining length to the MSS value. */ + remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; + } + + /* Setup pointer to buffer. */ + buffer_ptr = packet_ptr -> nx_packet_append_ptr; + } + + /* Put the file information followed by the file name */ + buffer_ptr[0] = ((attributes & FX_DIRECTORY) ? 'd' : '-'); + if (attributes & FX_READ_ONLY) + { + memcpy(&buffer_ptr[1], "r--r--r--", 9); + } + else + { + memcpy(&buffer_ptr[1], "rw-rw-rw-", 9); + } + memcpy(&buffer_ptr[10], " 1 owner group ", 16); + _nx_ftp_server_number_to_ascii(&buffer_ptr[26], 10, size); + buffer_ptr[36] = ' '; + buffer_ptr[37] = (UCHAR)months[month - 1][0]; + buffer_ptr[38] = (UCHAR)months[month - 1][1]; + buffer_ptr[39] = (UCHAR)months[month - 1][2]; + buffer_ptr[40] = ' '; + _nx_ftp_server_number_to_ascii(&buffer_ptr[41], 2, day); + buffer_ptr[43] = ' '; + _nx_ftp_server_number_to_ascii(&buffer_ptr[44], 2, hour); + buffer_ptr[46] = ':'; + _nx_ftp_server_number_to_ascii(&buffer_ptr[47], 2, minute); + buffer_ptr[49] = ' '; + memcpy(&buffer_ptr[50], filename, length); + length += 50; + buffer_ptr[length++] = '\r'; + buffer_ptr[length++] = '\n'; + + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length; + + /* Adjust the remaining length. */ + remaining_length = remaining_length - length; + } + } + + /* Now determine if the directory listing was a success. */ + if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length)) + { + + /* Send the directory data to the client. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), + packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + else + { + + /* Reset the status for the response processing below. */ + status = FX_NO_MORE_ENTRIES; + } + } + else if (packet_ptr) + { + + /* Release packet just in case! */ + nx_packet_release(packet_ptr); + } + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Send end block header for file size. */ + _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); + } + + /* Disconnect the data socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); + + /* Tear down the client data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Allocate a new packet. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Now determine if the directory listing was a success. */ + if (status == FX_NO_MORE_ENTRIES) + { + + /* The directory listing was successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "List End"); + } + else + { + + /* Directory listing command failed. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "List fail"); + } + } + else + { + /* Unsuccessful directory listing command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Bad Directory"); + } + break; + } + +#ifndef NX_DISABLE_IPV4 + case NX_FTP_PORT: + { + + + /* Check that only IPv4 packets can use the PORT command. */ + if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + /* Illegal PORT command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_NOT_IMPLEMENTED, "PORT illegal in IPv6"); + + /* Bail out! */ + break; + } + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First, pickup the IP address. */ + commas = 0; + ip_address = 0; + j = 0; + temp = 0; + status = NX_SUCCESS; + while (j < packet_ptr -> nx_packet_length) + { + + /* Is a numeric character present? */ + if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) + { + + /* Yes, numeric character is present. Update the IP address. */ + temp = (temp*10) + (ULONG) (buffer_ptr[j] - '0'); + } + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + { + status = NX_FTP_INVALID_COMMAND; + break; + } + + /* Determine if a comma is present. */ + if (buffer_ptr[j] == ',') + { + + /* Increment the comma count. */ + commas++; + + /* Setup next byte of IP address. */ + ip_address = (ip_address << 8) & 0xFFFFFFFF; + ip_address = ip_address | (temp & 0xFF); + temp = 0; + + /* Have we finished with the IP address? */ + if (commas == 4) + { + + /* Finished with IP address. */ + j++; + break; + } + + } + + /* Move to next character. */ + j++; + } + + /* Now pickup the port number. */ + port = 0; + temp = 0; + while (j < packet_ptr -> nx_packet_length) + { + + /* Is a numeric character present? */ + if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) + { + + /* Yes, numeric character is present. Update the IP port. */ + temp = (temp*10) + (UINT) (buffer_ptr[j] - '0'); + } + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + { + /* Good condition on the port number! */ + break; + } + + /* Determine if a comma is present. */ + if (buffer_ptr[j] == ',') + { + + /* Increment the comma count. */ + commas++; + + /* Move port number up. */ + port = (port << 8) & 0xFFFFFFFF; + port = port | (temp & 0xFF); + temp = 0; + + /* Have we finished with the IP address? */ + if (commas >= 6) + { + + /* Error, get out of the loop. */ + status = NX_FTP_INVALID_ADDRESS; + break; + } + } + + /* Move to next character. */ + j++; + } + + /* Move port number up. */ + port = (port << 8) & 0xFFFFFFFF; + port = port | (temp & 0xFF); + temp = 0; + + /* Determine if an error occurred. */ + if ((buffer_ptr[j] != 13) || (commas != 5) || (ip_address == 0) || (port == 0) || + (ip_address != connect_ip4_address)) + { + + /* Set the error status. */ + status = NX_FTP_INVALID_COMMAND; + } + + /* Save the data port. */ + client_req_ptr -> nx_ftp_client_request_data_port = port; + + /* Determine if the port command was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, the port command is successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Port set"); + } + else + { + + /* Unsuccessful port command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "Port Fail"); + } + + break; + } + + case NX_FTP_PASV: + { + + /* Try to find the data port. */ + status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr, + ftp_server_ptr -> nx_ftp_server_data_port++, &port); + + /* Determine if the PASV command was successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful port find. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "PASV Fail"); + + /* And we are done processing. */ + break; + } + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); + + /* Determine if the listen is successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful data socket create. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "PASV Fail"); + + /* And we are done processing. */ + break; + } + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Start listening on the data port. */ + status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0); + + /* Determine if the listen is successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful data socket listen. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "PASV Fail"); + + /* Delete data socket. */ + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* And we are done processing. */ + break; + } + + /* Wait for the data connection to connect. */ + nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Pickup the IPv4 address of this IP instance. */ + ip_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address; + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build PASV response. "227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)." */ + + /* Build the string. "227 Entering Passive Mode " */ + memcpy(buffer_ptr, "227 Entering Passive Mode ", 26); + + /* Build the IP address and port. */ + buffer_ptr[26] = '('; + + buffer_ptr[27] = (UCHAR)('0' + (ip_address >> 24)/100); + buffer_ptr[28] = (UCHAR)('0' + ((ip_address >> 24)/10)%10); + buffer_ptr[29] = (UCHAR)('0' + (ip_address >> 24)%10); + buffer_ptr[30] = ','; + + buffer_ptr[31] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)/100); + buffer_ptr[32] = (UCHAR)('0' + (((ip_address >> 16) & 0xFF)/10)%10); + buffer_ptr[33] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)%10); + buffer_ptr[34] = ','; + + buffer_ptr[35] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)/100); + buffer_ptr[36] = (UCHAR)('0' + (((ip_address >> 8) & 0xFF)/10)%10); + buffer_ptr[37] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)%10); + buffer_ptr[38] = ','; + + buffer_ptr[39] = (UCHAR)('0' + (ip_address & 0xFF)/100); + buffer_ptr[40] = (UCHAR)('0' + ((ip_address & 0xFF)/10)%10); + buffer_ptr[41] = (UCHAR)('0' + (ip_address & 0xFF)%10); + buffer_ptr[42] = ','; + + buffer_ptr[43] = (UCHAR)('0' + (port >> 8)/100); + buffer_ptr[44] = (UCHAR)('0' + ((port >> 8)/10)%10); + buffer_ptr[45] = (UCHAR)('0' + ((port >> 8)%10)); + buffer_ptr[46] = ','; + + buffer_ptr[47] = (UCHAR)('0' + (port & 255)/100); + buffer_ptr[48] = (UCHAR)('0' + ((port & 255)/10)%10); + buffer_ptr[49] = (UCHAR)('0' + ((port & 255)%10)); + + buffer_ptr[50] = ')'; + buffer_ptr[51] = '.'; + + /* Set the CR/LF. */ + buffer_ptr[52] = 13; + buffer_ptr[53] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 54; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the PASV response message. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Delete data socket. */ + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Yes, passive transfer enabled. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE; + + break; + } +#endif /* NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 + case NX_FTP_EPRT: + { + + + /* Check that only IPv6 packets can use the EPRT command. */ + if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4) + { + /* Illegal EPRT command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_NOT_IMPLEMENTED, "EPRT illegal in IPv4"); + + /* Bail out! */ + break; + } + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First, pickup the IPv6 address. */ + status = _nx_ftp_utility_parse_IPv6_address((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &ipduo_address); + + if (status != NX_SUCCESS) + { + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "Bad IPv6 address"); + + return; + } + + /* Now pickup the port number. */ + status = _nx_ftp_utility_parse_port_number((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &port); + + /* Save the data port. */ + client_req_ptr -> nx_ftp_client_request_data_port = port; + + /* Determine if the EPRT command was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, the EPRT command is successful! */ + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "EPRT command set"); + } + else + { + + /* Unsuccessful EPRT command. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "EPRT command failed"); + } + + break; + + } + + case NX_FTP_EPSV: + { + + /* Try to find the data port. */ + status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr, + ftp_server_ptr -> nx_ftp_server_data_port++, &port); + + /* Determine if the EPSV command was successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful port find. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); + + /* And we are done processing. */ + break; + } + + /* Create an FTP client data socket. */ + status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", + NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); + + /* Determine if the listen is successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful data socket create. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); + + /* And we are done processing. */ + break; + } + + /* Make sure each socket points to the corresponding FTP server. */ + client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; + + /* Start listening on the data port. */ + status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0); + + /* Determine if the listen is successful. */ + if (status != NX_SUCCESS) + { + + /* Unsuccessful data socket listen. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); + + /* Delete data socket. */ + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* And we are done processing. */ + break; + } + + /* Wait for the data connection to connect. */ + nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now build EPSV response. "229 Entering Extended Passive Mode (|||6446|)." */ + + /* Build the string. "229 Entering Extended Passive Mode " */ + memcpy(buffer_ptr, "229 Entering Extended Passive Mode ", 35); + + /* Build the IPv6 address and port. */ + buffer_ptr[35] = '('; + buffer_ptr[36] = '|'; + buffer_ptr[37] = '|'; + buffer_ptr[38] = '|'; + + port_size = _nx_ftp_server_utility_fill_port_number((CHAR*)(&buffer_ptr[39]), port); + + buffer_ptr[39 + port_size] = '|'; + buffer_ptr[40 + port_size] = ')'; + + /* Set the CR/LF. */ + buffer_ptr[41 + port_size] = 13; + buffer_ptr[42 + port_size] = 10; + + /* Set the packet length. */ + packet_ptr -> nx_packet_length = 43 + port_size; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Send the EPSV response message. */ + status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Delete data socket. */ + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port); + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Yes, passive transfer enabled. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE; + + break; + } +#endif /* FEATURE_NX_IPV6 */ + + case NX_FTP_CDUP: + case NX_FTP_CWD: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, + &(client_req_ptr -> nx_ftp_client_local_path)); + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* If CDUP command, create the "up one directory" pathname string. */ + if (ftp_command == NX_FTP_CDUP) + { + buffer_ptr[0] = '.'; + buffer_ptr[1] = '.'; + buffer_ptr[2] = NX_NULL; + } + + /* Otherwise CWD command, parse the pathname string. */ + else + { + + /* Find the end of the message. */ + j = 0; + while (j < packet_ptr -> nx_packet_length - 1) + { + + /* Determine if a CR/LF is present. */ + if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + break; + + /* Move to next character. */ + j++; + } + + /* If specified path ends with slash or backslash, strip it. */ + if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) + { + j--; + } + + /* Ensure the name is NULL terminated. */ + buffer_ptr[j] = NX_NULL; + } + + /* Set the local path to the path specified. */ + status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, + &(client_req_ptr -> nx_ftp_client_local_path), (CHAR *) buffer_ptr); + + /* Determine if it was successful. */ + if (status == NX_SUCCESS) + { + + CHAR *local_dir; + + + /* Successful change directory. */ + + /* Get the actual path */ + fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); + + /* Now send a successful response to the client. */ + _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "set successfully", local_dir); + } + else + { + + /* Unsuccessful directory change. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "Change Dir Fail"); + } + break; + } + + case NX_FTP_PWD: + { + + /* Change to the default directory of this connection. */ + fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); + + { + + CHAR *local_dir; + + /* Pickup the current directory. */ + fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); + + /* Now send a successful response to the client. */ + _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_MADE_DIR, "is current Directory", local_dir); + } + + break; + } + + case NX_FTP_TYPE: + { + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if a binary transfer is specified. */ + if (buffer_ptr[0] == 'I') + { + + /* Yes, a binary image is specified and supported. */ + client_req_ptr -> nx_ftp_client_request_transfer_type = 'I'; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Type Binary"); + } + + /* Not Binary - check if ASCII type is specified */ + else if (buffer_ptr[0] == 'A') + { + + /* Yes, a ASCII image is specified and supported. */ + client_req_ptr -> nx_ftp_client_request_transfer_type = 'A'; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Type ASCII"); + } + else + { + + /* Otherwise, a non-binary type is requested. */ + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Type Non ASCII or Binary"); + } + break; + } + + case NX_FTP_MODE: + { + + /* Setup pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if stream mode is specified. */ + if (buffer_ptr[0] == 'S') + { + + /* Yes, stream mode is specified and supported. */ + client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Mode Stream"); + } + + /* Not stream - check if block mode is specified */ + else if (buffer_ptr[0] == 'B') + { + + /* Yes, stream mode is specified and supported. */ + client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_BLOCK; + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "Mode Block"); + } + else + { + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_TYPE, "Mode Non Stream or Block"); + } + break; + } + + case NX_FTP_NOOP: + + /* Now send a successful response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CMD_OK, "NOOP Success"); + break; + + default: + + /* Unimplemented Command. */ + + /* Increment the number of unknown commands. */ + ftp_server_ptr -> nx_ftp_server_unknown_commands++; + + /* Now send an error response to the client. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_NOT_IMPLEMENTED, "Not Implemented"); + break; + } + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_connect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all FTP client connections received. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ftp_server_response Build and send response */ +/* fx_directory_local_path_set Set local path */ +/* nx_tcp_server_socket_accept Accept connection on socket */ +/* nx_tcp_server_socket_relisten Relisten for connection */ +/* nx_tcp_server_socket_unaccept Unaccept connection */ +/* nx_ftp_packet_allocate Allocate a packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_connect_process(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +UINT status; +NX_PACKET *packet_ptr; +NX_FTP_CLIENT_REQUEST *client_req_ptr; + + + /* One of the control ports is in the process of connection. */ + + /* Search the connections to see which one. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Now see if this socket was the one that is in being connected. */ + if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_CLOSED) && + (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_ESTABLISHED) && + (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port)) + { + + /* Yes, we have found the socket being connected. */ + + /* Increment the number of connection requests. */ + ftp_server_ptr -> nx_ftp_server_connection_requests++; + + /* Attempt to accept on this socket. */ + status = nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); + + /* Determine if it is successful. */ + if (status) + { + + /* Not successful, simply unaccept on this socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); + } + else + { + + /* Set the request type. */ + if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + + client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V6; + } + else + { + client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V4; + } + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; + + /* Send a connection ACK back to the client, indicating a successful connection + has been established. */ + + /* Allocate a packet for sending the connection ACK. */ + status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the packet allocation was successful. */ + if (status == NX_SUCCESS) + { + + /* Now send "220" ACK message to indicate connection is ready. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_CONNECTION_OK, "Connection Ready"); + + /* Set the local path to the root directory. */ + fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path), "\\"); + } + else + { + + /* Increment allocation error count. */ + ftp_server_ptr -> nx_ftp_server_allocation_errors++; + } + } + } + } + + /* Now look for a socket that is closed to relisten on. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Now see if this socket is closed. */ + if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + /* Relisten on this socket. */ + status = nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, + &(client_req_ptr -> nx_ftp_client_request_control_socket)); + /* Check for bad status. */ + if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + + /* Increment the error count and keep trying. */ + ftp_server_ptr -> nx_ftp_server_relisten_errors++; + continue; + } + + /* Break out of loop. */ + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_command_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all FTP client commands received on */ +/* the control socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* control_socket_ptr Socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX receive packet callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_command_present(NX_TCP_SOCKET *control_socket_ptr) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the command event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_COMMAND, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_connection_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all FTP client connections received on */ +/* the control socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* control_socket_ptr Socket event occurred */ +/* port Port the connection occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_connection_present(NX_TCP_SOCKET *control_socket_ptr, UINT port) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the connect event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONNECT, TX_OR); + + NX_PARAMETER_NOT_USED(port); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_data_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all FTP client disconnections received on */ +/* the data socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* data_socket_ptr Socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_data_disconnect(NX_TCP_SOCKET *data_socket_ptr) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_FTP_SERVER *) data_socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the disconnect event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA_DISCONNECT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_data_disconnect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes all FTP client disconnections received on */ +/* the data socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file */ +/* nx_ftp_packet_allocate Allocate a packet */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_socket_delete Delete socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_data_disconnect_process(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +UINT status; +UINT block_status; +ULONG length; +NX_PACKET *packet_ptr; +NX_FTP_CLIENT_REQUEST *client_req_ptr; + + + /* Now look for a socket that has receive data. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Initialize block status as NX_TRUE. */ + block_status = NX_TRUE; + + /* Now see if this socket has entered a disconnect state. */ + while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) + { + + /* Yes, a disconnect is present, which signals an end of file of a client FTP write request. */ + + /* First, cleanup this data socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); + + /* Unbind/unaccept the data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + + /* And finally delete the data socket. */ + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Check if receive all block bytes. */ + if (client_req_ptr -> nx_ftp_client_request_total_bytes != client_req_ptr -> nx_ftp_client_request_block_bytes) + block_status = NX_FALSE; + + /* Reset the transfer mode as stream mode. */ + client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Reset the block bytes. */ + client_req_ptr -> nx_ftp_client_request_block_bytes = 0; + } + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; + + /* Pickup the file length. */ + length = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size; + + /* Close the file. */ + status = fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + + /* Allocate a packet for sending the file write response. */ + _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Now determine if the operation was successful. */ + if ((status == FX_SUCCESS) && (length == client_req_ptr -> nx_ftp_client_request_total_bytes) && (block_status == NX_TRUE)) + { + + /* Successful client file write. */ + + /* Now send "250" message to indicate successful file write. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_COMPLETED, "File Written"); + } + else + { + + /* Unsuccessful client file write. */ + + /* Now send "550" message to indicate unsuccessful file write. */ + _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, + NX_FTP_CODE_BAD_FILE, "File Write Failed"); + } + + /* Clear the open type. */ + client_req_ptr -> nx_ftp_client_request_open_type = 0; + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_data_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the FTP server thread of data received */ +/* from a client on a data socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* data_socket_ptr Socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_data_present(NX_TCP_SOCKET *data_socket_ptr) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_FTP_SERVER *)data_socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_data_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes all FTP client data packets received on */ +/* the data socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_write Write client data to file */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive from data socket */ +/* _nx_ftp_server_block_header_retrieve Retrieve the block header */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_data_process(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +UINT status; +ULONG length; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; +NX_FTP_CLIENT_REQUEST *client_req_ptr; + + + /* Now look for a socket that has receive data. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Now see if this socket has data. If so, process all of it now! */ + while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_receive_queue_count) + { + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; + + /* Attempt to read a packet from this socket. */ + status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_data_socket), &packet_ptr, NX_NO_WAIT); + + /* Check for not data present. */ + if (status != NX_SUCCESS) + { + + /* Just continue the loop and look at the next socket. */ + continue; + } + + /* Check for open type. */ + if (client_req_ptr -> nx_ftp_client_request_open_type != NX_FTP_OPEN_FOR_WRITE) + { + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + + /* Continue the loop. */ + continue; + } + + /* Determine if the block mode is enabled. */ + if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) + { + + /* Retrieve the block header. */ + status = _nx_ftp_server_block_header_retrieve(client_req_ptr, packet_ptr); + + /* Determine if an error occurred. */ + if (status) + { + + /* Continue the loop. */ + continue; + } + } + + /* Update the total bytes for this file. This will be checked on close to see if + any error occurred. */ + client_req_ptr -> nx_ftp_client_request_total_bytes += packet_ptr -> nx_packet_length; + + /* Write the packet to the file. */ + length = packet_ptr -> nx_packet_length; + next_packet_ptr = packet_ptr; + do + { + + /* Write to the already opened file. */ + status = fx_file_write(&(client_req_ptr -> nx_ftp_client_request_file), next_packet_ptr -> nx_packet_prepend_ptr, + (ULONG)((next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr))); + + /* If unsuccessful file write, ok to receive the rest of the socket + packets from the receive queue. */ + + if (status == FX_SUCCESS) + { + + /* Increment the number of bytes received. */ + ftp_server_ptr -> nx_ftp_server_total_bytes_received += + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + } + + /* If not successful, keep retrieving packets from the socket receive queue so we can free + up the packets. */ + + /* Update the remaining length to write. */ + length = length - (ULONG) (next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + next_packet_ptr = NX_NULL; +#else + /* Pickup next packet pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while ((next_packet_ptr) && (length)); + + /* Release the packet and continue the loop. */ + nx_packet_release(packet_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_parse_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines which FTP request is present, returns */ +/* a code for it, and adjusts the packet pointer to the next token. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to FTP packet */ +/* */ +/* OUTPUT */ +/* */ +/* FTP command code */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process FTP command process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_parse_command(NX_PACKET *packet_ptr) +{ + +UINT i; +char *buffer_ptr; + + + /* Setup pointer to command buffer area. */ + buffer_ptr = (char *) packet_ptr -> nx_packet_prepend_ptr; + + /* Search the packet to find the end of the token, converting the token to Uppercase. */ + i = 0; + while ((buffer_ptr[i] != ' ') && (buffer_ptr[i] != (char) 13) && (i < packet_ptr -> nx_packet_length - 1)) + { + + /* Determine if the character is lowercase. */ + if ((buffer_ptr[i] >= 'a') && (buffer_ptr[i] <= 'z')) + { + + /* Convert to uppercase. */ + buffer_ptr[i] = (char) (((UCHAR) buffer_ptr[i]) - ((UCHAR) 0x20)); + } + + /* Move to next character. */ + i++; + } + + /* Set the NULL termination for the command. */ + buffer_ptr[i] = NX_NULL; + + /* Move the packet pointer to the next token. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + (i + 1); + + /* Decrease the length of the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (i + 1); + + /* Is it the "USER" command? */ + if (strcmp(buffer_ptr, "USER") == 0) + { + return(NX_FTP_USER); + } + + /* Is the the "PASS" command? */ + if (strcmp(buffer_ptr, "PASS") == 0) + { + return(NX_FTP_PASS); + } + + /* Is it the "QUIT" command? */ + if (strcmp(buffer_ptr, "QUIT") == 0) + { + return(NX_FTP_QUIT); + } + + /* Is it the "RETR" command? */ + if (strcmp(buffer_ptr, "RETR") == 0) + { + return(NX_FTP_RETR); + } + + /* Is it the "STOR" command? */ + if (strcmp(buffer_ptr, "STOR") == 0) + { + return(NX_FTP_STOR); + } + + /* Is it the "RNFR" command? */ + if (strcmp(buffer_ptr, "RNFR") == 0) + { + return(NX_FTP_RNFR); + } + + /* Is it the "RNTO" command? */ + if (strcmp(buffer_ptr, "RNTO") == 0) + { + return(NX_FTP_RNTO); + } + + /* Is it the "DELE" command? */ + if (strcmp(buffer_ptr, "DELE") == 0) + { + return(NX_FTP_DELE); + } + + /* Is it the "RMD" or "XRMD" command? */ + if ((strcmp(buffer_ptr, "RMD") == 0) || (strcmp(buffer_ptr, "XRMD") == 0)) + { + return(NX_FTP_RMD); + } + + /* Is it the "MKD" or "XMKD" command? */ + if ((strcmp(buffer_ptr, "MKD") == 0) || (strcmp(buffer_ptr, "XMKD")== 0)) + { + return(NX_FTP_MKD); + } + + /* Is it the "CDUP" command? */ + if (strcmp(buffer_ptr, "CDUP") == 0) + { + return(NX_FTP_CDUP); + } + + /* Is it the "CWD" command? */ + if (strcmp(buffer_ptr, "CWD") == 0) + { + return(NX_FTP_CWD); + } + + /* Is it the "PWD" command? */ + if (strcmp(buffer_ptr, "PWD") == 0) + { + return(NX_FTP_PWD); + } + + /* Is it the "NLST" command? */ + if (strcmp(buffer_ptr, "NLST") == 0) + { + return(NX_FTP_NLST); + } + + /* Is it the "LIST" command? */ + if (strcmp(buffer_ptr, "LIST") == 0) + { + return(NX_FTP_LIST); + } + + /* Is it the "PORT" command? */ + if (strcmp(buffer_ptr, "PORT") == 0) + { + return(NX_FTP_PORT); + } + + /* Is it the "EPRT" command? */ + if (strcmp(buffer_ptr, "EPRT") == 0) + { + return(NX_FTP_EPRT); + } + + /* Is it the "TYPE" command? */ + if (strcmp(buffer_ptr, "TYPE") == 0) + { + return(NX_FTP_TYPE); + } + + /* Is it the "NOOP" command? */ + if (strcmp(buffer_ptr, "NOOP") == 0) + { + return(NX_FTP_NOOP); + } + + /* Is it the "PASV" command? */ + if (strcmp(buffer_ptr, "PASV") == 0) + { + return(NX_FTP_PASV); + } + + /* Is it the "EPSV" command? */ + if (strcmp(buffer_ptr, "EPSV") == 0) + { + return(NX_FTP_EPSV); + } + + /* Is it the "MODE" command? */ + if (strcmp(buffer_ptr, "MODE") == 0) + { + return(NX_FTP_MODE); + } + + /* Otherwise, just return INVALID. */ + return(NX_FTP_INVALID); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the periodic timer for this FTP server. Its duty */ +/* is to inform the FTP server that it is time to check for activity */ +/* timeouts. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_address FTP server's address */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX ThreadX timer callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_timeout(ULONG ftp_server_address) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. */ + server_ptr = (NX_FTP_SERVER *) ftp_server_address; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_ACTIVITY_TIMEOUT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_timeout_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reviews all the active FTP client connections and */ +/* looks for an activity timeout. If a connection has not had any */ +/* activity within NX_FTP_ACTIVITY_TIMEOUT seconds, the connection is */ +/* deleted and its resources are made available to a new connection. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file */ +/* nx_packet_release Release saved packet */ +/* nx_tcp_server_socket_relisten Relisten for another connect */ +/* nx_tcp_client_socket_unbind Unbind data socket */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_socket_delete Delete data socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_timeout_processing(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +NX_FTP_CLIENT_REQUEST *client_req_ptr; + + + /* Examine all the client request structures. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Now see if this socket has an activity timeout active. */ + if (client_req_ptr -> nx_ftp_client_request_activity_timeout) + { + + /* Decrement the activity timeout for this client request. */ + if (client_req_ptr -> nx_ftp_client_request_activity_timeout > NX_FTP_TIMEOUT_PERIOD) + client_req_ptr -> nx_ftp_client_request_activity_timeout = client_req_ptr -> nx_ftp_client_request_activity_timeout - NX_FTP_TIMEOUT_PERIOD; + else + client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; + + /* Determine if this entry has exceeded the activity timeout. */ + if (client_req_ptr -> nx_ftp_client_request_activity_timeout == 0) + { + + /* Yes, activity timeout has been exceeded. Tear down and cleanup the + entire client request structure. */ + + /* Increment the activity timeout counter. */ + ftp_server_ptr -> nx_ftp_server_activity_timeouts++; + + /* If create, cleanup the data socket. */ + if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) + { + + /* Disconnect client socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Unbind/unaccept the data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + + /* Delete the data socket. */ + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* Ensure the file is closed. */ + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + } + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Reset the transfer mode as stream mode. */ + client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Reset the block bytes. */ + client_req_ptr -> nx_ftp_client_request_block_bytes = 0; + + /* Now disconnect the command socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); + + /* Unaccept the server socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); + + /* Check to see if a packet is queued up. */ + if (client_req_ptr -> nx_ftp_client_request_packet) + { + + /* Yes, release it! */ + nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); + } + + /* Relisten on this socket. This will probably fail, but it is needed just in case all available + clients were in use at the time of the last relisten. */ + nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, + &(client_req_ptr -> nx_ftp_client_request_control_socket)); + } + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_control_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the FTP server thread of client disconnects */ +/* of the control socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* control_socket_ptr Control socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_control_disconnect(NX_TCP_SOCKET *control_socket_ptr) +{ + +NX_FTP_SERVER *server_ptr; + + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONTROL_DISCONNECT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_control_disconnect_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reviews all the active FTP client connections and */ +/* looks for a client initiated disconnect activity that was done */ +/* without a QUIT command. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ftp_server_ptr Pointer to FTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file */ +/* nx_packet_release Release saved packet */ +/* nx_tcp_server_socket_relisten Relisten for another connect */ +/* nx_tcp_client_socket_unbind Unbind data socket */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_socket_delete Delete data socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_thread_entry FTP server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER *ftp_server_ptr) +{ + +UINT i; +NX_FTP_CLIENT_REQUEST *client_req_ptr; + + + /* Examine all the client request structures. */ + for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); + + /* Determine if this socket is in a disconnect state. This should only happen + if the client issues a disconnect without issuing a QUIT command. */ + if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) || + ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_SYN_SENT) && + (client_req_ptr -> nx_ftp_client_request_activity_timeout > 0))) + { + + /* Yes, this socket needs to be torn down. */ + + /* Increment the number of disconnection requests. */ + ftp_server_ptr -> nx_ftp_server_disconnection_requests++; + + /* Clear authentication. */ + client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE; + + /* Disable the client request activity timeout. */ + client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; + + /* If create, cleanup the associated data socket. */ + if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) + { + + /* Disconnect client socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); + + /* Unbind/unaccept the data socket. */ + if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) + { + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); + } + else + { + nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + } + + /* Delete the data socket. */ + nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); + + /* Ensure the file is closed. */ + fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); + +#ifdef NX_FTP_FAULT_TOLERANT + + /* Flush the media. */ + fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); +#endif + } + + /* Clear the passive transfer enabled flag. */ + client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; + + /* Reset the transfer mode as stream mode. */ + client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; + + /* Reset the block bytes. */ + client_req_ptr -> nx_ftp_client_request_block_bytes = 0; + + /* Check if this client login. */ + if (client_req_ptr -> nx_ftp_client_request_login) + { + + /* Call the logout function. */ + +#ifndef NX_DISABLE_IPV4 + /* Does this server have an IPv4 login function? */ + if (ftp_server_ptr -> nx_ftp_logout_ipv4) + { + + /* Call the logout which takes IPv4 address input. */ + (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr, + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4, + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, NX_NULL); + } +#endif /* NX_DISABLE_IPV4 */ + if (ftp_server_ptr -> nx_ftp_logout) + { + + /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */ + (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), + client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, + client_req_ptr -> nx_ftp_client_request_username, + client_req_ptr -> nx_ftp_client_request_password, NX_NULL); + } + + /* Set the login as FALSE. */ + client_req_ptr -> nx_ftp_client_request_login = NX_FALSE; + } + + /* Now disconnect the command socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); + + /* Unaccept the server socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); + + /* Check to see if a packet is queued up. */ + if (client_req_ptr -> nx_ftp_client_request_packet) + { + + /* Yes, release it! */ + nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); + } + + /* Relisten on this socket. This will probably fail, but it is needed just in case all available + clients were in use at the time of the last relisten. */ + nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, + &(client_req_ptr -> nx_ftp_client_request_control_socket)); + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses knowledge of the client request connection type */ +/* to allocate the proper TCP packet type. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to packet pool */ +/* client_request_ptr Pointer to Client request */ +/* packet_ptr Pointer to allocated packet */ +/* packet_type Packet type, usually TCP */ +/* wait_option Wait option on packet alloc */ +/* */ +/* OUTPUT */ +/* */ +/* status Packet allocation status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate NetX packet allocate service */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Client command handler */ +/* _nx_ftp_server_control_disconnect_processing */ +/* Client disconnect handler */ +/* _nx_ftp_server_connect_process Client Connect request handler*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_ftp_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET **packet_ptr, UINT packet_type, UINT wait_option) +{ + +UINT status; + + + /* Determine type of packet to allocate based on client connection. */ + + if (client_request_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V6) + { + + /* This is an IPV6 connection. */ + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv6_TCP_PACKET, wait_option); + } + else + { + + /* This is an IPv4 connection. */ + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv4_TCP_PACKET, wait_option); + } + + + NX_PARAMETER_NOT_USED(packet_type); + + /* Return completion status. */ + return status; +} + + +#ifdef FEATURE_NX_IPV6 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_utility_parse_IPv6_address PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses a string containing a properly formatted IPv6 */ +/* string and while it does not assume it is part of the EPRT command */ +/* it does not expect to find any non IPv6 characters in the string */ +/* after checking for a leading 'EPRT |2|' and before an entire IPv6 */ +/* address is parsed. If there is a leading 'EPRT ' in the string, it */ +/* does check that it has the required '|2|' preamble to the IPv6 */ +/* address. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to the string to parse*/ +/* buffer_length Size of the IPv6 string */ +/* ipduo_address Pointer to the IPv6 address */ +/* parsed from the buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Proper IPv6 address parsed */ +/* NX_FTP_ERROR IPv6 address is bad */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Parse a received FTP command */ +/* packet service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_utility_parse_IPv6_address(CHAR *buffer_ptr, UINT buffer_length, NXD_ADDRESS *ipduo_address) +{ + +UINT j, k, i, m, colons, digit; +UINT number_consecutive_zeros_to_add, remaining_colons, actual_colons_left; +ULONG temp; + + + /* Initialize variables. */ + temp = 0; + colons = 0; + remaining_colons = 0; + actual_colons_left = 0; + j = 0; + k = 0; + i = 0; + + number_consecutive_zeros_to_add = 0; + + /* Check if the buffer includes the leading EPRT command. */ + if ( (buffer_ptr[0] == 'E' || buffer_ptr[0] == 'e') && + (buffer_ptr[1] == 'P' || buffer_ptr[1] == 'p') && + (buffer_ptr[2] == 'R' || buffer_ptr[2] == 'p') && + (buffer_ptr[3] == 'T' || buffer_ptr[3] == 't') && + (buffer_ptr[4] == ' ')) + { + + /* If this is an EPRT command it must be followed by a single + space and the |2| preamble. */ + if ((buffer_ptr[5] != '|') || (buffer_ptr[6] != '2') || (buffer_ptr[7] != '|')) + { + + /* It does not. Return error status. */ + return NX_FTP_INVALID_COMMAND; + } + + /* Set the start of where to resume parsing. */ + j = 8; + } + else + { + /* If the EPRT command has been removed already, check for the |2| preamble. */ + if ((buffer_ptr[0] == '|') && (buffer_ptr[1] == '2') && (buffer_ptr[2] == '|')) + { + + /* Set the start of where to resume parsing. */ + j = 3; + } + } + + /* Parse the buffer till the end is reached (or a complete + IPv6 address is parsed. */ + while (j < buffer_length) + { + + /* Is a numeric or hex character present? */ + if (((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) || + ((buffer_ptr[j] >= 'A') && (buffer_ptr[j] <= 'F')) || + ((buffer_ptr[j] >= 'a') && (buffer_ptr[j] <= 'f'))) + { + + /* Yes, is a numeric character is present? Update the IP address. */ + if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9') + { + temp = (temp*16) + (ULONG) (buffer_ptr[j] - '0'); + } + else + { + /* Is a hex character present? */ + switch (buffer_ptr[j] ) + { + case 'A': + case 'a': + digit = 10; + break; + + case 'B': + case 'b': + digit = 11; + break; + + case 'C': + case 'c': + digit = 12; + break; + + case 'D': + case 'd': + digit = 13; + break; + + case 'E': + case 'e': + digit = 14; + break; + + case 'F': + case 'f': + digit = 15; + break; + + default: + digit = 0; + } + + /* Update the ULONG. */ + temp = (temp*16 + digit); + } + + /* Increase the size of the digit by one. */ + i++; + + /* Check if the size of this digit is out of range. */ + if (i > 4) + { + + /* Yes, return an error status. */ + return NX_FTP_INVALID_ADDRESS; + } + } + + /* Determine if a CR/LF is present. */ + else if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) + { + + /* Whether this is a prematurely terminated IPv6 string, abort any further parsing. */ + break; + } + + /* Determine if a colon is present. */ + else if (buffer_ptr[j] == ':') + { + + /* Increment the colon count. */ + colons++; + + /* Are we in the middle of a ULONG? */ + if (colons % 2 == 1) + { + + /* Yes, add this temp to the lower half. */ + ipduo_address -> nxd_ip_address.v6[k] = temp; + } + else + { + + /* No, shift the existing 16 bits left first. */ + ipduo_address -> nxd_ip_address.v6[k] <<= 16; + + /* Mask out the lower 16 bits. */ + ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; + + /* Add the number we just parsed. */ + ipduo_address -> nxd_ip_address.v6[k] += temp; + + /* Move to the next ULONG in the nxd_ip_address array. */ + k++; + } + + /* Reset our counters and temporary ULONG. */ + i = 0; + temp = 0; + + /* Check if we have encountered a double colon. */ + if (buffer_ptr[j + 1] == ':') + { + + /* Yes; Check if we already encountered a double colon. */ + if (remaining_colons) + { + + /* Yes we have. This is an improperly formatted IPv6 address. */ + return NX_FTP_INVALID_ADDRESS; + } + + /* Move the index to the second colon. */ + j++; + + /* Compute how many more colons should there be. */ + remaining_colons = 7 - colons; + + /* Start looking for the rest of the colons after the double. */ + m = j + 1; + + /* Count colons in the rest of the string. */ + while (m < buffer_length) + { + + /* Do we have another colon? */ + if (buffer_ptr [m] == ':') + { + + /* Yes, update the count. */ + actual_colons_left++; + } + m++; + } + + /* Compute the number of zeros to insert into the NXD_ADDRESS IPv6 ULONG array. */ + number_consecutive_zeros_to_add = remaining_colons - actual_colons_left; + + /* Add the zeroes until its time to start parsing rest of the IPv6 address string. */ + while (number_consecutive_zeros_to_add) + { + + /* Determine where to add the 16 bits depending + on odd or even number colon we're on. */ + + /* Are we in the middle of the current v6 ULONG?*/ + if (colons % 2 == 1) + { + + /* Yes, shift the bits in v6[k] left, and insert a zero at the least significant end. */ + ipduo_address -> nxd_ip_address.v6[k] <<= 16; + ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; + k++; + } + else + { + + /* No, starting the next ULONG in v6 so just set to zero. */ + ipduo_address -> nxd_ip_address.v6[k] = 0; + } + + /* Keep track of how many colons would have been in the IPv6 string + without the double colon. */ + colons++; + + number_consecutive_zeros_to_add--; + } + } + + } + /* Have we hit the end of the IPv6 address? */ + else if (buffer_ptr[j] == '|' && k <= 3) + { + + /* Yes, shift the existing 16 bits left first. */ + ipduo_address -> nxd_ip_address.v6[k] <<= 16; + + /* Mask out the lower 16 bits. */ + ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; + + /* Add the number we just parsed. */ + ipduo_address -> nxd_ip_address.v6[k] += temp; + + /* Clear the temporary ULONG so we know we applied it to our IPv6 address array. */ + temp = 0; + + /* This is the end of the IP address. Bail out...*/ + break; + } + else /* No hex, not a seperator or part of the EPRT command. */ + { + /* Unknown character in the IPv6 string. */ + return NX_FTP_INVALID_ADDRESS; + } + + j++; + } + + /* Did we parse the full IP address? */ + if (colons != 7 ) + { + + /* No, it is either too long or too short. */ + return NX_FTP_INVALID_ADDRESS; + } + + /* Is there a parsed number to apply to the last ULONG e.g. no terminating '|' + in the buffer? */ + if (temp) + { + /* Yes, shift the existing 16 bits left first. */ + ipduo_address -> nxd_ip_address.v6[3] <<= 16; + + /* Mask out the lower 16 bits. */ + ipduo_address -> nxd_ip_address.v6[3] = ipduo_address -> nxd_ip_address.v6[3] & 0xFFFF0000; + + /* Add the number we just parsed. */ + ipduo_address -> nxd_ip_address.v6[3] += temp; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_utility_parse_port_number PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses a port number from the input buffer. It assumes*/ +/* the buffer holds an EPRT command string and therefore looks for the */ +/* last '|' separator in the string. If it does not find one, it */ +/* returns an error. If it encounters anything after this separator, */ +/* other than a digit or CRLF before reaching the end of the buffer it */ +/* returns an error. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to the string to parse*/ +/* buffer_length Size of the string */ +/* portnumber Pointer to the port number */ +/* parsed from the buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Proper port number parsed */ +/* NX_FTP_ERROR Port number is bad */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Parse a received FTP command */ +/* packet service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_ftp_utility_parse_port_number(CHAR *buffer_ptr, UINT buffer_length, UINT *portnumber) +{ + +UINT j; +UINT digits = 0; + + + j = (buffer_length - 1); + *portnumber = 0; + + /* Find the terminating CRLF. */ + while (j >= 1) + { + if (buffer_ptr[j - 1] == 13 && buffer_ptr[j] == 10) + { + /* Subtract for the extra LF character. */ + j--; + + /* We're ready to move on to the port number extraction. */ + break; + } + j--; + } + + /* Find the port number. There may be separators between the port number + and the CRLF. */ + while (j >= 1) + { + /* Skip everything except for digits. */ + if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9') + { + break; + } + + /* But we should not encounter a colon! */ + if (buffer_ptr[j] == ':') + { + + /* Return an error status. */ + return NX_FTP_INVALID_NUMBER; + } + + j--; + } + + while ((INT)j >= 0) + { + + /* Is this a space separator '|'? */ + if (buffer_ptr[j] == '|') + { + /* Yes, so the port number must be adjacent. */ + j++; + + /* Now go back up the buffer. */ + while(j < buffer_length - 2) + { + + /* Check if we have backed up into the IPv6 address? */ + if ((buffer_ptr[j] == ':')) + { + /* Yes, apparently this string is missing the separator and port number. */ + return NX_FTP_INVALID_NUMBER; + } + + /* Is a numeric character present? */ + if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) + { + + /* Yes, numeric character is present. Update the port number. */ + *portnumber = (*portnumber * 10) + (ULONG) (buffer_ptr[j] - '0'); + digits++; + + /* Check for overflow. */ + if (digits > 5) + { + return NX_FTP_INVALID_NUMBER; + } + /* Determine if a CR/LF or | separator is present. This marks + the end of the port number. */ + if ((buffer_ptr[j+1] == '|') || (buffer_ptr[j+1] == 13) || (buffer_ptr[j+2] == 10)) + { + return NX_SUCCESS; + } + + + } + else + { + + /* This is a non numeric character, and not a CRLF either. */ + return NX_FTP_INVALID_NUMBER; + } + j++; + } + + /* If we got here we did not parse a properly formatted port number. */ + return NX_FTP_INVALID_NUMBER; + } + + j--; + } + + /* If we got here we did not parse a properly formatted port number. */ + return NX_FTP_INVALID_NUMBER; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_utility_fill_port_number PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number to ascii text e.g. and fill the */ +/* text port into the buffer. */ +/* */ +/* INPUT */ +/* */ +/* number Port number to convert to ASCII */ +/* numstring Pointer to ascii portnumber string */ +/* */ +/* OUTPUT */ +/* */ +/* size Size of port number */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Processes FTP commands */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_utility_fill_port_number(CHAR *buffer_ptr, UINT port_number) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < 10) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + buffer_ptr[j] = buffer_ptr[j-1]; + } + + /* Compute the next decimal digit. */ + digit = (port_number % 10); + + /* Update the input number. */ + port_number = (port_number / 10); + + /* Store the new digit in ASCII form. */ + buffer_ptr[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (port_number == 0) + break; + } + + /* Determine if there is an overflow error. */ + if (port_number) + { + + /* Error, return bad values to user. */ + return(0); + } + + /* Return size to caller. */ + return(size); +} +#endif /* FEATURE_NX_IPV6 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_block_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the block size for LIST and NLST in block mode. */ +/* */ +/* INPUT */ +/* */ +/* client_request_ptr Pointer to FTP client */ +/* block_size The size of block data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* fx_directory_first_full_entry_find Find first directory entry */ +/* fx_directory_next_full_entry_find Find next directory entry */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Process command */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ftp_server_block_size_get(NX_FTP_SERVER *ftp_server_ptr, UINT ftp_command, CHAR *filename, ULONG *block_size) +{ + +UINT j = 0; +UINT attributes; +ULONG size; +UINT year, month, day; +UINT hour, minute, second; +UINT length; +UINT status; + + + /* Block size for LIST and NLST. */ + *block_size = 0; + + /* Now get the full directory listing. */ + do + { + if (j == 0) + { + + /* First directory entry. */ + status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + j++; + } + else + { + + /* Not the first entry - pickup the next! */ + status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, + &attributes, &size, &year, &month, &day, &hour, &minute, &second); + } + + /* Determine if successful. */ + if (status == NX_SUCCESS) + { + + /* Calculate the size of the name. */ + if (_nx_utility_string_length_check(filename, &length, FX_MAX_LONG_NAME_LEN - 1)) + { + return; + } + + /* Check the command. */ + if (ftp_command == NX_FTP_NLST) + { + + /* NLST. Add extra "cr/lf" (2 bytes). */ + (*block_size) += (length + 2); + } + else + { + + /* Check if the month is valid. */ + if ((month < 1) || (month > 12)) + continue; + + /* LIST. Add extra file info (52 bytes). + File Info is 10 chars for permissions, 15 chars for owner and group, + 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */ + (*block_size) += (length + 52); + } + } + } while (status == NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_block_header_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the block header for block mode. */ +/* */ +/* INPUT */ +/* */ +/* client_request_ptr Pointer to FTP client */ +/* block_size The size of block data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send data packet to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process Process command */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_block_header_send(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, ULONG block_size) +{ + +UINT status; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; + + + /* Use block mode to transfer data. RFC959, Section3.4.2, Page21-22. */ + + /* Allocate the packet. */ + status = _nx_ftp_packet_allocate(pool_ptr, client_request_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Set the block header. */ + if (block_size) + { + + /* Descriptor. */ + buffer_ptr[0] = 0; + + /* Byte count. */ + buffer_ptr[1] = (UCHAR)(block_size >> 8); + buffer_ptr[2] = (UCHAR)(block_size); + } + else + { + + /* Descriptor. */ + buffer_ptr[0] = 64; + + /* Byte count. */ + buffer_ptr[1] = 0; + buffer_ptr[2] = 0; + } + + /* Setup the length of the packet. */ + packet_ptr -> nx_packet_length = 3; + + /* Setup the packet append pointer. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Write packet payload to the file. */ + status = nx_tcp_socket_send(&(client_request_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); + + /* Determine if the send was unsuccessful. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Return success to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_block_header_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the block header for block mode. */ +/* */ +/* INPUT */ +/* */ +/* client_request_ptr Pointer to FTP client */ +/* packet_ptr Pointer to packet to write */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_data_process Process client write data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST *ftp_client_ptr, NX_PACKET *packet_ptr) +{ + +ULONG remaining_bytes; +ULONG delta; +UCHAR *buffer_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN +NX_PACKET *before_last_packet; +NX_PACKET *last_packet; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + + /* Check if it is the first packet. */ + if (ftp_client_ptr -> nx_ftp_client_request_block_bytes == 0) + { + + /* Check the packet length. */ + if ((packet_ptr -> nx_packet_length < 3) || + (packet_ptr -> nx_packet_prepend_ptr + 3 > packet_ptr -> nx_packet_append_ptr)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_SERVER_INVALID_SIZE); + } + + /* We have a packet, setup pointer to the buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Process block header. */ + ftp_client_ptr -> nx_ftp_client_request_block_bytes = (ULONG)((buffer_ptr[1] << 8) | buffer_ptr[2]); + + /* Skip the block header. */ + packet_ptr -> nx_packet_prepend_ptr += 3; + packet_ptr -> nx_packet_length -= 3; + } + + /* Check if have remaining data. */ + remaining_bytes = ftp_client_ptr -> nx_ftp_client_request_block_bytes - ftp_client_ptr -> nx_ftp_client_request_total_bytes; + if (remaining_bytes == 0) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_FTP_SERVER_END_OF_BLOCK); + } + + /* Check the data of current packet. */ + if (remaining_bytes < packet_ptr -> nx_packet_length) + { + + /* Remove the extra data, such as: end block header. */ + + /* Calculate the difference in the length. */ + delta = packet_ptr -> nx_packet_length - remaining_bytes; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta; + + /* Adjust the append pointer. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Loop to process adjustment that spans multiple packets. */ + while (delta) + { + + /* Determine if the packet is chained (or still chained after the adjustment). */ + if (packet_ptr -> nx_packet_last == NX_NULL) + { + + /* No, packet is not chained, simply adjust the append pointer in the packet. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; + + /* Break out of the loop, since the adjustment is complete. */ + break; + } + + /* Pickup the pointer to the last packet. */ + last_packet = packet_ptr -> nx_packet_last; + + /* Determine if the amount to adjust is less than the payload in the last packet. */ + /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ + if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta) + { + + /* Yes, simply adjust the append pointer of the last packet in the chain. */ + /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ + last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta; + + /* Get out of the loop, since the adjustment is complete. */ + break; + } + else + { + + /* Adjust the delta by the amount in the last packet. */ + delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)); + + /* Find the packet before the last packet. */ + before_last_packet = packet_ptr; + while (before_last_packet -> nx_packet_next != last_packet) + { + + /* Move to the next packet in the chain. */ + before_last_packet = before_last_packet -> nx_packet_next; + } + + /* At this point, we need to release the last packet and adjust the other packet + pointers. */ + + /* Ensure the next packet pointer is NULL in what is now the last packet. */ + before_last_packet -> nx_packet_next = NX_NULL; + + /* Determine if the packet is still chained. */ + if (packet_ptr != before_last_packet) + { + + /* Yes, the packet is still chained, setup the last packet pointer. */ + packet_ptr -> nx_packet_last = before_last_packet; + } + else + { + + /* The packet is no longer chained, set the last packet pointer to NULL. */ + packet_ptr -> nx_packet_last = NX_NULL; + } + + /* Release the last packet. */ + _nx_packet_release(last_packet); + } + } +#else + + /* Simply adjust the append pointer in the packet. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ftp_server_number_to_ascii PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number to ascii text. Fill space at the */ +/* beginning if possible. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to output string buffer */ +/* buffer_size Size of output buffer */ +/* number Number to convert to ASCII */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ftp_server_command_process */ +/* Process command */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number) +{ +UINT digit; +UINT size; + + /* Initialize counters. */ + size = 1; + + /* Initialize buffer with spaces. */ + memset(buffer_ptr, ' ', buffer_size); + + /* Loop to convert the number to ASCII. */ + while (size < buffer_size) + { + + /* Compute the next decimal digit. */ + digit = (number % 10); + + /* Update the input number. */ + number = (number / 10); + + /* Store the new digit in ASCII form. */ + buffer_ptr[buffer_size - size] = (UCHAR)(digit + '0'); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } +} diff --git a/addons/ftp/nxd_ftp_server.h b/addons/ftp/nxd_ftp_server.h new file mode 100644 index 00000000..a6c5fbd6 --- /dev/null +++ b/addons/ftp/nxd_ftp_server.h @@ -0,0 +1,438 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_ftp_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Duo File Transfer Protocol (FTP over */ +/* IPv6) component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_FTP_SERVER_H +#define NXD_FTP_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +#ifndef NX_FTP_NO_FILEX +#include "fx_api.h" +#else +#include "filex_stub.h" +#endif + + +/* Define the FTP Server ID. */ + +#define NXD_FTP_SERVER_ID 0x46545201UL + + +/* Define the maximum number of clients the FTP Server can accommodate. */ + +#ifndef NX_FTP_MAX_CLIENTS +#define NX_FTP_MAX_CLIENTS 4 +#endif + + +/* Define FTP TCP socket create options. */ + + +#ifndef NX_FTP_CONTROL_TOS +#define NX_FTP_CONTROL_TOS NX_IP_NORMAL +#endif + +#ifndef NX_FTP_DATA_TOS +#define NX_FTP_DATA_TOS NX_IP_NORMAL +#endif + +#ifndef NX_FTP_FRAGMENT_OPTION +#define NX_FTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_FTP_CONTROL_WINDOW_SIZE +#define NX_FTP_CONTROL_WINDOW_SIZE 400 +#endif + +#ifndef NX_FTP_DATA_WINDOW_SIZE +#define NX_FTP_DATA_WINDOW_SIZE 2048 +#endif + + +#ifndef NX_FTP_TIME_TO_LIVE +#define NX_FTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_FTP_SERVER_TIMEOUT +#define NX_FTP_SERVER_TIMEOUT NX_IP_PERIODIC_RATE +#endif + +#ifndef NX_FTP_SERVER_PRIORITY +#define NX_FTP_SERVER_PRIORITY 16 +#endif + +#ifndef NX_FTP_SERVER_TIME_SLICE +#define NX_FTP_SERVER_TIME_SLICE 2 +#endif + +#ifndef NX_FTP_USERNAME_SIZE +#define NX_FTP_USERNAME_SIZE 20 +#endif + +#ifndef NX_FTP_PASSWORD_SIZE +#define NX_FTP_PASSWORD_SIZE 20 +#endif + +#ifndef NX_FTP_ACTIVITY_TIMEOUT +#define NX_FTP_ACTIVITY_TIMEOUT 240 /* Seconds allowed with no activity */ +#endif + +#ifndef NX_FTP_TIMEOUT_PERIOD +#define NX_FTP_TIMEOUT_PERIOD 60 /* Number of seconds to check */ +#endif + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 /* Number of bytes to reserve at the end of buffer */ +#endif + +/* Define the FTP data port retry parameters. */ + +#ifndef NX_FTP_SERVER_RETRY_SECONDS +#define NX_FTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ +#endif + +#ifndef NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH +#define NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ +#endif + +#ifndef NX_FTP_SERVER_RETRY_MAX +#define NX_FTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ +#endif + +#ifndef NX_FTP_SERVER_RETRY_SHIFT +#define NX_FTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ +#endif + +/* The minimum FTP Server packet size must accomodate the largest expected packet sent e.g. the LIST command: + The filename can be up to 256 bytes, plus file info (which has a fixed size of 52 bytes). + Note the 256 value is the assumed max size of a filename, defined by FX_MAX_LONG_NAME_LEN. + . + File download (data) packets can be split up over multiple packets, but commands should be in one packet. */ + +#ifndef NX_FTP_SERVER_MIN_PACKET_PAYLOAD +#define NX_FTP_SERVER_MIN_PACKET_PAYLOAD (256 + 52 + NX_TCP_PACKET + NX_PHYSICAL_TRAILER) +#endif + + +/* Define open types. */ + +#define NX_FTP_OPEN_FOR_READ 0x01 /* FTP file open for reading */ +#define NX_FTP_OPEN_FOR_WRITE 0x02 /* FTP file open for writing */ + + +/* Define transfer modes. Note: just support stream mode and block mode yet. */ + +#define NX_FTP_TRANSFER_MODE_STREAM 0 /* FTP stream transfer mode */ +#define NX_FTP_TRANSFER_MODE_BLOCK 1 /* FTP block transfer mode */ +#define NX_FTP_TRANSFER_MODE_COMPRESSED 2 /* FTP compressed transfer mode */ + + +/* Define Server thread events. */ + +#define NX_FTP_SERVER_CONNECT 0x01 /* FTP connection is present */ +#define NX_FTP_SERVER_DATA_DISCONNECT 0x02 /* FTP data disconnection is present */ +#define NX_FTP_SERVER_COMMAND 0x04 /* FTP client command is present */ +#define NX_FTP_SERVER_DATA 0x08 /* FTP client data is present */ +#define NX_FTP_SERVER_ACTIVITY_TIMEOUT 0x10 /* FTP activity timeout check */ +#define NX_FTP_SERVER_CONTROL_DISCONNECT 0x20 /* FTP client disconnect of control socket */ +#define NX_FTP_STOP_EVENT 0x40 /* FTP stop service */ +#define NX_FTP_ANY_EVENT 0xFF /* Any FTP event */ + + +/* Define return code constants. */ + +#define NX_FTP_ERROR 0xD0 /* Generic FTP internal error - deprecated */ +#define NX_FTP_TIMEOUT 0xD1 /* FTP timeout occurred */ +#define NX_FTP_FAILED 0xD2 /* FTP error */ +#define NX_FTP_NOT_CONNECTED 0xD3 /* FTP not connected error */ +#define NX_FTP_NOT_DISCONNECTED 0xD4 /* FTP not disconnected error */ +#define NX_FTP_NOT_OPEN 0xD5 /* FTP not opened error */ +#define NX_FTP_NOT_CLOSED 0xD6 /* FTP not closed error */ +#define NX_FTP_END_OF_FILE 0xD7 /* FTP end of file status */ +#define NX_FTP_END_OF_LISTING 0xD8 /* FTP end of directory listing status */ +#define NX_FTP_EXPECTED_1XX_CODE 0xD9 /* Expected a 1xx response from server */ +#define NX_FTP_EXPECTED_2XX_CODE 0xDA /* Expected a 2xx response from server */ +#define NX_FTP_EXPECTED_22X_CODE 0xDB /* Expected a 22x response from server */ +#define NX_FTP_EXPECTED_23X_CODE 0xDC /* Expected a 23x response from server */ +#define NX_FTP_EXPECTED_3XX_CODE 0xDD /* Expected a 3xx response from server */ +#define NX_FTP_EXPECTED_33X_CODE 0xDE /* Expected a 33x response from server */ +#define NX_FTP_INVALID_NUMBER 0xDF /* Extraced an invalid number from server response */ +#define NX_FTP_INVALID_ADDRESS 0x1D0 /* Invalid IP address parsed from FTP command */ +#define NX_FTP_INVALID_COMMAND 0x1D1 /* Invalid FTP command (bad syntax, unknown command) */ +#define NX_FTP_INVALID_LOGIN 0x1D2 /* Unable to perform successful user login */ +#define NX_FTP_INSUFFICIENT_PACKET_PAYLOAD 0x1D3 /* Packet payload less than the max length filename */ +#define NX_FTP_SERVER_INVALID_SIZE 0x1D4 /* Invalid FTP file size */ +#define NX_FTP_SERVER_END_OF_BLOCK 0x1D5 /* FTP end of block */ + +/* Define FTP connection states. */ + +#define NX_FTP_STATE_NOT_CONNECTED 1 /* FTP not connected */ +#define NX_FTP_STATE_CONNECTED 2 /* FTP connected */ +#define NX_FTP_STATE_OPEN 3 /* FTP file open for reading */ +#define NX_FTP_STATE_WRITE_OPEN 4 /* FTP file open for writing */ + + +/* Define the FTP Server TCP port numbers. */ + +#define NX_FTP_SERVER_CONTROL_PORT 21 /* Control Port for FTP server */ +#define NX_FTP_SERVER_DATA_PORT 20 /* Data Port for FTP server */ + +/* Define the size for buffer to store an IPv6 address represented in ASCII. */ +#define NX_FTP_IPV6_ADDRESS_BUFSIZE 60 + +/* Define the FTP basic commands. The ASCII command will be parsed and converted to the numerical + representation shown below. */ + +#define NX_FTP_NOOP 0 +#define NX_FTP_USER 1 +#define NX_FTP_PASS 2 +#define NX_FTP_QUIT 3 +#define NX_FTP_RETR 4 +#define NX_FTP_STOR 5 +#define NX_FTP_RNFR 6 +#define NX_FTP_RNTO 7 +#define NX_FTP_DELE 8 +#define NX_FTP_RMD 9 +#define NX_FTP_MKD 10 +#define NX_FTP_NLST 11 +#define NX_FTP_PORT 12 +#define NX_FTP_CWD 13 +#define NX_FTP_PWD 14 +#define NX_FTP_TYPE 15 +#define NX_FTP_LIST 16 +#define NX_FTP_CDUP 17 +#define NX_FTP_INVALID 18 +#define NX_FTP_EPRT 19 +#define NX_FTP_PASV 20 +#define NX_FTP_EPSV 21 +#define NX_FTP_MODE 22 + + + +/* Define the per client request structure for the FTP Server data structure. */ + +typedef struct NX_FTP_CLIENT_REQUEST_STRUCT +{ + UINT nx_ftp_client_request_data_port; /* Client's data port */ + UINT nx_ftp_client_request_ip_type; /* Client IP type (IPv4 or IPv6) */ + UINT nx_ftp_client_request_open_type; /* Open type of client request */ + UINT nx_ftp_client_request_authenticated; /* Authenticated flag */ + CHAR nx_ftp_client_request_read_only; /* Read-only flag */ + CHAR nx_ftp_client_request_transfer_type; /* FTP Data transfer type */ + CHAR nx_ftp_client_request_login; /* FTP Login flag */ + CHAR nx_ftp_client_request_passive_transfer_enabled; /* Client enabled for passive transfer */ + UINT nx_ftp_client_request_transfer_mode; /* Client transfer mode */ + ULONG nx_ftp_client_request_activity_timeout; /* Timeout for client activity */ + ULONG nx_ftp_client_request_total_bytes; /* Total bytes read or written */ + ULONG nx_ftp_client_request_block_bytes; /* Block bytes in block mode */ + CHAR nx_ftp_client_request_username[NX_FTP_USERNAME_SIZE]; + CHAR nx_ftp_client_request_password[NX_FTP_PASSWORD_SIZE]; + NX_PACKET *nx_ftp_client_request_packet; /* Previous request packet */ + FX_FILE nx_ftp_client_request_file; /* File control block */ + FX_LOCAL_PATH nx_ftp_client_local_path; /* Local path control block */ + NX_TCP_SOCKET nx_ftp_client_request_control_socket; /* Client control socket */ + NX_TCP_SOCKET nx_ftp_client_request_data_socket; /* Client data socket */ +} NX_FTP_CLIENT_REQUEST; + + +/* Define the FTP Server data structure. */ + +typedef struct NX_FTP_SERVER_STRUCT +{ + ULONG nx_ftp_server_id; /* FTP Server ID */ + CHAR *nx_ftp_server_name; /* Name of this FTP server */ + NX_IP *nx_ftp_server_ip_ptr; /* Pointer to associated IP structure */ + + NX_PACKET_POOL *nx_ftp_server_packet_pool_ptr; /* Pointer to FTP server packet pool */ + FX_MEDIA *nx_ftp_server_media_ptr; /* Pointer to media control block */ + ULONG nx_ftp_server_connection_requests; /* Number of connection requests */ + ULONG nx_ftp_server_disconnection_requests; /* Number of disconnection requests */ + ULONG nx_ftp_server_login_errors; /* Number of login errors */ + ULONG nx_ftp_server_authentication_errors; /* Number of access w/o authentication */ + ULONG nx_ftp_server_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_ftp_server_total_bytes_received; /* Number of total bytes received */ + ULONG nx_ftp_server_unknown_commands; /* Number of unknown commands received */ + ULONG nx_ftp_server_allocation_errors; /* Number of allocation errors */ + ULONG nx_ftp_server_relisten_errors; /* Number of relisten errors */ + ULONG nx_ftp_server_activity_timeouts; /* Number of activity timeouts */ + UINT nx_ftp_server_data_port; /* Port the data socket binds */ + NX_FTP_CLIENT_REQUEST /* FTP client request array */ + nx_ftp_server_client_list[NX_FTP_MAX_CLIENTS]; + TX_EVENT_FLAGS_GROUP + nx_ftp_server_event_flags; /* FTP server thread events */ + TX_TIMER nx_ftp_server_timer; /* FTP server activity timeout timer */ + TX_THREAD nx_ftp_server_thread; /* FTP server thread */ + UINT (*nx_ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); + UINT (*nx_ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); +#ifndef NX_DISABLE_IPV4 + UINT (*nx_ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); + UINT (*nx_ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); +#endif /* NX_DISABLE_IPV4 */ + + struct NX_FTP_SERVER_STRUCT + *nx_ftp_next_server_ptr, + *nx_ftp_previous_server_ptr; +} NX_FTP_SERVER; + + +#ifndef NX_FTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_ftp_server_create _nx_ftp_server_create +#define nxd_ftp_server_create _nxd_ftp_server_create +#define nx_ftp_server_delete _nx_ftp_server_delete +#define nx_ftp_server_start _nx_ftp_server_start +#define nx_ftp_server_stop _nx_ftp_server_stop + +#else + +/* Services with error checking. */ + +#define nx_ftp_server_create _nxe_ftp_server_create +#define nxd_ftp_server_create _nxde_ftp_server_create +#define nx_ftp_server_delete _nxe_ftp_server_delete +#define nx_ftp_server_start _nxe_ftp_server_start +#define nx_ftp_server_stop _nxe_ftp_server_stop + +#endif + +/* Define the prototypes accessible to the application software. */ +UINT nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); +UINT nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); +UINT nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); + +#else + +/* FTP source code is being compiled, do not perform any API mapping. */ +UINT _nxe_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT _nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT _nxde_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT _nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +UINT _nxe_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); +UINT _nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); +UINT _nxe_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); +UINT _nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); +UINT _nxe_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); +UINT _nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); + +/* Internal FTP functions. */ +UINT _nx_ftp_server_create_internal(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); +VOID _nx_ftp_server_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message); +VOID _nx_ftp_server_directory_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message, CHAR *directory); +VOID _nx_ftp_server_thread_entry(ULONG ftp_server_address); +VOID _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr); +VOID _nx_ftp_server_connect_process(NX_FTP_SERVER *ftp_server_ptr); +VOID _nx_ftp_server_command_present(NX_TCP_SOCKET *control_socket_ptr); +VOID _nx_ftp_server_connection_present(NX_TCP_SOCKET *control_socket_ptr, UINT port); +VOID _nx_ftp_server_data_disconnect(NX_TCP_SOCKET *data_socket_ptr); +VOID _nx_ftp_server_data_disconnect_process(NX_FTP_SERVER *ftp_server_ptr); +VOID _nx_ftp_server_data_present(NX_TCP_SOCKET *data_socket_ptr); +VOID _nx_ftp_server_data_process(NX_FTP_SERVER *ftp_server_ptr); +UINT _nx_ftp_server_parse_command(NX_PACKET *packet_ptr); +VOID _nx_ftp_server_timeout(ULONG ftp_server_address); +VOID _nx_ftp_server_timeout_processing(NX_FTP_SERVER *ftp_server_ptr); +VOID _nx_ftp_server_control_disconnect(NX_TCP_SOCKET *control_socket_ptr); +VOID _nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER *ftp_server_ptr); + +#endif /* NX_FTP_SOURCE_CODE */ + +/* Internal functions. */ +#ifdef FEATURE_NX_IPV6 +UINT _nx_ftp_utility_parse_IPv6_address(CHAR *buffer_ptr, UINT buffer_length, NXD_ADDRESS *ipduo_address); +UINT _nx_ftp_utility_parse_port_number(CHAR *buffer_ptr, UINT buffer_length, UINT *portnumber); +UINT _nx_ftp_server_utility_fill_port_number(CHAR *buffer_ptr, UINT port_number); +#endif + +UINT _nx_ftp_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET **packet_ptr, UINT packet_type, UINT wait_option); +VOID _nx_ftp_server_block_size_get(NX_FTP_SERVER *ftp_server_ptr, UINT ftp_command, CHAR *filename, ULONG *block_size); +UINT _nx_ftp_server_block_header_send(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, ULONG block_size); +UINT _nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET *packet_ptr); + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_FTP_SERVER_H */ diff --git a/addons/http/nxd_http_client.c b/addons/http/nxd_http_client.c new file mode 100644 index 00000000..9e938adc --- /dev/null +++ b/addons/http/nxd_http_client.c @@ -0,0 +1,3418 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_HTTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" +#include "nxd_http_client.h" +#include "stdio.h" +#include "string.h" + + +/* Define global HTTP variables and strings. */ + + +/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing + into this array yields the base64 representation of the 6bit number. */ + +CHAR _nx_http_client_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* client_name Name of HTTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* window_size Size of HTTP client rx window */ +/* http_client_size Size of HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id == NXD_HTTP_CLIENT_ID) || + (pool_ptr == NX_NULL) || (http_client_size != sizeof(NX_HTTP_CLIENT))) + return(NX_PTR_ERROR); + + /* Pickup a packet from the supplied packet pool. */ + packet_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ + if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_HTTP_CLIENT_MIN_PACKET_SIZE) + return(NX_HTTP_POOL_ERROR); + + /* Call actual client create function. */ + status = _nx_http_client_create(client_ptr, client_name, ip_ptr, pool_ptr, window_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a HTTP client on the specified IP. In doing */ +/* so this function creates an TCP socket for subsequent HTTP */ +/* transfers. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* client_name Name of HTTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* window_size Size of HTTP client rx window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create HTTP client socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size) +{ + +UINT status; + + + /* Clear the HTTP Client structure. */ + memset((void *) client_ptr, 0, sizeof(NX_HTTP_CLIENT)); + + /* Create the Client's TCP socket. */ + status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_http_client_socket), client_name, + NX_HTTP_TYPE_OF_SERVICE, NX_HTTP_FRAGMENT_OPTION, NX_HTTP_TIME_TO_LIVE, + window_size, NX_NULL, NX_NULL); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, return error code. */ + return(status); + } + + /* Save the Client name. */ + client_ptr -> nx_http_client_name = client_name; + + /* Save the IP pointer address. */ + client_ptr -> nx_http_client_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + client_ptr -> nx_http_client_packet_pool_ptr = pool_ptr; + + /* Set the client state to ready to indicate a get or put operation can be done. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Set the Client ID to indicate the HTTP client thread is ready. */ + client_ptr -> nx_http_client_id = NXD_HTTP_CLIENT_ID; + + /* Set the default port the client connects to the HTTP server on (80). */ + client_ptr -> nx_http_client_connect_port = NX_HTTP_SERVER_PORT; + + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_delete Actual client delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_delete(NX_HTTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nx_http_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created HTTP client on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_delete Delete the HTTP client socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_delete(NX_HTTP_CLIENT *client_ptr) +{ + + /* Clear the client ID to indicate the HTTP client is no longer ready. */ + client_ptr -> nx_http_client_id = 0; + + /* Determine if a GET or PUT state is present. */ + if ((client_ptr -> nx_http_client_state == NX_HTTP_CLIENT_STATE_PUT) || + (client_ptr -> nx_http_client_state == NX_HTTP_CLIENT_STATE_GET)) + { + + /* Check for a saved packet. */ + if (client_ptr -> nx_http_client_first_packet) + { + + /* Release the packet. */ + nx_packet_release(client_ptr -> nx_http_client_first_packet); + } + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), NX_HTTP_CLIENT_TIMEOUT); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + } + + /* Delete the TCP socket. */ + nx_tcp_socket_delete(&(client_ptr -> nx_http_client_socket)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_set_connect_port PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client set connect port */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* port Port to connect to server on */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_set_connect_port Actual set port call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + else if (port == 0) + { + return(NX_INVALID_PORT); + } + + status = _nx_http_client_set_connect_port(client_ptr, port); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_set_connect_port PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the HTTP Client port to connect to the server on.*/ +/* This is useful if the HTTP Client needs to connect to a server on */ +/* another port than the default 80 port. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* port Port to connect to server on */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port) +{ + + client_ptr-> nx_http_client_connect_port = port; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client get start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_get_start Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, + UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || (resource == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_http_client_get_start(client_ptr, ip_address, resource, input_ptr, input_size, + username, password, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(input_ptr); + NX_PARAMETER_NOT_USED(input_size); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client get start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_get_start_extended Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, + CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || (resource == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_http_client_get_start_extended(client_ptr, ip_address, resource, resource_length, + input_ptr, input_size, username, username_length, + password, password_length, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(resource_length); + NX_PARAMETER_NOT_USED(input_ptr); + NX_PARAMETER_NOT_USED(input_size); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(username_length); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(password_length); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is a wrapper for the actual _nxd_http_client_get_start*/ +/* service that enables HTTP applications running on IPv4 to access */ +/* HTTP duo API without enabling IPv6. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_get_start Actual HTTP Client duo get */ +/* start service */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, + UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_ip_addr; + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; + server_ip_addr.nxd_ip_address.v4 = ip_address; + + /* Call the NetX HTTP 'duo' get start service. */ + status = _nxd_http_client_get_start(client_ptr, &server_ip_addr, resource, input_ptr, input_size, + username, password, wait_option); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(input_ptr); + NX_PARAMETER_NOT_USED(input_size); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is a wrapper for the actual _nxd_http_client_get_start*/ +/* service that enables HTTP applications running on IPv4 to access */ +/* HTTP duo API without enabling IPv6. */ +/* */ +/* Note: The strings of resource, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length to resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_get_start_extended Actual HTTP Client duo get */ +/* start service */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, + CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_ip_addr; + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; + server_ip_addr.nxd_ip_address.v4 = ip_address; + + /* Call the NetX HTTP 'duo' get start service. */ + status = _nxd_http_client_get_start_extended(client_ptr, &server_ip_addr, resource, resource_length, + input_ptr, input_size, username, username_length, + password, password_length, wait_option); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(resource_length); + NX_PARAMETER_NOT_USED(input_ptr); + NX_PARAMETER_NOT_USED(input_size); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(username_length); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(password_length); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo client get start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_get_start Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, + CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !ip_address) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nxd_http_client_get_start(client_ptr, ip_address, resource, input_ptr, input_size, + username, password, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo client get start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_get_start_extended Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, + CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !ip_address) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nxd_http_client_get_start_extended(client_ptr, ip_address, resource, resource_length, + input_ptr, input_size, username, username_length, + password, password_length, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. If input was specified, the request will actually be */ +/* sent as a POST instead of a GET. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_get_start_extended Actual client get start call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, CHAR *input_ptr, + UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) +{ + +UINT resource_length = 0; +UINT username_length = 0; +UINT password_length = 0; +UINT status; + + /* Make sure there is enough room in the destination string. */ + if((username) && (password)) + { + if (_nx_utility_string_length_check(username, &username_length, NX_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &password_length, NX_HTTP_MAX_PASSWORD)) + { + + /* Error, return to caller. */ + return(NX_HTTP_PASSWORD_TOO_LONG); + } + } + + /* Check resource length. */ + if (_nx_utility_string_length_check(resource, &resource_length, NX_MAX_STRING_LENGTH)) + { + return(NX_HTTP_ERROR); + } + + status = _nxd_http_client_get_start_extended(client_ptr, server_ip, resource, resource_length, + input_ptr, input_size, username, username_length, + password, password_length, wait_option); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. If input was specified, the request will actually be */ +/* sent as a POST instead of a GET. */ +/* */ +/* Note: The strings of resource, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* input_ptr Additional input pointer */ +/* input_size Additional input size */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_base64_encode Encode username/password */ +/* _nx_http_client_calculate_content_offset Calculate content offset */ +/* _nx_http_client_content_length_get Get content length */ +/* _nx_http_client_number_convert Convert number to ASCII */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_append Append data to packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_client_socket_bind Bind client socket to port */ +/* nxd_tcp_client_socket_connect Connect to HTTP Server */ +/* nx_tcp_socket_disconnect Disconnect client socket */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_socket_receive Get response packet */ +/* nx_tcp_socket_send Send request to Server */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, UINT resource_length, + CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG wait_option) +{ + +UINT status; +NX_PACKET *packet_ptr; +UINT length = 0, offset = 0; +NX_PACKET *response_packet_ptr; +CHAR string1[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; +CHAR string2[NX_HTTP_MAX_STRING + 1]; +CHAR *buffer_ptr; +CHAR crlf[2] = {13,10}; +UINT string1_length; +UINT string2_length; +UINT temp_resource_length = 0; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + + /* Determine if the client is in a ready state. */ + if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_READY) + { + + /* Client not ready, return error. */ + return(NX_HTTP_NOT_READY); + } + + /* Make sure there is enough room in the destination string. */ + if((username) && (password)) + { + if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || + _nx_utility_string_length_check(password, &temp_password_length, password_length)) + { + + /* Error, return to caller. */ + return(NX_HTTP_PASSWORD_TOO_LONG); + } + + /* Validate string length. */ + if ((username_length != temp_username_length) || + (password_length != temp_password_length)) + { + return(NX_HTTP_ERROR); + } + } + + /* Check resource length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, resource_length)) + { + return(NX_HTTP_ERROR); + } + + /* Validate string length. */ + if (resource_length != temp_resource_length) + { + return(NX_HTTP_ERROR); + } + + /* Otherwise, attempt to bind the client socket. */ + status = nx_tcp_client_socket_bind(&(client_ptr -> nx_http_client_socket), NX_ANY_PORT, wait_option); + + /* Check status of the bind. */ + if (status != NX_SUCCESS) + { + + /* Error binding to a port, return to caller. */ + return(status); + } + + /* Invoke the connection call. */ + status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_http_client_socket), server_ip, + client_ptr -> nx_http_client_connect_port, wait_option); + + /* Check for connection status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + return(status); + } + + /* At this point we have a connection setup with an HTTP server! */ + + /* Allocate a packet for the GET (or POST) message. */ + if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_IPv4_TCP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_IPv6_TCP_PACKET, wait_option); + } + + /* Check allocation status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + return(status); + } + + /* Determine if a GET or POST is requested. */ + if ((input_ptr) && (input_size)) + { + + /* Additional information requested, build the POST request. */ + nx_packet_data_append(packet_ptr, "POST ", 5, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + } + else + { + + /* No additional information, build the GET request. */ + nx_packet_data_append(packet_ptr, "GET ", 4, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + } + + /* Determine if the resource needs a leading "/". */ + if (resource[0] != '/') + { + + /* Is this another website e.g. begins with http and has a colon? */ + if ( + ((resource[0] == 'h') || (resource[0] == 'H')) && + ((resource[1] == 't') || (resource[1] == 'T')) && + ((resource[2] == 't') || (resource[2] == 'T')) && + ((resource[3] == 'p') || (resource[3] == 'P')) && + (resource[4] == ':') + ) + { + + /* Yes, to send this string as is. */ + } + else + { + + /* Local file URI which needs a leading '/' character. */ + nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + /* Else URI string refers to root directory file, and has a leading '/' character already. */ + + /* Place the resource in the header. */ + nx_packet_data_append(packet_ptr, resource, resource_length, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + + /* Place the HTTP version in the header. */ + nx_packet_data_append(packet_ptr, " HTTP/1.0", 9, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + + /* Place the end of line character in the header. */ + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + + /* Determine if basic authentication is required. */ + if ((username) && (password)) + { + + /* Yes, attempt to build basic authentication. */ + nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, client_ptr -> nx_http_client_packet_pool_ptr, + NX_WAIT_FOREVER); + + /* Encode and append the "name:password" into next. */ + + /* Place the name and password in a single string. */ + + /* Copy the name into the merged string. */ + memcpy(string1, username, username_length); + + /* Insert the colon. */ + string1[username_length] = ':'; + + /* Copy the password into the merged string. */ + memcpy(&string1[username_length + 1], password, password_length); + + /* Make combined string NULL terminated. */ + string1[username_length + password_length + 1] = NX_NULL; + + /* Now encode the username:password string. */ + _nx_http_client_base64_encode(string1, username_length + password_length + 1, string2); + + /* Check string length. */ + _nx_utility_string_length_check(string2, &string2_length, NX_HTTP_MAX_STRING); + nx_packet_data_append(packet_ptr, string2, string2_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Check to see if a Content-Length field is needed. */ + if ((input_ptr) && (input_size)) + { + + /* Now build the content-length entry. */ + nx_packet_data_append(packet_ptr, "Content-Length: ", 16, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + string1_length = _nx_http_client_number_convert(input_size, string1); + nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Place an extra cr/lf to signal the end of the HTTP header. */ + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Check to see if we need to append the additional user data. */ + if ((input_ptr) && (input_size)) + { + + /* Now build the content-length entry. */ + nx_packet_data_append(packet_ptr, input_ptr, input_size, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Now send the packet to the HTTP server. */ + status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return an error. */ + return(status); + } + + /* Pickup the response from the Server. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, wait_option); + + /* Check for a response from the Server. */ + if (status == NX_SUCCESS) + { + + /* Setup pointer to server response. */ + buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; + + /* Check if packet contains the HTTP status. */ + if ((buffer_ptr + 11) >= (CHAR *)response_packet_ptr -> nx_packet_append_ptr) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr->nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr->nx_http_client_socket)); + + /* Return an error. */ + return(NX_HTTP_FAILED); + } + + /* Determine if the request was successful. */ + if (buffer_ptr[9] == '2') + { + + /* Determine if we need to copy the packet. */ + if ((response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_data_start) < NX_HTTP_CLIENT_MIN_PACKET_SIZE) + { + + /* Copy the packet to a packet in the packet pool. */ + nx_packet_copy(response_packet_ptr, &packet_ptr, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Release the original packet. */ + nx_packet_release(response_packet_ptr); + + /* Copy the packet pointer. */ + response_packet_ptr = packet_ptr; + } + + /* Pickup the content length. */ + length = _nx_http_client_content_length_get(response_packet_ptr); + + /* Pickup the content offset. */ + offset = _nx_http_client_calculate_content_offset(response_packet_ptr); + + /* Indicate a successful completion. */ + status = NX_SUCCESS; + } + /* Determine if it is an authentication error. */ + else if ((buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Inform caller of an authentication error. */ + status = NX_HTTP_AUTHENTICATION_ERROR; + } + else + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + } + } + + /* Check for error processing received packet. */ + if (status != NX_SUCCESS) + { + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + return status; + } + + /* Check for invalid packet parameters. */ + if ((length == 0) || (offset == 0)) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return an error. */ + return(NX_HTTP_FAILED); + } + + + /* Determine if the offset is in this request. */ + if (response_packet_ptr -> nx_packet_length > (offset + 3)) + { + + /* Adjust the pointers to skip over the response header. */ + response_packet_ptr -> nx_packet_prepend_ptr = response_packet_ptr -> nx_packet_prepend_ptr + offset; + + /* Reduce the length. */ + response_packet_ptr -> nx_packet_length = response_packet_ptr -> nx_packet_length - offset; + + /* Save the packet pointer for the get packet call. */ + client_ptr -> nx_http_client_first_packet = response_packet_ptr; + } + else + { + + /* Clear the saved packet pointer. */ + client_ptr -> nx_http_client_first_packet = NX_NULL; + + /* This packet only contains the header, just release it! */ + nx_packet_release(response_packet_ptr); + } + + /* Store the total number of bytes to receive. */ + client_ptr -> nx_http_client_total_transfer_bytes = length; + client_ptr -> nx_http_client_actual_bytes_transferred = 0; + + /* Enter the GET state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_GET; + + /* Return success to the caller. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_get_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client get packet call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Destination for packet pointer*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_get_packet Actual client get packet call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET packet routine. */ + status = _nx_http_client_get_packet(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_get_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets a data packet associated with the resource */ +/* specified by the previous GET start request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Destination for packet pointer*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_socket_disconnect Disconnect client socket */ +/* nx_tcp_socket_receive Receive a resource data packet*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +NX_PACKET *data_packet_ptr; +UINT status; + + + /* Default the return packet to NULL. */ + *packet_ptr = NX_NULL; + + /* Determine if the client is in a get state. */ + if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_GET) + { + + /* Client not ready, return error. */ + return(NX_HTTP_NOT_READY); + } + + /* Determine if the GET packet operation is complete. */ + if (client_ptr -> nx_http_client_total_transfer_bytes == client_ptr -> nx_http_client_actual_bytes_transferred) + { + + /* Yes, we are finished. */ + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Reenter the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return the GET done code. */ + return(NX_HTTP_GET_DONE); + } + + /* Determine if there is a queued packet. */ + if (client_ptr -> nx_http_client_first_packet) + { + + /* Yes, just use the saved packet. */ + data_packet_ptr = client_ptr -> nx_http_client_first_packet; + + /* Clear the saved packet pointer. */ + client_ptr -> nx_http_client_first_packet = NX_NULL; + } + else + { + + /* Receive a data packet from the TCP connection. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &data_packet_ptr, wait_option); + + /* Determine if a packet is available. */ + if (status != NX_SUCCESS) + { + + /* Ensure the packet pointer is NULL. */ + data_packet_ptr = NX_NULL; + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + return status; + } + } + + /* Check for an error condition. */ + if (data_packet_ptr -> nx_packet_length > (client_ptr -> nx_http_client_total_transfer_bytes - client_ptr -> nx_http_client_actual_bytes_transferred)) + { + + /* Release the invalid HTTP packet. */ + nx_packet_release(data_packet_ptr); + + /* Error, break down the connection and return to the caller. */ + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Reenter the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return an error. */ + return(NX_HTTP_BAD_PACKET_LENGTH); + } + + /* Adjust the actual transfer bytes. */ + client_ptr -> nx_http_client_actual_bytes_transferred = client_ptr -> nx_http_client_actual_bytes_transferred + + data_packet_ptr -> nx_packet_length; + + /* Move the packet pointer into the return pointer. */ + *packet_ptr = data_packet_ptr; + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP (IPv4) Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_put_start Actual IPv4 HTTP Client put */ +/* start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, + CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + resource == NX_NULL || !ip_address) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_http_client_put_start(client_ptr, ip_address, resource, username, password, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(total_bytes); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP (IPv4) Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_put_start_extended Actual IPv4 HTTP Client put */ +/* start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, + UINT resource_length, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + resource == NX_NULL || !ip_address) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_http_client_put_start_extended(client_ptr, ip_address, resource, resource_length, + username, username_length, password, password_length, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(resource_length); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(username_length); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(password_length); + NX_PARAMETER_NOT_USED(total_bytes); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is a wrapper for the actual _nxd_http_client_put_start*/ +/* service that enables HTTP applications running on IPv4 to access */ +/* HTTP duo API without enabling IPv6. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_put_start Actual put start service for */ +/* HTTP Duo Client */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, + CHAR *password, ULONG total_bytes, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_ip_addr; + + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; + server_ip_addr.nxd_ip_address.v4 = ip_address; + + status = _nxd_http_client_put_start(client_ptr, &server_ip_addr, resource, username, + password, total_bytes, wait_option); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(total_bytes); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is a wrapper for the actual _nxd_http_client_put_start*/ +/* service that enables HTTP applications running on IPv4 to access */ +/* HTTP duo API without enabling IPv6. */ +/* */ +/* Note: The strings of resource, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* ip_address IPv4 address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_put_start_extended Actual put start service for */ +/* HTTP Duo Client */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, + UINT resource_length, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_ip_addr; + + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; + server_ip_addr.nxd_ip_address.v4 = ip_address; + + status = _nxd_http_client_put_start_extended(client_ptr, &server_ip_addr, resource, resource_length, + username, username_length, password, password_length, + total_bytes, wait_option); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(resource); + NX_PARAMETER_NOT_USED(resource_length); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(username_length); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(password_length); + NX_PARAMETER_NOT_USED(total_bytes); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_put_start Actual client put start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, + CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + resource == NX_NULL || !server_ip) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nxd_http_client_put_start(client_ptr, server_ip, resource, username, password, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_put_start_extended Actual client put start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, + UINT resource_length, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + resource == NX_NULL || !server_ip) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nxd_http_client_put_start_extended(client_ptr, server_ip, resource, resource_length, + username, username_length, password, password_length, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processesthe application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_http_client_put_start_extended Actual client put start call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, + CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) + +{ + +UINT resource_length = 0; +UINT username_length = 0; +UINT password_length = 0; +UINT status; + + /* Make sure there is enough room in the destination string. */ + if((username) && (password)) + { + if (_nx_utility_string_length_check(username, &username_length, NX_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &password_length, NX_HTTP_MAX_PASSWORD)) + { + + /* Error, return to caller. */ + return(NX_HTTP_PASSWORD_TOO_LONG); + } + } + + /* Check resource length. */ + if (_nx_utility_string_length_check(resource, &resource_length, NX_MAX_STRING_LENGTH)) + { + return(NX_HTTP_ERROR); + } + + status = _nxd_http_client_put_start_extended(client_ptr, server_ip, resource, resource_length, + username, username_length, password, password_length, + total_bytes, wait_option); + + /* Return status to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processesthe application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* Note: The strings of resource, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length Length of resource (URL) */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_base64_encode Encode username/password */ +/* _nx_http_client_number_convert Convert number to ASCII */ +/* nx_http_client_type_get Get the HTTP file type */ +/* nx_packet_allocate Allocate a packet */ +/* nx_packet_data_append Append data to packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_client_socket_bind Bind client socket to port */ +/* nxd_tcp_client_socket_connect Connect to HTTP Server */ +/* nx_tcp_socket_disconnect Disconnect client socket */ +/* nx_tcp_client_socket_unbind Unbind client socket */ +/* nx_tcp_socket_send Send request to Server */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, + UINT resource_length, CHAR *username, UINT username_length, + CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) + +{ + +NX_PACKET *packet_ptr; +CHAR string1[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; +CHAR string2[NX_HTTP_MAX_STRING + 1]; +CHAR crlf[2] = {13,10}; +UINT status; +UINT string1_length; +UINT string2_length; +UINT temp_resource_length = 0; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + + + /* Determine if the client is in a ready state. */ + if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_READY) + { + + /* Client not ready, return error. */ + return(NX_HTTP_NOT_READY); + } + + if ((username) && (password)) + { + + /* Make sure there is enough room in the destination string. */ + if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || + _nx_utility_string_length_check(password, &temp_password_length, password_length)) + { + + /* Error, return to caller. */ + return(NX_HTTP_USERNAME_TOO_LONG); + } + + /* Validate string length. */ + if ((username_length != temp_username_length) || + (password_length != temp_password_length)) + { + return(NX_HTTP_ERROR); + } + } + + /* Check resource length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, resource_length)) + { + return(NX_HTTP_ERROR); + } + + /* Validate string length. */ + if (resource_length != temp_resource_length) + { + return(NX_HTTP_ERROR); + } + + /* Otherwise, attempt to bind the client socket. */ + status = nx_tcp_client_socket_bind(&(client_ptr -> nx_http_client_socket), NX_ANY_PORT, wait_option); + + /* Check status of the bind. */ + if (status != NX_SUCCESS) + { + + /* Error binding to a port, return to caller. */ + return(status); + } + + /* Connect to the HTTP server. */ + + /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */ + status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_http_client_socket), server_ip, + client_ptr -> nx_http_client_connect_port, wait_option); + + /* Check for connection status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + return(status); + } + + /* At this point we have a connection setup with an HTTP server! */ + + /* Allocate a packet for the PUT message. */ + if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_IPv4_TCP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_IPv6_TCP_PACKET, wait_option); + } + + /* Check allocation status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + return(status); + } + + /* Build the PUT request. */ + nx_packet_data_append(packet_ptr, "PUT ", 4, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if this is a root directory based URI string. */ + if (resource[0] != '/') + { + + /* Then check if this another website e.g. begins with http and has a colon. */ + if ( + ((resource[0] == 'h') || (resource[0] == 'H')) && + ((resource[1] == 't') || (resource[1] == 'T')) && + ((resource[2] == 't') || (resource[2] == 'T')) && + ((resource[3] == 'p') || (resource[3] == 'P')) && + (resource[4] == ':') + ) + { + + /* Yes, ok to send this string as is. */ + } + else + { + + /* This URI is a root directory based file but it needs a leading / character. */ + nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + + /* (Else the URI begins with a '/' and is ok to send as is.) */ + + /* Place the resource in the header. */ + nx_packet_data_append(packet_ptr, resource, resource_length, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the HTTP version in the header. */ + nx_packet_data_append(packet_ptr, " HTTP/1.0", 9, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the end of line character in the header. */ + nx_packet_data_append(packet_ptr, crlf, 2, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if basic authentication is required. */ + if ((username) && (password)) + { + + /* Yes, attempt to build basic authentication. */ + nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Encode and append the "name:password" into next. */ + + /* Place the name and password in a single string. */ + + /* Copy the name into the merged string. */ + memcpy(string1, username, username_length); + + /* Insert the colon. */ + string1[username_length] = ':'; + + /* Copy the password into the merged string. */ + memcpy(&string1[username_length + 1], password, password_length); + + /* Make combined string NULL terminated. */ + string1[username_length + password_length + 1] = NX_NULL; + + /* Now encode the username:password string. */ + _nx_http_client_base64_encode(string1, username_length + password_length + 1, string2); + + /* Check string length. */ + _nx_utility_string_length_check(string2, &string2_length, NX_HTTP_MAX_STRING); + nx_packet_data_append(packet_ptr, string2, string2_length, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Now build the content-type entry. */ + nx_packet_data_append(packet_ptr, "Content-Type: ", 14, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + string1_length = _nx_http_client_type_get(resource, string1); + nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Now build the content-length entry. */ + nx_packet_data_append(packet_ptr, "Content-Length: ", 16, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + string1_length = _nx_http_client_number_convert(total_bytes, string1); + nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place an extra cr/lf to signal the end of the HTTP header. */ + nx_packet_data_append(packet_ptr, crlf, 2, + client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Now send the packet to the HTTP server. */ + status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return an error. */ + return(status); + } + + /* Store the total number of bytes to send. */ + client_ptr -> nx_http_client_total_transfer_bytes = total_bytes; + client_ptr -> nx_http_client_actual_bytes_transferred = 0; + + /* Enter the PUT state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_PUT; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_client_put_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client put packet call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Resource data packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_client_put_packet Actual client put packet call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Ensure there is enough room for the TCP packet header. */ + if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_TCP_PACKET) + { + + /* Return an invalid packet error. */ + return(NX_INVALID_PACKET); + } + + /* Call actual PUT data routine. */ + status = _nx_http_client_put_packet(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_put_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a packet of resource data associated with */ +/* the previous PUT request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Resource data packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release the packet */ +/* nx_tcp_client_socket_unbind Unbind the client socket */ +/* nx_tcp_socket_disconnect Disconnect form Server */ +/* nx_tcp_socket_receive Receive response from Server */ +/* nx_tcp_socket_send Send resource data packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +NX_PACKET *response_packet_ptr; +CHAR *buffer_ptr; +UINT length; +UINT status; + + + /* First, check and see if the client instance is still in the PUT state. */ + if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_PUT) + { + + /* Client not ready, return error. */ + return(NX_HTTP_NOT_READY); + } + + /* Next, check and see if there is a response from the Server. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, NX_NO_WAIT); + + /* Check for an early response from the Server. */ + if (status == NX_SUCCESS) + { + + /* This is an error condition since the Server should not respond until the PUT is complete. */ + + /* Setup pointer to server response. */ + buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if it is an authentication error. */ + if (((buffer_ptr + 11) < (CHAR *)response_packet_ptr -> nx_packet_append_ptr) && + (buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) + { + + /* Inform caller of an authentication error. */ + status = NX_HTTP_AUTHENTICATION_ERROR; + } + else + { + + /* Inform caller of general Server failure. */ + status = NX_HTTP_INCOMPLETE_PUT_ERROR; + } + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return to the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return error to caller. */ + return(status); + } + + /* Otherwise, determine if the packet length fits in the available bytes to send. */ + if (packet_ptr -> nx_packet_length > + (client_ptr -> nx_http_client_total_transfer_bytes - client_ptr -> nx_http_client_actual_bytes_transferred)) + { + + /* Request doesn't fit into the remaining transfer window. */ + return(NX_HTTP_BAD_PACKET_LENGTH); + } + + /* Remember the packet length. */ + length = packet_ptr -> nx_packet_length; + + /* Now send the packet out. */ + status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return to the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return an error. */ + return(status); + } + + /* Otherwise, update the actual bytes transferred. */ + client_ptr -> nx_http_client_actual_bytes_transferred = client_ptr -> nx_http_client_actual_bytes_transferred + length; + + /* Are we finished? */ + if (client_ptr -> nx_http_client_total_transfer_bytes > client_ptr -> nx_http_client_actual_bytes_transferred) + { + + /* No, we are not finished so just return success to the caller. */ + return(NX_SUCCESS); + } + + /* We are finished sending the PUT data. Now wait for a response from the Server. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, wait_option); + + if (status != NX_SUCCESS) + { + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return to the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return status to caller. */ + return(status); + } + + + /* Setup pointer to server response. */ + buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if the request was successful. */ + if (((buffer_ptr + 9) >= (CHAR *) response_packet_ptr -> nx_packet_append_ptr) || + (buffer_ptr[9] != '2')) + { + + /* Inform caller of a successful completion. */ + status = NX_HTTP_REQUEST_UNSUCCESSFUL_CODE; + } + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); + + /* Return to the READY state. */ + client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; + + /* Return status to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_client_put_start_extended Start the PUT process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_type_get(CHAR *name, CHAR *http_type_string) +{ + +UINT i; + + + /* First find the end of the string. */ + i = 0; + while (name[i] != (CHAR) NX_NULL) + { + i++; + } + + /* Now look backwards to find the last period that signals the + file extension. */ + while ((i) && (name[i] != '.')) + { + i--; + } + + /* Position forward again, past the period. */ + i++; + + /* Now see what HTTP file type to return. */ + + /* Check for .txt file extension. */ + if (((name[i] == 't') || (name[i] == 'T')) && + ((name[i+1] == 'x') || (name[i+1] == 'X')) && + ((name[i+2] == 't') || (name[i+2] == 'T'))) + { + + /* Yes, we have a plain text file. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'p'; + http_type_string[6] = 'l'; + http_type_string[7] = 'a'; + http_type_string[8] = 'i'; + http_type_string[9] = 'n'; + + /* Return the size of the HTTP ASCII type string. */ + return(10); + } + + /* Check for .htm[l] file extension. */ + else if (((name[i] == 'h') || (name[i] == 'H')) && + ((name[i+1] == 't') || (name[i+1] == 'T')) && + ((name[i+2] == 'm') || (name[i+2] == 'M'))) + { + + /* Yes, we have an HTML text file. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'h'; + http_type_string[6] = 't'; + http_type_string[7] = 'm'; + http_type_string[8] = 'l'; + + /* Return the size of the HTTP ASCII type string. */ + return(9); + } + + /* Check for .gif file extension. */ + else if (((name[i] == 'g') || (name[i] == 'G')) && + ((name[i+1] == 'i') || (name[i+1] == 'I')) && + ((name[i+2] == 'f') || (name[i+2] == 'F'))) + { + + /* Yes, we have a GIF image file. */ + http_type_string[0] = 'i'; + http_type_string[1] = 'm'; + http_type_string[2] = 'a'; + http_type_string[3] = 'g'; + http_type_string[4] = 'e'; + http_type_string[5] = '/'; + http_type_string[6] = 'g'; + http_type_string[7] = 'i'; + http_type_string[8] = 'f'; + + /* Return the size of the HTTP ASCII type string. */ + return(9); + } + + /* Check for .xbm file extension. */ + else if (((name[i] == 'x') || (name[i] == 'X')) && + ((name[i+1] == 'b') || (name[i+1] == 'B')) && + ((name[i+2] == 'm') || (name[i+2] == 'M'))) + { + + /* Yes, we have a x-xbitmap image file. */ + http_type_string[0] = 'i'; + http_type_string[1] = 'm'; + http_type_string[2] = 'a'; + http_type_string[3] = 'g'; + http_type_string[4] = 'e'; + http_type_string[5] = '/'; + http_type_string[6] = 'x'; + http_type_string[7] = '-'; + http_type_string[8] = 'x'; + http_type_string[9] = 'b'; + http_type_string[10] = 'i'; + http_type_string[11] = 't'; + http_type_string[12] = 'm'; + http_type_string[13] = 'a'; + http_type_string[14] = 'p'; + + /* Return the size of the HTTP ASCII type string. */ + return(15); + } + + /* Default to plain text. */ + else + { + + /* Default to plain text. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'p'; + http_type_string[6] = 'l'; + http_type_string[7] = 'a'; + http_type_string[8] = 'i'; + http_type_string[9] = 'n'; + + /* Return the size of the HTTP ASCII type string. */ + return(10); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the content length of the supplied HTTP */ +/* response packet. If the packet is no content or the packet is */ +/* invalid, a zero is returned. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* length Length of content */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_client_get_start Start the GET operation */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_content_length_get(NX_PACKET *packet_ptr) +{ + +UINT length; +CHAR *buffer_ptr; +UINT found = NX_FALSE; + + + /* Default the content length to an invalid value. */ + length = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Content-length:" token first. */ + while ((buffer_ptr+14) < (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + + /* Check for the Content-length token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && + ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && + ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && + ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && + (*(buffer_ptr+7) == '-') && + ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && + ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && + ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && + ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && + ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && + ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && + (*(buffer_ptr+14) == ':')) + { + + /* Yes, found content-length token. */ + found = NX_TRUE; + + /* Move past the Content-Length: field. Exit the loop. */ + buffer_ptr += 15; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Check if found the content-length token. */ + if (found != NX_TRUE) + { + + /* No, return an invalid length indicating a bad HTTP packet. */ + return(length); + } + + /* Now skip over white space. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + buffer_ptr++; + } + + /* Now convert the length into a numeric value. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + { + + /* Update the content length. */ + length = length * 10; + length = length + (((UINT) (*buffer_ptr)) - 0x30); + + /* Move the buffer pointer forward. */ + buffer_ptr++; + } + + /* Determine if the content length was picked up properly. */ + if ((buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || + ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR)13))) + { + + /* Error, set the length to zero. */ + length = 0; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_calculate_content_offset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the byte offset to the start of the */ +/* HTTP request content area. This area immediately follows the HTTP */ +/* request header (which ends with a blank line). */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to request packet */ +/* */ +/* OUTPUT */ +/* */ +/* Byte Offset (0 implies no content) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_client_get_start Start GET processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_calculate_content_offset(NX_PACKET *packet_ptr) +{ + +UINT offset; +CHAR *buffer_ptr; + + + /* Default the content offset to zero. */ + offset = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "cr,lf,cr,lf" token. */ + while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the token. This signals a blank line, which also + specifies the start of the content. */ + if ((*buffer_ptr == (CHAR) 13) && + (*(buffer_ptr+1) == (CHAR) 10) && + (*(buffer_ptr+2) == (CHAR) 13) && + (*(buffer_ptr+3) == (CHAR) 10)) + { + + /* Adjust the offset. */ + offset = offset + 4; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + + /* Increment the offset. */ + offset++; + } + + /* Return the offset to the caller. */ + return(offset); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* string Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_client_get_start_extended Start GET processing */ +/* _nx_http_client_put_start_extended Start PUT processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_client_number_convert(UINT number, CHAR *string) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Default string to return '0'. */ + string[0] = '0'; + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while ((size < 10) && (number)) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string[j] = string[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + string[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + } + + /* Make the string NULL terminated. */ + string[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_client_base64_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the input string into a base64 */ +/* representation. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* length Length of name */ +/* base64name Encoded base64 name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_client_get_start_extended Start GET processing */ +/* _nx_http_client_put_start_extended Start PUT processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name) +{ + +UINT pad; +UINT i, j; +UINT step; + + + /* Adjust the length to represent the base64 name. */ + length = ((length * 8) / 6); + + /* Default padding to none. */ + pad = 0; + + /* Determine if an extra conversion is needed. */ + if ((length * 6) % 24) + { + + /* Some padding is needed. */ + + /* Calculate the number of pad characters. */ + pad = (length * 6) % 24; + pad = (24 - pad) / 6; + pad = pad - 1; + + /* Adjust the length to pickup the character fraction. */ + length++; + } + + /* Setup index into the base64name. */ + j = 0; + + /* Compute the base64name. */ + step = 0; + i = 0; + while (j < length) + { + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first 6 bits of name character for index. */ + base64name[j++] = _nx_http_client_base64_array[((UINT) name[i]) >> 2]; + step++; + } + else if (step == 1) + { + + /* Use last 2 bits of name character and first 4 bits of next name character for index. */ + base64name[j++] = _nx_http_client_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; + i++; + step++; + } + else if (step == 2) + { + + /* Use last 4 bits of name character and first 2 bits of next name character for index. */ + base64name[j++] = _nx_http_client_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; + i++; + step++; + } + else /* Step 3 */ + { + + /* Use last 6 bits of name character for index. */ + base64name[j++] = _nx_http_client_base64_array[(((UINT) name[i]) & 0x3F)]; + i++; + step = 0; + } + } + + /* Determine if the index needs to be advanced. */ + if (step != 3) + i++; + + /* Now add the PAD characters. */ + while ((pad--) && (j < NX_HTTP_MAX_STRING)) + { + + /* Pad base64name with '=' characters. */ + base64name[j++] = '='; + } + + /* Put a NULL character in. */ + base64name[j] = NX_NULL; +} + diff --git a/addons/http/nxd_http_client.h b/addons/http/nxd_http_client.h new file mode 100644 index 00000000..0756bcd6 --- /dev/null +++ b/addons/http/nxd_http_client.h @@ -0,0 +1,294 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_http_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_HTTP_CLIENT_H +#define NXD_HTTP_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_api.h" + +/* Define the HTTP ID. */ + +#define NXD_HTTP_CLIENT_ID 0x48545450UL + + +/* Define HTTP TCP socket create options. */ + +#ifndef NX_HTTP_TYPE_OF_SERVICE +#define NX_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_HTTP_FRAGMENT_OPTION +#define NX_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_HTTP_TIME_TO_LIVE +#define NX_HTTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_HTTP_MAX_RESOURCE +#define NX_HTTP_MAX_RESOURCE 40 +#endif + +#ifndef NX_HTTP_MAX_NAME +#define NX_HTTP_MAX_NAME 20 +#endif + +#ifndef NX_HTTP_MAX_PASSWORD +#define NX_HTTP_MAX_PASSWORD 20 +#endif + +#ifndef NX_HTTP_CLIENT_TIMEOUT +#define NX_HTTP_CLIENT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 +#endif + +#ifndef NX_HTTP_CLIENT_MIN_PACKET_SIZE +#define NX_HTTP_CLIENT_MIN_PACKET_SIZE 600 +#endif + +/* NX_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ +#define NX_HTTP_MAX_STRING ((NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 1) * 4 / 3 + 1) +#define NX_HTTP_MAX_BINARY_MD5 16 +#define NX_HTTP_MAX_ASCII_MD5 32 + + +/* Define HTTP Client states. */ + +#define NX_HTTP_CLIENT_STATE_READY 1 +#define NX_HTTP_CLIENT_STATE_GET 2 +#define NX_HTTP_CLIENT_STATE_PUT 3 + + +/* Define return code constants. */ + +#define NX_HTTP_ERROR 0xE0 /* HTTP internal error */ +#define NX_HTTP_TIMEOUT 0xE1 /* HTTP timeout occurred */ +#define NX_HTTP_FAILED 0xE2 /* HTTP error */ +#define NX_HTTP_DONT_AUTHENTICATE 0xE3 /* HTTP authentication not needed */ +#define NX_HTTP_BASIC_AUTHENTICATE 0xE4 /* HTTP basic authentication requested */ +#define NX_HTTP_DIGEST_AUTHENTICATE 0xE5 /* HTTP digest authentication requested */ +#define NX_HTTP_NOT_FOUND 0xE6 /* HTTP request not found */ +#define NX_HTTP_DATA_END 0xE7 /* HTTP end of content area */ +#define NX_HTTP_CALLBACK_COMPLETED 0xE8 /* HTTP user callback completed the processing */ +#define NX_HTTP_POOL_ERROR 0xE9 /* HTTP supplied pool payload is too small */ +#define NX_HTTP_NOT_READY 0xEA /* HTTP client not ready for operation */ +#define NX_HTTP_AUTHENTICATION_ERROR 0xEB /* HTTP client authentication failed */ +#define NX_HTTP_GET_DONE 0xEC /* HTTP client get is complete */ +#define NX_HTTP_BAD_PACKET_LENGTH 0xED /* Invalid packet received - length incorrect */ +#define NX_HTTP_REQUEST_UNSUCCESSFUL_CODE 0xEE /* Received an error code instead of 2xx from server */ +#define NX_HTTP_INCOMPLETE_PUT_ERROR 0xEF /* Server responds before PUT is complete */ +#define NX_HTTP_PASSWORD_TOO_LONG 0xF0 /* Password exceeded expected length */ +#define NX_HTTP_USERNAME_TOO_LONG 0xF1 /* Username exceeded expected length */ +#define NX_HTTP_NO_QUERY_PARSED 0xF2 /* Server unable to find query in client request */ + +/* Define the default HTTP Server TCP port number. To change this at runtime + see nx_http_client_set_connect_port(). */ + +#define NX_HTTP_SERVER_PORT 80 + + +#ifdef NX_HTTP_DIGEST_ENABLE + +/* Include the MD5 digest header file. */ + +#include "nx_md5.h" + +#endif + + +/* Define the HTTP Client data structure. */ + +typedef struct NX_HTTP_CLIENT_STRUCT +{ + ULONG nx_http_client_id; /* HTTP Server ID */ + CHAR *nx_http_client_name; /* Name of this HTTP Client */ + UINT nx_http_client_state; /* Current state of HTTP Client */ + UINT nx_http_client_connect_port; /* Client port to connect to the server */ + NX_IP *nx_http_client_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_http_client_packet_pool_ptr; /* Pointer to HTTP Client packet pool */ + ULONG nx_http_client_total_transfer_bytes; /* Total number of bytes to transfer */ + ULONG nx_http_client_actual_bytes_transferred; /* Number of bytes actually transferred */ + NX_PACKET *nx_http_client_first_packet; /* Pointer to first packet with data */ + NX_TCP_SOCKET nx_http_client_socket; /* HTTP Client TCP socket */ +#ifdef NX_HTTP_DIGEST_ENABLE + NX_MD5 nx_http_client_md5data; /* HTTP Client MD5 work area */ +#endif +} NX_HTTP_CLIENT; + + + +#ifndef NX_HTTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_http_client_create _nx_http_client_create +#define nx_http_client_delete _nx_http_client_delete +#define nx_http_client_get_start _nx_http_client_get_start +#define nx_http_client_get_start_extended _nx_http_client_get_start_extended +#define nx_http_client_get_packet _nx_http_client_get_packet +#define nx_http_client_put_start _nx_http_client_put_start +#define nx_http_client_put_start_extended _nx_http_client_put_start_extended +#define nx_http_client_put_packet _nx_http_client_put_packet +#define nx_http_client_set_connect_port _nx_http_client_set_connect_port +#define nxd_http_client_get_start _nxd_http_client_get_start +#define nxd_http_client_get_start_extended _nxd_http_client_get_start_extended +#define nxd_http_client_put_start _nxd_http_client_put_start +#define nxd_http_client_put_start_extended _nxd_http_client_put_start_extended + +#else + +/* Services with error checking. */ + +#define nx_http_client_create(p,n,i,pp,w) _nxe_http_client_create(p,n,i,pp,w, sizeof(NX_HTTP_CLIENT)) +#define nx_http_client_delete _nxe_http_client_delete +#define nx_http_client_get_start _nxe_http_client_get_start +#define nx_http_client_get_start_extended _nxe_http_client_get_start_extended +#define nx_http_client_get_packet _nxe_http_client_get_packet +#define nx_http_client_put_start _nxe_http_client_put_start +#define nx_http_client_put_start_extended _nxe_http_client_put_start_extended +#define nx_http_client_put_packet _nxe_http_client_put_packet +#define nx_http_client_set_connect_port _nxe_http_client_set_connect_port +#define nxd_http_client_put_start _nxde_http_client_put_start +#define nxd_http_client_put_start_extended _nxde_http_client_put_start_extended +#define nxd_http_client_get_start _nxde_http_client_get_start +#define nxd_http_client_get_start_extended _nxde_http_client_get_start_extended + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +#ifdef NX_DISABLE_ERROR_CHECKING +UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); +#else +UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); +#endif /* NX_DISABLE_ERROR_CHECKING */ +UINT nx_http_client_delete(NX_HTTP_CLIENT *client_ptr); +UINT nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); +UINT nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); + +#else + +/* HTTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); +UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); +UINT _nxe_http_client_delete(NX_HTTP_CLIENT *client_ptr); +UINT _nx_http_client_delete(NX_HTTP_CLIENT *client_ptr); +UINT _nxe_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxe_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT _nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT _nxe_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nxe_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT _nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT _nxe_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nxe_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); +UINT _nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); +UINT _nxde_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxde_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT _nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT _nxde_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nxde_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT _nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); + +/* Define internal HTTP functions. */ + +UINT _nx_http_client_type_get(CHAR *name, CHAR *http_type_string); +UINT _nx_http_client_content_length_get(NX_PACKET *packet_ptr); +UINT _nx_http_client_calculate_content_offset(NX_PACKET *packet_ptr); +UINT _nx_http_client_number_convert(UINT number, CHAR *string); +VOID _nx_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name); + + +#endif /* NX_HTTP_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_HTTP_CLIENT_H */ diff --git a/addons/http/nxd_http_server.c b/addons/http/nxd_http_server.c new file mode 100644 index 00000000..fe66c208 --- /dev/null +++ b/addons/http/nxd_http_server.c @@ -0,0 +1,9253 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_HTTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_http_server.h" +#include "stdio.h" +#include "string.h" +#ifdef NX_HTTP_DIGEST_ENABLE +#include "nx_md5.h" +#endif + + +/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing + into this array yields the base64 representation of the 6bit number. */ + +CHAR _nx_http_server_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +#ifdef NX_HTTP_DIGEST_ENABLE +/* Define the default nonce, used only for MD5 authentication. For security reasons, this ASCII value should + change over time. */ + +CHAR _nx_http_server_nonce[] = "a4b8c8d7e0f6a7b2c3d2e4f5a4b7c5d2e7f"; +#endif + +/* Define date strings. */ +const CHAR *_nx_http_server_weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const CHAR *_nx_http_server_month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +/* Define basic MIME maps. */ +static NX_HTTP_SERVER_MIME_MAP _nx_http_server_mime_maps[] = +{ + {"html", "text/html"}, + {"htm", "text/html"}, + {"txt", "text/plain"}, + {"gif", "image/gif"}, + {"jpg", "image/jpeg"}, + {"ico", "image/x-icon"}, +}; + + +/* Create two arrays to hold encoded and decoded username/password data. */ +static CHAR authorization_request[NX_HTTP_MAX_STRING + 1]; +static CHAR authorization_decoded[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_content_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP content get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_content_get Actual server content get call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server content get function. */ + status = _nx_http_server_content_get(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_content_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the user's specified portion of the HTTP */ +/* content. Content is typically included in POST and PUT requests */ +/* from the client. This routine is designed to be called from the */ +/* application's request notify callback. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive another packet */ +/* _nx_http_server_content_length_get Pickup the content length */ +/* _nx_http_server_calculate_content_offset Pickup content offset */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +ULONG content_length; +ULONG get_offset; +ULONG offset; +#ifndef NX_DISABLE_PACKET_CHAIN +UINT status; +#endif /* NX_DISABLE_PACKET_CHAIN */ +UINT remaining_bytes; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; + + + /* Default the actual size to zero. */ + *actual_size = 0; + + /* Determine if there is content in this HTTP request. */ + content_length = (ULONG) _nx_http_server_content_length_get(packet_ptr); + + /* Make sure the content length is at least greater than the byte offset supplied. */ + if (content_length <= byte_offset) + { + + /* No more data in this buffer. */ + return(NX_HTTP_DATA_END); + } + + /* Determine if the destination size is greater than the content length. */ + if (destination_size > content_length) + { + + /* Yes, make the destination size equal to the content length. */ + destination_size = content_length; + } + + /* Calculate the offset to the requested content area. */ + get_offset = ((ULONG) _nx_http_server_calculate_content_offset(packet_ptr)) + byte_offset; + + /* Determine if we need to read one or more additional packets. */ + while (get_offset >= packet_ptr -> nx_packet_length) + { + +#ifdef NX_DISABLE_PACKET_CHAIN + NX_PARAMETER_NOT_USED(server_ptr); + + return NX_HTTP_ERROR; +#else + /* Read another packet because the offset reaches past the current packet + length. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* Otherwise, we have a new packet to append to the head packet. */ + + /* Determine if the current packet is already chained. */ + if (packet_ptr -> nx_packet_next) + { + + /* Yes, link the current last packet to the new packet. */ + (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; + } + else + { + + /* Otherwise, this is our first chained packet. Link to the head. */ + packet_ptr -> nx_packet_next = new_packet_ptr; + } + + /* Is the new packet chained? */ + if (new_packet_ptr -> nx_packet_next) + { + + /* Yes, there is a last packet pointer. Point to this from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; + } + else + { + + /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr; + } + + /* Update the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Default the buffer pointer to NULL. */ + buffer_ptr = NX_NULL; + + /* Now find the packet that contains the offset. */ + offset = 0; + new_packet_ptr = packet_ptr; + do + { + + /* Determine if the get request falls into this packet. */ + if (get_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) + { + + /* Yes, the get offset is in this packet. */ + + /* Setup the starting byte pointer. */ + buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (get_offset - offset); + break; + } + + /* Otherwise update the offset. */ + offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + new_packet_ptr = NX_NULL; +#else + /* Move to next packet in the chain. */ + new_packet_ptr = new_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while (new_packet_ptr); + + /* Determine if an error occurred in the search. */ + if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) + return(NX_HTTP_ERROR); + + /* Now determine if the maximum buffer size has to be adjusted. */ + if (destination_size > (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr)) + { + + /* Adjust the destination size downward. */ + destination_size = (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr); + } + + /* Initialize the remaining bytes. */ + remaining_bytes = destination_size; + + /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ + while (remaining_bytes--) + { + + /* Copy a byte to the destination. */ + *destination_ptr++ = *buffer_ptr++; + } + + /* Successful completion. */ + *actual_size = destination_size; + return(NX_SUCCESS); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_packet_content_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP packet content find */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to pointer to the */ +/* packet that contains the */ +/* HTTP header */ +/* content_length Pointer to content length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_packet_content_find Actual server packet content */ +/* find call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) +{ + + + /* Check for invalid packet pointer. */ + if((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (*packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server content length get function. */ + return(_nx_http_server_packet_content_find(server_ptr, packet_ptr, content_length)); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_packet_content_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the content length specified in the HTTP */ +/* header, and move the nx_packet_prepend_ptr to the beginning of */ +/* the content. If the beginning of the content is not in the packet, */ +/* this function attempts to read the HTTP server socket for the */ +/* next packet. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to pointer to the */ +/* packet that contains the */ +/* HTTP header */ +/* content_length Pointer to content length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive another packet */ +/* _nx_http_server_calculate_content_offset Pickup content offset */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) +{ + +ULONG get_offset; +UINT status; + + /* Determine if there is content in this HTTP request. */ + if(content_length) + *content_length = (ULONG) _nx_http_server_content_length_get(*packet_ptr); + + + get_offset = (ULONG)_nx_http_server_calculate_content_offset(*packet_ptr); + + while((*packet_ptr) -> nx_packet_length <= get_offset) + { + /* Data is not present in this packet. So we have to read the next packet from the socket. */ + get_offset -= (*packet_ptr) -> nx_packet_length; + + /* Release this packet. */ + nx_packet_release(*packet_ptr); + + /* Make the receive call to obtain the next packet. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + if(status != NX_SUCCESS) + { + return(NX_HTTP_TIMEOUT); + } + + } + + (*packet_ptr) -> nx_packet_prepend_ptr += get_offset; + (*packet_ptr) -> nx_packet_length -= get_offset; + + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_packet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server packet get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to the packet to */ +/* be returned. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_packet_get Actual server packet get call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ + + + /* Check for invalid packet pointer. */ + if((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server content length get function. */ + return(_nx_http_server_packet_get(server_ptr, packet_ptr)); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_packet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function obtains the next packet from the HTTP server socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to the packet to */ +/* be returned. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive another packet */ +/* nx_packet_release Packet release */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ +NX_PACKET *new_packet_ptr; +UINT status; + + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + *packet_ptr = new_packet_ptr; + + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP content length get */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_content_length_get Actual server content length */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_content_length_get(NX_PACKET *packet_ptr) +{ + +UINT length; + + /* Check for invalid packet pointer. */ + if (packet_ptr == NX_NULL) + return(0); + + /* Call actual server content length get function. */ + length = _nx_http_server_content_length_get(packet_ptr); + + /* Return the length. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the content length of the supplied HTTP */ +/* request packet. If the packet is no content or the packet is */ +/* invalid, a zero is returned. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* length Length of content */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_content_length_get(NX_PACKET *packet_ptr) +{ + +UINT length; +CHAR *buffer_ptr; + + + /* Default the content length to zero. */ + length = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Content-length: " token first. */ + while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Content-length token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && + ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && + ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && + ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && + (*(buffer_ptr+7) == '-') && + ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && + ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && + ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && + ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && + ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && + ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && + (*(buffer_ptr+14) == ':') && + (*(buffer_ptr+15) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 16; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now convert the length into a numeric value. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + { + + /* Update the content length. */ + length = length * 10; + length = length + (((UINT) (*buffer_ptr)) - 0x30); + + /* Move the buffer pointer forward. */ + buffer_ptr++; + } + + /* Determine if the content length was picked up properly. */ + if ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13)) + { + + /* Error, set the length to zero. */ + length = 0; + } + + /* Return the length to the caller. */ + return(length); +} +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_content_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP extended get content */ +/* service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_content_get_extended Actual extended get content */ +/* get service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server content get function. */ + status = _nx_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_content_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the user's specified portion of the HTTP */ +/* content. Content is typically included in POST and PUT requests */ +/* from the client. This routine is designed to be called from the */ +/* application's request notify callback. */ +/* */ +/* This API is identical to _nx_http_server_content_get service except */ +/* for detecting a valid Content Length of length zero. In this case, */ +/* it sets the actual_size pointer to that value and returns a */ +/* successful outcome (empty POST requests are allowed in HTTP */ +/* 1.0/1.1). If this is called from a request notify callback the */ +/* caller is responsible for responding to the HTTP Client. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive another packet */ +/* _nx_http_server_content_length_get_extended */ +/* Get content length with error */ +/* status returned separately */ +/* content length value. */ +/* _nx_http_server_calculate_content_offset */ +/* Pickup content offset */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +ULONG content_length; +ULONG get_offset; +ULONG offset; +UINT status; +UINT remaining_bytes; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; + + + /* Default the actual size to zero. */ + *actual_size = 0; + + /* Determine if there is content in this HTTP request. */ + status = (ULONG) _nx_http_server_content_length_get_extended(packet_ptr, &content_length); + + if (status != NX_SUCCESS) + { + return status; + } + + /* Check for a empty POST request. */ + if (content_length == 0) + { + + /* Return the zero message body (content-length) size. */ + *actual_size = content_length; + + /* No more data in this buffer. */ + return(NX_SUCCESS); + } + + /* Make sure the content length is at least greater than the byte offset supplied. */ + if (content_length <= byte_offset) + { + + /* No more data in this buffer. */ + return(NX_HTTP_DATA_END); + } + + /* Determine if the destination size is greater than the content length. */ + if (destination_size > content_length) + { + + /* Yes, make the destination size equal to the content length. */ + destination_size = content_length; + } + + /* Calculate the offset to the requested content area. */ + get_offset = ((ULONG) _nx_http_server_calculate_content_offset(packet_ptr)) + byte_offset; + + /* Determine if we need to read one or more additional packets. */ + while (get_offset >= packet_ptr -> nx_packet_length) + { + +#ifdef NX_DISABLE_PACKET_CHAIN + NX_PARAMETER_NOT_USED(server_ptr); + + return NX_HTTP_ERROR; +#else + /* Read another packet because the offset reaches past the current packet + length. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* Otherwise, we have a new packet to append to the head packet. */ + + /* Determine if the current packet is already chained. */ + if (packet_ptr -> nx_packet_next) + { + + /* Yes, link the current last packet to the new packet. */ + (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; + } + else + { + + /* Otherwise, this is our first chained packet. Link to the head. */ + packet_ptr -> nx_packet_next = new_packet_ptr; + } + + /* Is the new packet chained? */ + if (new_packet_ptr -> nx_packet_next) + { + + /* Yes, there is a last packet pointer. Point to this from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; + } + else + { + + /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr; + } + + /* Update the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Default the buffer pointer to NULL. */ + buffer_ptr = NX_NULL; + + /* Now find the packet that contains the offset. */ + offset = 0; + new_packet_ptr = packet_ptr; + do + { + + /* Determine if the get request falls into this packet. */ + if (get_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) + { + + /* Yes, the get offset is in this packet. */ + + /* Setup the starting byte pointer. */ + buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (get_offset - offset); + break; + } + + /* Otherwise update the offset. */ + offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + new_packet_ptr = NX_NULL; +#else + /* Move to next packet in the chain. */ + new_packet_ptr = new_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while (new_packet_ptr); + + /* Determine if an error occurred in the search. */ + if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) + return(NX_HTTP_ERROR); + + /* Now determine if the maximum buffer size has to be adjusted. */ + if (destination_size > (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr)) + { + + /* Adjust the destination size downward. */ + destination_size = (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr); + } + + /* Initialize the remaining bytes. */ + remaining_bytes = destination_size; + + /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ + while (remaining_bytes--) + { + + /* Copy a byte to the destination. */ + *destination_ptr++ = *buffer_ptr++; + } + + /* Successful completion. */ + *actual_size = destination_size; + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_content_length_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the extended HTTP content length */ +/* service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP paclet */ +/* content_length Pointer for returning content */ +/* length value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_content_length_get_extended */ +/* Actual extended get content */ +/* length service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *content_length) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (content_length == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server content length get function. */ + status = _nx_http_server_content_length_get_extended(packet_ptr, content_length); + + /* Return completion status. */ + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_content_length_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function find a valid content length field and returns a */ +/* successful completion status (NX_SUCCESS) if so. Otherwise it */ +/* it returns an error status. A valid content length value is */ +/* zero or more and matches the size of the message body. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* content_length Pointer to a valid Content */ +/* Length value */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Content length extracted */ +/* status Invalid content length */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Threads */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length) +{ + +CHAR *buffer_ptr; + + + /* Default the content length to no data. */ + *length = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Content-length: " token first. */ + while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Content-length token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && + ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && + ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && + ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && + (*(buffer_ptr+7) == '-') && + ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && + ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && + ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && + ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && + ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && + ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && + (*(buffer_ptr+14) == ':') && + (*(buffer_ptr+15) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 16; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now convert the length into a numeric value. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + { + + /* Update the content length. */ + *length = *length * 10; + *length = *length + (((UINT) (*buffer_ptr)) - 0x30); + + /* Move the buffer pointer forward. */ + buffer_ptr++; + } + + /* Determine if the content length was picked up properly. */ + if ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13)) + { + + /* Error, set the length to zero. */ + return NX_HTTP_INCOMPLETE_PUT_ERROR; + } + + /* Return successful completion status to the caller. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* http_server_name Name of HTTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* authentication_check Pointer to application's */ +/* authentication checking */ +/* request_notify Pointer to application's */ +/* request notify service */ +/* http_server_size Size of HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), + UINT http_server_size) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id == NXD_HTTP_SERVER_ID) || + (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL) || + (http_server_size != sizeof(NX_HTTP_SERVER))) + return(NX_PTR_ERROR); + + /* Pickup a packet from the supplied packet pool. */ + packet_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ + if (((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) - NX_PHYSICAL_TRAILER) + < NX_HTTP_SERVER_MIN_PACKET_SIZE) + return(NX_HTTP_POOL_ERROR); + + /* Call actual server create function. */ + status = _nx_http_server_create(http_server_ptr, http_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, + authentication_check, request_notify); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a HTTP server on the specified IP. In doing */ +/* so this function creates an TCP socket for subsequent HTTP */ +/* transfers and a thread for the HTTP server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* http_server_name Name of HTTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* authentication_check Pointer to application's */ +/* authentication checking */ +/* request_notify Pointer to application's */ +/* request notify service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create HTTP server socket */ +/* nx_tcp_socket_delete Delete the HTTP server socket */ +/* tx_thread_create Create the HTTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)) +{ + +UINT status; + + + /* Clear the HTTP server structure. */ + memset((void *) http_server_ptr, 0, sizeof(NX_HTTP_SERVER)); + + /* Create the Server's TCP socket. */ + status = nx_tcp_socket_create(ip_ptr, &(http_server_ptr -> nx_http_server_socket), http_server_name, + NX_HTTP_TYPE_OF_SERVICE, NX_HTTP_FRAGMENT_OPTION, NX_HTTP_TIME_TO_LIVE, + NX_HTTP_SERVER_WINDOW_SIZE, NX_NULL, NX_NULL); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, return error code. */ + return(status); + } + + /* Now create the HTTP Server thread. */ + status = tx_thread_create(&(http_server_ptr -> nx_http_server_thread), "HTTP Server Thread", _nx_http_server_thread_entry, + (ULONG) http_server_ptr, stack_ptr, stack_size, NX_HTTP_SERVER_PRIORITY, NX_HTTP_SERVER_PRIORITY, + NX_HTTP_SERVER_THREAD_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred creating the thread. */ + if (status != NX_SUCCESS) + { + + /* Delete the TCP socket. */ + nx_tcp_socket_delete(&(http_server_ptr -> nx_http_server_socket)); + + /* Yes, return error code. */ + return(status); + } + + /* Save the Server name. */ + http_server_ptr -> nx_http_server_name = http_server_name; + + /* Save the IP pointer address. */ + http_server_ptr -> nx_http_server_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + http_server_ptr -> nx_http_server_packet_pool_ptr = pool_ptr; + + /* Save the media pointer address. */ + http_server_ptr -> nx_http_server_media_ptr = media_ptr; + + /* Save the user-supplied routines, if specified. */ + http_server_ptr -> nx_http_server_authentication_check = authentication_check; + http_server_ptr -> nx_http_server_request_notify = request_notify; + + + /* Remember this server structure in the TCP socket. */ + http_server_ptr -> nx_http_server_socket.nx_tcp_socket_reserved_ptr = (void *) http_server_ptr; + + /* Set the server ID to indicate the HTTP server thread is ready. */ + http_server_ptr -> nx_http_server_id = NXD_HTTP_SERVER_ID; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_delete Actual server delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_delete(NX_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_http_server_delete(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_delete Delete the HTTP server socket */ +/* nx_tcp_socket_disconnect Disconnect HTTP server socket */ +/* nx_tcp_socket_unaccept Unaccept HTTP server connect */ +/* nx_tcp_socket_unlisten Unlisten on the HTTP port */ +/* tx_thread_delete Delete the HTTP server thread */ +/* tx_thread_suspend Suspend the HTTP server thread*/ +/* tx_thread_terminate Terminate the HTTP server */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr) +{ + + + /* Clear the server ID to indicate the HTTP server is no longer ready. */ + http_server_ptr -> nx_http_server_id = 0; + + /* Disconnect the TCP socket. */ + nx_tcp_socket_disconnect(&(http_server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); + + /* Unaccept any remaining connection on the TCP socket. */ + nx_tcp_server_socket_unaccept(&(http_server_ptr -> nx_http_server_socket)); + + /* Delete the TCP socket. */ + nx_tcp_socket_delete(&(http_server_ptr -> nx_http_server_socket)); + + /* Unlisten on the HTTP server port. */ + nx_tcp_server_socket_unlisten(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT); + + /* Suspend the HTTP server thread. */ + tx_thread_suspend(&(http_server_ptr -> nx_http_server_thread)); + + /* Terminate server thread. */ + tx_thread_terminate(&(http_server_ptr -> nx_http_server_thread)); + + /* Delete server thread. */ + tx_thread_delete(&(http_server_ptr -> nx_http_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_param_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP parameter get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* param_number Parameter number (start at 0) */ +/* param_ptr Pointer to destination */ +/* max_param_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_param_get Actual server parameter get */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (param_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server parameter get function. */ + status = _nx_http_server_param_get(packet_ptr, param_number, param_ptr, max_param_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_param_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the requested parameter specified in the URL */ +/* requested by the client. If the specified parameter is not present, */ +/* a not found error is returned to the caller. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* param_number Parameter number (start at 0) */ +/* param_ptr Pointer to destination */ +/* max_param_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size) +{ + +UINT i; +UINT current_param; +CHAR *buffer_ptr; + + + /* Set the destination string to NULL. */ + param_ptr[0] = (CHAR) NX_NULL; + + /* Set current parameter to 0. */ + current_param = 0; + + /* Setup a pointer to the HTTP buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Position to the start of the URL. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Move the buffer pointer. */ + buffer_ptr++; + } + + /* Not find URL. */ + if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) + { + return(NX_HTTP_NOT_FOUND); + } + + /* Loop through the buffer to search for the specified parameter. */ + do + { + + /* Determine if the character is a semicolon, indicating a parameter + is present. */ + if (*buffer_ptr == ';') + { + + /* Yes, a parameter is present. */ + + /* Move the buffer pointer forward. */ + buffer_ptr++; + + /* Is this the parameter requested? */ + if (current_param == param_number) + { + + + /* Yes, we have found the parameter. */ + for (i = 0; i < max_param_size; i++) + { + + /* Check if reach the end of the packet data. */ + if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + return(NX_HTTP_NOT_FOUND); + } + + /* Check for end of parameter. */ + if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || + (*buffer_ptr == '&') || (*buffer_ptr == ' ') || + (*buffer_ptr == (CHAR) 13)) + { + + /* Yes, we are finished and need to get out of the loop. */ + break; + } + + /* Otherwise, store the character in the destination. */ + param_ptr[i] = *buffer_ptr++; + } + + /* NULL terminate the parameter. */ + if (i < max_param_size) + param_ptr[i] = (CHAR) NX_NULL; + + /* Return to caller. */ + if (param_ptr[i] == (CHAR) NX_NULL) + return(NX_SUCCESS); + else + return(NX_HTTP_IMPROPERLY_TERMINATED_PARAM); + } + else + { + + /* Increment the current parameter. */ + current_param++; + } + } + else + { + + /* Check for any other character that signals the end of the param list. */ + if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == '&')) + break; + + /* Update the buffer pointer. */ + buffer_ptr++; + } + + } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); + + /* Return a not found error. */ + return(NX_HTTP_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_query_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP query get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* query_number Query number (start at 0) */ +/* query_ptr Pointer to destination */ +/* max_query_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_query_get Actual server query get */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (query_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server query get function. */ + status = _nx_http_server_query_get(packet_ptr, query_number, query_ptr, max_query_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_query_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the requested query specified in the URL */ +/* requested by the client. If the specified query is not present, */ +/* a not found error is returned to the caller. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* query_number Query number (start at 0) */ +/* query_ptr Pointer to destination */ +/* max_query_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size) +{ + +UINT i; +UINT current_query; +CHAR *buffer_ptr; + + + /* Set the destination string to NULL. */ + query_ptr[0] = (CHAR) NX_NULL; + + /* Set current query number to 0. */ + current_query = 0; + + /* Setup a pointer to the HTTP buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Position to the start of the URL. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Move the buffer pointer. */ + buffer_ptr++; + } + + /* Not find URL. */ + if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) + { + return(NX_HTTP_NOT_FOUND); + } + + /* Loop through the buffer to search for the specified query instance. */ + do + { + + /* Determine if the character is a '?' or a '&', indicating a query + is present. */ + if (((*buffer_ptr == '?') && (current_query == 0)) || + ((*buffer_ptr == '&') && (current_query != 0))) + { + + /* Yes, a query is present. */ + + /* Move the buffer pointer forward. */ + buffer_ptr++; + + /* Is this the query requested? */ + if (current_query == query_number) + { + + + /* Yes, we have found the query. */ + for (i = 0; i < max_query_size; i++) + { + + /* Check if reach the end of the packet data. */ + if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + return(NX_HTTP_NOT_FOUND); + } + + /* Check for end of query. */ + if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || + (*buffer_ptr == '&') || (*buffer_ptr == ' ') || + (*buffer_ptr == (CHAR) 13)) + { + + /* Yes, we are finished and need to get out of the loop. */ + break; + } + + /* Otherwise, store the character in the destination. */ + query_ptr[i] = *buffer_ptr++; + } + + /* NULL terminate the query. */ + query_ptr[i] = (CHAR) NX_NULL; + + /* Return to caller. */ + if (i) + return(NX_SUCCESS); + else + return(NX_HTTP_NO_QUERY_PARSED); + } + else + { + + /* Increment the current query. */ + current_query++; + } + } + else + { + + /* Check for any other character that signals the end of the query list. */ + if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == ';')) + break; + + /* Update the buffer pointer. */ + buffer_ptr++; + } + + } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); + + /* Return a not found error. */ + return(NX_HTTP_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_start Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_start(NX_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nx_http_server_start(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts a previously created HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_listen Start listening on HTTP port */ +/* tx_thread_resume Resume the HTTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_start(NX_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + + /* Start listening on the HTTP server port. */ + status = nx_tcp_server_socket_listen(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, + &(http_server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_MAX_PENDING, + _nx_http_server_connection_present); + + /* Determine if the listen was unsuccessful. */ + if (status != NX_SUCCESS) + { + + /* Just return an HTTP error. */ + return(status); + } + + /* Start the HTTP server thread. */ + tx_thread_resume(&(http_server_ptr -> nx_http_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_stop Actual server stop call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_stop(NX_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server stop function. */ + status = _nx_http_server_stop(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops a previously started HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend the HTTP server thread*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr) +{ + + /* Disconnect the TCP socket. */ + nx_tcp_socket_disconnect(&(http_server_ptr -> nx_http_server_socket), NX_NO_WAIT); + + /* Unaccept any remaining connection on the TCP socket. */ + nx_tcp_server_socket_unaccept(&(http_server_ptr -> nx_http_server_socket)); + + /* Unlisten on the HTTP server port. */ + nx_tcp_server_socket_unlisten(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_data_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks errors for sending data. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* data_ptr Pointer to data to send */ +/* data_length Length of data to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_data_send Actual data send call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual data send function. */ + status = _nx_http_server_callback_data_send(server_ptr, data_ptr, data_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_data_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends data to the client from the application */ +/* callback function. This is typically done to satisfy a GET or */ +/* POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* data_ptr Pointer to data to send */ +/* data_length Length of data to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a NetX packet */ +/* nx_packet_data_append Append data to packet */ +/* nx_tcp_socket_send Send TCP data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) +{ + +NX_PACKET *new_packet_ptr; +UINT status; + + + /* Allocate a new packet for data. */ + status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &new_packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Error, return to caller. */ + return(NX_HTTP_ERROR); + } + + /* Now append the data to the packet. */ + status = nx_packet_data_append(new_packet_ptr, data_ptr, data_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Release the initial packet. */ + nx_packet_release(new_packet_ptr); + + /* Error, return to caller. */ + return(status); + } + + /* Send the data back to the client. */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Determine if this is successful. */ + if (status != NX_SUCCESS) + { + + /* Map the status to the generic HTTP error. */ + status = status; + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks errors for sending HTTP response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* header Pointer to HTTP header string */ +/* information Pointer to HTTP info string */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_response_send */ +/* Actual HTTP response send call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *header, CHAR *information, CHAR *additional_info) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (header == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual data send function. */ + status = _nx_http_server_callback_response_send(server_ptr, header, information, additional_info); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the completion response to the client from the */ +/* application callback function. This is typically done to satisfy a */ +/* GET or POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* header Pointer to HTTP header string */ +/* information Pointer to HTTP info string */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_response_send Send HTTP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *header, CHAR *information, CHAR *additional_info) +{ + +UINT header_length = 0; +UINT information_length = 0; +UINT additional_info_length = 0; +UINT status; + + /* Check length of header, information and additional information. */ + if (_nx_utility_string_length_check(header, &header_length, NX_MAX_STRING_LENGTH) || + (information && _nx_utility_string_length_check(information, &information_length, NX_MAX_STRING_LENGTH)) || + (additional_info && _nx_utility_string_length_check(additional_info, &additional_info_length, NX_MAX_STRING_LENGTH))) + { + return(NX_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + status = _nx_http_server_response_send(server_ptr, header, header_length, information, information_length, additional_info, additional_info_length); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_response_send_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks errors for sending HTTP response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* header Pointer to HTTP header string */ +/* header_length Length of HTTP header string */ +/* information Pointer to HTTP info string */ +/* information_length Length of HTTP info string */ +/* additional_info Pointer to additional HTTP */ +/* information */ +/* additional_info_length Length of additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_response_send_extended */ +/* Actual HTTP response send call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *header, UINT header_length, CHAR *information, + UINT information_length, CHAR *additional_info, UINT additional_info_length) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (header == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual data send function. */ + status = _nx_http_server_callback_response_send_extended(server_ptr, header, header_length, information, + information_length, additional_info, additional_info_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_response_send_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the completion response to the client from the */ +/* application callback function. This is typically done to satisfy a */ +/* GET or POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* Note: The strings of header, information and additional info must */ +/* be NULL-terminated and length of this string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* header Pointer to HTTP header string */ +/* header_length Length of HTTP header string */ +/* information Pointer to HTTP info string */ +/* information_length Length of HTTP info string */ +/* additional_info Pointer to additional HTTP */ +/* information */ +/* additional_info_length Length of additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_response_send Send HTTP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *header, UINT header_length, CHAR *information, + UINT information_length, CHAR *additional_info, UINT additional_info_length) +{ +UINT status; +UINT temp_header_length = 0; +UINT temp_information_length = 0; +UINT temp_additional_info_length = 0; + + /* Check length of header, information and additional information. */ + if (_nx_utility_string_length_check(header, &temp_header_length, NX_MAX_STRING_LENGTH) || + (information && _nx_utility_string_length_check(information, &temp_information_length, NX_MAX_STRING_LENGTH)) || + (additional_info && _nx_utility_string_length_check(additional_info, &temp_additional_info_length, NX_MAX_STRING_LENGTH))) + { + return(NX_HTTP_ERROR); + } + + /* Validate string length. */ + if ((temp_header_length != header_length) || + (information && (temp_information_length != information_length)) || + (additional_info && (temp_additional_info_length != additional_info_length))) + { + return(NX_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + status = _nx_http_server_response_send(server_ptr, header, header_length, information, information_length, additional_info, additional_info_length); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_connection_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the callback function executed whenever a client */ +/* connection appears on the HTTP Server port. It is responsible for */ +/* waking up the HTTP Server thread. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to HTTP Server socket */ +/* port HTTP Server port */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_resume Server thread resume */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port) +{ + +NX_HTTP_SERVER *server_ptr; + + NX_PARAMETER_NOT_USED(port); + + /* Pickup the server pointer. */ + server_ptr = (NX_HTTP_SERVER *) socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the connection pending flag. */ + server_ptr -> nx_http_connection_pending = NX_TRUE; + + /* Resume the HTTP Server thread. */ + tx_thread_resume(&(server_ptr -> nx_http_server_thread)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry of the HTTP server. All basic */ +/* processing is initiated by this function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_address Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_delete_process Process client DELETE request */ +/* _nx_http_server_get_client_request Get complete HTTP request */ +/* _nx_http_server_get_process Process client GET request */ +/* _nx_http_server_put_process Process client PUT request */ +/* _nx_http_server_response_send Send HTTP Server response */ +/* nx_packet_release Release request packet */ +/* nx_tcp_server_socket_accept Accept HTTP client connect */ +/* nx_tcp_socket_disconnect Disconnect from HTTP client */ +/* nx_tcp_server_socket_relisten Relisten for another HTTP */ +/* client connection */ +/* nx_tcp_server_socket_unaccept Unaccept HTTP client connect */ +/* tx_thread_preemption_change Disable/restore preemption */ +/* tx_thread_suspend Self suspend HTTP thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_thread_entry(ULONG http_server) +{ + +NX_HTTP_SERVER *server_ptr; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT original_threshold; +UINT status; +UINT loop_endlessly = NX_TRUE; + + + /* Set the HTTP server pointer. */ + server_ptr = (NX_HTTP_SERVER *) http_server; + + /* Loop to process HTTP Server requests. */ + while(loop_endlessly) + { + + /* Temporarily disable preemption. */ + tx_thread_preemption_change(&(server_ptr -> nx_http_server_thread), 0, &original_threshold); + + /* Is the connection pending flag not set? */ + if (server_ptr -> nx_http_connection_pending == NX_FALSE) + { + + /* If not, suspend the server thread. */ + tx_thread_suspend(&(server_ptr -> nx_http_server_thread)); + } + + /* Clear the connection pending flag. */ + server_ptr -> nx_http_connection_pending = NX_FALSE; + + /* Restore preemption. */ + tx_thread_preemption_change(&(server_ptr -> nx_http_server_thread), original_threshold, &original_threshold); + + /* Wait for connection on HTTP Server port. */ + status = nx_tcp_server_socket_accept(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_ACCEPT); + + /* Determine if we have an HTTP connection error. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of failed connections. */ + server_ptr -> nx_http_server_connection_failures++; + + /* Unaccept the connection. */ + nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); + + /* Relisten on the HTTP Server port. */ + nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, + &(server_ptr -> nx_http_server_socket)); + /* Restart the loop. */ + continue; + } + + /* Increment the number of successful connections. */ + server_ptr -> nx_http_server_connection_successes++; + + /* Get the complete HTTP client request. */ + status = _nx_http_server_get_client_request(server_ptr, &packet_ptr); + + /* Check if the HTTP request is valid. */ + if (status == NX_SUCCESS) + { + if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 7) + { + nx_packet_release(packet_ptr); + status = NX_HTTP_ERROR; + } + } + + /* Determine if it was successful. */ + if (status != NX_SUCCESS) + { + + if(status != NX_NO_PACKET) + { + + /* Increment the number of invalid HTTP requests. */ + server_ptr -> nx_http_server_invalid_http_headers++; + } + + /* Disconnect from the current connection. */ + nx_tcp_socket_disconnect(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); + + /* Unaccept the connection. */ + nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); + + /* Relisten on the HTTP Server port. */ + nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, + &(server_ptr -> nx_http_server_socket)); + /* Restart the loop. */ + continue; + } + + /* Otherwise, we have received an HTTP client request successfully. */ + + /* Setup a pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Determine what type of request is present. */ + + /* Check for a GET request. */ + if ((buffer_ptr[0] == 'G') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) + { + + /* We have a HTTP GET request to get a resource from this HTTP Server. */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_GET_REQUEST; + + /* Increment the number of GET requests. */ + server_ptr -> nx_http_server_get_requests++; + + /* Process the GET request. */ + _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_GET_REQUEST, packet_ptr); + } + + /* Check for a PUT request. */ + else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'U') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) + { + + /* We have a HTTP PUT request to store a resource on this HTTP Server. */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_PUT_REQUEST; + + /* Increment the number of PUT requests. */ + server_ptr -> nx_http_server_put_requests++; + + /* Process the PUT request. */ + _nx_http_server_put_process(server_ptr, packet_ptr); + } + + /* Check for a DELETE request. */ + else if ((buffer_ptr[0] == 'D') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'L') && (buffer_ptr[3] == 'E') && + (buffer_ptr[4] == 'T') && (buffer_ptr[5] == 'E') && (buffer_ptr[6] == ' ')) + { + + /* We have a HTTP DELETE request to delete a resource from this HTTP Server. */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_DELETE_REQUEST; + + /* Increment the number of DELETE requests. */ + server_ptr -> nx_http_server_delete_requests++; + + /* Process the Delete request. */ + _nx_http_server_delete_process(server_ptr, packet_ptr); + } + + /* Check for a POST request. */ + else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'O') && (buffer_ptr[2] == 'S') && + (buffer_ptr[3] == 'T') && (buffer_ptr[4] == ' ')) + { + + /* We have a HTTP POST request to send data to this HTTP Server for processing. Note that the POST + request is nearly identical to the GET request, except the parameter/query data is found in the + content rather than as part of the URL (resource). */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_POST_REQUEST; + + /* Increment the number of POST requests. */ + server_ptr -> nx_http_server_post_requests++; + +#ifdef NX_HTTP_MULTIPART_ENABLE + + /* Reset last received multipart packet. */ + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = NX_NULL; +#endif /* NX_HTTP_MULTIPART_ENABLE */ + + /* Process the POST request. */ + _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_POST_REQUEST, packet_ptr); + +#ifdef NX_HTTP_MULTIPART_ENABLE + /* Restore the packet to release. */ + if (server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet) + packet_ptr = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet; +#endif /* NX_HTTP_MULTIPART_ENABLE */ + } + + /* Check for a HEAD request. */ + else if ((buffer_ptr[0] == 'H') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'A') && + (buffer_ptr[3] == 'D') && (buffer_ptr[4] == ' ')) + { + + /* We have a HTTP HEAD request to get a resource header from this HTTP Server. Note that the HEAD + request is nearly identical to the GET request, except the requested content is not returned to + the client. */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_HEAD_REQUEST; + + /* Increment the number of HEAD requests. */ + server_ptr -> nx_http_server_head_requests++; + + /* Process the HEAD request. */ + _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_HEAD_REQUEST, packet_ptr); + } + + /* Unhandled request. */ + else + { + + /* We have an unhandled HTTP request. */ + server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_UNKNOWN_REQUEST; + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_IMPLEMENTED, sizeof(NX_HTTP_STATUS_NOT_IMPLEMENTED) - 1, + "NetX HTTP Request Not Implemented", sizeof("NetX HTTP Request Not Implemented") - 1, NX_NULL, 0); + + /* Increment the number of unhandled requests. */ + server_ptr -> nx_http_server_unknown_requests++; + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect from the current connection. */ + nx_tcp_socket_disconnect(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); + + /* Unaccept the connection. */ + nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); + + /* Relisten on the HTTP Server port. */ + nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, + &(server_ptr -> nx_http_server_socket)); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_get_client_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds the complete HTTP client request in a single */ +/* NetX packet. Doing this makes the other parsing and searching */ +/* routines simple. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Destination for request */ +/* packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy packet */ +/* nx_packet_data_append Move data into packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive an HTTP request packet*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_thread_entry HTTP Server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_get_client_request(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ + +NX_PACKET *head_packet_ptr; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; +UINT status; +NX_PACKET *work_ptr; +UINT crlf_found = 0; +NX_PACKET *tmp_ptr; + + + /* Default the return packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Wait for a request on the HTTP TCP well know port 80. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &head_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* At this point we have a connection setup with an HTTP server! */ + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Return an error condition. */ + return(status); + } + + /* Setup pointer to start of buffer. */ + buffer_ptr = (CHAR *) head_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if the packet is an HTTP request. */ + if ((buffer_ptr[0] != 'G') && (buffer_ptr[0] != 'g') && (buffer_ptr[0] != 'P') && (buffer_ptr[0] != 'p') && + (buffer_ptr[0] != 'D') && (buffer_ptr[0] != 'd') && (buffer_ptr[0] != 'H') && (buffer_ptr[0] != 'h') && + (buffer_ptr[0] != 'T') && (buffer_ptr[0] != 't')) + { + + /* Invalid first packet for HTTP request. */ + + /* Release the packet. */ + nx_packet_release(head_packet_ptr); + + /* Return an error. */ + return(NX_HTTP_ERROR); + } + + /* Determine if this packet is large enough. */ + if (((head_packet_ptr -> nx_packet_data_end - head_packet_ptr -> nx_packet_data_start) - + NX_PHYSICAL_TRAILER)< NX_HTTP_SERVER_MIN_PACKET_SIZE) + { + + /* Copy the packet into a packet allocated from the Server's packet pool (which must have packets + with a payload size >= NX_HTTP_SERVER_MIN_PACKET_SIZE. */ + status = nx_packet_copy(head_packet_ptr, &new_packet_ptr, server_ptr -> nx_http_server_packet_pool_ptr, NX_HTTP_SERVER_TIMEOUT); + + /* Determine if the packet copy was successful. */ + if (status != NX_SUCCESS) + { + + /* Error in packet copy. Release packet and return an error. */ + nx_packet_release(head_packet_ptr); + return(status); + } + + /* Copy is successful, release the original pointer and move the new pointer to the head pointer. */ + nx_packet_release(head_packet_ptr); + head_packet_ptr = new_packet_ptr; + } + + crlf_found = 0; + work_ptr = head_packet_ptr; + + /* Build a pointer to the buffer area. */ + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + + do + { + + /* See if there is a blank line present in the buffer. */ + /* Search the buffer for a cr/lf pair. */ + while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) + { + if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) + { + + /* Found CR. */ + crlf_found++; + } + else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) + { + + /* Found LF. */ + crlf_found++; + } + else + { + + /* Reset the CRLF marker. */ + crlf_found = 0; + } + + if (crlf_found == 4) + { + + /* Yes, we have found the end of the HTTP request header. */ + + /* Set the return packet pointer. */ + *packet_ptr = head_packet_ptr; + + /* Return a successful completion. */ + return(NX_SUCCESS); + } + + /* Move the buffer pointer up. */ + buffer_ptr++; + } + + /* Determine if the packet has already overflowed into another packet. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + + if (work_ptr -> nx_packet_next != NX_NULL) + { + /* Get the next packet in the chain. */ + work_ptr = work_ptr -> nx_packet_next; + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + } + else + +#endif + { + /* Receive another packet from the HTTP server port. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Release the current head packet. */ + nx_packet_release(head_packet_ptr); + + /* Return an error condition. */ + return(status); + } + + /* Successfully received another packet. Its contents now need to be placed in the head packet. */ + tmp_ptr = new_packet_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN + while (tmp_ptr) + { +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Copy the contents of the current packet into the head packet. */ + status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, + (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), + server_ptr -> nx_http_server_packet_pool_ptr, NX_HTTP_SERVER_TIMEOUT); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, an error is present. */ + + /* Release both packets. */ + nx_packet_release(head_packet_ptr); + nx_packet_release(new_packet_ptr); + + /* Return an error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + tmp_ptr = tmp_ptr -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Release the new packet. */ + nx_packet_release(new_packet_ptr); + } + + } while (status == NX_SUCCESS); + + /* Release the packet. */ + nx_packet_release(head_packet_ptr); + + return NX_HTTP_ERROR; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_get_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the GET, POST, and HEAD HTTP client */ +/* requests. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* request_type Type of request (GET, POST, */ +/* or HEAD) */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_basic_authenticate Process basic authentication */ +/* _nx_http_server_digest_authenticate Process digest authentication */ +/* _nx_http_server_calculate_content_offset Retrieve content offset */ +/* _nx_http_server_content_length_get Retrieve content length */ +/* _nx_http_server_response_send Send response back to client */ +/* _nx_http_server_retrieve_resource Retrieve resource from request*/ +/* _nx_http_server_type_get_extended Derive file type */ +/* fx_directory_information_get Get length of resource file */ +/* fx_file_close Close resource file */ +/* fx_file_open Open resource file */ +/* fx_file_read Read data from resource file */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_thread_entry HTTP Server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_get_process(NX_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr) +{ + +ULONG length = 0; +UINT status; +NX_PACKET *new_packet_ptr; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +ULONG temp; +CHAR temp_string[30]; +UINT auth_request_present = NX_FALSE; +UINT resource_length; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if a POST is present. */ + if (request_type == NX_HTTP_SERVER_POST_REQUEST) + { + + /* It is. Check for a valid content-length field. */ + status = _nx_http_server_content_length_get_extended(packet_ptr, &length); + + /* Check for errors. */ + if ( status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Length", sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Check for an invalid content offset . */ + if (_nx_http_server_calculate_content_offset(packet_ptr) == 0) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Offset", sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + +#ifdef NX_HTTP_MULTIPART_ENABLE + /* Cleanup the multipart field. */ + memset(&server_ptr -> nx_http_server_multipart, 0, sizeof(NX_HTTP_SERVER_MULTIPART)); +#endif /* NX_HTTP_MULTIPART_ENABLE */ + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_http_server_authentication_check || + server_ptr -> nx_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if (status == NX_HTTP_BASIC_AUTHENTICATE || + status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); + } +#ifdef NX_HTTP_DIGEST_ENABLE + else if (status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); + } +#endif + + /* Determine if the authentication failed. */ + if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes it did. Inform the HTTP server application about the failed authentication. */ + if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) + { + + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, request_type); + } + } + + return; + } + } + + /* Check whether a full response is necessary. */ + if((server_ptr -> nx_http_server_cache_info_get) && + (server_ptr -> nx_http_server_request_type == NX_HTTP_SERVER_GET_REQUEST)) + { + + /* Searching for "If-Modified-Since" header. */ + if(_nx_http_server_field_value_get(packet_ptr, (UCHAR *)"if-modified-since", 17, (UCHAR *)temp_string, sizeof(temp_string)) == NX_SUCCESS) + { + UINT max_age; + NX_HTTP_SERVER_DATE date; + CHAR date_string[30]; + + /* Get last modified date of this resource. */ + if(server_ptr -> nx_http_server_cache_info_get(server_ptr -> nx_http_server_request_resource, &max_age, &date) == NX_TRUE) + { + + /* Convert date to string, return length is always 29. */ + temp = _nx_http_server_date_to_string(&date, date_string); + date_string[temp] = 0; + + /* Check the last modified date with if-modified-since. */ + if(memcmp(temp_string, date_string, temp + 1) == 0) + { + + /* Send not modified. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_HTTP_STATUS_NOT_MODIFIED) - 1, NX_NULL, 0, NX_NULL, 0); + + /* Return to caller. */ + return; + } + } + } + } + + /* Setup the server socket with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(&(server_ptr -> nx_http_server_socket), + NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_HTTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_HTTP_SERVER_RETRY_MAX, + NX_HTTP_SERVER_RETRY_SHIFT); + + /* At this point, either there isn't any required authentication for this resource or the authentication is + complete. */ + + /* If the HTTP server receives an empty POST request (no message body, content length = 0, it is the + responsibility of the request notify callback to send a response (if any) to the HTTP Client. + The HTTP server will process the request no further. */ + + /* Determine if a user supplied get function has been specified. */ + if (server_ptr -> nx_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the get request. */ + status = (server_ptr -> nx_http_server_request_notify)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, packet_ptr); + +#ifdef NX_HTTP_MULTIPART_ENABLE + /* Release the packet that is not processed by callback function. */ + if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_next_packet) + nx_packet_release(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_next_packet); +#endif /* NX_HTTP_MULTIPART_ENABLE */ + + /* Determine if the user supplied routine is requesting the get should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_HTTP_CALLBACK_COMPLETED) + { + + /* User callback routine already sent success response back to HTTP Client. */ + return; + } + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Yes, error was detected. Abort the remainder of the get processing. */ + return; + } + } + + /* Was there a message body in the request? */ + if ((request_type == NX_HTTP_SERVER_POST_REQUEST) && (length == 0)) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + /* Get the length of request resource. */ + if (_nx_utility_string_length_check(server_ptr -> nx_http_server_request_resource, &resource_length, + sizeof(server_ptr -> nx_http_server_request_resource) - 1)) + { + return; + } + + /* Open the specified file for reading. */ + status = fx_file_open(server_ptr -> nx_http_server_media_ptr, &(server_ptr -> nx_http_server_file), server_ptr -> nx_http_server_request_resource, FX_OPEN_FOR_READ); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_FOUND, sizeof(NX_HTTP_STATUS_NOT_FOUND) - 1, + "NetX HTTP Server unable to find file: ", sizeof("NetX HTTP Server unable to find file: ") - 1, server_ptr -> nx_http_server_request_resource, resource_length); + + /* Error, return to caller. */ + return; + } + + /* Calculate the size of the file. */ + length = 0; + fx_directory_information_get(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource, FX_NULL, + &length, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL); + + /* Derive the file type. */ + temp = (ULONG) _nx_http_server_type_get_extended(server_ptr, server_ptr -> nx_http_server_request_resource, resource_length, temp_string, sizeof(temp_string)); + temp_string[temp] = 0; + + /* Now build a response header. */ + status = _nx_http_server_generate_response_header(server_ptr, &new_packet_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, length, temp_string, temp, NX_NULL, 0); + if(status) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Close the file. */ + fx_file_close(&(server_ptr -> nx_http_server_file)); + + /* Error, return to caller. */ + return; + } + + /* Check to see if only a response is required. */ + if ((!length) || (request_type == NX_HTTP_SERVER_HEAD_REQUEST)) + { + + /* Yes, only a response is required... send it! */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Determine if this is successful. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Force zero length. */ + length = 0; + } + } + + /* Get length of packet */ + temp = new_packet_ptr -> nx_packet_length; + + /* Now, loop to send the data contents. If the request type is "HEAD", skip this loop to output the + file contents. */ + while ((length) && (request_type != NX_HTTP_SERVER_HEAD_REQUEST)) + { + + /* Determine if we need to allocate a new packet for data. */ + if (!temp) + { + + /* Yes, allocate a new packet. */ + status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &new_packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Error, return to caller. */ + break; + } + } + + /* Calculate the maximum length. */ + temp = ((ULONG) (new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_append_ptr)) - NX_PHYSICAL_TRAILER; + + /* Determine if this exceeds the MSS of the peer. */ + if (temp > server_ptr -> nx_http_server_socket.nx_tcp_socket_connect_mss) + { + + /* Yes, reduce the maximum size to the mss size. */ + temp = server_ptr -> nx_http_server_socket.nx_tcp_socket_connect_mss; + } + + /* Read data from the file. */ + status = fx_file_read(&(server_ptr -> nx_http_server_file), new_packet_ptr -> nx_packet_append_ptr, + temp, &temp); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Error, return. */ + break; + } + + /* Update the packet information with the data read. */ + new_packet_ptr -> nx_packet_length = new_packet_ptr -> nx_packet_length + temp; + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_append_ptr + temp; + + /* Send the packet out. */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for success. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Return to caller. */ + break; + } + + /* Increment the bytes sent count. */ + server_ptr -> nx_http_server_total_bytes_sent = server_ptr -> nx_http_server_total_bytes_sent + temp; + + /* Adjust the file length based on what we have sent. */ + length = length - temp; + + /* Indicate new packet needed */ + temp = 0; + } + + /* Close the file. */ + fx_file_close(&(server_ptr -> nx_http_server_file)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_put_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the PUT HTTP client requests. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_basic_authenticate Process basic authentication */ +/* _nx_http_server_digest_authenticate Process digest authentication */ +/* _nx_http_server_calculate_content_offset Retrieve content offset */ +/* _nx_http_server_content_length_get Retrieve content length */ +/* _nx_http_server_response_send Send response back to client */ +/* _nx_http_server_retrieve_resource Retrieve resource from request*/ +/* fx_file_close Close resource file */ +/* fx_file_create Create resource file */ +/* fx_file_open Open resource file */ +/* fx_file_write Write data to resource file */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive HTTP data from client */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_content_get Content get processing */ +/* _nx_http_server_get_process GET request processing */ +/* _nx_http_server_put_process PUT request processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_put_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +ULONG length; +UINT offset; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +NX_PACKET *data_packet_ptr; +NX_PACKET *next_packet_ptr; +UINT auth_request_present = NX_FALSE; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Calculate the content length from the request. */ + status = _nx_http_server_content_length_get_extended(packet_ptr, &length); + + /* Determine if the content length is valid. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Length", sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Calculate the offset to the content (the two Cr LF tokens) in the request. */ + offset = _nx_http_server_calculate_content_offset(packet_ptr); + + /* Determine if the offset to the content is valid. */ + if (offset == 0) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Offset", sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_http_server_authentication_check || + server_ptr -> nx_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if (status == NX_HTTP_BASIC_AUTHENTICATE || + status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); + } +#ifdef NX_HTTP_DIGEST_ENABLE + else if (status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); + } +#endif + + /* Determine if the authentication is currently in progress. */ + if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ + if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) + { + + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, NX_HTTP_SERVER_PUT_REQUEST); + } + } + + return; + } + } + + /* At this point, either there isn't any required authentication for this resource or the authentication is + complete. */ + + /* If the request is empty (content-length = 0) the request notify callback is where a response is generated + to return to the Client. NetX HTTP Server will not process an empty request further. */ + + /* Determine if a user supplied get function has been specified. */ + if (server_ptr -> nx_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the put request. */ + status = (server_ptr -> nx_http_server_request_notify)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, packet_ptr); + + /* Determine if the user supplied routine is requesting the put should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_HTTP_CALLBACK_COMPLETED) + { + + /* Send success response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); + return; + } + + /* No, an error was detected. Abort the remainder of the get processing. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + return; + } + } + + /* Was there a message body in the request? */ + if (length == 0) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + /* Otherwise, everything is okay... complete the request. */ + + /* Create the specified file. */ + status = fx_file_create(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource); + + + if (status != NX_SUCCESS) + { + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Create Failed", sizeof("NetX HTTP File Create Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Open the specified file for writing. */ + status = fx_file_open(server_ptr -> nx_http_server_media_ptr, &(server_ptr -> nx_http_server_file), server_ptr -> nx_http_server_request_resource, FX_OPEN_FOR_WRITE); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Open Failed", sizeof("NetX HTTP File Open Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + + /* Determine if there is any content in the first packet. */ + if ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) > offset) + { + + /* Write the content found in this packet. */ + status = fx_file_write(&(server_ptr -> nx_http_server_file), (packet_ptr -> nx_packet_prepend_ptr + offset), + ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); + + /* Increment the bytes received count. */ + server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + + ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); + } + + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Loop to write chained packets out to the file. */ + next_packet_ptr = packet_ptr -> nx_packet_next; + while ((length) && (next_packet_ptr)) + { + + /* Write the content of the next packet. */ + status = fx_file_write(&(server_ptr -> nx_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Increment the bytes received count. */ + server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Move to the next pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* If necessary, receive more packets from the TCP socket to complete the write request. */ + while (length) + { + + /* Wait for a request on the HTTP TCP well know port 80. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &data_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Receive Timeout", sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Loop to write the packet chain out to the file. */ + next_packet_ptr = data_packet_ptr; + do + { + + /* Write the content of this packet. */ + status = fx_file_write(&(server_ptr -> nx_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Release the previous data packet. */ + nx_packet_release(data_packet_ptr); + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - (UINT)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Increment the bytes received count. */ + server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + next_packet_ptr = NX_NULL; +#else + /* Move to the next pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while ((length) && (next_packet_ptr)); + + /* Release the previous data packet. */ + nx_packet_release(data_packet_ptr); + } + + /* Success, at this point close the file and prepare a successful response for the client. */ + fx_file_close(&(server_ptr -> nx_http_server_file)); + + + /* Now build a response header. */ + status = _nx_http_server_generate_response_header(server_ptr, &data_packet_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); + if (status == NX_SUCCESS) + { + + /* Send the response back to the client. */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), data_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(data_packet_ptr); + } + } + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_delete_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the DELETE HTTP client requests. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_basic_authenticate Process basic authentication */ +/* _nx_http_server_digest_authenticate Process digest authentication */ +/* _nx_http_server_response_send Send response back to client */ +/* _nx_http_server_retrieve_resource Retrieve resource from request*/ +/* fx_file_delete Delete resource file */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_thread_entry HTTP Server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_delete_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +NX_PACKET *response_ptr; +UINT auth_request_present = NX_FALSE; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_http_server_authentication_check || + server_ptr -> nx_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if (status == NX_HTTP_BASIC_AUTHENTICATE || + status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); + } +#ifdef NX_HTTP_DIGEST_ENABLE + else if (status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); + } +#endif + + /* Determine if the authentication is currently in progress. */ + if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ + if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) + { + + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, NX_HTTP_SERVER_DELETE_REQUEST); + } + } + + return; + } + } + + /* Determine if a user supplied notify function has been specified. */ + if (server_ptr -> nx_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the delete request. */ + status = (server_ptr -> nx_http_server_request_notify)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, packet_ptr); + + /* Determine if the user supplied routine is requesting the delete should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_HTTP_CALLBACK_COMPLETED) + { + + /* Send success response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); + return; + } + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Yes, error was detected. Abort the remainder of the delete processing. */ + return; + } + } + + /* Otherwise, everything is okay... complete the request. */ + + /* Delete the specified file. */ + status = fx_file_delete(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Delete Failed", sizeof("NetX HTTP File Delete Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Now build a response header. */ + status = _nx_http_server_generate_response_header(server_ptr, &response_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); + if (status == NX_SUCCESS) + { + + /* Send the response back to the client. */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), response_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(response_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_invalid_userpassword_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for service to set invalid */ +/* username password callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* invalid_username_password_callback Pointer to application's */ +/* invalid username password */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) +{ + +UINT status; + + + if ((http_server_ptr == NX_NULL) || (invalid_username_password_callback == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_http_server_invalid_userpassword_notify_set(http_server_ptr, invalid_username_password_callback); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_http_server_invalid_userpassword_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets invalid username password callback function. */ +/* */ +/* Note: The string length of resource in */ +/* invalid_username_password_callback is limited by */ +/* NX_HTTP_MAX_RESOURCE. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* invalid_username_password_callback Pointer to application's */ +/* invalid username password */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) +{ + + http_server_ptr -> nx_http_server_invalid_username_password_callback = invalid_username_password_callback; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the specified Server response to the requesting */ +/* HTTP client. */ +/* */ +/* Note: The strings of status code, information and additional info */ +/* must be NULL-terminated and length of this string matches the length*/ +/* specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* status_code Status-code and reason-phrase */ +/* information Pointer to HTTP info string */ +/* information_length Length of HTTP info string */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* additional_info_length Length of additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_thread_entry HTTP Server thread */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_put_process Process PUT request */ +/* _nx_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_information, UINT additional_info_length) +{ + +UINT status; +UINT length; +NX_PACKET *packet_ptr; + + + /* Determine if there is additional information. */ + if(information) + { + + /* Calculate the size of the information field. */ + length = information_length; + + /* Determine if there is additional information. */ + if (additional_information) + { + + /* Update the length with it as well. */ + length = length + additional_info_length; + } + } + else + length = 0; + + /* Generate response header. */ + status = _nx_http_server_generate_response_header(server_ptr, &packet_ptr, status_code, status_code_length, length, NX_NULL, 0, NX_NULL, 0); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Just return. */ + return(NX_HTTP_ERROR); + } + + /* Determine if there is additional information. */ + if (information) + { + + /* Place the first informational field. */ + status = nx_packet_data_append(packet_ptr, information, information_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* If there is additional information, place it in the buffer as well. */ + if (additional_information) + { + + /* Now, place the additional informational field. */ + status += nx_packet_data_append(packet_ptr, additional_information, additional_info_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet and return. */ + nx_packet_release(packet_ptr); + return(NX_HTTP_ERROR); + } + + /* Send the response back to the client. */ + status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_basic_authenticate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for basic (name & password) authentication. */ +/* If found and correct, it returns a success. Otherwise, it returns */ +/* an authentication request to the requesting client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* name_ptr Pointer to name string */ +/* password_ptr Pointer to password string */ +/* realm_ptr Pointer to realm string */ +/* realm_length Length of realm string */ +/* auth_request_present Indicate if authentication */ +/* must be performed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_retrieve_basic_authorization Pickup authorization */ +/* _nx_http_base64_decode Decode authorization */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_put_process Process PUT request */ +/* _nx_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_basic_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present) +{ + +UINT i, j; +UINT status, status1; +CHAR quote[2] = {0x22, 0}; +CHAR crlf[2] = {13,10}; +UINT match; +UINT length; + + /* Default to no authentication request detected. */ + *auth_request_present = NX_FALSE; + + /* Default the status to authenticate. */ + status = NX_HTTP_BASIC_AUTHENTICATE; + + memset(&authorization_request[0], 0, sizeof(authorization_request)); + + memset(&authorization_decoded[0], 0, sizeof(authorization_decoded)); + + /* Is the authorization request present? */ + length = _nx_http_server_retrieve_basic_authorization(packet_ptr, authorization_request); + if (length) + { + + /* Yes, an authorization request is present. */ + *auth_request_present = NX_TRUE; + + /* Convert the request from Base64 representation to ASCII. */ + _nx_http_base64_decode(authorization_request, length, authorization_decoded); + + /* See if it is valid. */ + + /* Compare the name. */ + i = 0; + match = NX_TRUE; + while (name_ptr[i] && (i < sizeof(authorization_decoded))) + { + + /* Is there a mismatch? */ + if (name_ptr[i] != authorization_decoded[i]) + { + + /* Name mismatch. Continue to avoid timing attack. */ + match = NX_FALSE; + } + + /* Move to next character. */ + i++; + } + + /* Determine if everything matches. */ + if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == ':')) + { + + /* Move the authorization index past the semicolon. */ + i++; + + /* Now compare the passwords. */ + j = 0; + match = NX_TRUE; + while (password_ptr[j] && (i < sizeof(authorization_decoded))) + { + + /* Is there a mismatch? */ + if (password_ptr[j] != authorization_decoded[i]) + { + + /* Password mismatch. Continue to avoid timing attack. */ + match = NX_FALSE; + } + + /* Move to next character. */ + i++; + j++; + } + + /* Determine if we have a match. */ + if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == (CHAR) NX_NULL)) + { + + /* Yes, we have successful authorization!! */ + status = NX_SUCCESS; + } + } + } + + /* Determine if we need to send back an unauthorized request. */ + if (status == NX_HTTP_BASIC_AUTHENTICATE) + { + + /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ + + /* Allocate a packet for sending the response back. */ + status1 = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if (status1 != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Just return. */ + return(status1); + } + + /* Insert the response header. */ + nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, NX_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_HTTP_STATUS_UNAUTHORIZED) - 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the type of authentication requested. */ + nx_packet_data_append(packet_ptr, "WWW-Authenticate: Basic realm=", 30, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the realm string into the buffer. */ + nx_packet_data_append(packet_ptr, realm_ptr, realm_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place another into the buffer to signal end of FULL HTTP response. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Send the response back to the client. */ + status1 = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status1) + { + + /* Return the internal NetX error. */ + status = status1; + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Return the result of the authentication request. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_retrieve_basic_authorization PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves basic authentication information from the */ +/* HTTP request packet. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Request packet pointer */ +/* authorization_request_ptr Pointer to destination for */ +/* authorization string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_basic_authenticate Basic authenticate processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr) +{ + +UINT length; +UINT found; +CHAR *buffer_ptr; + + + /* Set the found flag to false. */ + found = NX_FALSE; + + /* Default the authorization request to zero. */ + length = 0; + + /* Set the authorization request string to NULL. */ + authorization_request_ptr[0] = NX_NULL; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + + /* Find the "Authorization: " token first. */ + while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Authorization: token. */ + if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && + ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && + ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && + ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && + ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && + ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && + ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && + ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && + ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && + ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && + ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && + ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && + (*(buffer_ptr+13) == ':') && + (*(buffer_ptr+14) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 15; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now check for the "Basic " token. */ + while (((buffer_ptr+6) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Basic token. */ + if (((*buffer_ptr == 'b') || (*buffer_ptr == 'B')) && + ((*(buffer_ptr+1) == 'a') || (*(buffer_ptr+1) == 'A')) && + ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+3) == 'i') || (*(buffer_ptr+3) == 'I')) && + ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+4) == 'C')) && + (*(buffer_ptr+5) == ' ')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 6; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the authorization string. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_STRING)) + { + + /* Copy a character of the authorization string into the destination. */ + authorization_request_ptr[length] = *buffer_ptr++; + length++; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_retrieve_resource PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource (URL) portion of the request */ +/* and places it in the destination. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* destination Destination for resource */ +/* max_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* Status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_put_process Process PUT request */ +/* _nx_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_retrieve_resource(NX_PACKET *packet_ptr, CHAR *destination, UINT max_size) +{ + +UINT i; +CHAR *buffer_ptr; + + + /* Set the destination to NULL. */ + destination[0] = (CHAR) 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the first space which is the start position of URI. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ')) + { + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Check for an error condition. */ + if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) + return(NX_HTTP_ERROR); + + buffer_ptr++; + + if ((buffer_ptr + 7 < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Check whether it is an absoluteURI*/ + if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && + ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && + ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 1) == 'T')) && + ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 1) == 'P')) && + (*(buffer_ptr + 4) == ':') && + (*(buffer_ptr + 5) == '/') && + (*(buffer_ptr + 6) == '/')) + { + + /* Yes it is. Find the absolute path. */ + buffer_ptr += 7; + + /* Find the first slash character. The first slash marks the beginning of the URL. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != '/')) + { + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + } + } + + /* Check for an error condition. */ + if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != '/')) + return(NX_HTTP_ERROR); + + /* Copy the rest of the resource to the destination. Space, semicolon, and question mark characters signal the + end of the resource. */ + i = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ') && (*buffer_ptr != ';') && (*buffer_ptr != '?') && (i < (max_size-1))) + { + + /* Check escape characters. */ + if(*buffer_ptr == '%') + { + + /* It is an escape character. */ + if((buffer_ptr + 2) < (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + + /* Convert the HEX number. */ + buffer_ptr++; + if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + destination[i] = (CHAR)(*buffer_ptr - '0'); + else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) + destination[i] = (CHAR)(*buffer_ptr - 'a' + 10); + else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) + destination[i] = (CHAR)(*buffer_ptr - 'A' + 10); + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_HTTP_ERROR); + } + destination[i] = (CHAR)(destination[i] << 4); + + /* Convert the HEX number. */ + buffer_ptr++; + if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - '0')); + else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'a' + 10)); + else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'A' + 10)); + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_HTTP_ERROR); + } + + /* Move to the next byte. */ + i++; + buffer_ptr++; + } + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_HTTP_ERROR); + } + } + else + { + + /* Copy the URL name into the destination. */ + destination[i++] = *buffer_ptr++; + } + } + + /* Determine if the resource was retrieved. */ + if ((destination[0] == (CHAR) 0) || (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || ((*buffer_ptr != ' ') && (*buffer_ptr != '?') && (*buffer_ptr != ';'))) + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_HTTP_ERROR); + } + + /* Everything is okay, place a NULL at the end of the resource. */ + destination[i] = (CHAR) 0; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_calculate_content_offset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the byte offset to the start of the */ +/* HTTP request content area. This area immediately follows the HTTP */ +/* request header (which ends with a blank line). */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to request packet */ +/* */ +/* OUTPUT */ +/* */ +/* Byte Offset (0 implies no content) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_content_get Application content get */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_put_process Process PUT request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_calculate_content_offset(NX_PACKET *packet_ptr) +{ + +UINT offset; +CHAR *buffer_ptr; + + + /* Default the content offset to zero. */ + offset = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "cr,lf,cr,lf" token. */ + while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the token. This signals a blank line, which also + specifies the start of the content. */ + if ((*buffer_ptr == (CHAR) 13) && + (*(buffer_ptr+1) == (CHAR) 10) && + (*(buffer_ptr+2) == (CHAR) 13) && + (*(buffer_ptr+3) == (CHAR) 10)) + { + + /* Adjust the offset. */ + offset = offset + 4; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + + /* Increment the offset. */ + offset++; + } + + /* Return the offset to the caller. */ + return(offset); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* string Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_response_send Send response to client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_number_convert(UINT number, CHAR *string) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < 10) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string[j] = string[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + string[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Make the string NULL terminated. */ + string[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for deriving the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_type_get */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (name == NX_NULL) || (http_type_string == NX_NULL)) + return(0); + + return _nx_http_server_type_get(server_ptr, name, http_type_string); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_type_get_extended */ +/* _nx_utility_string_length_check */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string) +{ +UINT name_length = 0; + + if (_nx_utility_string_length_check(name, &name_length, NX_MAX_STRING_LENGTH)) + { + return(0); + } + + return _nx_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, NX_MAX_STRING_LENGTH + 1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_type_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for deriving the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* name_length Length of name string */ +/* http_type_string Destination HTTP type string */ +/* http_type_string_max_size Size of the destination string*/ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string, or */ +/* 0 if http_type_string is too */ +/* small for the resource string*/ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_type_get_extended */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (name == NX_NULL) || (http_type_string == NX_NULL)) + return(0); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, http_type_string_max_size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_type_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* Note: The string of name must be NULL-terminated and length of each */ +/* string matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* name_length Length of name string */ +/* http_type_string Destination HTTP type string */ +/* http_type_string_max_size Size of the destination string*/ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string, or */ +/* 0 if http_type_string is too */ +/* small for the resource */ +/* string, or name exceeds */ +/* NX_HTTP_MAX_RESOURCE */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_memicmp */ +/* _nx_utility_string_length_check */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size) +{ + +UINT i; +CHAR *ch; +UINT ext_length; +UINT map_ext_length; +UINT map_type_length; +UINT temp_name_length; + + /* Check name length. */ + if (_nx_utility_string_length_check(name, &temp_name_length, name_length)) + { + return(NX_HTTP_ERROR); + } + + /* Validate string length. */ + if (name_length != temp_name_length) + { + return(NX_HTTP_ERROR); + } + + /* First find the end of the string. */ + ch = name + name_length; + + /* Now look backwards to find the last period that signals the + file extension. */ + ext_length = 0; + while ((ch >= name) && (*ch != '.') &&(*ch != '/')) + { + ch--; + ext_length++; + } + + if(*ch != '.') + { + + /* No extension is found. Return the default mime type. */ + if(http_type_string_max_size < (sizeof(NX_HTTP_SERVER_DEFAULT_MIME))) + { + /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into + the caller-supplied http_type_string. */ + return (0); + } + + /* return the default MIME type. */ + memcpy(http_type_string, NX_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_HTTP_SERVER_DEFAULT_MIME)); + return(sizeof(NX_HTTP_SERVER_DEFAULT_MIME) - 1); + } + + /* Position forward again, past the period. */ + ch++; + ext_length--; + + /* Now see what HTTP file type to return. */ + /* Search user defined MIME maps first. */ + if(server_ptr -> nx_http_server_mime_maps_additional && + (server_ptr -> nx_http_server_mime_maps_additional_num > 0)) + { + for(i = 0; i < server_ptr -> nx_http_server_mime_maps_additional_num; i++) + { + /* Check map extension and type length. */ + if (_nx_utility_string_length_check(server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_extension, + &map_ext_length, ext_length) || + _nx_utility_string_length_check(server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_type, + &map_type_length, http_type_string_max_size - 1)) + { + continue; + } + + if(_nx_http_server_memicmp((UCHAR *)ch, ext_length, + (UCHAR *)server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_extension, + map_ext_length) == NX_SUCCESS) + { + + /* Find the extension. Return the mapped MIME type. */ + memcpy(http_type_string, server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_type, map_type_length + 1); + return(map_type_length); + } + } + } + + /* Search default MIME maps. */ + for(i = 0; i < sizeof(_nx_http_server_mime_maps) / sizeof(NX_HTTP_SERVER_MIME_MAP); i++) + { + + /* Check map extension and type length. */ + if (_nx_utility_string_length_check(_nx_http_server_mime_maps[i].nx_http_server_mime_map_extension, + &map_ext_length, ext_length) || + _nx_utility_string_length_check(_nx_http_server_mime_maps[i].nx_http_server_mime_map_type, + &map_type_length, http_type_string_max_size - 1)) + { + continue; + } + + if(_nx_http_server_memicmp((UCHAR *)ch, ext_length, + (UCHAR *)_nx_http_server_mime_maps[i].nx_http_server_mime_map_extension, + map_ext_length) == NX_SUCCESS) + { + + /* Find the extension. Return the mapped MIME type. */ + memcpy(http_type_string, _nx_http_server_mime_maps[i].nx_http_server_mime_map_type, map_type_length + 1); + return(map_type_length); + } + } + + /* No extension matches. Return the default mime type. */ + if(http_type_string_max_size < (sizeof(NX_HTTP_SERVER_DEFAULT_MIME))) + { + /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into + the caller-supplied http_type_string. */ + return (0); + } + + /* return the default MIME type. */ + memcpy(http_type_string, NX_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_HTTP_SERVER_DEFAULT_MIME)); + return(sizeof(NX_HTTP_SERVER_DEFAULT_MIME) - 1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_base64_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the input string into a base64 */ +/* representation. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* length Length of name */ +/* base64name Encoded base64 name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_base64_encode(CHAR *name, UINT length, CHAR *base64name) +{ + +UINT pad; +UINT i, j; +UINT step; + + + /* Adjust the length to represent the base64 name. */ + length = ((length * 8) / 6); + + /* Default padding to none. */ + pad = 0; + + /* Determine if an extra conversion is needed. */ + if ((length * 6) % 24) + { + + /* Some padding is needed. */ + + /* Calculate the number of pad characters. */ + pad = (length * 6) % 24; + pad = (24 - pad) / 6; + pad = pad - 1; + + /* Adjust the length to pickup the character fraction. */ + length++; + } + + /* Setup index into the base64name. */ + j = 0; + + /* Compute the base64name. */ + step = 0; + i = 0; + while (j < length) + { + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first 6 bits of name character for index. */ + base64name[j++] = _nx_http_server_base64_array[((UINT) name[i]) >> 2]; + step++; + } + else if (step == 1) + { + + /* Use last 2 bits of name character and first 4 bits of next name character for index. */ + base64name[j++] = _nx_http_server_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; + i++; + step++; + } + else if (step == 2) + { + + /* Use last 4 bits of name character and first 2 bits of next name character for index. */ + base64name[j++] = _nx_http_server_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; + i++; + step++; + } + else /* Step 3 */ + { + + /* Use last 6 bits of name character for index. */ + base64name[j++] = _nx_http_server_base64_array[(((UINT) name[i]) & 0x3F)]; + i++; + step = 0; + } + } + + /* Determine if the index needs to be advanced. */ + if (step != 3) + i++; + + /* Now add the PAD characters. */ + while ((pad--) && (j < NX_HTTP_MAX_STRING)) + { + + /* Pad base64name with '=' characters. */ + base64name[j++] = '='; + } + + /* Put a NULL character in. */ + base64name[j] = NX_NULL; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_base64_decode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decodes the input base64 ASCII string and converts */ +/* it into a standard ASCII representation. */ +/* */ +/* INPUT */ +/* */ +/* base64name Encoded base64 name string */ +/* length Length of encoded base64 name */ +/* name Name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_basic_authenticate Basic authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_base64_decode(CHAR *base64name, UINT length, CHAR *name) +{ + +UINT i, j; +UINT value1, value2; +UINT step; + + + /* Adjust the length to represent the ASCII name. */ + length = ((length * 6) / 8); + + /* Setup index into the ASCII name. */ + j = 0; + + /* Compute the ASCII name. */ + step = 0; + i = 0; + while ((j < length) && (base64name[i]) && (base64name[i] != '=')) + { + + /* Derive values of the Base64 name. */ + if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) + value1 = (UINT) (base64name[i] - 'A'); + else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) + value1 = (UINT) (base64name[i] - 'a') + 26; + else if ((base64name[i] >= '0') && (base64name[i] <= '9')) + value1 = (UINT) (base64name[i] - '0') + 52; + else if (base64name[i] == '+') + value1 = 62; + else if (base64name[i] == '/') + value1 = 63; + else + value1 = 0; + + /* Derive value for the next character. */ + if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) + value2 = (UINT) (base64name[i+1] - 'A'); + else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) + value2 = (UINT) (base64name[i+1] - 'a') + 26; + else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) + value2 = (UINT) (base64name[i+1] - '0') + 52; + else if (base64name[i+1] == '+') + value2 = 62; + else if (base64name[i+1] == '/') + value2 = 63; + else + value2 = 0; + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first value and first 2 bits of second value. */ + name[j++] = (CHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); + i++; + step++; + } + else if (step == 1) + { + + /* Use last 4 bits of first value and first 4 bits of next value. */ + name[j++] = (CHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); + i++; + step++; + } + else if (step == 2) + { + + /* Use first 2 bits and following 6 bits of next value. */ + name[j++] = (CHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); + i++; + i++; + step = 0; + } + } + + /* Put a NULL character in. */ + name[j] = NX_NULL; +} + + +#ifdef NX_HTTP_DIGEST_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_digest_authenticate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for digest (MD5 only) authentication. */ +/* If the digest is correct, it returns a success. Otherwise, it */ +/* returns an authentication request to the requesting client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* name_ptr Pointer to name string */ +/* name_length Length of name string */ +/* password_ptr Pointer to password string */ +/* password_length Length of password string */ +/* realm_ptr Pointer to realm string */ +/* realm_length Length of realm string */ +/* auth_request_present Indicate if authentication */ +/* must be performed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_retrieve_digest_authorization Pickup authorization */ +/* _nx_http_server_digest_response_calculate Calculate the digest */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process Process GET request */ +/* _nx_http_server_put_process Process PUT request */ +/* _nx_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_digest_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, UINT name_length, CHAR *password_ptr, UINT password_length, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present) +{ + +CHAR authorization_response[NX_HTTP_MAX_ASCII_MD5 + 1]; +CHAR calculated_response[NX_HTTP_MAX_ASCII_MD5 + 1]; +CHAR authorization_uri[NX_HTTP_MAX_RESOURCE + 1]; +CHAR method[8]; +CHAR quote[2] = {0x22, 0}; +CHAR *buffer_ptr; +UINT i; +UINT status, status1, callback_status; +CHAR crlf[2] = {13,10}; +CHAR authorization_nc[NX_HTTP_MAX_RESOURCE + 1]; +CHAR authorization_cnonce[NX_HTTP_MAX_RESOURCE + 1]; + + /* Default to no authentication request detected. */ + *auth_request_present = NX_FALSE; + + /* Default the status to authenticate. */ + status = NX_HTTP_DIGEST_AUTHENTICATE; + + /* Is the authorization request present? */ + if (_nx_http_server_retrieve_digest_authorization(packet_ptr, authorization_response, authorization_uri, authorization_nc, authorization_cnonce)) + { + + /* Yes, an authorization request is present. */ + *auth_request_present = NX_TRUE; + + /* Pickup method from the packet. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + i = 0; + while (((buffer_ptr + i) < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (buffer_ptr[i] != ' ') && (i < (sizeof(method) - 1))) + { + + /* Copy bytes of method. */ + method[i] = buffer_ptr[i]; + i++; + } + + /* Null terminate method. */ + method[i] = (CHAR) NX_NULL; + + /* If the digest authenticate callback function is set, invoke the callback function. */ + if(server_ptr -> nx_http_server_digest_authenticate_callback) + { + callback_status = (server_ptr -> nx_http_server_digest_authenticate_callback)(server_ptr, name_ptr, realm_ptr, password_ptr, method, authorization_uri, authorization_nc, authorization_cnonce); + } + else + { + + /* If the digest authenticate callback is not set, assume it is success, for backward + compatibility reasons. */ + callback_status = NX_SUCCESS; + } + + + /* Calculate what the MD5 should be. */ + _nx_http_server_digest_response_calculate(server_ptr, name_ptr, name_length, realm_ptr, realm_length, password_ptr, password_length, _nx_http_server_nonce, method, authorization_uri, authorization_nc, authorization_cnonce, calculated_response); + + /* Determine if the calculated response is the same as the received response. */ + i = 0; + status = NX_SUCCESS; + while (i < NX_HTTP_MAX_ASCII_MD5 + 1) + { + /* Is there a mismatch? */ + if (calculated_response[i] != authorization_response[i]) + { + + /* Authorization mismatch. Continue to avoid timing attack. */ + status = NX_HTTP_DIGEST_AUTHENTICATE; + } + + /* Otherwise, look at next character. */ + i++; + } + /* If digest authenticate callback function returns non-success value, the request is + considered unauthenticated. */ + if(callback_status != NX_SUCCESS) + status = NX_HTTP_DIGEST_AUTHENTICATE; + } + + /* Determine if we need to send back an unauthorized request. */ + if (status == NX_HTTP_DIGEST_AUTHENTICATE) + { + + /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ + + /* Allocate a packet for sending the response back. */ + status1 = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if (status1 != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Return the internal NetX error. */ + return(status1); + } + + /* Insert the response header. */ + nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, NX_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_HTTP_STATUS_UNAUTHORIZED) - 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the type of authentication requested. */ + nx_packet_data_append(packet_ptr, "WWW-Authenticate: Digest realm=", 31, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the realm string into the buffer. */ + nx_packet_data_append(packet_ptr, realm_ptr, realm_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place a comma into the buffer. */ + nx_packet_data_append(packet_ptr, ",", 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the algorithm into the buffer. */ + nx_packet_data_append(packet_ptr, " algorithm=", 11, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the md5 tag into the buffer. */ + nx_packet_data_append(packet_ptr, "md5", 3, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place a comma into the buffer. */ + nx_packet_data_append(packet_ptr, ",", 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the nonce into the buffer. */ + nx_packet_data_append(packet_ptr, " nonce=", 7, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the nonce string into the buffer. */ + nx_packet_data_append(packet_ptr, _nx_http_server_nonce, sizeof(_nx_http_server_nonce) - 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the qop="auth" parameter string into the buffer. */ + nx_packet_data_append(packet_ptr, ", qop=\"auth\"", 12, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place another into the buffer to signal end of FULL HTTP response. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Send the response back to the client. */ + status1 = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status1) + { + + /* Set the internal NetX error as the status return. */ + status = status1; + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Return the result of the authentication request. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_digest_response_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the MD5 digest based on the supplied input */ +/* parameters. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* username Username string */ +/* realm Realm string */ +/* password Password string */ +/* nonce Authentication nonce string */ +/* method Request method string */ +/* uri Resource request string */ +/* nc Nonce count string */ +/* cnonce Client nonce string */ +/* result Computed digest string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_hex_ascii_convert Convert hex to ASCII */ +/* _nx_md5_initialize Initialize MD5 algorithm */ +/* _nx_md5_update Update MD5 digest */ +/* _nx_md5_digest_calculate Complete the MD5 algorithm */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_digest_authenticate Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_digest_response_calculate(NX_HTTP_SERVER *server_ptr, CHAR *username, UINT username_length, CHAR *realm, UINT realm_length, CHAR *password, UINT password_length, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result) +{ + +CHAR md5_binary[NX_HTTP_MAX_BINARY_MD5]; +CHAR ha1_string[NX_HTTP_MAX_ASCII_MD5 + 1]; +CHAR ha2_string[NX_HTTP_MAX_ASCII_MD5 + 1]; +UINT method_length; +UINT uri_length; +UINT nonce_length; +UINT nc_length; +UINT cnonce_length; + + /* Check string length. */ + if (_nx_utility_string_length_check(method, &method_length, 7) || + _nx_utility_string_length_check(uri, &uri_length, NX_HTTP_MAX_RESOURCE) || + _nx_utility_string_length_check(nonce, &nonce_length, sizeof(_nx_http_server_nonce) - 1) || + _nx_utility_string_length_check(nc, &nc_length, NX_HTTP_MAX_RESOURCE) || + _nx_utility_string_length_check(cnonce, &cnonce_length, NX_HTTP_MAX_RESOURCE)) + { + return; + } + + + /* Calculate the H(A1) portion of the digest. */ + _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) username, username_length); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) realm, realm_length); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) password, password_length); + _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); + + /* Convert this H(A1) portion to ASCII Hex representation. */ + _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, ha1_string); + + /* Make the H(A2) portion of the digest. */ + _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) method, method_length); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) uri, uri_length); + _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); + + /* Convert this H(A2) portion to ASCII Hex representation. */ + _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, ha2_string); + + /* Now make the final MD5 digest. */ + _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ha1_string, sizeof(ha1_string) - 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) nonce, nonce_length); + + /* Start of Internet Explorer bug work-around. */ + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) nc, nc_length); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) cnonce, cnonce_length); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":auth", 5); + /* End of Internet Explorer bug work-around. */ + + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ha2_string, sizeof(ha2_string) - 1); + _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); + + /* Finally, convert the response back to an ASCII string and place in + the destination. */ + _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, result); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_retrieve_digest_authorization PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the MD5 digest parameters from the */ +/* supplied request packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Request packet pointer */ +/* response Digest response pointer */ +/* uri URI from response pointer */ +/* nc Nonce count string */ +/* cnonce Client nonce string */ +/* */ +/* OUTPUT */ +/* */ +/* length Length of response (should be */ +/* 32). A value of 0 indicates */ +/* an error is present */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_digest_authenticate Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce) +{ + +UINT length; +UINT found; +CHAR *buffer_ptr; +CHAR *saved_buffer_ptr; + + + /* Set the found flag to false. */ + found = NX_FALSE; + + /* Default the authorization request to zero. */ + length = 0; + + /* Set the response and uri strings to NULL. */ + response[0] = NX_NULL; + uri[0] = NX_NULL; + + /* Internet Explorer bug work-around. */ + nc[0] = NX_NULL; + cnonce[0] = NX_NULL; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Authorization: " token first. */ + while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Authorization: token. */ + if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && + ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && + ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && + ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && + ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && + ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && + ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && + ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && + ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && + ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && + ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && + ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && + (*(buffer_ptr+13) == ':') && + (*(buffer_ptr+14) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 15; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Set the found flag back to false. */ + found = NX_FALSE; + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now check for the "Digest " token. */ + while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Digest token. */ + if (((*buffer_ptr == 'd') || (*buffer_ptr == 'D')) && + ((*(buffer_ptr+1) == 'i') || (*(buffer_ptr+1) == 'I')) && + ((*(buffer_ptr+2) == 'g') || (*(buffer_ptr+2) == 'G')) && + ((*(buffer_ptr+3) == 'e') || (*(buffer_ptr+3) == 'E')) && + ((*(buffer_ptr+4) == 's') || (*(buffer_ptr+4) == 'S')) && + ((*(buffer_ptr+5) == 't') || (*(buffer_ptr+5) == 'T')) && + (*(buffer_ptr+6) == ' ')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 7; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the second token was found. */ + if (!found) + { + + /* No, digest is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Start of Internet Explorer bug work-around (Parses nc and cnonce parameters). */ + + /* Save current buffer pointer, so each parameter search always starts from here. */ + saved_buffer_ptr = buffer_ptr; + + /* Now look for the nc in the digest response. */ + while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the nc token. */ + if (((*buffer_ptr == 'n') || (*buffer_ptr == 'N')) && + ((*(buffer_ptr+1) == 'c') || (*(buffer_ptr+1) == 'C')) && + (*(buffer_ptr+2) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 3; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes (should be no starting quote). */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the nc string (should be 8 hex characters; should not be quoted). */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote or comma is present (should be no ending quote). */ + if ((*buffer_ptr == (CHAR) 0x22) || (*buffer_ptr == ',')) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + nc[length++] = *buffer_ptr++; + } + + /* Null terminate the NC. */ + nc[length] = (CHAR) NX_NULL; + + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the cnonce in the digest response. */ + while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'n') || (*(buffer_ptr+1) == 'N')) && + ((*(buffer_ptr+2) == 'o') || (*(buffer_ptr+2) == 'O')) && + ((*(buffer_ptr+3) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+2) == 'C')) && + ((*(buffer_ptr+5) == 'e') || (*(buffer_ptr+2) == 'E')) && + (*(buffer_ptr+6) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 7; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the cnonce string. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + cnonce[length++] = *buffer_ptr++; + } + + /* Null terminate the CNONCE. */ + cnonce[length] = (CHAR) NX_NULL; + + /* End of Internet Explorer bug work-around. */ + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the uri in the digest response. */ + while (((buffer_ptr+4) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'u') || (*buffer_ptr == 'U')) && + ((*(buffer_ptr+1) == 'r') || (*(buffer_ptr+1) == 'R')) && + ((*(buffer_ptr+2) == 'i') || (*(buffer_ptr+2) == 'I')) && + (*(buffer_ptr+3) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 4; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the uri string. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + uri[length++] = *buffer_ptr++; + } + + /* Null terminate the URI. */ + uri[length] = (CHAR) NX_NULL; + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the digest response. */ + while (((buffer_ptr+9) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'r') || (*buffer_ptr == 'R')) && + ((*(buffer_ptr+1) == 'e') || (*(buffer_ptr+1) == 'E')) && + ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+3) == 'p') || (*(buffer_ptr+2) == 'P')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+2) == 'O')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+6) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+7) == 'e') || (*(buffer_ptr+2) == 'E')) && + (*(buffer_ptr+8) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 9; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and leading quote. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Finally, pickup the response. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (*buffer_ptr != (CHAR) 0x3A) && (length < NX_HTTP_MAX_ASCII_MD5)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the response string into the destination. */ + response[length++] = *buffer_ptr++; + } + + /* Null terminate response. */ + response[length] = (CHAR) NX_NULL; + + /* Check for an error. */ + if ((length != 32) || (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != (CHAR) 0x22)) + { + + /* Error, clear the length and the response string. */ + length = 0; + response[0] = (CHAR) NX_NULL; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_hex_ascii_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts hexadecimal characters into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* source Source hex string */ +/* source_length Length of source string */ +/* destination Pointer to destination string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_digest_response_calculate Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) +{ + +UINT i,j; +CHAR digit; + + + /* Setup destination index. */ + j = 0; + + /* Loop to process the entire source string. */ + for (i = 0; i < source_length; i++) + { + + /* Pickup the first nibble. */ + digit = (source[i] >> 4) & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + + /* Pickup the second nibble. */ + digit = source[i] & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + } + + /* Finally, place a NULL in the destination string. */ + destination[j] = (CHAR) NX_NULL; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_get_entity_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for getting the entity header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* entity_header_buffer Buffer to get entity header */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_get_entity_header */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) +{ + +#ifdef NX_HTTP_MULTIPART_ENABLE + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL)) + return NX_PTR_ERROR; + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_http_server_get_entity_header(server_ptr, packet_pptr, entity_header_buffer, buffer_size); +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(entity_header_buffer); + NX_PARAMETER_NOT_USED(buffer_size); + + return NX_HTTP_ERROR; +#endif /* NX_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_get_entity_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the entity header and skip header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* entity_header_buffer Buffer to get entity header */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_field_value_get */ +/* _nx_http_server_memicmp */ +/* _nx_http_server_boundary_find */ +/* nx_packet_release */ +/* nx_tcp_socket_receive */ +/* _nx_utility_string_length_check */ +/* memmove */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) +{ + +#ifdef NX_HTTP_MULTIPART_ENABLE +NX_HTTP_SERVER_MULTIPART *multipart_ptr; +UINT status; +UINT offset; +NX_PACKET *available_packet; +UINT crlf_match_count = 0; +UINT end_boundary_count = 2; +UINT skip_count = 2; +UCHAR *ch; +UINT index; + + /* Get multipart context. */ + multipart_ptr = &server_ptr -> nx_http_server_multipart; + + /* Is the multipart context initialized? */ + if(multipart_ptr -> nx_http_server_multipart_boundary[0] == 0) + { + ULONG field_length; + UINT quotation_index; + UINT i; + + /* No, it is not initialized. */ + + /* Get content type. */ + status = _nx_http_server_field_value_get(*packet_pptr, (UCHAR *)"content-type", 12, + multipart_ptr -> nx_http_server_multipart_boundary, NX_HTTP_MAX_HEADER_FIELD + 1); + if(status) + return status; + + /* Is the content type "multipart"? */ + /* Check the length. The length of "multipart/" is 10. */ + if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_http_server_multipart_boundary, (UINT *)&field_length, NX_HTTP_MAX_HEADER_FIELD)) + return NX_HTTP_ERROR; + if(field_length < 10) + return NX_HTTP_NOT_FOUND; + + /* Check the data. */ + if(_nx_http_server_memicmp(multipart_ptr -> nx_http_server_multipart_boundary, 10, + (UCHAR *)"multipart/", 10) != NX_SUCCESS) + return NX_HTTP_NOT_FOUND; + + /* Find the boundary. The length of "boundary=" is 9. */ + index = 0; + while((index + 9) < field_length) + { + if(_nx_http_server_memicmp(&multipart_ptr -> nx_http_server_multipart_boundary[index], 9, + (UCHAR *)"boundary=", 9) == NX_SUCCESS) + { + + break; + } + + /* Move the pointer up to the next character. */ + index++; + } + + /* Move the pointer up to the boundary value. */ + index += 9; + + /* Is boundary string found? */ + if((field_length - index) <= 1) + { + + /* Boundary not found or no boundary value. */ + return NX_HTTP_NOT_FOUND; + } + + /* Boundary is started with "CRLF--". */ + multipart_ptr -> nx_http_server_multipart_boundary[0] = 13; + multipart_ptr -> nx_http_server_multipart_boundary[1] = 10; + multipart_ptr -> nx_http_server_multipart_boundary[2] = '-'; + multipart_ptr -> nx_http_server_multipart_boundary[3] = '-'; + + /* Remove quotation. */ + if(multipart_ptr -> nx_http_server_multipart_boundary[index] == '"') + { + + /* Find the right quotation. */ + index++; + for(quotation_index = field_length; quotation_index > index; quotation_index--) + { + if(multipart_ptr -> nx_http_server_multipart_boundary[quotation_index] == '"') + break; + } + + /* Is the right quotation found? */ + if(quotation_index > index) + multipart_ptr -> nx_http_server_multipart_boundary[quotation_index] = 0; + else + { + + /* Boundary not valid. */ + return NX_HTTP_NOT_FOUND; + } + + /* Leave boundary string only. */ + memmove(&multipart_ptr -> nx_http_server_multipart_boundary[4], + &multipart_ptr -> nx_http_server_multipart_boundary[index], + quotation_index - index + 1); + } + else + { + + /* Directly copy boundary string to the head field. */ + i = 4; + index -= 4; + do + { + multipart_ptr -> nx_http_server_multipart_boundary[i] = multipart_ptr -> nx_http_server_multipart_boundary[index + i]; + i++; + }while((multipart_ptr -> nx_http_server_multipart_boundary[i - 1] != 0) && + (multipart_ptr -> nx_http_server_multipart_boundary[i - 1] != ' ')); + + /* Set the terminal character. */ + multipart_ptr -> nx_http_server_multipart_boundary[i - 1] = 0; + } + } + + /* Find the boundary. */ + while(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_FALSE) + { + if(_nx_http_server_boundary_find(server_ptr, packet_pptr) != NX_SUCCESS) + break; + } + + /* Whether the boundary is found? */ + if(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_FALSE) + return NX_HTTP_NOT_FOUND; + + /* Update the packet and offset. */ + _nx_http_server_boundary_find(server_ptr, packet_pptr); + + /* Get offset of available data in the packet. */ + offset = multipart_ptr -> nx_http_server_multipart_available_offset; + + /* Skip data that are not header. */ + available_packet = *packet_pptr; + + if(offset >= available_packet -> nx_packet_length) + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* All data has been processed. Get a new packet. */ + if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* FIXME: Check if the "offset" should be updated. */ + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; + } +#ifndef NX_DISABLE_PACKET_CHAIN + else + { + while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) + { + offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); + + /* Get next packet. */ + available_packet = available_packet -> nx_packet_next; + } + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Get entity header. */ + ch = available_packet -> nx_packet_prepend_ptr + offset; + index = 0; + while((entity_header_buffer == NX_NULL) || (index < buffer_size)) + { + + /* Calculate valid CRLF. */ + if((*ch == 13) && ((crlf_match_count & 1) == 0)) + crlf_match_count++; + else if((*ch == 10) && ((crlf_match_count & 1) == 1)) + crlf_match_count++; + else if(*ch == '-') + { + + /* Check whether the last boundary is found. */ + if(end_boundary_count < 3) + end_boundary_count--; + + if(end_boundary_count == 0) + break; + } + else + { + end_boundary_count = 0xFF; + crlf_match_count = 0; + } + + /* Copy data to buffer. */ + if(skip_count >0) + skip_count--; + else + { + if(entity_header_buffer) + entity_header_buffer[index] = *ch; + index++; + } + multipart_ptr -> nx_http_server_multipart_available_offset++; + + /* Check whether two CRLFs are found. */ + if(crlf_match_count == 4) + break; + + /* Get next character. */ + if((ch + 1) >= available_packet -> nx_packet_append_ptr) + { + + /* ch points to the end of this packet. */ +#ifndef NX_DISABLE_PACKET_CHAIN + if(available_packet -> nx_packet_next) + { + + /* Copy data from next packet. */ + available_packet = available_packet -> nx_packet_next; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* Get a new packet and copy data from it. */ + status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; + + /* Reset the offset. */ + multipart_ptr -> nx_http_server_multipart_available_offset = 0; + } + + ch = available_packet -> nx_packet_prepend_ptr; + } + else + ch++; + + } + + /* Check whether two CRLFs are found. */ + if(crlf_match_count == 4) + { + + /* Set terminal 0. */ + if(entity_header_buffer) + entity_header_buffer[index - 4] = 0; + return NX_SUCCESS; + } + else + return NX_HTTP_NOT_FOUND; +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(entity_header_buffer); + NX_PARAMETER_NOT_USED(buffer_size); + + return NX_HTTP_ERROR; +#endif /* NX_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_get_entity_content PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for getting the entity content. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* available_offset Return the offset */ +/* available_length Return the length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_get_entity_content */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) +{ + +#ifdef NX_HTTP_MULTIPART_ENABLE + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (available_offset == NX_NULL) || (available_length == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check whether boundary is found. */ + if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_boundary[0] == 0) + return(NX_HTTP_ERROR); + + return _nx_http_server_get_entity_content(server_ptr, packet_pptr, available_offset, available_length); +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(available_offset); + NX_PARAMETER_NOT_USED(available_length); + + return NX_HTTP_ERROR; +#endif /* NX_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_get_entity_content PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the entity content. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* available_offset Return the offset */ +/* available_length Return the length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_boundary_find */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) +{ + +#ifdef NX_HTTP_MULTIPART_ENABLE +UINT status; + + /* Whether the boundary is found? */ + if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_boundary_find == NX_TRUE) + return NX_HTTP_BOUNDARY_ALREADY_FOUND; + + status = _nx_http_server_boundary_find(server_ptr, packet_pptr); + if(status) + return status; + + /* Set the offset and length. */ + *available_offset = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_available_offset; + *available_length = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_available_length; + + return NX_SUCCESS; +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(available_offset); + NX_PARAMETER_NOT_USED(available_length); + + return NX_HTTP_ERROR; +#endif /* NX_HTTP_MULTIPART_ENABLE */ +} + + +#ifdef NX_HTTP_MULTIPART_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_boundary_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds boundary in packet even if it is chained. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release */ +/* nx_tcp_socket_receive */ +/* _nx_http_server_match_string */ +/* _nx_utility_string_length_check */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_entity_header */ +/* _nx_http_server_get_entity_content */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_boundary_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr) +{ + +NX_HTTP_SERVER_MULTIPART *multipart_ptr; +NX_PACKET *available_packet; +UINT offset; +ULONG match_count = 0; +UCHAR *match_end_ptr; +UINT boundary_length; + + /* Get multipart context. */ + multipart_ptr = &server_ptr -> nx_http_server_multipart; + + /* Is boundary already found? */ + if(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_TRUE) + { + + /* Yes. Update the packet and offset. */ + if(multipart_ptr -> nx_http_server_multipart_next_packet != NX_NULL) + { + nx_packet_release(*packet_pptr); + *packet_pptr = multipart_ptr -> nx_http_server_multipart_next_packet; + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = multipart_ptr -> nx_http_server_multipart_next_packet; + } + + multipart_ptr -> nx_http_server_multipart_available_offset = multipart_ptr -> nx_http_server_multipart_next_available_offset; + + /* Reset next packet and available offset. */ + multipart_ptr -> nx_http_server_multipart_next_packet = NX_NULL; + multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; + + /* Reset boundary find. */ + multipart_ptr -> nx_http_server_multipart_boundary_find = NX_FALSE; + + return NX_SUCCESS; + } + + /* Is the boundary in the next packet? */ + if(multipart_ptr -> nx_http_server_multipart_next_packet) + { + + /* Yes, we're done with this packet. */ + nx_packet_release(*packet_pptr); + + /* Update the packet and multipart offset. */ + *packet_pptr = multipart_ptr -> nx_http_server_multipart_next_packet; + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = multipart_ptr -> nx_http_server_multipart_next_packet; + multipart_ptr -> nx_http_server_multipart_available_offset = 0; + } + else if(multipart_ptr -> nx_http_server_multipart_next_available_offset) + { + + /* Find boundary in this packet. */ + /* Update the offset. */ + multipart_ptr -> nx_http_server_multipart_available_offset = multipart_ptr -> nx_http_server_multipart_next_available_offset; + } + else + { + + /* Find boundary from this packet. */ + /* Initialize the offset. */ + multipart_ptr -> nx_http_server_multipart_next_available_offset = multipart_ptr -> nx_http_server_multipart_available_offset; + } + + /* Reset next packet. */ + multipart_ptr -> nx_http_server_multipart_next_packet = NX_NULL; + + /* Reset boundary find. */ + multipart_ptr -> nx_http_server_multipart_boundary_find = NX_FALSE; + + + /* Get offset of available data in the packet. */ + offset = multipart_ptr -> nx_http_server_multipart_available_offset; + + /* Skip data that are not header. */ + available_packet = *packet_pptr; + + if(offset >= available_packet -> nx_packet_length) + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* All data has been processed. Get a new packet. */ + if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; + + /* Reset the offset. */ + multipart_ptr -> nx_http_server_multipart_available_offset = 0; + multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; + offset = 0; + } + else + { +#ifndef NX_DISABLE_PACKET_CHAIN + while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) + { + offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); + + /* Get next packet. */ + available_packet = available_packet -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Check boundary length. */ + if (_nx_utility_string_length_check((CHAR *)multipart_ptr->nx_http_server_multipart_boundary, &boundary_length, NX_HTTP_MAX_HEADER_FIELD)) + { + return(NX_HTTP_ERROR); + } + + /* Look for the boundary string in the (next) packet. */ + while(_nx_http_server_match_string(available_packet -> nx_packet_prepend_ptr + offset, + available_packet -> nx_packet_append_ptr, + multipart_ptr -> nx_http_server_multipart_boundary, + boundary_length, + &match_count, &match_end_ptr) != NX_SUCCESS) + { + + /* Match string in the next packet. */ +#ifndef NX_DISABLE_PACKET_CHAIN + if(available_packet -> nx_packet_next) + { + multipart_ptr -> nx_http_server_multipart_next_available_offset += (UINT)((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) - offset); + available_packet = available_packet -> nx_packet_next; + offset = 0; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + break; + } + + /* Is boundary matched? */ + if(match_end_ptr) + { + + /* Yes. Found a match. */ + multipart_ptr -> nx_http_server_multipart_next_available_offset += (UINT)((UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) - offset); + multipart_ptr -> nx_http_server_multipart_available_length = multipart_ptr -> nx_http_server_multipart_next_available_offset - multipart_ptr -> nx_http_server_multipart_available_offset - match_count; + multipart_ptr -> nx_http_server_multipart_boundary_find = NX_TRUE; + + } + else if(match_count) + { + + /* Set the available length to all remaining data. */ + multipart_ptr -> nx_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_http_server_multipart_available_offset; + + /* Partial match. Get another packet. */ + if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_HTTP_TIMEOUT); + } + + /* Match the boundary again. */ + if(_nx_http_server_match_string(available_packet -> nx_packet_prepend_ptr, + available_packet -> nx_packet_append_ptr, + multipart_ptr -> nx_http_server_multipart_boundary, + boundary_length, + &match_count, &match_end_ptr) == NX_SUCCESS) + { + + /* Yes. Find a match. */ + if((ULONG)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) < match_count) + { + + /* The boundary is between two packets. */ + multipart_ptr -> nx_http_server_multipart_next_available_offset = (UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr); + multipart_ptr -> nx_http_server_multipart_available_length -= boundary_length - multipart_ptr -> nx_http_server_multipart_next_available_offset; + multipart_ptr -> nx_http_server_multipart_boundary_find = NX_TRUE; + } + else + { + + /* The boundary is in the next packet. */ + multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; + } + } + else + { + + /* The boundary is not found. */ + multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; + } + + /* Store the packet. */ + multipart_ptr -> nx_http_server_multipart_next_packet = available_packet; + + } + else + { + + /* Set the available length to all remaining data. */ + multipart_ptr -> nx_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_http_server_multipart_available_offset; + multipart_ptr -> nx_http_server_multipart_next_available_offset = (*packet_pptr) -> nx_packet_length; + } + + return NX_SUCCESS; +} +#endif /* NX_HTTP_MULTIPART_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_match_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares a target string in specified memory area. */ +/* */ +/* INPUT */ +/* */ +/* src_start Pointer to start of source */ +/* src_end Pointer to end of source */ +/* target Pointer to target */ +/* target_length Length of target */ +/* match_count Return the match count */ +/* match_end_ptr Return the end match position */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check */ +/* memcmp */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_boundary_find */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr) +{ + +UCHAR *ch; +ULONG pre_match = *match_count; +ULONG remain_match; + + /* Initialize. */ + *match_end_ptr = NX_NULL; + + /* Process part match. */ + while(pre_match) + { + + /* Compare pre-match. */ + if(memcmp(target, target + (*match_count - pre_match), pre_match) == 0) + { + + /* Calculate the remain match. */ + remain_match = target_length - pre_match; + + /* The pre-match is the same. */ + if((ULONG)(src_end - src_start) < remain_match) + remain_match = (ULONG)(src_end - src_start); + + if(memcmp(target + pre_match, src_start, remain_match) == 0) + { + + /* Remain part matches. */ + *match_count = pre_match + remain_match; + + if(*match_count < target_length) + { + + /* Part match. */ + return NX_HTTP_NOT_FOUND; + } + + /* Full match. */ + *match_end_ptr = src_start + remain_match; + return NX_SUCCESS; + } + } + + pre_match--; + } + + ch = src_start; + + /* Perform full match. */ + *match_count = target_length; + while(ch + *match_count <= src_end) + { + if(memcmp(ch, target, *match_count) == 0) + { + + /* Find a match. */ + *match_end_ptr = ch + *match_count; + return NX_SUCCESS; + } + + ch++; + } + + /* Perform part match. */ + for(*match_count = target_length - 1; *match_count > 0; *match_count = *match_count - 1) + { + if(ch + *match_count <= src_end) + { + if(memcmp(ch, target, *match_count) == 0) + { + + /* Find a match. */ + return NX_HTTP_NOT_FOUND; + } + + ch++; + } + } + + return NX_HTTP_NOT_FOUND; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_field_value_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets field value by field name from HTTP header. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet */ +/* field_name Name of filed in header */ +/* name_length Length of filed name */ +/* field_value Return fieald of value */ +/* field_value_size Size of fieald_value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check */ +/* _nx_http_server_memicmp */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process */ +/* _nx_http_server_get_entity_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size) +{ + +UCHAR *ch; +UINT index; + + + /* Initialize. */ + ch = packet_ptr -> nx_packet_prepend_ptr; + + /* Loop to find field name. */ + while(ch + name_length < packet_ptr -> nx_packet_append_ptr) + { + if(_nx_http_server_memicmp(ch, name_length, field_name, name_length) == NX_SUCCESS) + { + + /* Field name found. */ + break; + } + + /* Move the pointer up to the next character. */ + ch++; + } + + /* Skip field name and ':'. */ + ch += name_length + 1; + + /* Is field name found? */ + if(ch >= packet_ptr -> nx_packet_append_ptr) + return NX_HTTP_NOT_FOUND; + + /* Skip white spaces. */ + while(*ch == ' ') + { + if(ch >= packet_ptr -> nx_packet_append_ptr) + return NX_HTTP_NOT_FOUND; + + /* Get next character. */ + ch++; + } + + /* Copy field value. */ + index = 0; + while(index < field_value_size) + { + + /* Whether the end of line CRLF is not found? */ + if(ch + 2 > packet_ptr -> nx_packet_append_ptr) + return NX_HTTP_NOT_FOUND; + + /* Compare CRLF. */ + if((*ch == 13) && (*(ch + 1) == 10)) + break; + + /* Copy data. */ + field_value[index++] = *ch++; + } + + /* Buffer overflow? */ + if(index == field_value_size) + return NX_HTTP_NOT_FOUND; + + /* Trim white spaces. */ + while((index > 0) && (field_value[index - 1] == ' ')) + index--; + + /* Append terminal 0. */ + field_value[index] = 0; + + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_memicmp PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares two pieces of memory case insensitive. */ +/* */ +/* INPUT */ +/* */ +/* src Pointer to source */ +/* src_length Length of source */ +/* dest Pointer to destination */ +/* dest_length Length of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_entity_header */ +/* _nx_http_server_field_value_get */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) +{ +UCHAR ch; + + /* Compare the length. */ + if(src_length != dest_length) + return NX_HTTP_FAILED; + + while(src_length) + { + + /* Is src lowercase? */ + if((*src >= 'a') && (*src <= 'z')) + ch = (UCHAR)(*src - 'a' + 'A'); + + /* Is src uppercase? */ + else if((*src >= 'A') && (*src <= 'Z')) + ch = (UCHAR)(*src - 'A' + 'a'); + else + ch = *src; + + /* Compare case insensitive. */ + if((*src != *dest) && (ch != *dest)) + return NX_HTTP_FAILED; + + /* Pickup next character. */ + src_length--; + src++; + dest++; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_generate_response_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function generates HTTP response header. */ +/* */ +/* Note: The strings of status code, content type length and additional*/ +/* header length must be NULL-terminated and length of this string */ +/* matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate */ +/* nx_packet_data_append */ +/* memcmp */ +/* _nx_utility_string_length_check */ +/* _nx_http_server_number_convert */ +/* _nx_http_server_date_to_string */ +/* nx_packet_release */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process */ +/* _nx_http_server_put_process */ +/* _nx_http_server_delete_process */ +/* _nx_http_server_response_send */ +/* _nx_http_server_callback_generate_response_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length) +{ + +UINT status; +UINT temp; +CHAR temp_string[30]; +CHAR crlf[2] = {13,10}; +NX_PACKET *packet_ptr; +CHAR status_code_ok; +CHAR status_code_not_modified; + + /* Allocate a packet for sending the response back. */ + status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, packet_pptr, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if(status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_http_server_allocation_errors++; + + /* Just return. */ + return status; + } + else + packet_ptr = *packet_pptr; + + /* Check status code. */ + if(memcmp(status_code, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK)) == 0) + status_code_ok = NX_TRUE; + else + status_code_ok = NX_FALSE; + + if(memcmp(status_code, NX_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_HTTP_STATUS_NOT_MODIFIED)) == 0) + status_code_not_modified = NX_TRUE; + else + status_code_not_modified = NX_FALSE; + + /* Insert the status line. */ + /* Place HTTP-Version. */ + status = nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert space. */ + status += nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert Status-Code and Reason-Phrase. */ + status += nx_packet_data_append(packet_ptr, status_code, status_code_length, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if there is content_type. */ + if(content_type) + { + + /* Insert the content type. */ + status += nx_packet_data_append(packet_ptr, "Content-Type: ", 14, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + status += nx_packet_data_append(packet_ptr, content_type, content_type_length, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + +#ifndef NX_HTTP_SERVER_OMIT_CONTENT_LENGTH + /* Determine if there is content_length. */ + if(content_length || (status_code_not_modified == NX_TRUE)) + { + + /* Close. */ + status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if(content_length) + { + + /* Convert the content_length to ASCII representation. */ + temp = _nx_http_server_number_convert(content_length, temp_string); + + /* Place the "Content-Length" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Content-Length: ", 16, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + status += nx_packet_data_append(packet_ptr, temp_string, temp, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + } + else +#endif /* NX_HTTP_SERVER_OMIT_CONTENT_LENGTH */ + { + + /* Place the "Connection" field in the header. */ + + /* Force close the connection since there's no content-length. */ + status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Insert Date header if callback function is set. */ + if(server_ptr -> nx_http_server_gmt_get) + { + NX_HTTP_SERVER_DATE date; + + /* Get current date. */ + server_ptr -> nx_http_server_gmt_get(&date); + + /* Convert date to string. */ + temp = _nx_http_server_date_to_string(&date, temp_string); + + /* Place the "Date" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Date: ", 6, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert date. */ + status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Set Cache Control if callback function is set. */ + if((server_ptr -> nx_http_server_cache_info_get) && + ((status_code_ok == NX_TRUE) || (status_code_not_modified == NX_TRUE)) && + (server_ptr -> nx_http_server_request_type == NX_HTTP_SERVER_GET_REQUEST)) + { + UINT max_age; + + /* Get cache infomation. */ + if(server_ptr -> nx_http_server_cache_info_get(server_ptr -> nx_http_server_request_resource, &max_age, &date) == NX_TRUE) + { + + /* Place "Cache-control" header. */ + status += nx_packet_data_append(packet_ptr, "Cache-Control: max-age=", 23, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Convert the max-age to ASCII representation. */ + temp = _nx_http_server_number_convert(max_age, temp_string); + status += nx_packet_data_append(packet_ptr, temp_string, temp, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if(status_code_ok == NX_TRUE) + { + + /* Convert date to string. */ + temp = _nx_http_server_date_to_string(&date, temp_string); + + /* Place the "Last-Modified" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Last-Modified: ", 15, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert date. */ + status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + } + } + + /* Insert additional header. */ + if(additional_header) + { + + status += nx_packet_data_append(packet_ptr, additional_header, additional_header_length, + server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_generate_response_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for generating HTTP response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* content_length Length of content */ +/* content_type Type of content */ +/* additional_header Other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_generate_response_header */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (status_code == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_http_server_callback_generate_response_header(server_ptr, packet_pptr, status_code, content_length, content_type, additional_header); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_generate_response_header_extended */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for generating HTTP response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_generate_response_header_extended */ +/* Actual responder header */ +/* generation function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (status_code == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_http_server_callback_generate_response_header_extended(server_ptr, packet_pptr, status_code, status_code_length, content_length, + content_type, content_type_length, additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_generate_response_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to generate HTTP */ +/* response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* content_length Length of content */ +/* content_type Type of content */ +/* additional_header Other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_generate_response_header */ +/* Internal responder header */ +/* generation function */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header) +{ +UINT status_code_length = 0; +UINT content_type_length = 0; +UINT additional_header_length = 0; + + /* Check status code, content type and additional header length. */ + if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || + (content_type && _nx_utility_string_length_check(content_type, &content_type_length, NX_MAX_STRING_LENGTH)) || + (additional_header && _nx_utility_string_length_check(additional_header, &additional_header_length, NX_MAX_STRING_LENGTH))) + { + return(NX_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + return _nx_http_server_generate_response_header(server_ptr, packet_pptr, status_code, status_code_length, content_length, + content_type, content_type_length, additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_generate_response_header_extended */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to generate HTTP */ +/* response header. */ +/* */ +/* Note: The strings of status code, content type length and additional*/ +/* header length must be NULL-terminated and length of this string */ +/* matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_generate_response_header */ +/* Internal responder header */ +/* generation function */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length) +{ + +UINT temp_status_code_length = 0; +UINT temp_content_type_length = 0; +UINT temp_add_header_length = 0; + + /* Check status code, content type and additional header length. */ + if (_nx_utility_string_length_check(status_code, &temp_status_code_length, status_code_length) || + (content_type && _nx_utility_string_length_check(content_type, &temp_content_type_length, content_type_length)) || + (additional_header && _nx_utility_string_length_check(additional_header, &temp_add_header_length, additional_header_length))) + { + return(NX_HTTP_ERROR); + } + + /* Validate string length. */ + if ((status_code_length != temp_status_code_length) || + (content_type && content_type_length != temp_content_type_length) || + (additional_header && additional_header_length != temp_add_header_length)) + { + return(NX_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + return _nx_http_server_generate_response_header(server_ptr, packet_pptr, status_code, status_code_length, content_length, + content_type, content_type_length, additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_callback_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for sending a packet. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_callback_packet_send */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + return _nx_http_server_callback_packet_send(server_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_callback_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to send a packet. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_send */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + + /* Send internal. */ + return nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_gmt_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting gmt callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* gmt_get Pointer to application's */ +/* GMT time function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_gmt_callback_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (gmt_get == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_http_server_gmt_callback_set(server_ptr, gmt_get); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_gmt_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets gmt callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* gmt_get Pointer to application's */ +/* GMT time function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the function pointer. */ + server_ptr -> nx_http_server_gmt_get = gmt_get; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_cache_info_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting cache info callback function.*/ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* cache_info_get Pointer to application's */ +/* cache information function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_cache_info_callback_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (cache_info_get == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_http_server_cache_info_callback_set(server_ptr, cache_info_get); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_cache_info_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets cache info callback function. */ +/* */ +/* Note: The string length of resource in cache_info_get is limited by */ +/* NX_HTTP_MAX_RESOURCE. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* cache_info_get Pointer to application's */ +/* cache information function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the function pointer. */ + server_ptr -> nx_http_server_cache_info_get = cache_info_get; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_date_to_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts from date to string. */ +/* */ +/* INPUT */ +/* */ +/* date Pointer to HTTP date */ +/* string Pointer to output buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_date_convert */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_get_process */ +/* _nx_http_server_generate_response_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_date_to_string(NX_HTTP_SERVER_DATE *date, CHAR *string) +{ + +UINT index = 0; + + /* RDC1122-date. */ + /* Append weekday. */ + string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday]); + string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday] + 1); + string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday] + 2); + string[index++] = ','; + string[index++] = ' '; + + /* Convert and append day. */ + _nx_http_server_date_convert(date -> nx_http_server_day, 2, &string[index]); + index += 2; + string[index++] = ' '; + + /* Append month. */ + string[index++] = *(_nx_http_server_month[date -> nx_http_server_month]); + string[index++] = *(_nx_http_server_month[date -> nx_http_server_month] + 1); + string[index++] = *(_nx_http_server_month[date -> nx_http_server_month] + 2); + string[index++] = ' '; + + /* Convert and append year. */ + _nx_http_server_date_convert(date -> nx_http_server_year, 4, &string[index]); + index += 4; + string[index++] = ' '; + + /* Convert and append hour. */ + _nx_http_server_date_convert(date -> nx_http_server_hour, 2, &string[index]); + index += 2; + string[index++] = ':'; + + /* Convert and append minute. */ + _nx_http_server_date_convert(date -> nx_http_server_minute, 2, &string[index]); + index += 2; + string[index++] = ':'; + + /* Convert and append second. */ + _nx_http_server_date_convert(date -> nx_http_server_second, 2, &string[index]); + index += 2; + string[index++] = ' '; + string[index++] = 'G'; + string[index++] = 'M'; + string[index++] = 'T'; + + return index; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_date_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a date from number to string. */ +/* */ +/* INPUT */ +/* */ +/* date The number to convert */ +/* count Digital count for string */ +/* string Pointer to output buffer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_http_server_date_to_string */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_http_server_date_convert(UINT date, UINT count, CHAR *string) +{ + +UINT digit; + + /* Initialize all 4 bytes to digit 0. */ + *((ULONG*)string) = 0x30303030; + string[count] = 0; + + /* Loop to convert the number to ASCII. */ + while(count > 0) + { + count--; + + /* Compute the next decimal digit. */ + digit = date % 10; + + /* Update the input date. */ + date = date / 10; + + /* Store the new digit in ASCII form. */ + string[count] = (CHAR) (digit + 0x30); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_mime_maps_additional_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting additional MIME maps. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* mime_maps Pointer MIME map array */ +/* mime_maps_num Number of MIME map array */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_mime_maps_additional_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (mime_maps == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_http_server_mime_maps_additional_set(server_ptr, mime_maps, mime_maps_num); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_mime_maps_additional_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets additional MIME maps. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* mime_maps Pointer MIME map array */ +/* mime_maps_num Number of MIME map array */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the mime maps. */ + server_ptr -> nx_http_server_mime_maps_additional = mime_maps; + server_ptr -> nx_http_server_mime_maps_additional_num = mime_maps_num; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_digest_authenticate_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for service to set digest */ +/* authenticate callback function. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* digest_authenticate_callback Pointer to application's */ +/* digest authenticate callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_digest_authenticate_notify_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)) +{ + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (digest_authenticate_callback == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + return(_nx_http_server_digest_authenticate_notify_set(http_server_ptr, digest_authenticate_callback)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_digest_authenticate_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets digest authenticate callback function. */ +/* */ +/* Note: The string length of realm_ptr, name_ptr, and password_ptr in */ +/* digest_authenticate_callback is checked internally. The method, */ +/* authorization_uri, authorization_nc and authorization_cnonce in */ +/* digest_authenticate_callback are built internally. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* digest_authenticate_callback Pointer to application's */ +/* digest authenticate callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)) +{ + +#ifdef NX_HTTP_DIGEST_ENABLE + http_server_ptr -> nx_http_server_digest_authenticate_callback = digest_authenticate_callback; + + return(NX_SUCCESS); +#else + NX_PARAMETER_NOT_USED(http_server_ptr); + NX_PARAMETER_NOT_USED(digest_authenticate_callback); + + return(NX_NOT_SUPPORTED); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_http_server_authentication_check_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks errors for setting authentication checking */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* authentication_check_extended Pointer to application's */ +/* authentication checking */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_authentication_check_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (authentication_check_extended == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual authentication checking set function. */ + status= _nx_http_server_authentication_check_set(http_server_ptr, authentication_check_extended); + + /* Return staus. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_http_server_authentication_check_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the callback function of authentication checking.*/ +/* */ +/* Note: The strings of name, password and realm must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* authentication_check_extended Pointer to application's */ +/* authentication checking */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) +{ + + /* Set the extended authentication checking function. */ + http_server_ptr -> nx_http_server_authentication_check_extended = authentication_check_extended; + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/addons/http/nxd_http_server.h b/addons/http/nxd_http_server.h new file mode 100644 index 00000000..8b3401ed --- /dev/null +++ b/addons/http/nxd_http_server.h @@ -0,0 +1,652 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_http_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_HTTP_SERVER_H +#define NXD_HTTP_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_api.h" +/* If not using FileX, define this option and define the file writing services + declared in filex_stub.h. */ +/* #define NX_HTTP_NO_FILEX */ + +#ifndef NX_HTTP_NO_FILEX +#include "fx_api.h" +#else +#include "filex_stub.h" +#endif + +/* Define the HTTP Server ID. */ + +#define NXD_HTTP_SERVER_ID 0x48545451UL + + +/* Define the HTTP version. */ +#define NX_HTTP_VERSION "HTTP/1.0" + +/* Enable Digest authentication. +#define NX_HTTP_DIGEST_ENABLE +*/ + +/* Define HTTP TCP socket create options. */ + +#ifndef NX_HTTP_TYPE_OF_SERVICE +#define NX_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_HTTP_FRAGMENT_OPTION +#define NX_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_HTTP_TIME_TO_LIVE +#define NX_HTTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_HTTP_SERVER_PRIORITY +#define NX_HTTP_SERVER_PRIORITY 16 +#endif + +#ifndef NX_HTTP_SERVER_WINDOW_SIZE +#define NX_HTTP_SERVER_WINDOW_SIZE 2048 +#endif + +#ifndef NX_HTTP_SERVER_TIMEOUT_ACCEPT +#define NX_HTTP_SERVER_TIMEOUT_ACCEPT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_HTTP_SERVER_TIMEOUT_RECEIVE +#define NX_HTTP_SERVER_TIMEOUT_RECEIVE (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_HTTP_SERVER_TIMEOUT_SEND +#define NX_HTTP_SERVER_TIMEOUT_SEND (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_HTTP_SERVER_TIMEOUT_DISCONNECT +#define NX_HTTP_SERVER_TIMEOUT_DISCONNECT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_HTTP_SERVER_TIMEOUT +#define NX_HTTP_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_HTTP_SERVER_MAX_PENDING +#define NX_HTTP_SERVER_MAX_PENDING 5 +#endif + +#ifndef NX_HTTP_SERVER_THREAD_TIME_SLICE +#define NX_HTTP_SERVER_THREAD_TIME_SLICE 2 +#endif + +#ifndef NX_HTTP_MAX_RESOURCE +#define NX_HTTP_MAX_RESOURCE 40 +#endif + +#ifndef NX_HTTP_MAX_NAME +#define NX_HTTP_MAX_NAME 20 +#endif + +#ifndef NX_HTTP_MAX_PASSWORD +#define NX_HTTP_MAX_PASSWORD 20 +#endif + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 +#endif + +#ifndef NX_HTTP_SERVER_MIN_PACKET_SIZE +#define NX_HTTP_SERVER_MIN_PACKET_SIZE 600 +#endif + +/* Define the HTTP server retry parameters. */ + +#ifndef NX_HTTP_SERVER_RETRY_SECONDS +#define NX_HTTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ +#endif + +#ifndef NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH +#define NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ +#endif + +#ifndef NX_HTTP_SERVER_RETRY_MAX +#define NX_HTTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ +#endif + +#ifndef NX_HTTP_SERVER_RETRY_SHIFT +#define NX_HTTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ +#endif + +/* NX_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ +#define NX_HTTP_MAX_STRING ((NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 1) * 4 / 3 + 1) + +#define NX_HTTP_MAX_BINARY_MD5 16 +#define NX_HTTP_MAX_ASCII_MD5 32 + + +/* Define HTTP Server request types. */ + +#define NX_HTTP_SERVER_UNKNOWN_REQUEST 0 +#define NX_HTTP_SERVER_GET_REQUEST 1 +#define NX_HTTP_SERVER_POST_REQUEST 2 +#define NX_HTTP_SERVER_HEAD_REQUEST 3 +#define NX_HTTP_SERVER_PUT_REQUEST 4 +#define NX_HTTP_SERVER_DELETE_REQUEST 5 + + +/* Define return code constants. */ + +#define NX_HTTP_ERROR 0xE0 /* HTTP internal error */ +#define NX_HTTP_TIMEOUT 0xE1 /* HTTP timeout occurred */ +#define NX_HTTP_FAILED 0xE2 /* HTTP error */ +#define NX_HTTP_DONT_AUTHENTICATE 0xE3 /* HTTP authentication not needed */ +#define NX_HTTP_BASIC_AUTHENTICATE 0xE4 /* HTTP basic authentication requested */ +#define NX_HTTP_DIGEST_AUTHENTICATE 0xE5 /* HTTP digest authentication requested */ +#define NX_HTTP_NOT_FOUND 0xE6 /* HTTP request not found */ +#define NX_HTTP_DATA_END 0xE7 /* HTTP end of content area */ +#define NX_HTTP_CALLBACK_COMPLETED 0xE8 /* HTTP user callback completed the processing */ +#define NX_HTTP_POOL_ERROR 0xE9 /* HTTP supplied pool payload is too small */ +#define NX_HTTP_NOT_READY 0xEA /* HTTP client not ready for operation */ +#define NX_HTTP_AUTHENTICATION_ERROR 0xEB /* HTTP client authentication failed */ +#define NX_HTTP_GET_DONE 0xEC /* HTTP client get is complete */ +#define NX_HTTP_BAD_PACKET_LENGTH 0xED /* Invalid packet received - length incorrect */ +#define NX_HTTP_REQUEST_UNSUCCESSFUL_CODE 0xEE /* Received an error code instead of 2xx from server */ +#define NX_HTTP_INCOMPLETE_PUT_ERROR 0xEF /* Server responds before PUT is complete */ +#define NX_HTTP_PASSWORD_TOO_LONG 0xF0 /* Password exceeded expected length */ +#define NX_HTTP_USERNAME_TOO_LONG 0xF1 /* Username exceeded expected length */ +#define NX_HTTP_NO_QUERY_PARSED 0xF2 /* Server unable to find query in client request */ +#define NX_HTTP_IMPROPERLY_TERMINATED_PARAM 0xF3 /* Client request parameter not properly terminated */ +#define NX_HTTP_BOUNDARY_ALREADY_FOUND 0xF4 /* Boundary is already found. */ + +/* Define the HTTP Server TCP port number */ + +#define NX_HTTP_SERVER_PORT 80 /* Port for HTTP server */ + +#ifdef NX_HTTP_DIGEST_ENABLE + +/* Include the MD5 digest header file. */ + +#include "nx_md5.h" + +#endif + +/* Define the status code. */ + +#define NX_HTTP_STATUS_CONTINUE "100 Continue" +#define NX_HTTP_STATUS_SWITCHING_PROTOCOLS "101 Switching Protocols" +#define NX_HTTP_STATUS_OK "200 OK" +#define NX_HTTP_STATUS_CREATED "201 Created" +#define NX_HTTP_STATUS_ACCEPTED "202 Accepted" +#define NX_HTTP_STATUS_NON_AUTH_INFO "203 Non-Authoritative Information" +#define NX_HTTP_STATUS_NO_CONTENT "204 No Content" +#define NX_HTTP_STATUS_RESET_CONTENT "205 Reset Content" +#define NX_HTTP_STATUS_PARTIAL_CONTENT "206 Partial Content" +#define NX_HTTP_STATUS_MULTIPLE_CHOICES "300 Multiple Choices" +#define NX_HTTP_STATUS_MOVED_PERMANETLY "301 Moved Permanently" +#define NX_HTTP_STATUS_FOUND "302 Found" +#define NX_HTTP_STATUS_SEE_OTHER "303 See Other" +#define NX_HTTP_STATUS_NOT_MODIFIED "304 Not Modified" +#define NX_HTTP_STATUS_USE_PROXY "305 Use Proxy" +#define NX_HTTP_STATUS_TEMPORARY_REDIRECT "307 Temporary Redirect" +#define NX_HTTP_STATUS_BAD_REQUEST "400 Bad Request" +#define NX_HTTP_STATUS_UNAUTHORIZED "401 Unauthorized" +#define NX_HTTP_STATUS_PAYMENT_REQUIRED "402 Payment Required" +#define NX_HTTP_STATUS_FORBIDDEN "403 Forbidden" +#define NX_HTTP_STATUS_NOT_FOUND "404 Not Found" +#define NX_HTTP_STATUS_METHOD_NOT_ALLOWED "405 Method Not Allowed" +#define NX_HTTP_STATUS_NOT_ACCEPTABLE "406 Not Acceptable" +#define NX_HTTP_STATUS_PROXY_AUTH_REQUIRED "407 Proxy Authentication Required" +#define NX_HTTP_STATUS_REQUEST_TIMEOUT "408 Request Time-out" +#define NX_HTTP_STATUS_CONFLICT "409 Conflict" +#define NX_HTTP_STATUS_GONE "410 Gone" +#define NX_HTTP_STATUS_LENGTH_REQUIRED "411 Length Required" +#define NX_HTTP_STATUS_PRECONDITION_FAILED "412 Precondition Failed" +#define NX_HTTP_STATUS_ENTITY_TOO_LARGE "413 Request Entity Too Large" +#define NX_HTTP_STATUS_URL_TOO_LARGE "414 Request-URL Too Large" +#define NX_HTTP_STATUS_UNSUPPORTED_MEDIA "415 Unsupported Media Type" +#define NX_HTTP_STATUS_RANGE_NOT_SATISFY "416 Requested range not satisfiable" +#define NX_HTTP_STATUS_EXPECTATION_FAILED "417 Expectation Failed" +#define NX_HTTP_STATUS_INTERNAL_ERROR "500 Internal Server Error" +#define NX_HTTP_STATUS_NOT_IMPLEMENTED "501 Not Implemented" +#define NX_HTTP_STATUS_BAD_GATEWAY "502 Bad Gateway" +#define NX_HTTP_STATUS_SERVICE_UNAVAILABLE "503 Service Unavailable" +#define NX_HTTP_STATUS_GATEWAY_TIMEOUT "504 Gateway Time-out" +#define NX_HTTP_STATUS_VERSION_ERROR "505 HTTP Version not supported" + + +/* Define the max length of header field. */ + +#ifndef NX_HTTP_MAX_HEADER_FIELD +#define NX_HTTP_MAX_HEADER_FIELD 256 +#endif + + +/* Define default MIME type. */ +/* Page 14, Section 5.2, RFC 2045 */ +#define NX_HTTP_SERVER_DEFAULT_MIME "text/plain" + + +/* Define the MIME map structure. */ + +typedef struct NX_HTTP_SERVER_MIME_MAP_STRUCT +{ + CHAR *nx_http_server_mime_map_extension; /* Extension of file */ + CHAR *nx_http_server_mime_map_type; /* MIME type of file */ +} NX_HTTP_SERVER_MIME_MAP; + + +/* Define the date structure. */ + +typedef struct NX_HTTP_SERVER_DATE_STRUCT +{ + USHORT nx_http_server_year; /* Year */ + UCHAR nx_http_server_month; /* Month */ + UCHAR nx_http_server_day; /* Day */ + UCHAR nx_http_server_hour; /* Hour */ + UCHAR nx_http_server_minute; /* Minute */ + UCHAR nx_http_server_second; /* Second */ + UCHAR nx_http_server_weekday; /* Weekday */ +} NX_HTTP_SERVER_DATE; + +/* Define the multipart context data structure. */ + +typedef struct NX_HTTP_SERVER_MULTIPART_STRUCT +{ + + /* Boundary string. */ + UCHAR nx_http_server_multipart_boundary[NX_HTTP_MAX_HEADER_FIELD + 1]; + + /* Offset of available data. */ + UINT nx_http_server_multipart_available_offset; + + /* Length of available data. */ + UINT nx_http_server_multipart_available_length; + + /* Boundary find status. */ + volatile UINT nx_http_server_multipart_boundary_find; + + /* The next packet to process. */ + NX_PACKET *nx_http_server_multipart_next_packet; + + /* Offset of next available data. */ + UINT nx_http_server_multipart_next_available_offset; + + /* The packet returned at last. */ + NX_PACKET *nx_http_server_multipart_last_packet; + +} NX_HTTP_SERVER_MULTIPART; + + +/* Define the HTTP Server data structure. */ + +typedef struct NX_HTTP_SERVER_STRUCT +{ + ULONG nx_http_server_id; /* HTTP Server ID */ + CHAR *nx_http_server_name; /* Name of this HTTP Server */ + NX_IP *nx_http_server_ip_ptr; /* Pointer to associated IP structure */ + CHAR nx_http_server_request_resource[NX_HTTP_MAX_RESOURCE + 1]; + /* Uniform Resource Locator (URL) */ + UINT nx_http_connection_pending; /* Connection pending flag */ + NX_PACKET_POOL *nx_http_server_packet_pool_ptr; /* Pointer to HTTP Server packet pool */ + FX_MEDIA *nx_http_server_media_ptr; /* Pointer to media control block */ + ULONG nx_http_server_get_requests; /* Number of get requests */ + ULONG nx_http_server_head_requests; /* Number of head requests */ + ULONG nx_http_server_put_requests; /* Number of put requests */ + ULONG nx_http_server_delete_requests; /* Number of delete requests */ + ULONG nx_http_server_post_requests; /* Number of post requests */ + ULONG nx_http_server_unknown_requests; /* Number of unknown requests */ + ULONG nx_http_server_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_http_server_total_bytes_received; /* Number of total bytes received */ + ULONG nx_http_server_allocation_errors; /* Number of allocation errors */ + ULONG nx_http_server_connection_failures; /* Number of failed connections */ + ULONG nx_http_server_connection_successes; /* Number of successful connections */ + ULONG nx_http_server_invalid_http_headers; /* Number of invalid http headers */ + FX_FILE nx_http_server_file; /* HTTP file control block */ + NX_TCP_SOCKET nx_http_server_socket; /* HTTP Server TCP socket */ + TX_THREAD nx_http_server_thread; /* HTTP server thread */ +#ifdef NX_HTTP_DIGEST_ENABLE + NX_MD5 nx_http_server_md5data; /* HTTP server MD5 work area */ +#endif /* NX_HTTP_DIGEST_ENABLE */ + +#ifdef NX_HTTP_MULTIPART_ENABLE + NX_HTTP_SERVER_MULTIPART + nx_http_server_multipart; /* HTTP multipart area */ +#endif /* NX_HTTP_MULTIPART_ENABLE */ + + UINT nx_http_server_request_type; /* HTTP request type */ + NX_HTTP_SERVER_MIME_MAP + *nx_http_server_mime_maps_additional; /* Additional HTTP MIME maps */ + UINT nx_http_server_mime_maps_additional_num; /* Number of additional HTTP MIME maps */ + /* Define the user supplied routines that are used to inform the application of particular server requests. */ + + UINT (*nx_http_server_authentication_check)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm); + UINT (*nx_http_server_authentication_check_extended)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length); + UINT (*nx_http_server_request_notify)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr); + UINT (*nx_http_server_invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type); + VOID (*nx_http_server_gmt_get)(NX_HTTP_SERVER_DATE *date); + UINT (*nx_http_server_cache_info_get)(CHAR *resource, UINT *max_age, NX_HTTP_SERVER_DATE *last_modified); +#ifdef NX_HTTP_DIGEST_ENABLE + UINT (*nx_http_server_digest_authenticate_callback)(struct NX_HTTP_SERVER_STRUCT *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce); +#endif +} NX_HTTP_SERVER; + + +#ifndef NX_HTTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_http_server_callback_data_send _nx_http_server_callback_data_send +#define nx_http_server_callback_response_send _nx_http_server_callback_response_send +#define nx_http_server_callback_response_send_extended _nx_http_server_callback_response_send_extended +#define nx_http_server_content_get _nx_http_server_content_get +#define nx_http_server_content_length_get _nx_http_server_content_length_get +#define nx_http_server_create _nx_http_server_create +#define nx_http_server_delete _nx_http_server_delete +#define nx_http_server_param_get _nx_http_server_param_get +#define nx_http_server_query_get _nx_http_server_query_get +#define nx_http_server_start _nx_http_server_start +#define nx_http_server_stop _nx_http_server_stop +#define nx_http_server_content_get_extended _nx_http_server_content_get_extended +#define nx_http_server_content_length_get_extended _nx_http_server_content_length_get_extended +#define nx_http_server_get_entity_header _nx_http_server_get_entity_header +#define nx_http_server_get_entity_content _nx_http_server_get_entity_content +#define nx_http_server_callback_generate_response_header _nx_http_server_callback_generate_response_header +#define nx_http_server_callback_generate_response_header_extended _nx_http_server_callback_generate_response_header_extended +#define nx_http_server_callback_packet_send _nx_http_server_callback_packet_send +#define nx_http_server_gmt_callback_set _nx_http_server_gmt_callback_set +#define nx_http_server_cache_info_callback_set _nx_http_server_cache_info_callback_set +#define nx_http_server_mime_maps_additional_set _nx_http_server_mime_maps_additional_set +#define nx_http_server_type_get _nx_http_server_type_get +#define nx_http_server_type_get_extended _nx_http_server_type_get_extended +#define nx_http_server_packet_content_find _nx_http_server_packet_content_find +#define nx_http_server_packet_get _nx_http_server_packet_get +#define nx_http_server_invalid_userpassword_notify_set _nx_http_server_invalid_userpassword_notify_set +#define nx_http_server_digest_authenticate_notify_set _nx_http_server_digest_authenticate_notify_set +#define nx_http_server_authentication_check_set _nx_http_server_authentication_check_set + +#else + +/* Services with error checking. */ + +#define nx_http_server_callback_data_send _nxe_http_server_callback_data_send +#define nx_http_server_callback_response_send _nxe_http_server_callback_response_send +#define nx_http_server_callback_response_send_extended _nxe_http_server_callback_response_send_extended +#define nx_http_server_content_get _nxe_http_server_content_get +#define nx_http_server_content_length_get _nxe_http_server_content_length_get +#define nx_http_server_create(p,n,i,m,sp,ss,pp,a,r) _nxe_http_server_create(p,n,i,m,sp,ss,pp,a,r,sizeof(NX_HTTP_SERVER)) +#define nx_http_server_delete _nxe_http_server_delete +#define nx_http_server_param_get _nxe_http_server_param_get +#define nx_http_server_query_get _nxe_http_server_query_get +#define nx_http_server_start _nxe_http_server_start +#define nx_http_server_stop _nxe_http_server_stop +#define nx_http_server_content_get_extended _nxe_http_server_content_get_extended +#define nx_http_server_content_length_get_extended _nxe_http_server_content_length_get_extended +#define nx_http_server_get_entity_header _nxe_http_server_get_entity_header +#define nx_http_server_get_entity_content _nxe_http_server_get_entity_content +#define nx_http_server_callback_generate_response_header _nxe_http_server_callback_generate_response_header +#define nx_http_server_callback_generate_response_header_extended _nxe_http_server_callback_generate_response_header_extended +#define nx_http_server_callback_packet_send _nxe_http_server_callback_packet_send +#define nx_http_server_gmt_callback_set _nxe_http_server_gmt_callback_set +#define nx_http_server_cache_info_callback_set _nxe_http_server_cache_info_callback_set +#define nx_http_server_mime_maps_additional_set _nxe_http_server_mime_maps_additional_set +#define nx_http_server_type_get _nxe_http_server_type_get +#define nx_http_server_type_get_extended _nxe_http_server_type_get_extended +#define nx_http_server_packet_content_find _nxe_http_server_packet_content_find +#define nx_http_server_packet_get _nxe_http_server_packet_get +#define nx_http_server_invalid_userpassword_notify_set _nxe_http_server_invalid_userpassword_notify_set +#define nx_http_server_digest_authenticate_notify_set _nxe_http_server_digest_authenticate_notify_set +#define nx_http_server_authentication_check_set _nxe_http_server_authentication_check_set + +#endif + +/* Define the prototypes accessible to the application software. */ + + +UINT nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT information_length, CHAR *additional_info, UINT additional_info_length); +UINT nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); +UINT nx_http_server_content_length_get(NX_PACKET *packet_ptr); +#ifdef NX_DISABLE_ERROR_CHECKING +UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); +#else +UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), + UINT http_server_size); +#endif /* NX_DISABLE_ERROR_CHECKING */ +UINT nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr); +UINT nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); +UINT nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); +UINT nx_http_server_start(NX_HTTP_SERVER *http_server_ptr); +UINT nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr); +UINT nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length); +UINT nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length); +UINT nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)); +UINT nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); +UINT nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); +UINT nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); +UINT nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); +UINT nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + +#else + +/* HTTP source code is being compiled, do not perform any API mapping. */ + +UINT _nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT _nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT _nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT infomation_length, CHAR *additional_info, UINT additional_info_length); +UINT _nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nx_http_server_content_length_get(NX_PACKET *packet_ptr); +UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); +UINT _nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr); +UINT _nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); +UINT _nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); +UINT _nx_http_server_start(NX_HTTP_SERVER *http_server_ptr); +UINT _nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr); +UINT _nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length); +UINT _nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT _nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT _nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT _nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length); +UINT _nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_callback)(NX_HTTP_SERVER_DATE *)); +UINT _nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); +UINT _nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT _nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); +UINT _nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT _nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); +UINT _nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT _nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + + + +/* Define internal HTTP Server functions. */ + +VOID _nx_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); +VOID _nx_http_server_thread_entry(ULONG http_server_address); +UINT _nx_http_server_get_client_request(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +VOID _nx_http_server_get_process(NX_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr); +VOID _nx_http_server_put_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +VOID _nx_http_server_delete_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nx_http_server_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT information_length, CHAR *additional_info, UINT additional_info_length); +UINT _nx_http_server_basic_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present); +UINT _nx_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr); +UINT _nx_http_server_retrieve_resource(NX_PACKET *packet_ptr, CHAR *destination, UINT max_size); +UINT _nx_http_server_calculate_content_offset(NX_PACKET *packet_ptr); +UINT _nx_http_server_number_convert(UINT number, CHAR *string); +UINT _nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); +UINT _nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); +VOID _nx_http_base64_encode(CHAR *name, UINT length, CHAR *base64name); +VOID _nx_http_base64_decode(CHAR *base64name, UINT length, CHAR *name); + +#ifdef NX_HTTP_DIGEST_ENABLE +UINT _nx_http_server_digest_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, UINT name_length, CHAR *password_ptr, UINT password_length, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present); +VOID _nx_http_server_digest_response_calculate(NX_HTTP_SERVER *server_ptr, CHAR *username, UINT username_length, CHAR *realm, UINT realm_length, CHAR *password, UINT password_length, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result); +UINT _nx_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce); +VOID _nx_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); +#endif + +#ifdef NX_HTTP_MULTIPART_ENABLE +UINT _nx_http_server_boundary_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr); +#endif /* NX_HTTP_MULTIPART_ENABLE */ + +UINT _nx_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr); +UINT _nx_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size); +UINT _nx_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); + +UINT _nx_http_server_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length); +UINT _nx_http_server_date_to_string(NX_HTTP_SERVER_DATE *date, CHAR *string); +VOID _nx_http_server_date_convert(UINT date, UINT count, CHAR *string); + +UINT _nxe_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT _nxe_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT _nxe_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT infomation_length, CHAR *additional_info, UINT additional_info_length); +UINT _nxe_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nxe_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); +UINT _nxe_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT _nxe_http_server_content_length_get(NX_PACKET *packet_ptr); +UINT _nxe_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nxe_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *content_length); +UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), + UINT http_server_size); +UINT _nxe_http_server_delete(NX_HTTP_SERVER *http_server_ptr); +UINT _nxe_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); +UINT _nxe_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); +UINT _nxe_http_server_start(NX_HTTP_SERVER *http_server_ptr); +UINT _nxe_http_server_stop(NX_HTTP_SERVER *http_server_ptr); +UINT _nxe_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)); +UINT _nxe_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); +UINT _nxe_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); +UINT _nxe_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT _nxe_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT _nxe_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT _nxe_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, UINT additional_header_length); +UINT _nxe_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nxe_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)); +UINT _nxe_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); +UINT _nxe_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT _nxe_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT _nxe_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + +#endif /* NX_HTTP_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_HTTP_SERVER_H */ diff --git a/addons/mdns/nxd_mdns.c b/addons/mdns/nxd_mdns.c new file mode 100644 index 00000000..4a12357e --- /dev/null +++ b/addons/mdns/nxd_mdns.c @@ -0,0 +1,13867 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Multicast Domain Name System (mDNS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define NX_MDNS_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif /* NX_DISABLE_ERROR_CHECKING */ + + +/* Include necessary system files. */ +#include "nxd_mdns.h" +#include "tx_thread.h" + +/* Define the application protocol. */ +static CHAR *nx_mdns_app_protocol[]= {"_tcp", "_udp", NX_NULL}; + +/* Define the service type. */ +#ifndef NX_MDNS_DISABLE_CLIENT +static CHAR *nx_mdns_service_types[] = +{ + "_device-info", + "_http", + "_https", + "_guid", + "_h323", + "_ntp", + "_objective", + "_rdp", + "_remote", + "_rtsp", + "_sip", + "_smb", + "_soap", + "_ssh", + "_telnet", + "_tftp", + "_xmpp-client", + NX_NULL +}; +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/* Define the mDNS internal Function. */ +static VOID _nx_mdns_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); +static VOID _nx_mdns_timer_entry(ULONG mdns_value); +static VOID _nx_mdns_timer_set(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr, ULONG timer_count); +static VOID _nx_mdns_timer_event_process(NX_MDNS *mdns_ptr); +static VOID _nx_mdns_thread_entry(ULONG mdns_value); +static UINT _nx_mdns_packet_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index); +static UINT _nx_mdns_packet_create(NX_MDNS *mdns_ptr, NX_PACKET **packet_ptr, UCHAR type); +static VOID _nx_mdns_packet_send(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index); +static UINT _nx_mdns_packet_rr_add(NX_PACKET *packet_ptr, NX_MDNS_RR *rr, UINT op, UINT packet_type); +static UINT _nx_mdns_packet_rr_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op, UINT interface_index); +static UINT _nx_mdns_packet_rr_data_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op); +#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK +static UINT _nx_mdns_packet_address_check(NX_PACKET *packet_ptr); +#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ +static UINT _nx_mdns_service_name_assemble(UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *domain, UCHAR *record_buffer, UINT buffer_size, UINT *type_index); +static UINT _nx_mdns_service_name_resolve(UCHAR *srv_name, UCHAR **name, UCHAR **type, UCHAR **domain); +static UINT _nx_mdns_rr_delete(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr); +static UINT _nx_mdns_rr_size_get(UCHAR *resource); +static UINT _nx_mdns_name_match(UCHAR *src, UCHAR *dst, UINT length); +static UINT _nx_mdns_name_size_calculate(UCHAR *name); +static UINT _nx_mdns_name_string_encode(UCHAR *ptr, UCHAR *name); +static UINT _nx_mdns_name_string_decode(UCHAR *data, UINT start, UCHAR *buffer, UINT size); +static UINT _nx_mdns_txt_string_encode(UCHAR *ptr, UCHAR *name); +static UINT _nx_mdns_txt_string_decode(UCHAR *data, UINT data_length, UCHAR *buffer, UINT size); +static VOID _nx_mdns_short_to_network_convert(UCHAR *ptr, USHORT value); +static VOID _nx_mdns_long_to_network_convert(UCHAR *ptr, ULONG value); + +#ifndef NX_MDNS_DISABLE_SERVER +static VOID _nx_mdns_address_change_process(NX_MDNS *mdns_ptr); +static UINT _nx_mdns_host_name_register(NX_MDNS *mdns_ptr, UCHAR type, UINT interface_index); +static UINT _nx_mdns_service_interface_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT interface_index); +#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 +static UINT _nx_mdns_rr_a_aaaa_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG *address, UINT addr_length, UCHAR type, UINT interface_index); +#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ +static UINT _nx_mdns_rr_srv_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, USHORT priority, USHORT weights, USHORT port, UCHAR *target, NX_MDNS_RR **insert_rr, UINT interface_index); +static UINT _nx_mdns_rr_txt_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *txt, NX_MDNS_RR **insert_rr, UINT interface_index); +static UINT _nx_mdns_rr_ptr_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *ptr_name, UCHAR is_valid, NX_MDNS_RR **insert_rr, UINT interface_index); + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES +static UINT _nx_mdns_rr_nsec_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR add_a, UCHAR add_aaaa, UCHAR type, UINT interface_index); +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + +static UINT _nx_mdns_rr_parameter_set(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, ULONG ttl, UINT rdata_length, UCHAR set, UCHAR is_register, UCHAR is_valid, NX_MDNS_RR *rr_record, UINT interface_index); +static UINT _nx_mdns_conflict_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr); +static UINT _nx_mdns_additional_resource_record_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr); +static VOID _nx_mdns_additional_a_aaaa_find(NX_MDNS *mdns_ptr, UCHAR *name, UINT interface_index); +static VOID _nx_mdns_probing_send(NX_MDNS *mdns_ptr, UINT interface_index); +static VOID _nx_mdns_announcing_send(NX_MDNS *mdns_ptr, UINT interface_index); +static VOID _nx_mdns_response_send(NX_MDNS *mdns_ptr, UINT interface_index); +static VOID _nx_mdns_ip_address_change_notify(NX_IP *ip_ptr, VOID *additional_info); +#ifdef NX_MDNS_ENABLE_IPV6 +static VOID _nx_mdns_ipv6_address_change_notify(NX_IP *ip_ptr, UINT method, UINT interface_index, UINT index, ULONG *ipv6_address); +#endif /* NX_MDNS_ENABLE_IPV6 */ +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT +static VOID _nx_mdns_service_change_notify_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *new_rr, UCHAR is_present); +static UINT _nx_mdns_service_addition_info_get(NX_MDNS *mdns_ptr, UCHAR *srv_name, NX_MDNS_SERVICE *service, UINT interface_index); +static UINT _nx_mdns_service_mask_match(NX_MDNS *mdns_ptr, UCHAR *service_type, ULONG service_mask); +static UINT _nx_mdns_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, NX_MDNS_RR **out_rr, ULONG wait_option, UINT interface_index); +static UINT _nx_mdns_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT interface_index); +static VOID _nx_mdns_query_send(NX_MDNS *mdns_ptr, UINT interface_index); +static UINT _nx_mdns_query_check(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT one_shot, NX_MDNS_RR **search_rr, UINT interface_index); +static VOID _nx_mdns_query_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +static VOID _nx_mdns_query_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), + NX_MDNS *mdns_ptr, NX_MDNS_RR **rr, ULONG wait_option); +static VOID _nx_mdns_query_thread_resume(TX_THREAD **suspension_list_head, NX_MDNS *mdns_ptr, NX_MDNS_RR *rr); +static UINT _nx_mdns_known_answer_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr); +static UINT _nx_mdns_packet_rr_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UINT interface_index); +#endif /* NX_MDNS_DISABLE_CLIENT */ + +UINT _nx_mdns_cache_initialize(NX_MDNS *mdns_ptr, VOID *local_cache_ptr, UINT local_cache_size, VOID *peer_cache_ptr, UINT peer_cache_size); +UINT _nx_mdns_cache_add_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, NX_MDNS_RR **insert_ptr, UCHAR *is_present); +UINT _nx_mdns_cache_delete_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr); +UINT _nx_mdns_cache_find_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, UINT match_type, NX_MDNS_RR **search_result); +UINT _nx_mdns_cache_add_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len, VOID **insert_ptr, UCHAR find_string, UCHAR add_name); +UINT _nx_mdns_cache_delete_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len); +VOID _nx_mdns_cache_delete_rr_string(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_rr); + + +/* Define the mDNS STRUCT. */ +static struct NX_MDNS_STRUCT *_nx_mdns_created_ptr; +static CHAR _nx_mdns_dns_sd[NX_MDNS_DNS_SD_MAX + 1] = "_services._dns-sd._udp.local"; +static UCHAR temp_string_buffer[NX_MDNS_NAME_MAX + 1]; +static UCHAR target_string_buffer[NX_MDNS_NAME_MAX + 1]; + +#ifdef NX_MDNS_ENABLE_IPV6 +static NXD_ADDRESS NX_MDNS_IPV6_MULTICAST_ADDRESS; +#endif /* NX_MDNS_ENABLE_IPV6 */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS create function call */ +/* */ +/* Note: the name string is generated by internal logic and it is */ +/* always NULL-terminated. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* ip_ptr Pointer to IP instance */ +/* priority The priority of mDNS Thread */ +/* stack_ptr Stack pointer for mDNS Thread */ +/* stack_size Stack size for mDNS Thread */ +/* host_name Pointer to host name */ +/* local_cache_ptr Pointer to local cache */ +/* local_cache_size The size of local cache */ +/* peer_cache_ptr Pointer to peer cache */ +/* peer_cache_size The size of peer cache */ +/* probing_notify mDNS probing notify */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_create Actual mDNS create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, + UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, + VOID *local_cache_ptr, UINT local_cache_size, + VOID *peer_cache_ptr, UINT peer_cache_size, + VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)) +{ + +UINT status; +UCHAR *ptr; + + + /* Check for invalid input pointers. */ + if ((!ip_ptr) || (!mdns_ptr) || (!stack_ptr) || (!packet_pool) || (!host_name)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if ((ip_ptr -> nx_ip_id != NX_IP_ID) || + (stack_size < TX_MINIMUM_STACK) || + (mdns_ptr -> nx_mdns_id == NX_MDNS_ID)) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check the host name format, RFC 1033,1034,1035 recomend that host names contain only letters, digits, and hyphens RFC6763, Appendix E, Page44. */ + ptr = host_name; + while (*ptr != '\0') + { + if (((*ptr >= 'a') && (*ptr <= 'z')) || + ((*ptr >= 'A') && (*ptr <= 'Z')) || + ((*ptr >= '0') && (*ptr <= '9')) || + ((*ptr == '-'))) + ptr++; + else + return(NX_MDNS_HOST_NAME_ERROR); + } + + /* Check the default domain name size. */ + if ((sizeof("local") - 1) > NX_MDNS_DOMAIN_NAME_MAX) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Check for invalid input pointers, cache header and tail (8 bytes). */ + if ((!local_cache_ptr) || (local_cache_size < 8)) + { + return(NX_PTR_ERROR); + } + + /* Make sure record_buffer is 4-byte aligned. */ + if ((((UINT)local_cache_ptr & 0x3) != 0) || + ((local_cache_size & 0x3) != 0)) + { + return(NX_MDNS_CACHE_ERROR); + } +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT + + /* Check for invalid input pointers, cache header and tail (8 bytes). */ + if ((!peer_cache_ptr) || (peer_cache_size < 8)) + { + return(NX_PTR_ERROR); + } + + /* Make sure peer cache is 4-byte aligned. */ + if ((((UINT)peer_cache_ptr & 0x3) != 0) || + ((peer_cache_size & 0x3) != 0)) + { + return(NX_MDNS_CACHE_ERROR); + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + + /* Call actual mDNS create service. */ + status = _nx_mdns_create(mdns_ptr, ip_ptr, packet_pool, priority, + stack_ptr, stack_size, host_name, + local_cache_ptr, local_cache_size, + peer_cache_ptr, peer_cache_size, + probing_notify); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the mDNS structure and associated IP */ +/* instance for mDNS operation. In doing so, it creates a UDP socket */ +/* for communication with the server and a mDNS processing thread */ +/* */ +/* Note: the name string is generated by internal logic and it is */ +/* always NULL-terminated. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* ip_ptr Pointer to IP instance */ +/* priority The priority of mDNS Thread */ +/* stack_ptr Stack pointer for mDNS Thread */ +/* stack_size Stack size for mDNS Thread */ +/* host_name Pointer to host name */ +/* local_cache_ptr Pointer to local cache */ +/* local_cache_size The size of local cache */ +/* peer_cache_ptr Pointer to peer cache */ +/* peer_cache_size The size of peer cache */ +/* probing_notify mDNS probing notify */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_create Create the mDNS UDP socket */ +/* nx_udp_socket_delete Delete the mDNS UDP socket */ +/* nx_udp_socket_bind Bind the mDNS UDP socket */ +/* nx_udp_socket_unbind Unbind the mDNS UDP socket */ +/* nx_udp_socket_receive_notify Register the mDNS function */ +/* nx_ip_address_change_notify Register IPv4 address function*/ +/* nxd_ipv6_address_change_notify Register IPv6 address function*/ +/* tx_mutex_create Create the mDNS mutex */ +/* tx_mutex_delete Delete the mDNS mutex */ +/* tx_thread_create Create the mDNS thread */ +/* tx_thread_delete Delete the mDNS thread */ +/* tx_event_flags_create Create the ThreadX flag event */ +/* _nx_mdns_cache_initialize Initialize the mDNS cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, + UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, + VOID *local_cache_ptr, UINT local_cache_size, + VOID *peer_cache_ptr, UINT peer_cache_size, + VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)) +{ + +UINT status; +UINT host_name_size; + + + /* Check the size of the host name string. The last four characters in the + host_name are reserved so DNS-SD is able to append " (2)" during the conflict + resolution process. */ +#if (NX_MDNS_HOST_NAME_MAX >= NX_MDNS_LABEL_MAX) + if (_nx_utility_string_length_check((CHAR *)host_name, &host_name_size, (NX_MDNS_LABEL_MAX - 4))) +#else + if (_nx_utility_string_length_check((CHAR *)host_name, &host_name_size, (NX_MDNS_HOST_NAME_MAX - 4))) +#endif + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Initialize the mDNS control block to zero. */ + memset((void *) mdns_ptr, 0, sizeof(NX_MDNS)); + +#ifdef NX_MDNS_ENABLE_IPV6 + + /* Initialize the IPv6 Multicast address. */ + memset(&NX_MDNS_IPV6_MULTICAST_ADDRESS, 0, sizeof(NXD_ADDRESS)); + NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_version = NX_IP_VERSION_V6; + NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0] = 0xFF020000; + NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1] = 0x00000000; + NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2] = 0x00000000; + NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3] = 0x000000FB; +#endif /* NX_MDNS_ENABLE_IPV6 */ + + /* Save the IP pointer. */ + mdns_ptr -> nx_mdns_ip_ptr = ip_ptr; + + /* Save the Packet pool. */ + mdns_ptr -> nx_mdns_packet_pool_ptr = packet_pool; + + /* Save the host name. */ + memcpy((char*)mdns_ptr -> nx_mdns_host_name, (const char*)host_name, (host_name_size + 1)); + + /* Set the domain name as "local" by default. */ + memcpy((char*)mdns_ptr -> nx_mdns_domain_name, "local", sizeof("local")); + + /* Assign the resource record change notify. */ + mdns_ptr -> nx_mdns_probing_notify = probing_notify; + + /* Set the mDNS announcing period. */ + mdns_ptr -> nx_mdns_announcing_period = (USHORT)NX_MDNS_ANNOUNCING_PERIOD; + + /* Set the mDNS announcing retransmission interval. */ + mdns_ptr -> nx_mdns_announcing_retrans_interval = (USHORT)NX_MDNS_ANNOUNCING_RETRANS_INTERVAL; + + /* Set the mDNS announcing period interval. */ + mdns_ptr -> nx_mdns_announcing_period_interval = (ULONG)NX_MDNS_ANNOUNCING_PERIOD_INTERVAL; + + /* Set the mDNS announcing count between one announcing period. */ + mdns_ptr -> nx_mdns_announcing_count = (UCHAR)NX_MDNS_ANNOUNCING_COUNT; + + /* Set the mDNS announcing factor. */ + mdns_ptr -> nx_mdns_announcing_factor = (UCHAR)NX_MDNS_ANNOUNCING_FACTOR; + + /* Set the mDNS announcing max time. */ + mdns_ptr -> nx_mdns_announcing_max_time = (UCHAR)NX_MDNS_ANNOUNCING_MAX_TIME; + + /* Set the pointer of global variable mDNS. */ + _nx_mdns_created_ptr = mdns_ptr; + +#ifndef NX_MDNS_DISABLE_SERVER + /* Register IP address change callback. */ + status = nx_ip_address_change_notify(mdns_ptr -> nx_mdns_ip_ptr, _nx_mdns_ip_address_change_notify, NX_NULL); + + /* Check for error */ + if (status) + { + return(status); + } + +#ifdef NX_MDNS_ENABLE_IPV6 + /* Register IPv6 address change callback. */ + status = nxd_ipv6_address_change_notify(mdns_ptr -> nx_mdns_ip_ptr, _nx_mdns_ipv6_address_change_notify); + + /* Check for error */ + if (status) + { + return(status); + } +#endif /* NX_MDNS_ENABLE_IPV6 */ +#endif /* NX_MDNS_DISABLE_SERVER */ + + /* Create the Socket and check the status */ + status = nx_udp_socket_create(mdns_ptr -> nx_mdns_ip_ptr, &(mdns_ptr -> nx_mdns_socket), "Multicast DNS", + NX_MDNS_UDP_TYPE_OF_SERVICE, NX_MDNS_UDP_FRAGMENT_OPTION, + NX_MDNS_UDP_TIME_TO_LIVE, NX_MDNS_UDP_QUEUE_DEPTH); + + /* Determine if it was successful. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Bind the UDP socket to the mDNS port. */ + status = nx_udp_socket_bind(&(mdns_ptr -> nx_mdns_socket), NX_MDNS_UDP_PORT, TX_NO_WAIT); + + /* Check for error */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + return(status); + } + + /* Register UDP receive callback. */ + status = nx_udp_socket_receive_notify(&(mdns_ptr -> nx_mdns_socket), _nx_mdns_udp_receive_notify); + + /* Check for error */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + return(status); + } + + /* Create the mDNS mutex. */ + status = tx_mutex_create(&(mdns_ptr -> nx_mdns_mutex), + "mDNS Mutex", TX_NO_INHERIT); + + /* Determine if the semaphore creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* No, return error status. */ + return(status); + } + + /* Create the internal mDNS event flag object. */ + status = tx_event_flags_create(&mdns_ptr -> nx_mdns_events, "mDNS Thread Events"); + + /* Determine if the event flags creation was successful. */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* Delete the mDNS mutex. */ + tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); + + /* No, return error status. */ + return(status); + } + + /* Create the mDNS processing thread. */ + status = tx_thread_create(&(mdns_ptr -> nx_mdns_thread), "mDNS Thread", + _nx_mdns_thread_entry, (ULONG) mdns_ptr, + stack_ptr, stack_size, priority, priority, + 1, TX_AUTO_START); + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* Delete the mDNS mutex. */ + tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); + + /* Delete the mDNS events. */ + tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); + + /* No, return error status. */ + return(status); + } + + /* Create the timer of Resource record lifetime. */ + status = tx_timer_create(&(mdns_ptr -> nx_mdns_timer), "mDNS Timer", + _nx_mdns_timer_entry, (ULONG) mdns_ptr, + 0xFFFFFFFF, 0, TX_NO_ACTIVATE); + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* Delete the mDNS mutex. */ + tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); + + /* Delete the mDNS events. */ + tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); + + /* Delete the mDNS thread. */ + tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); + + /* No, return error status. */ + return(status); + } + + /* Initialize the buffer. */ + status = _nx_mdns_cache_initialize(mdns_ptr, local_cache_ptr, local_cache_size, + peer_cache_ptr, peer_cache_size); + + /* Determine if the buffer initialize was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* Delete the mDNS timer. */ + tx_timer_delete(&(mdns_ptr -> nx_mdns_timer)); + + /* Delete the mDNS mutex. */ + tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); + + /* Delete the mDNS events. */ + tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); + + /* Delete the mDNS thread. */ + tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); + + /* No, return error status. */ + return(status); + } + + /* Update the mDNS structure ID. */ + mdns_ptr -> nx_mdns_id = NX_MDNS_ID; + + /* The random delay of first probing for RR. */ + mdns_ptr -> nx_mdns_first_probing_delay = (ULONG)(1 + (NX_RAND() % NX_MDNS_PROBING_TIMER_COUNT)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS delete function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_delete Actual mDNS delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_delete(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS delete service. */ + status = _nx_mdns_delete(mdns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS instance. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind the mDNS UDP socket */ +/* nx_udp_socket_delete Delete the mDNS UDP socket */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* tx_mutex_delete Delete the mDNS mutex */ +/* tx_thread_terminate Terminate the mDNS thread */ +/* tx_thread_delete Delete the mDNS thread */ +/* tx_event_flags_delete Delete the mDNS events flag */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_delete(NX_MDNS *mdns_ptr) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Clear the mDNS structure ID. */ + mdns_ptr -> nx_mdns_id = 0; + + /* Set the pointer of global variable mDNS. */ + _nx_mdns_created_ptr = NX_NULL; + + /* Unbind the port. */ + nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); + + /* Terminate the mDNS processing thread. */ + tx_thread_terminate(&(mdns_ptr -> nx_mdns_thread)); + + /* Delete the mDNS processing thread. */ + tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); + + /* Delete the event flags. */ + tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); + + /* Delete the timer. */ + tx_timer_delete(&(mdns_ptr -> nx_mdns_timer)); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Delete the mDNS mutex. */ + tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS cache full notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_notify_set Actual cache notify */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT, UINT)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS cache notify set function. */ + status = _nx_mdns_cache_notify_set(mdns_ptr, cache_full_notify_cb); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the cache full notify function. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT, UINT)) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the cache notify. */ + mdns_ptr -> nx_mdns_cache_full_notify = cache_full_notify_cb; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_cache_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS cache full notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_notify_clear Actual cache notify */ +/* clear function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_cache_notify_clear(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS cache notify clear function. */ + status = _nx_mdns_cache_notify_clear(mdns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the cache full notify function. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_notify_clear(NX_MDNS *mdns_ptr) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Clear the cache notify. */ + mdns_ptr -> nx_mdns_cache_full_notify = NX_NULL; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_ignore_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS service ignore mask */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* service_mask The service mask */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_ignore_set Actual ignore set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS service ignore mask set function. */ + status = _nx_mdns_service_ignore_set(mdns_ptr, service_mask); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_ignore_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the service mask to ignore the service. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* service_mask The service mask */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the MDNS mutex */ +/* tx_mutex_put Put the MDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the service ignore mask. */ + mdns_ptr -> nx_mdns_service_ignore_mask = service_mask; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS service notify function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* service_mask The service mask */ +/* service_change_notify Service change notify function*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_notify_set Actual mDNS service notify */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, + VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS service notify set function. */ + status = _nx_mdns_service_notify_set(mdns_ptr, service_mask, service_change_notify); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the service mask and notify callback function. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* service_mask The service mask */ +/* service_change_notify Service change notify function*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, + VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the service mask. */ + mdns_ptr -> nx_mdns_service_notify_mask = service_mask; + + /* Assign the service change notify. */ + mdns_ptr -> nx_mdns_service_change_notify = service_change_notify; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS service notify function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_notify_clear Actual service notify */ +/* clear function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_notify_clear(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS service notify clear function. */ + status = _nx_mdns_service_notify_clear(mdns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_notify_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the service mask and notify callback function. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_notify_clear(NX_MDNS *mdns_ptr) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Clear the service mask. */ + mdns_ptr -> nx_mdns_service_notify_mask = 0; + + /* Clear the service change notify. */ + mdns_ptr -> nx_mdns_service_change_notify = NX_NULL; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_announcement_timing_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS announcement timing */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* t Announcing period */ +/* p Announcing count */ +/* k Announcing factor */ +/* retrans_interval Announcing retransmission */ +/* interval */ +/* interval Announcing period interval */ +/* max_time Announcing max time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_announcement_timing_set */ +/* Actual mDNS announcement */ +/* timing set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((!mdns_ptr) || (!t) || (!p) || (!k) || (!period_interval) || (!max_time)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS delete service. */ + status = _nx_mdns_service_announcement_timing_set(mdns_ptr, t, p, k, retrans_interval, period_interval, max_time); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_announcement_timing_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the service mask and notify callback function. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* t Announcing period */ +/* p Announcing count */ +/* k Announcing factor */ +/* retrans_interval Announcing retransmission */ +/* interval */ +/* interval Announcing period interval */ +/* max_time Announcing max time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time) +{ + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the mDNS announcing period. */ + mdns_ptr -> nx_mdns_announcing_period = (USHORT)t; + + /* Set the mDNS announcing count between one announcing period. */ + mdns_ptr -> nx_mdns_announcing_count = (UCHAR)p; + + /* Set the mDNS announcing factor. */ + mdns_ptr -> nx_mdns_announcing_factor = (UCHAR)k; + + /* Set the mDNS announcing retransmission interval. */ + mdns_ptr -> nx_mdns_announcing_retrans_interval = (USHORT)retrans_interval; + + /* Set the mDNS announcing period interval. */ + mdns_ptr -> nx_mdns_announcing_period_interval = (ULONG)period_interval; + + /* Set the mDNS announcing max time. */ + mdns_ptr -> nx_mdns_announcing_max_time = (UCHAR)max_time; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS enable function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_enable Actual mDNS enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input or invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS delete service. */ + status = _nx_mdns_enable(mdns_ptr, interface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the mDNS of the physical host interface by */ +/* interface index. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* nx_ipv4_multicast_interface_join Join the IPv4 Multicast group */ +/* nxd_ipv6_multicast_interface_join Join the IPv6 Multicast group */ +/* _nx_mdns_host_name_register Register the host name */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; + +#ifndef NX_MDNS_DISABLE_SERVER +ULONG *head; +NX_MDNS_RR *p; +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifdef NX_MDNS_ENABLE_IPV6 +NX_INTERFACE *interface_ptr; +NXD_IPV6_ADDRESS *ipv6_address; +#endif /* NX_MDNS_ENABLE_IPV6 */ + + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check to see if mDNS is already enabled on this interface. */ + if (mdns_ptr -> nx_mdns_interface_enabled[interface_index] == NX_TRUE) + { + return(NX_MDNS_ALREADY_ENABLED); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Enable the mdns function. */ + mdns_ptr -> nx_mdns_interface_enabled[interface_index] = NX_TRUE; + +#ifdef NX_MDNS_ENABLE_IPV6 + /* Set the interface pointer. */ + interface_ptr = &(mdns_ptr -> nx_mdns_ip_ptr -> nx_ip_interface[interface_index]); + + /* Find the link-local address as source adress. Get first address from interface. */ + ipv6_address = interface_ptr -> nxd_interface_ipv6_address_list_head; + + /* Loop to check the address. */ + while (ipv6_address) + { + + /* Check for link-local address. */ + if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL) + { + break; + } + ipv6_address = ipv6_address -> nxd_ipv6_address_next; + } + + /* Check if found the link-local address. */ + if(ipv6_address) + { + + /* Set the IPv6 link-local address index. */ + mdns_ptr -> nx_mdns_ipv6_address_index[interface_index] = ipv6_address -> nxd_ipv6_address_index; + } + else + { + + /* No available address, set the address index as 0xFFFFFFFF. */ + mdns_ptr -> nx_mdns_ipv6_address_index[interface_index] = 0xFFFFFFFF; + } +#endif /* NX_MDNS_ENABLE_IPV6 */ + + /* Join the group. */ + status = nx_ipv4_multicast_interface_join(mdns_ptr -> nx_mdns_ip_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, interface_index); + + /* Check status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(status); + } + +#ifdef NX_MDNS_ENABLE_IPV6 + status = nxd_ipv6_multicast_interface_join(mdns_ptr -> nx_mdns_ip_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, interface_index); + + /* Check status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(status); + } +#endif /* NX_MDNS_ENABLE_IPV6 */ + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Register the host name. */ + status = _nx_mdns_host_name_register(mdns_ptr, NX_TRUE, interface_index); + + /* Check status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(status); + } + + /* Probing the all resource record wheneven a Multicast DNS responder starts up, waks up from sleep, receives an indication of a network interface "Link CHange" event.RFC6762, Section8, Page25. */ + + /* Get the header to the local buffer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + /* Set the pointer. */ + head = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the state and delete flag, GOODBYE state and DELETE FLAG means this resource record should be deleted. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) && + (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DELETE)) + { + + /* Delete the resource records. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); + continue; + } + + /* Check the resource reocrd type. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC)) + { + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; + continue; + } + + /* Check the unique flag. */ + if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) + { + /* For a unique type, we need to probe it on the network + to guarantee its uniqueness. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; + p -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; + p -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; + } + else + { + /* If the record is not marked as unique, start the announcement process. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; + p -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; + p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; + + /* Check the announcing max time. */ + if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) + p -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); + else + p -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; + + /* Set the retransmit count. */ + if (mdns_ptr -> nx_mdns_announcing_retrans_interval) + p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; + else + p -> nx_mdns_rr_retransmit_count = 1; + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } +#endif /* NX_MDNS_DISABLE_SERVER */ + + /* Set the mdns started flag. */ + mdns_ptr -> nx_mdns_started = NX_TRUE; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return. */ + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS disable function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_disable Actual mDNS disable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input or invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS delete service. */ + status = _nx_mdns_disable(mdns_ptr, interface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the mDNS of the physical host interface by */ +/* interface index. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* nx_ipv4_multicast_leave Leave the IPv4 Multicast group*/ +/* nxd_ipv6_multicast_interface_leave Leave the IPv6 Multicast group*/ +/* _nx_mdns_cache_initialize Initialize the mDNS peer cache*/ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT dns_sd_size; +UINT i; +ULONG *head; +NX_MDNS_RR *p; + + + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check to see if mDNS is not enabled on this interface. + Note: Only support one interface yet. */ + if (mdns_ptr -> nx_mdns_interface_enabled[interface_index] == NX_FALSE) + { + return(NX_MDNS_NOT_ENABLED); + } + + /* Check the DNS-SD string. */ + if (_nx_utility_string_length_check((CHAR *)_nx_mdns_dns_sd, &dns_sd_size, NX_MDNS_DNS_SD_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Disable the mdns function. */ + mdns_ptr -> nx_mdns_interface_enabled[interface_index] = NX_FALSE; + + /* Leave the group. */ + nx_ipv4_multicast_interface_leave(mdns_ptr -> nx_mdns_ip_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, interface_index); + +#ifdef NX_MDNS_ENABLE_IPV6 + nxd_ipv6_multicast_interface_leave(mdns_ptr -> nx_mdns_ip_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, interface_index); +#endif /* NX_MDNS_ENABLE_IPV6 */ + +#ifndef NX_MDNS_DISABLE_CLIENT + + /* Get the local buffer head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + + /* Set the pointer. */ + head = (ULONG*)(*head); + + /* Delete all services on this interface. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Delete the resource record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Get the local buffer head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + /* Set the pointer. */ + head = (ULONG*)(*head); + + /* Send the Goodbye message, RFC6762, Section10.1, Page33. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Skip the NSEC and DNS-SD PTR resource record. */ + if ((p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) || + ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, dns_sd_size)))) + { + + /* Suspend the resource record. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; + } + else + { + + /* Set the state to send Goodbye packet. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; + + /* Clear the retransmit count. */ + p -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; + + /* Set the timer count. 250ms. */ + p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } + } +#endif /* NX_MDNS_DISABLE_SERVER */ + + /* Check if all interfaces are disabled. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + if (mdns_ptr -> nx_mdns_interface_enabled[i]) + break; + } + + /* Set the mdns started flag. */ + if (i == NX_MAX_PHYSICAL_INTERFACES) + mdns_ptr -> nx_mdns_started = NX_FALSE; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_local_domain_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS domain sets */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* domain_name Domain name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_domain_name_set Actual domain set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((!mdns_ptr) || (!domain_name)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input or invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS domain name set service. */ + status = _nx_mdns_domain_name_set(mdns_ptr, domain_name); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_domain_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the mDNS domain name. By default is "local". */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* domain_name Domain name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name) +{ + +UINT index; +UINT domain_name_size; + + + /* Check the size. */ + if (_nx_utility_string_length_check((CHAR *)domain_name, &domain_name_size, NX_MDNS_DOMAIN_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Save the new domain name. */ + memcpy(&mdns_ptr -> nx_mdns_domain_name[0], domain_name, domain_name_size); + mdns_ptr -> nx_mdns_domain_name[domain_name_size] = NX_NULL; + + /* Initialize the struct. */ + memset(_nx_mdns_dns_sd, 0, NX_MDNS_DNS_SD_MAX); + + /* Update the services dns-sd. */ + memcpy(_nx_mdns_dns_sd, "_services._dns-sd._udp.", (sizeof("_services._dns-sd._udp.") - 1)); + index = (sizeof("_services._dns-sd._udp.") - 1); + memcpy(&_nx_mdns_dns_sd[index], domain_name, domain_name_size); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS service add */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name Service instance name */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* txt The txt string of the service */ +/* ttl The ttl of the service */ +/* priority The priority of target host */ +/* weights Service weight */ +/* port The port on this target host */ +/* is_unique The RR set of the service */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_add Actual service add function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, + USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if ((mdns_ptr -> nx_mdns_id != NX_MDNS_ID) || (!port)) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check the size of the service name string. The last four characters in the + service name are reserved so DNS-SD is able to append " (2)" during the conflict + resolution process. */ +#if (NX_MDNS_SERVICE_NAME_MAX >= NX_MDNS_LABEL_MAX) + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, (NX_MDNS_LABEL_MAX - 4))) +#else + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, (NX_MDNS_SERVICE_NAME_MAX - 4))) +#endif + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check the type. */ + if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check the txt string size. */ + if (txt) + { + if (_nx_utility_string_length_check((CHAR *)txt, NX_NULL, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Check the txt string size. */ + if (sub_type) + { + if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Check the interface index. */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Call actual mDNS service add service. */ + status = _nx_mdns_service_add(mdns_ptr, name, type, sub_type, txt, ttl, priority, + weights, port, is_unique, interface_index); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS services, and the PTR, SRV and TXT */ +/* records into the local buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name Service nstance name */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* txt The txt string of the service */ +/* ttl The ttl of the service */ +/* priority The priority of target host */ +/* weights Service weight */ +/* port The port on this target host */ +/* is_unique The RR set of the service */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_rr_srv_add Add the SRV resource record */ +/* _nx_mdns_rr_txt_add Add the TXT resource record */ +/* _nx_mdns_rr_ptr_add Add the PTR resource record */ +/* _nx_mdns_rr_delete Delete the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, + USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index) +{ + +UINT status; +UINT type_index; +NX_MDNS_RR *srv_rr; +NX_MDNS_RR *txt_rr; +NX_MDNS_RR *ptr_rr; +NX_MDNS_RR *dns_sd_rr; +ULONG *head; +NX_MDNS_RR *p; +ULONG srv_ttl; +ULONG txt_ttl; +ULONG ptr_ttl; +UINT string_length; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Check the ttl value. */ + if (ttl) + { + + /* Use user supplied TTL value if it is not zero. */ + srv_ttl = ttl; + txt_ttl = ttl; + ptr_ttl = ttl; + } + else + { + + /* Use the RFC recommended TTL values if user doesn't supply one. */ + srv_ttl = NX_MDNS_RR_TTL_HOST; + txt_ttl = NX_MDNS_RR_TTL_OTHER; + ptr_ttl = NX_MDNS_RR_TTL_OTHER; + } + + /* Construct the SRV name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(&temp_string_buffer[0]), &string_length, NX_MDNS_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check whether the same service name exist. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + { + + /* Compare the service name. */ + if (!_nx_mdns_name_match(&temp_string_buffer[0], p -> nx_mdns_rr_name, string_length)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(NX_MDNS_EXIST_SAME_SERVICE); + } + } + } + + /* Construct the SRV target name. */ + status = _nx_mdns_service_name_assemble(mdns_ptr -> nx_mdns_host_name, NX_NULL, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &target_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Add the SRV resource records message. */ + status = _nx_mdns_rr_srv_add(mdns_ptr, &temp_string_buffer[0], srv_ttl, is_unique, priority, weights, port, &target_string_buffer[0], &srv_rr, interface_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(status); + } + + /* Add the TXT resource records message. */ + status = _nx_mdns_rr_txt_add(mdns_ptr, &temp_string_buffer[0], txt_ttl, is_unique, txt, &txt_rr, interface_index); + + /* Check the status. */ + if (status) + { + + /* Delete the SRV records. */ + _nx_mdns_rr_delete(mdns_ptr, srv_rr); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add the dns-sd PTR resource records message. */ + status = _nx_mdns_rr_ptr_add(mdns_ptr, (UCHAR *)_nx_mdns_dns_sd, ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[type_index], NX_TRUE, &dns_sd_rr, interface_index); + + /* Check the status. */ + if (status) + { + + /* Delete the TXT records. */ + _nx_mdns_rr_delete(mdns_ptr, txt_rr); + + /* Delete the SRV records. */ + _nx_mdns_rr_delete(mdns_ptr, srv_rr); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add the PTR resource records message. */ + status = _nx_mdns_rr_ptr_add(mdns_ptr, &temp_string_buffer[type_index], ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[0], NX_TRUE, &ptr_rr, interface_index); + + /* Check the status. */ + if (status) + { + + /* Delete the TXT records. */ + _nx_mdns_rr_delete(mdns_ptr, txt_rr); + + /* Delete the SRV records. */ + _nx_mdns_rr_delete(mdns_ptr, srv_rr); + + /* Delete the DNS_SD PTR records. */ + _nx_mdns_rr_delete(mdns_ptr, dns_sd_rr); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add another PTR type for the subtype. */ + if (sub_type) + { + + /* Construct the PTR target name. */ + status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &target_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return (status); + } + + /* Add the Sub PTR resource records message. */ + status = _nx_mdns_rr_ptr_add(mdns_ptr, &target_string_buffer[type_index], ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[0], NX_TRUE, NX_NULL, interface_index); + + /* Check the status. */ + if (status) + { + + /* Delete the PTR records. */ + _nx_mdns_rr_delete(mdns_ptr, ptr_rr); + + /* Delete the DNS_SD PTR records. */ + _nx_mdns_rr_delete(mdns_ptr, dns_sd_rr); + + /* Delete the SRV records. */ + _nx_mdns_rr_delete(mdns_ptr, srv_rr); + + /* Delete the TXT records. */ + _nx_mdns_rr_delete(mdns_ptr, txt_rr); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + } + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + + /* Add the NSEC resource record for service. */ + _nx_mdns_rr_nsec_add(mdns_ptr, &temp_string_buffer[0], NX_FALSE, NX_FALSE, NX_MDNS_ADD_NSEC_FOR_SERVICE, interface_index); +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS service delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_delete Actual service delete function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((!mdns_ptr) || (!name) || (!type)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check the size. */ + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX) || + _nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Call actual mDNS service delete service. */ + status = _nx_mdns_service_delete(mdns_ptr, name, type, sub_type); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS services. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_delete_internal Actual service delete function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT i; +UINT status = NX_MDNS_NOT_ENABLED; +UINT service_delete_success = NX_FALSE; + + /* Delete service from all enabled interfaces. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i ++) + { + + /* Call actual mDNS service delete service. */ + status = _nx_mdns_service_interface_delete(mdns_ptr, name, type, sub_type, i); + + /* Check status. */ + if (status == NX_MDNS_SUCCESS) + { + service_delete_success = NX_TRUE; + } + } + + /* Check if delete service on all enabled interface. */ + if (service_delete_success) + return(NX_MDNS_SUCCESS); + else + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_interface_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS services, and remove SRV and TXT */ +/* records from local buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_name_match Match the name string */ +/* _nx_mdns_rr_delete Delete the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_interface_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT interface_index) +{ + +UINT status; +UINT found; +UINT delete_flag; +UINT type_index; +ULONG *head; +NX_MDNS_RR *p; +UINT rr_name_length; +UINT rr_ptr_name_length; + + NX_PARAMETER_NOT_USED(sub_type); + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Initialize the parameters. */ + type_index = 0; + delete_flag = NX_FALSE; + + /* Construct the SRV name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Get head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Clear the found value. */ + found = NX_FALSE; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + continue; + } + + /* Compare the RDATA. */ + switch (p -> nx_mdns_rr_type) + { + + case NX_MDNS_RR_TYPE_SRV: + case NX_MDNS_RR_TYPE_TXT: + { + if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length)) + { + found = NX_TRUE; + delete_flag = NX_TRUE; + } + break; + } + case NX_MDNS_RR_TYPE_PTR: + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), &rr_ptr_name_length, NX_MDNS_NAME_MAX)) + { + break; + } + + /* Find the PTR and Sub PTR resource record which pointer to the SRV resource record.*/ + if (!_nx_mdns_name_match(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &temp_string_buffer[0], rr_ptr_name_length)) + { + found = NX_TRUE; + } + + /* Find one DNS-SD PRT which pointer to the PTR resource record. */ + if ((!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length)) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &temp_string_buffer[type_index], rr_ptr_name_length))) + { + + /* Check the count. */ + if (p -> nx_mdns_rr_count) + { + p -> nx_mdns_rr_count --; + } + else + { + + /* Delete this resource record directly. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); + } + } + break; + } + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + case NX_MDNS_RR_TYPE_NSEC: + { + if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length)) + { + + /* Delete this resource record directly. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); + } + break; + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + } + + if (found) + { + + /* Delete the resource records. */ + status = _nx_mdns_rr_delete(mdns_ptr, p); + + /* Check the status. */ + if (status) + { + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + } + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + if (delete_flag == NX_TRUE) + return(NX_MDNS_SUCCESS); + else + return(NX_MDNS_ERROR); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_one_shot_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS resource record query */ +/* add function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service Pointer to response service */ +/* timeout The timeour for service query */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_one_shot_query Actual query service function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((!mdns_ptr) || (!type) || (!service)) + { + return(NX_PTR_ERROR); + } + + /* Check for mDNS started flag. */ + if (!mdns_ptr -> nx_mdns_started) + { + return(NX_MDNS_NOT_STARTED); + } + + /* Check for name. */ + if (name) + { + + /* Check the name size. */ + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Check the type size. */ + if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check the sub type. */ + if (sub_type) + { + + /* Check the name size. */ + if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_service_one_shot_query(mdns_ptr, name, type, sub_type, service, timeout); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_one_shot_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts service one-shot query on all enabled */ +/* interfaces. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service Pointer to response service */ +/* timeout The timeour for service query */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_service_name_resolve Resolve the service name */ +/* _nx_mdns_query Send the One Shot query */ +/* _nx_mdns_service_addition_info_get Get additional info of service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout) +{ + +UINT type_index; +UINT status; +NX_MDNS_RR *answer_rr; +UCHAR *query_name; +USHORT query_type; +UINT i; +UINT name_length; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); + + /* Initialize the struct. */ + memset(service, 0, sizeof(NX_MDNS_SERVICE)); + + /* Loop to start one-shot query on all enabled interfaces until get the answer or query timeout. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Check if this interface is enabled. */ + if (!mdns_ptr -> nx_mdns_interface_enabled[i]) + continue; + + /* Step1. Construct the query name and set the query type. */ + if (name) + { + + /* Construct the SRV name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(status); + } + + /* Set the query name and query type (NX_MDNS_RR_TYPE_ALL for SRV and TXT). */ + query_name = temp_string_buffer; + query_type = NX_MDNS_RR_TYPE_ALL; + } + else + { + + /* Construct the PTR name. */ + status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Set the query name and query type. */ + query_name = &temp_string_buffer[type_index]; + query_type = NX_MDNS_RR_TYPE_PTR; + } + + /* Step2. Start one shot query. */ + status = _nx_mdns_one_shot_query(mdns_ptr, query_name, query_type, &answer_rr, timeout, i); + + /* Check the status. */ + if ((status == NX_SUCCESS) || + (status == NX_MDNS_EXIST_UNIQUE_RR) || + (status == NX_MDNS_EXIST_SHARED_RR)) + { + + /* Check the query type. */ + if (name) + { + + /* Store the service name from SRV record. */ + if (_nx_utility_string_length_check((CHAR *)answer_rr -> nx_mdns_rr_name, &name_length, NX_MDNS_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + memcpy((char *)(service -> buffer), (char*)(answer_rr -> nx_mdns_rr_name), name_length); + } + else + { + + /* Store the service name from PTR record. */ + if (_nx_utility_string_length_check((CHAR *)answer_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &name_length, NX_MDNS_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + memcpy((CHAR *)(service -> buffer), (CHAR *)(answer_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), name_length); + } + + /* Get the additional information of service. */ + _nx_mdns_service_addition_info_get(mdns_ptr, service -> buffer, service, i); + + /* Reslove the service name. */ + status = _nx_mdns_service_name_resolve(service -> buffer, &(service -> service_name), &(service -> service_type), &(service -> service_domain)); + + /* Check status. */ + if (status) + continue; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return success. */ + return (NX_MDNS_SUCCESS); + } + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return error. */ + return (NX_MDNS_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_one_shot_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into remote buffer, */ +/* mDNS thread send the query message. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* type The resource record type */ +/* out_rr Pointer to response RR */ +/* one_shot One shot or continuous */ +/* wait_option Wait option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _tx_thread_system_suspend Suspend the thread */ +/* _nx_mdns_query_check Check the query RR */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, NX_MDNS_RR **out_rr, ULONG wait_option, UINT interface_index) +{ + +UINT status; +NX_MDNS_RR *rr; +NX_MDNS_RR *insert_rr; +NX_MDNS_RR temp_resource_record; +UINT name_length; + + + /* Clear the return record. */ + *out_rr = NX_NULL; + + /* Check the query RR. */ + status = _nx_mdns_query_check(mdns_ptr, name, type, NX_TRUE, &rr, interface_index); + + /* Check the state. */ + if (status) + { + + /* Whether exists unique resource record in cache. */ + if ((status == NX_MDNS_EXIST_UNIQUE_RR) || + (status == NX_MDNS_EXIST_SHARED_RR)) + { + *out_rr = rr; + return (NX_MDNS_SUCCESS); + } + else + { + return(status); + } + } + + if (wait_option != 0) + { + + /* Initialize the struct. */ + memset(&temp_resource_record, 0, sizeof(NX_MDNS_RR)); + + if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, name, name_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_name), NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + return(status); + } + + /* Add the parameters. */ + temp_resource_record.nx_mdns_rr_type = type; + temp_resource_record.nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; + + /* Set the resource record status. */ + temp_resource_record.nx_mdns_rr_state = NX_MDNS_RR_STATE_QUERY; + + /* Remote resource record, set the owner flag. */ + temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_PEER); + + /* Set the interface index. */ + temp_resource_record.nx_mdns_rr_interface_index = interface_index; + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, &insert_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_resource_record.nx_mdns_rr_name, 0); + return(status); + } + + /* A multicast DNS querier should also delay the first query of the series by + a randomly chosen amount in the range 20-120ms. */ + insert_rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); + insert_rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); + + /* Release the mDNS mutex to process response. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Suspend the thread on this mDNS query attempt. */ + _nx_mdns_query_thread_suspend(&(mdns_ptr -> nx_mdns_rr_receive_suspension_list), _nx_mdns_query_cleanup, mdns_ptr, out_rr, wait_option); + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); + + /* Determine if a packet was received successfully. */ + if (_tx_thread_current_ptr -> tx_thread_suspend_status != NX_MDNS_SUCCESS) + { + + /* Delete the query resource record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, insert_rr); + } + + /* Return the status. */ + return(_tx_thread_current_ptr -> tx_thread_suspend_status); + } + else + { + + /* Immediate return, return error completion. */ + return(NX_MDNS_NO_RR); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_continuous_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS resource record query */ +/* add function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_continuous_query Actual mDNS query RR function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Check for mDNS stareted flag. */ + if (!mdns_ptr -> nx_mdns_started) + { + return(NX_MDNS_NOT_STARTED); + } + + /* Check the type. If the type is null,indicate lookup the all service type, the name and sub type must be null. */ + if (!type) + { + if ((name) || (sub_type)) + { + return(NX_MDNS_PARAM_ERROR); + } + } + else + { + + /* Check the name, If the name is non-null, the sub type must be null. */ + if ((name) && (sub_type)) + { + return(NX_MDNS_PARAM_ERROR); + } + } + + /* Check the name. */ + if (name) + { + + /* Check the name size. */ + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Check the type. */ + if (type) + { + + /* Check the type size. */ + if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Check the sub type. */ + if (sub_type) + { + + /* Check the sub type size. */ + if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_service_continuous_query(mdns_ptr, name, type, sub_type); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_continuous_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts service continuous query on all enabled */ +/* interfaces. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_service_name_resolve Resolve the service name */ +/* _nx_mdns_query Send the One Shot query */ +/* _nx_mdns_service_addition_info_get Get additional info of service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT status = NX_MDNS_ERROR; +UINT type_index; +UCHAR *query_name; +USHORT query_type; +UINT query_success = NX_FALSE; +UINT i; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Step1. Construct the query name and set the query type. */ + /* Check the type. if the type is null, indicate search all service. */ + if (!type) + { + + /* Set the query name and query type. */ + query_name = (UCHAR *)_nx_mdns_dns_sd; + query_type = NX_MDNS_RR_TYPE_PTR; + } + else if (name) + { + + /* Construct the SRV name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Set the query name and query type (NX_MDNS_RR_TYPE_ALL for SRV and TXT). */ + query_name = temp_string_buffer; + query_type = NX_MDNS_RR_TYPE_ALL; + } + else + { + + /* Construct the PTR name. */ + status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Set the query name and query type. */ + query_name = &temp_string_buffer[type_index]; + query_type = NX_MDNS_RR_TYPE_PTR; + } + + /* Step2. Loop to start continuous query on all enabled interfaces. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Check if this interface is enabled. */ + if (!mdns_ptr -> nx_mdns_interface_enabled[i]) + continue; + + /* Start continuous query. */ + status = _nx_mdns_continuous_query(mdns_ptr, query_name, query_type, i); + + /* Check the status. */ + if ((status == NX_SUCCESS) || + (status == NX_MDNS_EXIST_SAME_QUERY) || + (status == NX_MDNS_EXIST_UNIQUE_RR) || + (status == NX_MDNS_EXIST_SHARED_RR)) + query_success = NX_TRUE; + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Check if start continuous query success. */ + if (query_success) + return (NX_MDNS_SUCCESS); + else + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_continuous_query PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts continuous query on specified interfaces. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* interface_index The interface index */ +/* name The resource record name */ +/* type The resource record type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_query_check Check the query RR */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT interface_index) +{ + +UINT status; +NX_MDNS_RR *insert_rr; +NX_MDNS_RR temp_resource_record; +UINT name_length; + + + /* Check the query RR. */ + status = _nx_mdns_query_check(mdns_ptr, name, type, NX_FALSE, NX_NULL, interface_index); + + /* Check the state. */ + if (status) + { + return(status); + } + + /* Initialize the struct. */ + memset(&temp_resource_record, 0, sizeof(NX_MDNS_RR)); + + if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, name, name_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_name), NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + return(status); + } + + /* Add the parameters. */ + temp_resource_record.nx_mdns_rr_type = type; + temp_resource_record.nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; + + /* Set the resource record status. */ + temp_resource_record.nx_mdns_rr_state = NX_MDNS_RR_STATE_QUERY; + + /* Remote resource record, set the owner flag. */ + temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_PEER); + + /* Continuous query, set the query type flag. */ + if ((type != NX_MDNS_RR_TYPE_A) && + (type != NX_MDNS_RR_TYPE_AAAA)) + { + temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_CONTINUOUS_QUERY); + } + + /* Set the interface index. */ + temp_resource_record.nx_mdns_rr_interface_index = interface_index; + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, &insert_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_resource_record.nx_mdns_rr_name, 0); + return(status); + } + + /* A multicast DNS querier should also delay the first query of the series by + a randomly chosen amount in the range 20-120ms. */ + insert_rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); + insert_rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); + + /* Return success. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_query_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS resource record query */ +/* add function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_query_stop Actual query RR function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + if (name) + { + + /* Check the size. */ + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_service_query_stop(mdns_ptr, name, type, sub_type); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_query_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into peer service cache,*/ +/* mDNS thread send the query message using continuous type. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_name_match Match the name string */ +/* _nx_mdns_rr_delete Delete the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) +{ + +UINT status; +UINT type_index = 0; +UINT query_stop = NX_FALSE; +ULONG *head; +NX_MDNS_RR *p; +UINT rr_name_length; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + if (type) + { + if (name) + { + + /* Construct the SRV name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + } + else + { + + /* Construct the PTR name. */ + status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + } + } + + /* Get the remote buffer head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + + if (!head) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_MDNS_CACHE_ERROR); + } + + /* Set the pointer. */ + head = (ULONG*)(*head); + + /* Loop to delete query resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the resource record state. */ + if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) + continue; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + continue; + } + + if (!type) + { + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length))) + { + + /* Delete the resource records. */ + status = _nx_mdns_rr_delete(mdns_ptr, p); + + /* Check status. */ + if (status == NX_MDNS_SUCCESS) + query_stop = NX_TRUE; + } + } + else + { + if (name) + { + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_ALL) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length))) + { + + /* Delete the resource records. */ + status = _nx_mdns_rr_delete(mdns_ptr, p); + + /* Check status. */ + if (status == NX_MDNS_SUCCESS) + query_stop = NX_TRUE; + } + } + else + { + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR)&& + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[type_index], rr_name_length))) + { + + /* Delete the resource records. */ + status = _nx_mdns_rr_delete(mdns_ptr, p); + + /* Check status. */ + if (status == NX_MDNS_SUCCESS) + query_stop = NX_TRUE; + } + } + } + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Check if stop service continuous query. */ + if (query_stop == NX_TRUE) + return(NX_MDNS_SUCCESS); + else + return(NX_MDNS_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_service_lookup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS resource record query */ +/* add function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service_index The index of the service */ +/* service Pointer to Service instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_service_lookup Actual mDNS query RR function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + if (name) + { + + /* Check the size. */ + if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_service_lookup(mdns_ptr, name, type, sub_type, service_index, service); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_lookup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into peer service cache,*/ +/* mDNS thread send the query message using continuous type. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service_index The index of the service */ +/* service Pointer to Service instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* tx_time_get Get the time */ +/* _nx_mdns_service_name_assemble Assemble the service name */ +/* _nx_mdns_service_name_resolve Resolve the service name */ +/* _nx_mdns_service_addition_info_get Get additional info of service*/ +/* _nx_mdns_name_match Match the name string */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service) +{ + +UINT status; +UINT type_index; +UINT dns_sd_flag; +UINT sub_type_flag; +UINT index; +UINT count; +UINT found; +UCHAR *srv_name = NX_NULL; +UCHAR *ptr; +UCHAR *tmp_sub_type; +UCHAR *tmp_type; +UCHAR *tmp_domain; +NX_MDNS_RR *p = NX_NULL; +NX_MDNS_RR *p1; +ULONG *head, *tail; +UCHAR i; +UINT interface_index = 0; +UINT temp_string_length; +UINT dns_sd_length; +UINT srv_name_length; +UINT target_string_length; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Zero out the content of service */ + memset(service, 0, sizeof(NX_MDNS_SERVICE)); + + /* Initialize the struct. */ + count = 0; + found = NX_FALSE; + + /* Check the type. */ + if (type) + { + if (name) + { + + /* Construct the Service name. */ + status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); + + } + else + { + + /* Construct the Service name. */ + status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); + } + /* Check the status. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + } + + /* Check the DNS-SD string. */ + if (_nx_utility_string_length_check((CHAR *)_nx_mdns_dns_sd, &dns_sd_length, NX_MDNS_DNS_SD_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (status); + } + + /* Loop to search local and peer cache. */ + for(i = 0; i < 2; i++) + { + + /* Set the pointer. */ + if(i == NX_MDNS_CACHE_TYPE_LOCAL) + { +#ifndef NX_MDNS_DISABLE_SERVER + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + } + + if(head == NX_NULL) + continue; + + /* Set the pointer. */ + tail = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p < tail; p++) + { + + /* Check whether the resource record is valid. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) + continue; + + if((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) || (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV)) + { + + if(type) + { + if (_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], temp_string_length)) + continue; + } + else if(p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + continue; + + if(name && (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV)) + { + + /* Store the service name. */ + srv_name = p -> nx_mdns_rr_name; + interface_index = p -> nx_mdns_rr_interface_index; + } + else + { + + /* Set the service name pointer. */ + srv_name = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name; + interface_index = p -> nx_mdns_rr_interface_index; + } + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)srv_name, &srv_name_length, NX_MDNS_NAME_MAX)) + continue; + + /* Store the service name. */ + memcpy((CHAR *)(service -> buffer), (CHAR *)srv_name, srv_name_length + 1); + + /* Reslove the service name and check the PTR rdata name. Ignore the PTR when the PTR rdata does not pointer the service. */ + status = _nx_mdns_service_name_resolve(service -> buffer, &(service -> service_name), &(service -> service_type), &(service -> service_domain)); + + if (status) + continue; + + if(type == NX_NULL) + { + + /* Set the parameters. */ + sub_type_flag = NX_FALSE; + dns_sd_flag = NX_FALSE; + index = 0; + + /* Check the PTR resource record with sub type. */ + ptr = p -> nx_mdns_rr_name; + while (*ptr != '\0') + { + if (*ptr == '.') + { + if (!_nx_mdns_name_match(ptr - index, (UCHAR *)"_sub", 4)) + { + sub_type_flag = NX_TRUE; + break; + } + index = 0; + } + else + index ++; + ptr ++; + } + if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, dns_sd_length)) + { + dns_sd_flag = NX_TRUE; + } + + /* Check the DNS-SD PTR reousrce record. */ + if ((dns_sd_flag == NX_TRUE) || + (sub_type_flag == NX_TRUE)) + { + + /* Find the PTR resource record which pointer to the service. */ + for(p1 = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p1 < tail; p1++) + { + + /* Check whether the resource record is valid. */ + if ((p1 == p) || + (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || + (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) + continue; + + /* Check the interface index. */ + if (p1 -> nx_mdns_rr_interface_index != p -> nx_mdns_rr_interface_index) + continue; + + if (p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) + { + if ((dns_sd_flag == NX_TRUE)) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p1 -> nx_mdns_rr_name), &target_string_length, NX_MDNS_NAME_MAX)) + { + continue; + } + + /* Set the pointer. */ + memcpy((CHAR *)&target_string_buffer[0], (CHAR *)(p1 -> nx_mdns_rr_name), target_string_length + 1); + + /* Reslove the type. */ + status = _nx_mdns_service_name_resolve(&target_string_buffer[0], &tmp_sub_type, &tmp_type, &tmp_domain); + + if (status) + continue; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)tmp_type, &target_string_length, NX_MDNS_TYPE_MAX)) + { + continue; + } + + /* Construct the type and doamin, _http._tcp.local. */ + *(tmp_type + target_string_length) = '.'; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)tmp_type, &target_string_length, NX_MDNS_TYPE_MAX)) + { + continue; + } + + /* Compare the DNS_SD rdata. */ + if (!_nx_mdns_name_match(tmp_type, p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, target_string_length)) + { + + /* Exist resource record including more info. */ + count --; + break; + } + } + else + { + + /* Exist the PTR RR which pointer to the same service. */ + if (p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) + { + count --; + break; + } + } + } + } + } + } + + /* Check the count state. */ + if (count == service_index) + { + /* Yes, find. */ + found = NX_TRUE; + break; + } + count ++; + } + } + + /* Check if find the service. */ + if (found == NX_TRUE) + { + break; + } + } + + if (found) + { + + /* Update the elasped time. */ + p -> nx_mdns_rr_elapsed_time = tx_time_get(); + + /* Get the additional information. */ + _nx_mdns_service_addition_info_get(mdns_ptr, srv_name, service, interface_index); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(NX_MDNS_SUCCESS); + } + else + { + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return(NX_MDNS_NO_MORE_ENTRIES); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_peer_cache_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS peer service cache */ +/* clear function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_peer_cache_clear Actual peer cache clear */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_peer_cache_clear(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_peer_cache_clear(mdns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_peer_cache_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the mDNS peer service cache. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_cache_initialize Initialize the cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_peer_cache_clear(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + status = _nx_mdns_cache_initialize(mdns_ptr, NX_NULL, NX_NULL, mdns_ptr -> nx_mdns_peer_service_cache, mdns_ptr -> nx_mdns_peer_service_cache_size); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a error status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_mdns_host_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the mDNS host address get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service Pointer to response service */ +/* timeout The timeour for service query */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_host_address_get Actual mDNS host address */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((!mdns_ptr) || (!host_name)) + { + return(NX_PTR_ERROR); + } + + /* Check for mDNS started flag. */ + if (!mdns_ptr -> nx_mdns_started) + { + return(NX_MDNS_NOT_STARTED); + } + + /* Check the size. */ + if (_nx_utility_string_length_check((CHAR *)host_name, NX_NULL, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Call actual mDNS create service. */ + status = _nx_mdns_host_address_get(mdns_ptr, host_name, ipv4_address, ipv6_address, timeout); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_host_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS query record into peer buffer, */ +/* mDNS thread send the query message using one-shot type. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The name of the service */ +/* type The type of the service */ +/* subtype The subtype of the service */ +/* service Pointer to response service */ +/* timeout The timeour for service query */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* tx_time_get Get the mDNS time */ +/* _nx_mdns_host_check Check the host info */ +/* _nx_mdns_answer_wait Wait the answer */ +/* _nx_mdns_cache_add_query Add the query into cache */ +/* _nx_mdns_cache_delete_query Delete the query from cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout) +{ + +UINT status; +ULONG start_time; +ULONG current_time; +ULONG elapsed_time; +ULONG wait_time = timeout; +NX_MDNS_RR *a_rr; +NX_MDNS_RR *aaaa_rr; +UCHAR host_name_query[NX_MDNS_NAME_MAX + 1]; +UINT i = 0; +UCHAR domain_flag = NX_FALSE; +UINT answer = NX_FALSE; +UINT domain_name_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)host_name, NX_NULL, NX_MDNS_HOST_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); + + /* Clear the buffer. */ + memset(host_name_query, 0, NX_MDNS_NAME_MAX + 1); + + /* Copy the host name into host name query buffer. */ + while(host_name[i] != NX_NULL) + { + host_name_query[i] = host_name[i]; + if (host_name[i] == '.') + { + + /* Update the flag. */ + domain_flag = NX_TRUE; + } + i++; + } + + /* Check if include the domain. */ + if (domain_flag == NX_FALSE) + { + host_name_query[i++] = '.'; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_domain_name, &domain_name_length, NX_MDNS_DOMAIN_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr->nx_mdns_mutex)); + return (NX_MDNS_DATA_SIZE_ERROR); + } + + memcpy((char*)(&host_name_query[i]), (const char*)mdns_ptr -> nx_mdns_domain_name, domain_name_length + 1); + } + + /* Initialize the value. */ + if (ipv4_address) + *ipv4_address = NX_NULL; + if (ipv6_address) + memset(ipv6_address, 0, 16); + + /* Start host address query on all enabled interfaces until get the answer or query timeout. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Check if this interface is enabled. */ + if (!mdns_ptr -> nx_mdns_interface_enabled[i]) + continue; + + /* Get the query start time. */ + wait_time = timeout; + start_time = tx_time_get(); + + /* Get the host IPv4 address. */ + if (ipv4_address) + { + + /* One shot query for host name. */ + status = _nx_mdns_one_shot_query(mdns_ptr, host_name_query, NX_MDNS_RR_TYPE_A, &a_rr, wait_time, i); + + /* Check the status. */ + if (status == NX_MDNS_SUCCESS) + { + + /* Set the IPv4 address. */ + *ipv4_address = a_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address; + answer = NX_TRUE; + } + } + + /* Get the host IPv6 address. */ + if (ipv6_address) + { + + /* How much time has elapsed? */ + current_time = tx_time_get(); + + /* Has the time wrapped? */ + if (current_time >= start_time) + { + /* No, simply subtract to get the elapsed time. */ + elapsed_time = current_time - start_time; + } + else + { + + /* Yes it has. Time has rolled over the 32-bit boundary. */ + elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; + } + + /* Update the timeout. */ + if (wait_time > elapsed_time) + wait_time -= elapsed_time; + else + wait_time = 0; + + /* Lookup the service. */ + status = _nx_mdns_one_shot_query(mdns_ptr, host_name_query, NX_MDNS_RR_TYPE_AAAA, &aaaa_rr, wait_time, i); + + /* Check the status. */ + if (status == NX_MDNS_SUCCESS) + { + + /* Set the IPv6 address. */ + *ipv6_address = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[0]; + *(ipv6_address + 1) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[1]; + *(ipv6_address + 2) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[2]; + *(ipv6_address + 3) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[3]; + answer = NX_TRUE; + } + } + + /* Check if get IPv4 address or IPv6 address. */ + if (answer == NX_TRUE) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (NX_MDNS_SUCCESS); + } + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (NX_MDNS_ERROR); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +#ifndef NX_MDNS_DISABLE_SERVER +#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_a_aaaa_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS A/AAAA resource record into local cache.*/ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* set The resource record set */ +/* address The resource record address */ +/* insert_rr Pointer to insert resource */ +/* record */ +/* name Host name */ +/* ttl The resource record ttl */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_host_name_register Register the host name */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_a_aaaa_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG *address, UINT addr_length, UCHAR type, UINT interface_index) +{ +UINT status; +NX_MDNS_RR *insert_rr; +USHORT rr_type; +NX_MDNS_RR temp_resource_record; + + + /* Set the resource record type. */ + if(addr_length == 4) + rr_type = NX_MDNS_RR_TYPE_A; + else + rr_type = NX_MDNS_RR_TYPE_AAAA; + + /* Set the resource record parameters. */ + status = _nx_mdns_rr_parameter_set(mdns_ptr, name, rr_type, NX_MDNS_RR_TTL_HOST, addr_length, NX_MDNS_RR_SET_UNIQUE, type, NX_FALSE, &temp_resource_record, interface_index); + + /* Check for error. */ + if (status) + { + return(status); + } + + /* Add the parameters. */ + if(rr_type == NX_MDNS_RR_TYPE_A) + { + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address = *address; + } + else + { + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0] = *address; + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1] = *(address +1); + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2] = *(address + 2); + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3] = *(address + 3); + } + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &insert_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + + /* Delete the name strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + return(status); + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); + + /* Return a successful status. */ + return(NX_SUCCESS); +} +#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_ptr_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS PTR resource record into local buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* ttl The resource record ttl */ +/* set The resource record set */ +/* ptr_name The domain name */ +/* insert_rr Pointer to insert resource */ +/* record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_ptr_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *ptr_name, UCHAR is_valid, NX_MDNS_RR **insert_rr, UINT interface_index) +{ + +UINT status; +NX_MDNS_RR *ptr_rr; +NX_MDNS_RR temp_resource_record; +UINT ptr_name_length; + + + if (_nx_utility_string_length_check((CHAR *)ptr_name, &ptr_name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the resource record parameters. Rdata length: PTR name, string should include the first'.' and last '\0'. */ + status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_PTR, ttl, (ptr_name_length + 2), set, NX_TRUE, is_valid, &temp_resource_record, interface_index); + + /* Check for error. */ + if (status) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add the ptr name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, ptr_name, ptr_name_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), + NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + + /* Delete the strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &ptr_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, 0); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, ptr_rr, ptr_rr -> nx_mdns_rr_timer_count); + + if (insert_rr) + *insert_rr = ptr_rr; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_srv_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS SRV resource record into local buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name Service nstance name */ +/* ttl The ttl of the service */ +/* set The resource record set */ +/* priority The priority of target host */ +/* weights Service weight */ +/* port The port on this target host */ +/* target The target host */ +/* insert_rr Pointer to insert record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_srv_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, USHORT priority, + USHORT weights, USHORT port, UCHAR *target, NX_MDNS_RR **insert_rr, UINT interface_index) +{ + +UINT status; +NX_MDNS_RR *srv_rr; +NX_MDNS_RR temp_resource_record; +UINT target_length; + + if (_nx_utility_string_length_check((CHAR *)target, &target_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the resource record parameters. Rdata length: PRIORITY, WEIGHTS, PORT, TARGET, name string should include the first'.' and last '\0'. */ + status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_SRV, ttl, target_length + 8, set, NX_TRUE, NX_FALSE, &temp_resource_record, interface_index); + + /* Check for error. */ + if (status) + { + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Add the name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, target, target_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), + NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Set the SRV parameters. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority = priority; + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights = weights; + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port = port; + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &srv_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, 0); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, srv_rr, srv_rr -> nx_mdns_rr_timer_count); + + if (insert_rr) + *insert_rr = srv_rr; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_txt_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS TXT resource record into local buffer. */ +/* the TXT records are formatted in a "key=value" notation with ";" */ +/* acting as separator when more then one key is available. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* ttl The resource record ttl */ +/* set The resource record set */ +/* txt The txt string */ +/* insert_rr Pointer to insert record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into the cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_txt_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *txt, NX_MDNS_RR **insert_rr, UINT interface_index) +{ + +UINT status; +NX_MDNS_RR *txt_rr; +NX_MDNS_RR temp_resource_record; +UINT txt_length; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Set the resource record parameters. */ + status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_TXT, ttl, 0, set, NX_TRUE, NX_FALSE, &temp_resource_record, interface_index); + + /* Check for error. */ + if (status) + { + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + if (txt) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)txt, &txt_length, NX_MDNS_NAME_MAX)) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Calculate the text string.inlcude the one byte label. */ + temp_resource_record.nx_mdns_rr_rdata_length = (USHORT)(txt_length + 1); + + /* Add the name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, txt, txt_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), + NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + } + else + { + temp_resource_record.nx_mdns_rr_rdata_length = 1; + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data = NX_NULL; + } + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &txt_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr,NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + if (txt) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data, 0); + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + return(status); + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, txt_rr, txt_rr -> nx_mdns_rr_timer_count); + + if (insert_rr) + *insert_rr = txt_rr; + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_nsec_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS A resource record into local cache. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* add_a Flag for adding A record */ +/* add_aaaa Flag for adding AAAA record */ +/* type Type for host or service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_add_string Add the string into cache */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into cache */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_host_name_register Register the host name */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_nsec_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR add_a, UCHAR add_aaaa, UCHAR type, UINT interface_index) +{ +UINT status; +NX_MDNS_RR *insert_rr; +UCHAR bitmap_length = 0; +ULONG rdata_length = 0; +NX_MDNS_RR temp_resource_record; +UINT name_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the next domain name, include the first'.' and last '\0'. */ + rdata_length = name_length + 2; + + /* Add the window block and bitmap length. */ + rdata_length += 2; + + /* Add the NSEC with A/AAAA Bitmap. */ + if (type == NX_MDNS_ADD_NSEC_FOR_HOST) + { + /* Set the Bitmaps length. */ + if (add_aaaa == NX_TRUE) + bitmap_length = 4; + else + bitmap_length = 1; + } + else + { + + /* Add the NSEC with SRV/TXT Bitmap. */ + bitmap_length = 5; + } + + /* Add the Bitmaps. */ + rdata_length += bitmap_length; + + /* Set the resource record parameters. */ + status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_NSEC, NX_MDNS_RR_TTL_HOST, rdata_length, + NX_MDNS_RR_SET_UNIQUE, NX_FALSE, NX_TRUE, &temp_resource_record, interface_index); + + /* Check for error. */ + if (status) + { + return(status); + } + + /* Add the next domain name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, name, name_length, + (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain), + NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + { + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + return(status); + } + + /* Set the window block and bitmap length. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block = 0; + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length = bitmap_length; + + /* Add the Bitmap for host. */ + if (type == NX_MDNS_ADD_NSEC_FOR_HOST) + { + + /* Encode the Bitmap. */ + if ((add_a == NX_TRUE) && (add_aaaa == NX_TRUE)) + { + + /* Add the A Bitmap. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0] = 64; + + /* Add the AAAA Bitmap. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[3] = 8; + } + else if ((add_a == NX_TRUE)) + { + + /* Add the A Bit map. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0] = 64; + } + else + { + + /* Add the AAAA Bitmap. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[3] = 8; + } + } + else + { + /* Add the TXT Bitmap for service. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[2] = 128; + + /* Add the SRV Bitmap for service. */ + temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[4] = 64; + + } + + /* Add the resource record. */ + status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &insert_rr, NX_NULL); + + /* Check for error. */ + if (status) + { + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain, 0); + + return(status); + } + + /* Return a successful status. */ + return(NX_SUCCESS); +} +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_parameter_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the parameters of resource record. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* type The resource record type */ +/* ttl The resource record ttl */ +/* rdata_lenth The resource record length */ +/* set The resource record set */ +/* is_register Register flag */ +/* is_valid Valid flag */ +/* rr_record Pointer to resource record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_parameter_set(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, ULONG ttl, UINT rdata_length, + UCHAR set, UCHAR is_register, UCHAR is_valid, NX_MDNS_RR *rr_record, UINT interface_index) +{ + +UINT status; +UINT name_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Initialize the struct. */ + memset(rr_record, 0, sizeof(NX_MDNS_RR)); + + /* Add the name. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, name, name_length, + (VOID **)(&rr_record -> nx_mdns_rr_name), NX_FALSE, NX_TRUE); + + /* Check for error. */ + if (status) + return(status); + + /* Set the parameters. */ + rr_record -> nx_mdns_rr_interface_index = interface_index; + rr_record -> nx_mdns_rr_type = type; + rr_record -> nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; + rr_record -> nx_mdns_rr_ttl = ttl; + rr_record -> nx_mdns_rr_rdata_length = (USHORT)rdata_length; + + /* Set the resource record as uniqure. */ + if (set == NX_MDNS_RR_SET_UNIQUE) + rr_record -> nx_mdns_rr_word = (rr_record -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_UNIQUE); + + /* Check for mDNS started flag. */ + if (mdns_ptr -> nx_mdns_started) + { + + /* Check the valid flag for PTR resource record. */ + if (is_valid == NX_TRUE) + { + /* Set the resource record state. */ + rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; + } + else + { + + /* The is_register value be used for A/AAAA type, the value being NX_TRUE indicates the operation is to register the host name(probing and announcing the A/AAAA). The value being NX_FALSE indicates the operation is an address change, (announcing the A/AAAA). */ + if ((set == NX_MDNS_RR_SET_UNIQUE) && (is_register == NX_TRUE)) + { + + /* Set the resource record status. */ + rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; + rr_record -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; + rr_record -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; + } + else + { + + /* Set the resource record state. */ + rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; + rr_record -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; + rr_record -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; + + /* Check the announcing max time. */ + if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) + rr_record -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); + else + rr_record -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; + + /* Set the retransmit count. */ + if (mdns_ptr -> nx_mdns_announcing_retrans_interval) + rr_record -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; + else + rr_record -> nx_mdns_rr_retransmit_count = 1; + } + } + } + else + { + + /* Set the resource record status. */ + rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; + } + + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS resource record from the */ +/* local bufferor remote buffer according to the resource record set. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_rr The resource record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_delete(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr) +{ + +UINT status = NX_MDNS_SUCCESS; + +#ifndef NX_MDNS_DISABLE_CLIENT +ULONG *head; +NX_MDNS_RR *p; +#endif /* NX_MDNS_DISABLE_CLIENT */ + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + + /* Check for mDNS started flag. */ + if (mdns_ptr -> nx_mdns_started) + { + + /* Check the RR owner. */ + if (!(record_rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) + { + +#ifndef NX_MDNS_DISABLE_SERVER + if ((record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) + { + + /* Set the state to send Goodbye packet. */ + record_rr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; + + /* Set the retransmit count. */ + record_rr -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; + + /* Set the timer count. */ + record_rr -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; + + /* Set the delete flag. */ + record_rr -> nx_mdns_rr_word = (record_rr -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DELETE); + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, record_rr, record_rr -> nx_mdns_rr_timer_count); + } + else + { + + /* Delete the resource records. */ + status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, record_rr); + } + +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { + +#ifndef NX_MDNS_DISABLE_CLIENT + if (record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) + { + + /* Set the pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + + if(head) + { + head = (ULONG*)(*head); + + /* Check the remote resource record, stop the updating resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + if (p == record_rr) + continue; + + if ((p -> nx_mdns_rr_name == record_rr -> nx_mdns_rr_name) && + (p -> nx_mdns_rr_type == record_rr -> nx_mdns_rr_type) && + (p -> nx_mdns_rr_class == record_rr -> nx_mdns_rr_class)) + { + + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) + { + + /* Clear the Updating flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_UPDATING)); + } + + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING) + { + if (p -> nx_mdns_rr_retransmit_count) + { + + /* mDNS querier need not update the RR, The original updating ttl is at 80%, 85%, 90%, 95%. Update the timer.*/ + /* timer_count: P, timer_count: C, rr_ttl: T. + P = P + C * T * 5%. */ + p -> nx_mdns_rr_timer_count = (p -> nx_mdns_rr_timer_count + p -> nx_mdns_rr_retransmit_count * p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 5 /100); + + /* Clear the retransmit count. */ + p -> nx_mdns_rr_retransmit_count = 0; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } + } + } + } + } + } + + /* Delete the resource record. */ + status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, record_rr); + +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + } + else + { + /* Check the RR owner. */ + if (!(record_rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) + { + +#ifndef NX_MDNS_DISABLE_SERVER + status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, record_rr); +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { + +#ifndef NX_MDNS_DISABLE_CLIENT + status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, record_rr); +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return status. */ + return (status); +} + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_local_cache_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS instance. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_local_cache_clear Actual local cache clear */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_mdns_local_cache_clear(NX_MDNS *mdns_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!mdns_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid server attributes. */ + if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) + { + return(NX_MDNS_PARAM_ERROR); + } + + /* Call actual mDNS local cache clear service. */ + status = _nx_mdns_local_cache_clear(mdns_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_local_cache_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function clears the mDNS local cache. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from cache */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_local_cache_clear(NX_MDNS *mdns_ptr) +{ + +UINT status = NX_MDNS_SUCCESS; +ULONG *head; +NX_MDNS_RR *p; + + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Delete the resource records. */ + status = _nx_mdns_rr_delete(mdns_ptr, p); + + /* Check the status. */ + if (status) + break; + } + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Return a successful status. */ + return(status); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_name_resolve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resloves the service name, type, domain. */ +/* */ +/* INPUT */ +/* */ +/* srv_name Pointer to SRV name */ +/* name The name of the service */ +/* type The type of to the service */ +/* domain The domain */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* mDNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_service_name_resolve(UCHAR *srv_name, UCHAR **name, UCHAR **type, UCHAR **domain) +{ + +UINT i; +UINT count; +UINT prepend_index; +UINT append_index; +UINT type_index; +UINT domain_index; +UCHAR *pointer; +UINT protocol_length; + + + /* Initialize the parameters. */ + count = 0; + prepend_index = 0; + append_index = 0; + type_index = 0; + domain_index = 0; + + /* Set the service name pointer. */ + pointer = srv_name; + + /* Service Instance name, */ + /* .._tcp. : + name: + type: ._tcp + domain: . */ + while (*srv_name != '\0') + { + + /* Update the index. */ + append_index ++; + + if (*srv_name == '.') + { + + /* Set the value. */ + i = 0; + + while (nx_mdns_app_protocol[i]) + { + + /* Check string length. */ + if (_nx_utility_string_length_check(nx_mdns_app_protocol[i], &protocol_length, NX_MDNS_TYPE_MAX)) + { + continue; + } + + /* Find the key string. "_tcp" , "_udp" etc. */ + if (!_nx_mdns_name_match(pointer + prepend_index, (UCHAR *)(nx_mdns_app_protocol[i]), protocol_length)) + { + + /* Get the pointer. */ + /* EL-PC.Test._http._tcp.local + type index pointer to the _http._tcp, + domain_index pointer to the local. */ + domain_index = append_index; + + /* Set the name pointer. */ + if (type_index) + { + *name = pointer; + + /* Set the trailing null of name. */ + *(pointer + type_index -1) = '\0'; + } + else + { + *name = NX_NULL; + } + + /* Set the type pointer. */ + *type = pointer + type_index; + + /* Set the trailing null of type. */ + *(pointer + domain_index -1) = '\0'; + + /* Set the type pointer. */ + *domain = pointer + domain_index; + + return(NX_MDNS_SUCCESS); + } + i ++; + } + + /* Update the '.' count. */ + count ++; + + /* The type index is pointer to the . */ + if (count != 1) + { + + /* Update the type index. */ + type_index = prepend_index; + } + + prepend_index = append_index; + } + + srv_name ++; + } + + return(NX_MDNS_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_name_assemble PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resloves the service name, type, domain. */ +/* */ +/* INPUT */ +/* */ +/* srv_name Pointer to SRV name */ +/* name The name of the service */ +/* type The type of to the service */ +/* domain The domain */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* mDNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_service_name_assemble(UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *domain, UCHAR *record_buffer, UINT buffer_size, UINT *type_index) +{ + +UINT index; +UINT length; + + /* Initialize the struct. */ + index = 0; + memset(record_buffer, 0, buffer_size); + if (type_index) + { + *type_index = 0; + } + + /* Construct the service name. */ + + /* Add the name. */ + if (name) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)name, &length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + memcpy((CHAR *)(record_buffer + index), (const char*)name, length); + index += length; + + *(record_buffer + index) = '.'; + index ++; + } + + /* Add the sub type. */ + if (sub_type) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)sub_type, &length, NX_MDNS_LABEL_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + if (type_index) + { + *type_index = index; + } + memcpy((CHAR *)(record_buffer + index), (const char*)sub_type, length); + index += length; + *(record_buffer + index) = '.'; + index ++; + + /* Add the key word "_sub". */ + memcpy((CHAR *)(record_buffer + index), (const char*)"_sub", 5); + index += 4; + *(record_buffer + index) = '.'; + index ++; + } + + /* Add the type. */ + if (type) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)type, &length, NX_MDNS_TYPE_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Set the type index. */ + if ((type_index) && + (!sub_type)) + { + *type_index = index; + } + + memcpy((CHAR *)record_buffer + index, (const char*)type, length); + index += length; + *(record_buffer + index) = '.'; + index ++; + } + + /* Add the domain. */ + if (domain) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)domain, &length, NX_MDNS_DOMAIN_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + memcpy((CHAR *)(record_buffer + index), (const char*)domain, length); + index += length; + } + + /* Check the size. Compliant Multicast DNS implementations MUST support names up to 255 bytes plus a terminating zero, RFC6762, Page64. */ + if ((index > buffer_size) || + (index > NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + return(NX_MDNS_SUCCESS); +} + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_mdns_host_name_register PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resloves the service name, type, domain. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* type The type of operation */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_rr_a_aaaa_add Add the A/AAAA resource record*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_enable Enable mDNS */ +/* _nx_mdns_address_change_process Process address change */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_host_name_register(NX_MDNS *mdns_ptr, UCHAR type, UINT interface_index) +{ + +#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 +UINT status; +#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ +NX_IP *ip_ptr; +UINT index = 0; +UCHAR add_a = NX_FALSE; +UCHAR add_aaaa = NX_FALSE; +UINT host_name_length; + +#ifdef NX_MDNS_ENABLE_IPV6 +NXD_IPV6_ADDRESS *ipv6_address_ptr; +#endif /* NX_MDNS_ENABLE_IPV6 */ + + +#if defined NX_DISABLE_IPV4 && !defined NX_MDNS_ENABLE_IPV6 + NX_PARAMETER_NOT_USED(type); +#endif /* NX_DISABLE_IPV4 && ! NX_MDNS_ENABLE_IPV6 */ + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_host_name, &host_name_length, NX_MDNS_HOST_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Construct the A/AAAA name. */ + memcpy((CHAR *)(&temp_string_buffer[index]), (const char*)mdns_ptr -> nx_mdns_host_name, host_name_length); + index += host_name_length; + + temp_string_buffer[index] = '.'; + index ++; + memcpy((CHAR *)(&temp_string_buffer[index]), (CHAR *)"local", sizeof("local")); + + /* Set the ip pointer. */ + ip_ptr = mdns_ptr -> nx_mdns_ip_ptr; + + /* Get the IP mutex. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + +#ifndef NX_DISABLE_IPV4 + /* Add the A resource records message. */ + if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address) + { + + /* Add the A resource records message. */ + status = _nx_mdns_rr_a_aaaa_add(mdns_ptr, &temp_string_buffer[0], &(ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address), + NX_MDNS_IPV4_ADDRESS_LENGTH, type, interface_index); + + /* Check the status. */ + if (status) + { + + /* Release the IP mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(status); + } + + /* Set the flag. */ + add_a = NX_TRUE; + } +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + /* Get the IPv6 address pointer.*/ + ipv6_address_ptr = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head; + + while(ipv6_address_ptr) + { + + if (ipv6_address_ptr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID) + { + + /* Add the AAAA resource records message. */ + status = _nx_mdns_rr_a_aaaa_add(mdns_ptr, &temp_string_buffer[0], (ULONG *)(&ipv6_address_ptr -> nxd_ipv6_address[0]), + NX_MDNS_IPV6_ADDRESS_LENGTH, type, interface_index); + + /* Check the status. */ + if (status) + { + + /* Release the IP mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(status); + } + + /* Set the flag. */ + add_aaaa = NX_TRUE; + } + + /* Update the pointer. */ + ipv6_address_ptr = ipv6_address_ptr -> nxd_ipv6_address_next; + } +#endif /* NX_MDNS_ENABLE_IPV6 */ + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + + /* Add the NSEC resource record. */ + if ((add_a == NX_TRUE) || (add_aaaa == NX_TRUE)) + _nx_mdns_rr_nsec_add(mdns_ptr, &temp_string_buffer[0], add_a, add_aaaa, NX_MDNS_ADD_NSEC_FOR_HOST, interface_index); +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* Release the IP mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles waking up the mDNS helper thread to process */ +/* the timer event on a periodic basis. */ +/* */ +/* INPUT */ +/* */ +/* mdns_value mDNS instance for a ulong */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX system timer thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_timer_entry(ULONG mdns_value) +{ + +NX_MDNS *mdns_ptr; + + + /* Setup mDNS pointer from the input value. */ + mdns_ptr = (NX_MDNS *) mdns_value; + + /* Set the timer event. */ + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_TIMER_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_timer_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process all resource records according to the state, */ +/* Set the flags to send the probing, announcing, query, response and */ +/* goodbye mDNS message. Delete the resource record when the resource */ +/* record is invalid. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_info_get Get the timer info */ +/* tx_timer_deactivate Deactivate the timer */ +/* tx_timer_change Change the timer */ +/* tx_timer_activate Activate the timer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_enable Enable the mDNS */ +/* _nx_mdns_rr_a_aaaa_add Add the A/AAAA resource record*/ +/* _nx_mdns_rr_ptr_add Add the ptr resource record */ +/* _nx_mdns_rr_srv_add Add the srv resource record */ +/* _nx_mdns_rr_txt_add Add the txt resource record */ +/* _nx_mdns_rr_delete Delete the resource record */ +/* _nx_mdns_local_cache_clear Clear the local cache */ +/* _nx_mdns_query Send the continuous query */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* _nx_mdns_conflict_process Process the conflict */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_timer_set(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr, ULONG timer_count) +{ + + +TX_INTERRUPT_SAVE_AREA +ULONG remaining_ticks; +ULONG schedule_count; +UINT active; + + if (timer_count) + { + + /* Disable interrupt */ + TX_DISABLE + + /* Get the remaining_ticks of mDNS timer;*/ + tx_timer_info_get(&mdns_ptr -> nx_mdns_timer, TX_NULL, &active, &remaining_ticks, TX_NULL, TX_NULL); + + /* If the timer is not active, the remaining ticks and schedule count are set to 0. */ + if(active == NX_FALSE) + { + remaining_ticks = 0; + schedule_count = 0; + } + else + { + + /* Get the reschedule timer count of last timer. */ + schedule_count = mdns_ptr -> nx_mdns_timer_min_count; + } + + /* Check the timer. if exceed the timer count range, update the timer. */ + if((timer_count < remaining_ticks) || active == NX_FALSE) + { + + /* Set the minimum timer count. + The minimum timer count indicate the intervals between last timer event and next timer event. */ + mdns_ptr -> nx_mdns_timer_min_count = (schedule_count - remaining_ticks) + timer_count; + + /* Change the timer ticks with minimum timer count.*/ + tx_timer_deactivate(&(mdns_ptr -> nx_mdns_timer)); + tx_timer_change(&(mdns_ptr -> nx_mdns_timer), timer_count, timer_count ); + tx_timer_activate(&(mdns_ptr -> nx_mdns_timer)); + } + + /* Update the Resource record life timer count*/ + record_rr -> nx_mdns_rr_timer_count = (schedule_count - remaining_ticks) + timer_count; + + /* Restore interrupts. */ + TX_RESTORE + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_timer_event_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process all resource records according to the state, */ +/* Set the flags to send the probing, announcing, query, response and */ +/* goodbye mDNS message. Delete the resource record when the resource */ +/* record is invalid. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags to wake mDNS */ +/* tx_timer_deactivate Deactivate the timer */ +/* tx_timer_change Change the timer */ +/* tx_timer_activate Activate the timer */ +/* _nx_mdns_service_name_resolve Resolve the service name */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from the cache */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_thread_entry Processing thread for mDNS */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_timer_event_process(NX_MDNS *mdns_ptr) +{ + +ULONG event_flags = 0; +ULONG timer_min_count = 0xFFFFFFFF; +ULONG *head, *tail; +NX_MDNS_RR *p; +UCHAR i; + +#ifndef NX_MDNS_DISABLE_CLIENT +ULONG remaining_ticks; +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#ifndef NX_MDNS_DISABLE_SERVER +UINT status; +NX_MDNS_RR *p1; +UCHAR *service_name; +UCHAR *service_type; +UCHAR *service_domain; +UINT rr_name_length; +#endif /* NX_MDNS_DISABLE_SERVER */ + + + for(i = 0; i < 2; i++) + { + + /* Set the pointer. */ + if(i == NX_MDNS_CACHE_TYPE_LOCAL) + { +#ifndef NX_MDNS_DISABLE_SERVER + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { +#ifndef NX_MDNS_DISABLE_CLIENT + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + + if(head == NX_NULL) + continue; + + tail = (ULONG*)(*head); + + /* Check the remote resource record lifetime. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG*)p < tail; p++) + { + + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Update the remaining ticks of peer resource record. */ + if (((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING))) + { + if (p -> nx_mdns_rr_remaining_ticks > mdns_ptr -> nx_mdns_timer_min_count) + { + p -> nx_mdns_rr_remaining_ticks -= mdns_ptr -> nx_mdns_timer_min_count; + } + else + { + p -> nx_mdns_rr_remaining_ticks = 0; + } + } + + /* Calculate the time interval for two responses.*/ + if (p -> nx_mdns_rr_response_interval > (UCHAR)mdns_ptr -> nx_mdns_timer_min_count) + { + p -> nx_mdns_rr_response_interval = (UCHAR)(p -> nx_mdns_rr_response_interval - mdns_ptr -> nx_mdns_timer_min_count); + + /* Compare the timer count.and set the minimum timer count. */ + if ((p -> nx_mdns_rr_response_interval != 0) && + (p -> nx_mdns_rr_response_interval < timer_min_count)) + { + timer_min_count = p -> nx_mdns_rr_response_interval; + } + } + else + { + p -> nx_mdns_rr_response_interval = 0; + } + + /* If the timer count is zero, means do not do anything */ + if (p -> nx_mdns_rr_timer_count == 0) + continue; + + if (p -> nx_mdns_rr_timer_count > mdns_ptr -> nx_mdns_timer_min_count) + { + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_timer_count - mdns_ptr -> nx_mdns_timer_min_count; + + /* Check the timer count range. */ + if (p -> nx_mdns_rr_timer_count <= NX_MDNS_TIMER_COUNT_RANGE) + { + p -> nx_mdns_rr_timer_count = 0; + } + else + { + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + } + else + { + p -> nx_mdns_rr_timer_count = 0; + } + + /* If the timer count is zero, means the timeout. */ + if (p -> nx_mdns_rr_timer_count != 0) + continue; + + /* Check the state. */ + switch (p -> nx_mdns_rr_state) + { + +#ifndef NX_MDNS_DISABLE_SERVER + case NX_MDNS_RR_STATE_PROBING: + { + + /* mDNS Server probing the RRs at 0ms, 250ms, 500ms. RFC6762, Section8.1, Page26. */ + if (p -> nx_mdns_rr_retransmit_count) + { + + /* Set the send flag.*/ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the probing flag. */ + event_flags = event_flags | NX_MDNS_PROBING_SEND_EVENT; + + /* Set the timer count. 250ms. */ + p -> nx_mdns_rr_timer_count = NX_MDNS_PROBING_TIMER_COUNT; + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + else + { + + /* Probing complete, and move to the next step, Announcing. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; + + /* Set the first announcing timer interval. */ + p -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; + + /* Set the retransmit count. */ + if (mdns_ptr -> nx_mdns_announcing_retrans_interval) + p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; + else + p -> nx_mdns_rr_retransmit_count = 1; + + /* Set the next timer count. */ + p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; + + /* Check the announcing max time. */ + if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) + p -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); + else + p -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; + + /* Yes, probing complete, add the related PTR resource records. */ + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)p -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) + { + break; + } + + /* Store the service name. */ + memcpy((CHAR *)(&temp_string_buffer[0]), (const char*)p -> nx_mdns_rr_name, rr_name_length + 1); + + /* Reslove the service name. */ + status = _nx_mdns_service_name_resolve(&temp_string_buffer[0], &service_name, &service_type, &service_domain); + + /* Check the status. */ + if (status) + { + break; + } + + /* Service name registered success, invoke the notify function. */ + if (mdns_ptr -> nx_mdns_probing_notify) + { + (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, service_name, NX_MDNS_LOCAL_SERVICE_REGISTERED_SUCCESS); + } + } + + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) + { + + /* Service name registered success, invoke the notify function. */ + if (mdns_ptr -> nx_mdns_probing_notify) + { + (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, mdns_ptr -> nx_mdns_host_name, NX_MDNS_LOCAL_HOST_REGISTERED_SUCCESS); + } + } + + /* Probing complete, Has been wating for 250ms, Directly announcing the resource record. */ + p --; + } + break; + } + + case NX_MDNS_RR_STATE_ANNOUNCING: + { + + /* mDNS Server Announcing the Resource records. */ + if (p -> nx_mdns_rr_retransmit_count) + { + + /* Set the send flag to send the probing. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the announcing flag. */ + event_flags = event_flags | NX_MDNS_ANNOUNCING_SEND_EVENT; + + /* Yes, probing complete, add the related PTR resource records and NSEC resource records. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) + { + + for (p1 = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p1 < tail; p1++) + { + + /* Check the state. */ + if (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface. */ + if (p1 -> nx_mdns_rr_interface_index != p -> nx_mdns_rr_interface_index) + continue; + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + if ((p1 ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) && + (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_name)) + { + + /* Set the send flag to send the probing. */ + p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + } +#endif /*NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && + (p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && + (p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == p -> nx_mdns_rr_name)) + { + + /* Set the send flag to send the probing. */ + p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + } + } + } + + /* Check last the retransmit in this period announcing. */ + if (p -> nx_mdns_rr_retransmit_count - 1) + { + + if (mdns_ptr -> nx_mdns_announcing_retrans_interval) + { + + /* Set the timer count. */ + p -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_announcing_retrans_interval; + + /* Compare the timer count and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + } + else + { + if (p -> nx_mdns_rr_announcing_max_time) + { + + /* Update the timer count. */ + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_retransmit_lifetime; + + /* Calculate the next timer count. */ + p -> nx_mdns_rr_retransmit_lifetime = (ULONG)(p -> nx_mdns_rr_retransmit_lifetime * (ULONG)(2 << (mdns_ptr -> nx_mdns_announcing_factor - 1))); + + /* Check the announcing period time interval. */ + if (p -> nx_mdns_rr_retransmit_lifetime > mdns_ptr -> nx_mdns_announcing_period_interval) + p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period_interval; + + /* Set the retransmit count. */ + if (mdns_ptr -> nx_mdns_announcing_retrans_interval) + p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; + else + p -> nx_mdns_rr_retransmit_count = 1; + + /* Set the retransmit count. */ + p -> nx_mdns_rr_retransmit_count++; + + /* Check the announcing time. */ + if (p -> nx_mdns_rr_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) + p -> nx_mdns_rr_announcing_max_time--; + + /* Compare the timer count and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + else + { + + /* Announcing complete, Update the resource record state valid, . */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; + + /* Clear the timer count. */ + p -> nx_mdns_rr_timer_count = 0; + } + } + } + break; + } + + case NX_MDNS_RR_STATE_GOODBYE: + { + + /* mDNS Server send Goodbye packet. */ + if (p -> nx_mdns_rr_retransmit_count) + { + + /* Set the send flag to send the probing. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the announcing flag. */ + event_flags = event_flags | NX_MDNS_ANNOUNCING_SEND_EVENT; + + /* Set the timer count. */ + p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + else + { + + /* Check for RR delete flag. */ + if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DELETE) + { + + /* Delete the resource records. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); + } + else + { + + /* Suspend the resource record. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; + p -> nx_mdns_rr_timer_count = 0; + } + } + break; + } +#endif /* NX_MDNS_DISABLE_SERVER */ + + + case NX_MDNS_RR_STATE_VALID: + { + + if(i == NX_MDNS_CACHE_TYPE_PEER) + { + /* Set the resource record status. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_UPDATING; + + /* Check the updating flag. */ + if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UPDATING) + { + + /* Set the retransmit count. */ + p -> nx_mdns_rr_retransmit_count = NX_MDNS_RR_UPDATE_COUNT; + + /* 50% of the record lifetime has elapsed,the querier should plan to issure a query at 80%-82% of the record lifetime */ + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(30 + (NX_RAND() % 3)) / 100; + } + else + { + /* Set the retransmit count. */ + p -> nx_mdns_rr_retransmit_count = 0; + + /* 50% of the record lifetime has elapsed, Delete the resource record at 100% of the record lifetime */ + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 50 / 100; + } + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + + /* Check the send flag. */ + else + { + if (p -> nx_mdns_rr_send_flag) + { + + /* Set the send flag to send the response. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + /* Clear the NSEC additional send. */ + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) + p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_FALSE; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* mDNS Responder MUST NOT multicast a record until at least one second has elapsed since the last time that record was multicast. RFC6762, Section6, Page16. */ + /* Set the next response time interval. */ + p -> nx_mdns_rr_response_interval = (UCHAR)(NX_MDNS_RESPONSE_INTERVAL + NX_MDNS_TIMER_COUNT_RANGE); + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_response_interval < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_response_interval; + } + + /* Set the announcing flag. */ + event_flags = event_flags | NX_MDNS_RESPONSE_SEND_EVENT; + } + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + else + { + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) + { + if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send) + { + p -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_ADDITIONAL; + p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_FALSE; + + /* Set the announcing flag. */ + event_flags = event_flags | NX_MDNS_RESPONSE_SEND_EVENT; + } + } + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + } + break; + } + + +#ifndef NX_MDNS_DISABLE_CLIENT + case NX_MDNS_RR_STATE_QUERY: + { + + /* mDNS Client did not receive the response, send the query again. */ + if (!p -> nx_mdns_rr_timer_count) + { + + /* Check the Duplicate Question. If the flag set, Host should not send the query until the next timeout. */ + if (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DUPLICATE_QUERY)) + { + + /* Set the send flag to send the query. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the query flag. */ + event_flags = event_flags | NX_MDNS_QUERY_SEND_EVENT; + } + + /* Clear the duplicate flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & ~NX_MDNS_RR_FLAG_DUPLICATE_QUERY); + + /* Double the next timer count. */ + p -> nx_mdns_rr_retransmit_lifetime = p -> nx_mdns_rr_retransmit_lifetime << 1; + + /* The interval between the first two queries MUST be at least one second. RFC6762, Section5.2, Page9. */ + if (p -> nx_mdns_rr_retransmit_lifetime < NX_MDNS_QUERY_MIN_TIMER_COUNT) + { + p -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_QUERY_MIN_TIMER_COUNT; + } + + /* When the interval between queries reaches or exceeds 60 minutes, a querier MAY cap the interval to a maximum of 60 minutes. RFC6762, Section5.2, Page10. */ + if (p -> nx_mdns_rr_retransmit_lifetime > NX_MDNS_QUERY_MAX_TIMER_COUNT) + { + p -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_QUERY_MAX_TIMER_COUNT; + } + + /* Update the timer count. */ + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_retransmit_lifetime; + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + break; + } + + case NX_MDNS_RR_STATE_UPDATING: + { + + /* The querier should plan to issure a query at 80%-82% of the record lifetime, and then if no answer is received, + at 85%-87%, 90%-92% and 95%-97%. the record is deleted when it reaches 100% of its lifetime. RFC6762, Section5.2, Page10. */ + if (p -> nx_mdns_rr_retransmit_count) + { + + /* Set the send flag to retransmit its query. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the query flag. */ + event_flags = event_flags | NX_MDNS_QUERY_SEND_EVENT; + + /* Update the timer count. Client should send the updating message every 5% of ttl. */ + if (p -> nx_mdns_rr_retransmit_count == 1) + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_remaining_ticks; + else + { + remaining_ticks = p -> nx_mdns_rr_remaining_ticks; + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 5 / 100; + + /* Get the remaining ticks in 5% of TTL. */ + while(remaining_ticks > p -> nx_mdns_rr_timer_count) + remaining_ticks -= p -> nx_mdns_rr_timer_count; + + p -> nx_mdns_rr_timer_count = remaining_ticks + (p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(NX_RAND() % 3) / 100); + } + + /* Compare the timer count.and set the minimum timer count. */ + if (p -> nx_mdns_rr_timer_count < timer_min_count) + { + timer_min_count = p -> nx_mdns_rr_timer_count; + } + } + else + { + + /* Delete the resource record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); + } + break; + } + + case NX_MDNS_RR_STATE_DELETE: + case NX_MDNS_RR_STATE_POOF_DELETE: + { + + /* Delete the resource record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); + break; + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + + default: + { + break; + } + } + } + } + + /* If the specified timer rate is different with the new timer min count,then update it.*/ + if (mdns_ptr -> nx_mdns_timer_min_count != timer_min_count) + { + + /* Set the minimum timer count.*/ + mdns_ptr -> nx_mdns_timer_min_count = timer_min_count; + + /* Deactivate the timer. */ + tx_timer_deactivate(&(mdns_ptr -> nx_mdns_timer)); + + if (timer_min_count != 0xFFFFFFFF) + { + + /* Change the timer ticks with minimum timer count.*/ + tx_timer_change(&(mdns_ptr -> nx_mdns_timer), + mdns_ptr -> nx_mdns_timer_min_count, + mdns_ptr -> nx_mdns_timer_min_count); + tx_timer_activate(&(mdns_ptr -> nx_mdns_timer)); + } + } + + /* Set the event to send mDNS query. */ + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), event_flags, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_udp_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the mDNS UDP receive notify callback. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to udp socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* UDP receive callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + + + NX_PARAMETER_NOT_USED(socket_ptr); + + /* Check the mDNS. */ + if(_nx_mdns_created_ptr) + { + + /* Set the receive UDP packet notify. */ + tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_PKT_RX_EVENT, TX_OR); + } + + return; +} + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_ip_address_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the mDNS UDP receive notify callback. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to udp socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* UDP receive callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_ip_address_change_notify(NX_IP *ip_ptr, VOID *additional_info) +{ + + + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(additional_info); + + /* Check the mDNS. */ + if(_nx_mdns_created_ptr) + { + + /* Set the address change event event. */ + tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_ADDRESS_CHANGE_EVENT, TX_OR); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_ipv6_address_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the mDNS UDP receive notify callback. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to udp socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags */ +/* */ +/* CALLED BY */ +/* */ +/* UDP receive callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifdef NX_MDNS_ENABLE_IPV6 +static VOID _nx_mdns_ipv6_address_change_notify(NX_IP *ip_ptr, UINT method, UINT interface_index, UINT index, ULONG *ipv6_address) +{ + + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(method); + NX_PARAMETER_NOT_USED(interface_index); + NX_PARAMETER_NOT_USED(index); + NX_PARAMETER_NOT_USED(ipv6_address); + + /* Check the mDNS. */ + if(_nx_mdns_created_ptr) + { + + /* Set the address change event. */ + tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_ADDRESS_CHANGE_EVENT, TX_OR); + } + return; +} +#endif /* NX_MDNS_ENABLE_IPV6 */ +#endif /* NX_MDNS_DISABLE_SERVER */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point for the mDNS helper thread. */ +/* mDNS helper thread is responsible for processing mDNS events. */ +/* Receive and send the mDNS packet. */ +/* */ +/* INPUT */ +/* */ +/* mdns_value Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* tx_event_flags_get Get the mDNS events */ +/* nx_udp_socket_receive Receive the mDNS packet */ +/* nx_packet_release Release the mDNS packet */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* _nx_mdns_announcing_send Send announcing message */ +/* _nx_mdns_probing_send Send probing message */ +/* _nx_mdns_query_send Send query message */ +/* _nx_mdns_response_send Send response message */ +/* _nx_mdns_timer_event_process Process the mDNS timer event */ +/* _nx_mdns_address_change_process Process the address change */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_thread_entry(ULONG mdns_value) +{ + +NX_MDNS *mdns_ptr; +NX_PACKET *packet_ptr; +ULONG mdns_events; +UINT status; +UINT interface_index; + + + /* Setup mDNS pointer from the input value. */ + mdns_ptr = (NX_MDNS *) mdns_value; + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Loop to process events for this mDNS instance. */ + while(1) + { + + /* Release the mDNS mutex. */ + tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); + + /* Pickup mDNS event flags. */ + tx_event_flags_get(&mdns_ptr -> nx_mdns_events, + NX_MDNS_ALL_EVENTS, TX_OR_CLEAR, + &mdns_events, TX_WAIT_FOREVER); + + /* Get the mDNS mutex. */ + tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); + + /* Check for an UDP packet receive event. */ + if (mdns_events & NX_MDNS_PKT_RX_EVENT) + { + while (1) + { + + /* Receive a UDP packet. */ + status = _nx_udp_socket_receive(&mdns_ptr -> nx_mdns_socket, + &packet_ptr, TX_NO_WAIT); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Discard the chained packets. */ + if (packet_ptr -> nx_packet_next) + { + nx_packet_release(packet_ptr); + continue; + } +#endif + + /* Get the interface. */ + if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) + { + interface_index = packet_ptr -> nx_packet_ip_interface -> nx_interface_index; + } + else + { + interface_index = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached -> nx_interface_index; + } + + /* Check the interface. */ + if (!mdns_ptr -> nx_mdns_interface_enabled[interface_index]) + { + /* Release the packet since mDNS is not enabled on this interface. */ + nx_packet_release(packet_ptr); + continue; + } + + /* Yes, Get the mDNS packet, process it. */ + _nx_mdns_packet_process(mdns_ptr, packet_ptr, interface_index); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Loop to send mDNS message for each interface. */ + for (interface_index = 0; interface_index < NX_MAX_PHYSICAL_INTERFACES; interface_index++) + { + + /* Check if this interface is enabled. + Exception: Goodbye message can be sent out after disable. */ + if ((!mdns_ptr -> nx_mdns_interface_enabled[interface_index]) && + (!(mdns_events & NX_MDNS_ANNOUNCING_SEND_EVENT))) + continue; + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Check for an mDNS probing send event. */ + if (mdns_events & NX_MDNS_PROBING_SEND_EVENT) + { + + /* Send probing. */ + _nx_mdns_probing_send(mdns_ptr, interface_index); + } + + /* Check for an mDNS announcing send event. */ + if (mdns_events & NX_MDNS_ANNOUNCING_SEND_EVENT) + { + + /* Send announcing. */ + _nx_mdns_announcing_send(mdns_ptr, interface_index); + } + + /* Check for an mDNS response send event. */ + if (mdns_events & NX_MDNS_RESPONSE_SEND_EVENT) + { + + /* Send response. */ + _nx_mdns_response_send(mdns_ptr, interface_index); + } +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Check for an mDNS query send event. */ + if (mdns_events & NX_MDNS_QUERY_SEND_EVENT) + { + + /* Send query. */ + _nx_mdns_query_send(mdns_ptr, interface_index); + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Check for an mDNS address change event. */ + if (mdns_events & NX_MDNS_ADDRESS_CHANGE_EVENT) + { + + /* Process the address change event. */ + _nx_mdns_address_change_process(mdns_ptr); + } +#endif /* NX_MDNS_DISABLE_SERVER */ + + /* Check for an mDNS timer process event. */ + if (mdns_events & NX_MDNS_TIMER_EVENT) + { + + /* Process the timer event. */ + _nx_mdns_timer_event_process(mdns_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks the interface and the IP address of received */ +/* packet, then preocesses the packet. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* packet_ptr Pointer to mDNS packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release the mDNS packet */ +/* _tx_thread_system_resume Resume thread service */ +/* _nx_mdns_timer_set Set the mDNS timer */ +/* _nx_mdns_name_string_decode Decode the name size */ +/* _nx_mdns_name_size_calculate Calculate the name size */ +/* _nx_mdns_rr_size_get Get the resource record size */ +/* _nx_mdns_conflict_process Process the mDNS conflict */ +/* _nx_mdns_cache_find_resource_record Find the mDNS resource record */ +/* _nx_mdns_packet_address_check Check the address and port */ +/* _nx_mdns_packet_rr_process Process resource record */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* from cache */ +/* nxd_udp_packet_info_extract Extract the packet info */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_thread_entry Processing thread for mDNS */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index) +{ + +USHORT mdns_flags; +UCHAR *data_ptr; +USHORT question_count; +USHORT authority_count; +USHORT answer_count; +UINT index; +NX_MDNS_RR *rr_search; +NX_MDNS_RR temp_resource_record; + +#ifndef NX_MDNS_DISABLE_SERVER +ULONG *head; +NX_MDNS_RR *p; +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES +ULONG match_count; +NX_MDNS_RR *nsec_rr; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ +#endif /* NX_MDNS_DISABLE_SERVER */ + + +#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK + /* Check the address and port. */ + if (_nx_mdns_packet_address_check(packet_ptr)) + { + return(NX_MDNS_ERROR); + } +#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ + + /* Check the packet length. */ + if (packet_ptr -> nx_packet_length < NX_MDNS_QDSECT_OFFSET) + { + return(NX_MDNS_ERROR); + } + + /* Extract the message type which should be the first byte. */ + mdns_flags = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET); + + /* Get the question count. */ + question_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET); + + /* Determine if we have any 'answers' to our DNS query. */ + answer_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET); + + /* Also check if there are any 'hints' from the Authoritative nameserver. */ + authority_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET); + + /* Update the answer count. Ignore the authority count and additional count for query message. */ + if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) + { + answer_count = (USHORT)(answer_count + authority_count); + + /* Include Additional section as well */ + answer_count = (USHORT)(answer_count + NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET)); + } + + /* Skip the Header. Point at the start of the question. */ + data_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDSECT_OFFSET; + + /* Process all the Question Section. */ + for (index = 0; index < question_count; index++) + { + + /* Check for data_ptr. */ + if (data_ptr >= packet_ptr -> nx_packet_append_ptr) + break; + + if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) + { + + /* Multicast DNS responses MUST NOT contain any question in the Question Section, + Any questions in the Question Section of a received Multicast DNS response MUST be silently ignored. RFC6762, Section6, Page14. */ + data_ptr += (_nx_mdns_name_size_calculate(data_ptr) + 4); + } + else + { + +#ifndef NX_MDNS_DISABLE_CLIENT + + /* Step1, mDNS Client process the Duplicate Question Suppression, RFC6762, Section7.3, Page24. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_PEER_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) + { + + /* Check the class top bit "QM". */ + if ((temp_resource_record.nx_mdns_rr_class & NX_MDNS_RR_CLASS_TOP_BIT) != NX_MDNS_RR_CLASS_TOP_BIT) + { + + /* Find the same resource record in remote buffer. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) + { + + /* Duplicate Question Suppression. */ + if (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) + { + + if (_nx_mdns_known_answer_find(mdns_ptr, rr_search) == NX_MDNS_NO_KNOWN_ANSWER) + { + + /* Yes, set the duplicate flag. process this flag in timer event process function. */ + rr_search -> nx_mdns_rr_word = rr_search -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DUPLICATE_QUERY; + } + } + +#ifdef NX_MDNS_ENABLE_CLIENT_POOF + /* Passive Observation Of Failures, RFC6762, Section10.5, Page38. */ + if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE)) + { + rr_search -> nx_mdns_rr_poof_count ++; + + /* After seeing two or more of these queries, and seeing no multicast response containing the expected anser within ten seconds, the record should be flushed from the cache. */ + if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) && + (rr_search -> nx_mdns_rr_poof_count >= NX_MDNS_POOF_MIN_COUNT)) + { + rr_search -> nx_mdns_rr_state = NX_MDNS_RR_STATE_POOF_DELETE; + rr_search -> nx_mdns_rr_timer_count = NX_MDNS_POOF_TIMER_COUNT; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, rr_search, rr_search -> nx_mdns_rr_timer_count); + } + } +#endif /* NX_MDNS_ENABLE_CLIENT_POOF */ + } + } + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Step2, mDNS Server process the normal query. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) + { + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + /* Set the match count. */ + match_count = 0; + nsec_rr = NX_NULL; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* Get head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + /* Find the same record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check whether the same record it is. RFC6762, Section6, Page13. */ + /* The rules: rrname must match the question name. + rrtype must match the question qtype unless the qtype is "ANY" or the rrtype is "CNAME". + rrclass must match the question qclass unless the qclass is "ANY". */ + if (p -> nx_mdns_rr_name != temp_resource_record.nx_mdns_rr_name) + continue; + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + + /* Check the NSEC type. */ + if (p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) + nsec_rr = p; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + if ((p -> nx_mdns_rr_type != temp_resource_record.nx_mdns_rr_type) && + (temp_resource_record.nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL) && + (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_CNAME)) + continue; + + /* Check the RR class, Ignore the top bit. */ + if ((p -> nx_mdns_rr_class != (temp_resource_record.nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)) && + ((temp_resource_record.nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)!= NX_MDNS_RR_CLASS_ALL)) + continue; + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + + /* Update the match count. */ + match_count ++; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* Check the state. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) + { + + /* Check the send flag, Flag is set indicate this resource record shoud be sent. */ + if (p -> nx_mdns_rr_send_flag) + { + + /* Set the flag to send this Resource records via multicast. + Store the old flag into the top bits. + Store the new flag into the low bits. + Format: 0001 0001 */ + p -> nx_mdns_rr_send_flag = ((NX_MDNS_RR_SEND_MULTICAST << 4) | NX_MDNS_RR_SEND_MULTICAST); + } + else + { + + /* Set the flag to send this Resource records via multicast.*/ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + } + + /* In the case where the query has the TC (truncated) bit set, indicating that subsequent Known-Answer packets will follow, + Responders SHOULD delay their responses by a random amount of time selected with uniform random distribution in the range 400-500ms. RFC6762, Section6, Page 15. */ + if (mdns_flags & NX_MDNS_TC_FLAG) + { + p -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_TC_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_TC_DELAY_RANGE)); + } + else + { + + /* A mDNS responder is only required to delay its transmission as necessary to ensure an interval of at least 250ms + since the last time the record was multicast on that interface. RFC6762, Section6, Page16 */ + if (authority_count) + { + if (p -> nx_mdns_rr_response_interval > (NX_MDNS_RESPONSE_INTERVAL - NX_MDNS_RESPONSE_PROBING_TIMER_COUNT)) + p -> nx_mdns_rr_response_interval = (UCHAR)(p -> nx_mdns_rr_response_interval - (NX_MDNS_RESPONSE_INTERVAL - NX_MDNS_RESPONSE_PROBING_TIMER_COUNT)); + else + p -> nx_mdns_rr_response_interval = 0; + } + + /* Check the response interval. */ + if (p -> nx_mdns_rr_response_interval <= NX_MDNS_TIMER_COUNT_RANGE) + { + + /* Set the timer count according to the resource record set.RFC6762, Section6, Page14. */ + if ((p ->nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) == NX_MDNS_RR_FLAG_UNIQUE) + { + p -> nx_mdns_rr_timer_count = NX_MDNS_RESPONSE_UNIQUE_DELAY; + } + else + { + /* Set the timer count, delay 20-120ms. */ + p -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_SHARED_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_SHARED_DELAY_RANGE)); + } + } + else + { + p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_response_interval; + } + } + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } + } + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + /* Send this NSEC response as additional answer. */ + if ((match_count == 0) && (nsec_rr)) + { + nsec_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_TRUE; + nsec_rr -> nx_mdns_rr_timer_count = NX_MDNS_RESPONSE_UNIQUE_DELAY; + _nx_mdns_timer_set(mdns_ptr, nsec_rr, nsec_rr -> nx_mdns_rr_timer_count); + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + } +#endif /* NX_MDNS_DISABLE_SERVER */ + + /* Update the data_ptr. */ + data_ptr += (_nx_mdns_name_size_calculate(data_ptr) + 4); + } + } + + /* Process all the Known-Answer records. */ + for (index = 0; index < answer_count; index++) + { + + /* Check for data_ptr. */ + if (data_ptr >= packet_ptr -> nx_packet_append_ptr) + break; + + if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) + { + +#ifndef NX_MDNS_DISABLE_SERVER + /* Step1, Cooperating Multicast DNS Responders, RFC6762, Section6.6, Page21. */ + /* Does the same rname and rdata name of resource record exist in the local buffer. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_ANSWER, interface_index) == NX_MDNS_SUCCESS) + { + + /* Find the same rname, rrtype, rrclass of resource record in local buffer. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) + { + + /* Probing state, conflict Resolution. */ + if ((rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) && + (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_PROBING)) + { + _nx_mdns_conflict_process(mdns_ptr, rr_search); + + /* Update the data_ptr. */ + data_ptr += _nx_mdns_rr_size_get(data_ptr); + + continue; + } + } + + /* Find the same rname, rrtype, rrclass and identical rdata of resource record in local buffer. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_ALL, &rr_search) == NX_MDNS_SUCCESS) + { + + /* If the TTL in this record(B) is less than half the true TTL in local record(A), A MUST announce local record via multicast. RFC6762, Section6.6,Page21. */ + if ((temp_resource_record.nx_mdns_rr_ttl << 1) < rr_search -> nx_mdns_rr_ttl) + { + + /* Set the flag. */ + rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; + + /* Set the timer count, delay 20-120ms. */ + rr_search -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_SHARED_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_SHARED_DELAY_RANGE)); + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, rr_search, rr_search -> nx_mdns_rr_timer_count); + } + + /* Duplicate Answer Suppression, RFC6762, Section7.4,Page24. + The TTL in that record is not less than the TTL this host would have given. Host should not send this response again. */ + if (temp_resource_record.nx_mdns_rr_ttl >= rr_search -> nx_mdns_rr_ttl) + { + + if (rr_search -> nx_mdns_rr_send_flag) + { + + /* Clear the flag. */ + rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + + /* Check the resource records set. */ + if (rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) + { + + /* Update the data_ptr. */ + data_ptr += _nx_mdns_rr_size_get(data_ptr); + + continue; + } + } + } + + /* Did the same name of resource record have existed in local buffer. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) + { + + /* Find the same name, rrtype, rrclass and different rdata of resource record in local buffer. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) + { + + /* Check the resource records set. RFC6762, Section6.6, Page21. */ + if (rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) + { + _nx_mdns_conflict_process(mdns_ptr, rr_search); + + /* Update the data_ptr. */ + data_ptr += _nx_mdns_rr_size_get(data_ptr); + + continue; + } + } + } +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Step2. Add the response resource records in remote buffer. */ + _nx_mdns_packet_rr_process(mdns_ptr, packet_ptr, data_ptr, interface_index); +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + else + { +#ifndef NX_MDNS_DISABLE_CLIENT + /* Clear the record. */ + + /* Step1, mDNS Client process the Known-Answer about Duplicate Question Suppression. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_PEER_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) + { + + /* Find the same resource record in remote buffer. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) + { + + /* Duplicate Question Suppression. */ + if (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) + { + + /* Yes, the query includes the Known-Answer Section, clear the duplicate flag. */ + rr_search -> nx_mdns_rr_word = (USHORT)(rr_search -> nx_mdns_rr_word & ~NX_MDNS_RR_FLAG_DUPLICATE_QUERY); + } + +#ifdef NX_MDNS_ENABLE_CLIENT_POOF + /* Passive Observation Of Failures, RFC6762, Section10.5, Page38. */ + if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE)) + { + rr_search -> nx_mdns_rr_poof_count --; + + /* Check the count. */ + if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE) && + (rr_search -> nx_mdns_rr_poof_count < NX_MDNS_POOF_MIN_COUNT)) + { + rr_search -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; + rr_search -> nx_mdns_rr_timer_count = 0; + } + } +#endif /* NX_MDNS_ENABLE_CLIENT_POOF */ + } + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#ifndef NX_MDNS_DISABLE_SERVER + + /* Step2. mDNS Server process the Known-Answer of normal query. */ + if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_ANSWER, interface_index) == NX_MDNS_SUCCESS) + { + + /* Find the same resource record. */ + if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_ALL, &rr_search) == NX_MDNS_SUCCESS) + { + + /* mDNS responder Must Not answer a mDNS query if the answer included the Answer Section with an RR TTL at least half the correct value. RFC6762, Section7.1, Page23. */ + if ((!(rr_search -> nx_mdns_rr_send_flag & NX_MDNS_RR_SEND_FLAG_MASK)) && + ((temp_resource_record.nx_mdns_rr_ttl << 1) >= rr_search -> nx_mdns_rr_ttl)) + { + + /* Top four bit is zero and this resource reocrd is Known answer. + Clear the send flag. */ + rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + } +#endif /* NX_MDNS_DISABLE_SERVER */ + } + + /* Update the data_ptr. */ + data_ptr += _nx_mdns_rr_size_get(data_ptr); + } + + return(NX_MDNS_SUCCESS); +} + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_probing_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends mDNS probing message. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_probing_send(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG *head; +NX_MDNS_RR *p; +USHORT question_count = 0; +USHORT answer_count = 0; +USHORT authority_count = 0; +USHORT additional_count = 0; +UCHAR resend_flag = NX_FALSE; +USHORT total_size; +USHORT rr_size; +UINT name_size; +NX_MDNS_RR *p1; +UINT rr_name_length; + + + /* Create the mdns packet and add the mDNS header. */ + status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_TRUE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Set the total size. */ + total_size = (USHORT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr); + + /* Set the head pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + /* Add the answer resource record. */ + for (p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check the send flag. */ + if (p -> nx_mdns_rr_send_flag == 0) + continue; + + /* Check the state. */ + if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) + continue; + + /* Add the resource record into packet. */ + + /* Calculate the question and answer size before sending the probing message, make sure the question and authority in one packet. */ + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)p -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) + { + continue; + } + + /* Calculate the name size. The name should plus the '.' and '\0'. */ + name_size = rr_name_length + 2; + + /* Calculate the resource record size for question. QNAME, QTYPE, QCLASS. */ + rr_size = (USHORT)(name_size + 4); + + /* Calcuate the resource record size for authority. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ + rr_size = (USHORT)(rr_size + (name_size + 10 + p -> nx_mdns_rr_rdata_length)); + + /* Check if need add other authority answers for this same question. */ + for(p1 = (NX_MDNS_RR*)(head + 1); (ULONG)p1 < *head; p1++) + { + + /* Check the interface index. */ + if (p1 -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check the state. */ + if (p1 -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) + continue; + + /* Check the name and flag. */ + if ((p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_name) && + (p1 -> nx_mdns_rr_send_flag) && + (p1 != p)) + { + + /* Calculate the resource record size for other authority. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ + rr_size = (USHORT)(rr_size + (name_size + 10 + p1 -> nx_mdns_rr_rdata_length)); + + /* Check the packet size. */ + if (rr_size <= total_size) + { + + /* Set the authority answer flag. */ + p1 -> nx_mdns_rr_word = p1 -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_AUTHORIY_ANSWER; + + /* Clear the send flag. */ + p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + else + { + resend_flag = NX_TRUE; + break; + } + } + } + + /* Check the packet size. */ + if (rr_size > total_size) + { + resend_flag = NX_TRUE; + continue; + } + else + total_size = (USHORT)(total_size - rr_size); + + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_QUESTION, NX_MDNS_PACKET_PROBING); + + if (status) + { + resend_flag = NX_TRUE; + } + else + { + + /* Set the authority answer flag. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_AUTHORIY_ANSWER; + + /* Update the question count. */ + question_count ++; + + /* Clear the flag. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + + /* Add the authority answer resource record. */ + for (p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether set the resource record send flag. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_PROBING) && + (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_AUTHORIY_ANSWER)) + { + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_PROBING); + if (status) + resend_flag = NX_TRUE; + else + { + + /* Update the retransmit count. */ + p -> nx_mdns_rr_retransmit_count --; + + /* Update the authority count. */ + authority_count ++; + + /* Clear the additional flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_AUTHORIY_ANSWER)); + } + } + + /* Clear the answer flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); + } + + if (!question_count && + !answer_count && + !authority_count && + !additional_count) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Update the question count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); + + /* Update the answer count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); + + /* Send the mDNS packet. */ + _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); + + /* Resend the packet. */ + if (resend_flag) + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_PROBING_SEND_EVENT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_announcing_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends mDNS announcing message. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_announcing_send(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; +NX_PACKET *packet_ptr; +NX_PACKET *new_packet_ptr; +ULONG *head; +NX_MDNS_RR *p; +USHORT question_count = 0; +USHORT answer_count = 0; +USHORT authority_count = 0; +USHORT additional_count = 0; +UINT i; +UCHAR resend_flag = NX_FALSE; + + + /* Create the mdns packet and add the mDNS header. */ + status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_FALSE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Set the head pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + /* Add the answer resource record. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + if(p -> nx_mdns_rr_send_flag == 0) + continue; + + /* Check valid state. */ + if(!(((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID)))) + continue; + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); + + if (status) + { + resend_flag = NX_TRUE; + } + else + { + + /* Update the retransmit count. */ + p -> nx_mdns_rr_retransmit_count --; + + /* Update the count. */ + answer_count++; + + /* Clear the flag. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + + if (!question_count && + !answer_count && + !authority_count && + !additional_count) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Update the question count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); + + /* Update the answer count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); + + /* If the interval time is 0, repeat advertise. */ + if (!mdns_ptr -> nx_mdns_announcing_retrans_interval) + { + for (i = 1; i < mdns_ptr -> nx_mdns_announcing_count; i ++) + { + + /* Allocate new packet. */ + status = nx_packet_copy(packet_ptr, &new_packet_ptr, mdns_ptr -> nx_mdns_packet_pool_ptr, NX_NO_WAIT); + + /* Check for errors. */ + if (status) + { + break; + } + + /* Send the mDNS packet. */ + _nx_mdns_packet_send(mdns_ptr, new_packet_ptr, interface_index); + } + } + + /* Send the mDNS packet. */ + _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); + + /* Resend the packet. */ + if (resend_flag) + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_ANNOUNCING_SEND_EVENT, TX_OR); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends mDNS response. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_response_send(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG *head; +NX_MDNS_RR *p; +USHORT question_count = 0; +USHORT answer_count = 0; +USHORT authority_count = 0; +USHORT additional_count = 0; +UCHAR resend_flag = NX_FALSE; + + + /* Create the mdns packet and add the mDNS header. */ + status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_FALSE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Set the head pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + /* Add the answer resource record. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + if(p -> nx_mdns_rr_send_flag == 0) + continue; + + /* Check valid state. */ + if ((p -> nx_mdns_rr_timer_count != 0) || + !((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID))) + continue; + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); + + if (status) + { + resend_flag = NX_TRUE; + } + else + { + + /* Set the answer flag to skip the resource record which has been added in answer section when find the additional records. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ANSWER; + + /* When including a DNS-SD Service Instance Enumeration or Selective Instance Enumeration PTR record in a response packet, + the server/responder SHOULD include the folowing additional records, SRV,TXT, A and AAAA.RFC3763, Section12.1, Page30. */ + _nx_mdns_additional_resource_record_find(mdns_ptr, p); + + /* Update the count. */ + answer_count++; + + /* Clear the flag. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + + /* Add the additional answer resource record. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether set the resource record send flag. */ + if ((p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ADDITIONAL) && + ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING))) + { + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); + if (status) + { + resend_flag = NX_TRUE; + } + else + { + + /* Update the additional count. */ + additional_count++; + + /* Clear the additional flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ADDITIONAL)); + } + } + + /* Clear the answer flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); + } + + if (!question_count && + !answer_count && + !authority_count && + !additional_count) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Update the question count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); + + /* Update the answer count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); + + /* Send the mDNS packet. */ + _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); + + /* Resend the packet. */ + if (resend_flag) + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_RESPONSE_SEND_EVENT, TX_OR); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_query_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends mDNS query message. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* none */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_query_send(NX_MDNS *mdns_ptr, UINT interface_index) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG *head; +NX_MDNS_RR *p; +USHORT question_count = 0; +USHORT answer_count = 0; +USHORT authority_count = 0; +USHORT additional_count = 0; +UCHAR resend_flag = NX_FALSE; +USHORT tc_bit; +UCHAR more_known_answer = NX_FALSE; +UINT i; + + + /* Create the mdns packet and add the mDNS header. */ + status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_TRUE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Set the head pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + + /* Add the query resource record. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + if(p -> nx_mdns_rr_send_flag == 0) + continue; + + /* Check valid state. */ + if(!(((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING)))) + continue; + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_QUESTION, NX_MDNS_PACKET_QUERY); + + if (status) + { + resend_flag = NX_TRUE; + } + else + { + + /* Update the retransmit count for UPDATING state. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING) + p -> nx_mdns_rr_retransmit_count --; + + /* Update the count. */ + question_count++; + + /* Find the known answer resource records. */ + _nx_mdns_known_answer_find(mdns_ptr, p); + + /* Clear the flag. */ + p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; + } + } + + /* Add the known answer resource record. */ + for (i = 0; i < 2; i++) + { + if (i == 0) + { +#ifndef NX_MDNS_DISABLE_SERVER + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + } + + /* Add the peer resource code as known answer for query. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check whether set the resource record send flag. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) && + (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_KNOWN_ANSWER)) + { + + /* Add the resource record into packet. */ + status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_QUERY); + if (status) + { + more_known_answer = NX_TRUE; + resend_flag = NX_TRUE; + } + else + { + /* Update the count. */ + answer_count ++; + + /* Clear the additional flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_KNOWN_ANSWER)); + } + } + + /* Clear the answer flag. */ + p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); + } + } + + if (!question_count && + !answer_count && + !authority_count && + !additional_count) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Set the TC bit. */ + if (more_known_answer) + { + tc_bit = NX_MDNS_TC_FLAG; + *(USHORT *)(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET) |= NX_CHANGE_USHORT_ENDIAN(tc_bit); + } + + /* Update the question count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); + + /* Update the answer count in header. */ + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); + _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); + + /* Send the mDNS packet. */ + _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); + + /* Resend the packet. */ + if (resend_flag) + tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_QUERY_SEND_EVENT, TX_OR); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the mDNS packet and add the mDNS header data. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* packet_ptr Pointer to mDNS packet */ +/* is_query Query flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate the mDNS packet */ +/* nx_packet_release Release the mDNS packet */ +/* _nx_mdns_short_to_network_convert Add the data into the packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_announcing_send Send announcing message */ +/* _nx_mdns_probing_send Send probing message */ +/* _nx_mdns_query_send Send query message */ +/* _nx_mdns_response_send Send response message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_create(NX_MDNS *mdns_ptr, NX_PACKET **packet_ptr, UCHAR is_query) +{ + +UINT status; +USHORT flags; + + + /* Allocate the mDNS packet. */ +#ifdef NX_MDNS_ENABLE_IPV6 + status = nx_packet_allocate(mdns_ptr -> nx_mdns_packet_pool_ptr, packet_ptr, NX_IPv6_UDP_PACKET, NX_NO_WAIT); +#else + status = nx_packet_allocate(mdns_ptr -> nx_mdns_packet_pool_ptr, packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); +#endif /* NX_MDNS_ENABLE_IPV6 */ + + /* Check for errors. */ + if (status) + { + + /* Return error. */ + return(status); + } + + /* Check if there is enough room to fill with mDNS header. */ + if ((UINT)((*packet_ptr) -> nx_packet_data_end - (*packet_ptr) -> nx_packet_append_ptr) < NX_MDNS_QDSECT_OFFSET) + { + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + return(NX_MDNS_PACKET_ERROR); + } + + /* Add the mDNS header. */ + + /* Set the transaction ID. */ + *(USHORT *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_ID_OFFSET) = 0; + + /* Set the flags and Command. */ + if (is_query == NX_TRUE) + { + flags = NX_MDNS_QUERY_FLAG; + } + else + { + flags = (NX_MDNS_RESPONSE_FLAG | NX_MDNS_AA_FLAG); + } + + /* Adjust for endianness. */ + NX_CHANGE_USHORT_ENDIAN(flags); + + /* Set the flags and Command. */ + *(USHORT *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET) = flags; + + /* Initialize counts to 0. */ + *(ULONG *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET) = 0; + *(ULONG *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET) = 0; + + /* Set the pointer. */ + (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_QDSECT_OFFSET; + (*packet_ptr) -> nx_packet_length = NX_MDNS_QDSECT_OFFSET; + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the mDNS packet. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* packet_ptr Pointer to mDNS packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy the mDNS packet */ +/* nx_packet_release Release the mDNS packet */ +/* nx_udp_socket_send Send the udp packet */ +/* nxd_udp_socket_send Send the udp packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_announcing_send Send announcing message */ +/* _nx_mdns_probing_send Send probing message */ +/* _nx_mdns_query_send Send query message */ +/* _nx_mdns_response_send Send response message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_packet_send(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index) +{ + +#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 +UINT status; +#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ +#ifdef NX_MDNS_ENABLE_IPV6 +UINT ipv6_packet = NX_FALSE; +NX_PACKET *new_packet_ptr; +UINT address_index = mdns_ptr -> nx_mdns_ipv6_address_index[interface_index]; +#endif /* NX_MDNS_ENABLE_IPV6 */ + + +#if defined NX_DISABLE_IPV4 && !defined NX_MDNS_ENABLE_IPV6 + NX_PARAMETER_NOT_USED(mdns_ptr); + NX_PARAMETER_NOT_USED(interface_index); +#endif /* NX_DISABLE_IPV4 && ! NX_MDNS_ENABLE_IPV6 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + if (address_index != 0xFFFFFFFF) + { + + /* Allocate new IPv6 packet. */ + status = nx_packet_copy(packet_ptr, &new_packet_ptr, mdns_ptr -> nx_mdns_packet_pool_ptr, NX_NO_WAIT); + + /* Check for errors. */ + if (!status) + { + ipv6_packet = NX_TRUE; + } + } +#endif /* NX_MDNS_ENABLE_IPV6 */ + +#ifndef NX_DISABLE_IPV4 + /* Send the IPv4 mDNS message. */ + status = nx_udp_socket_source_send(&mdns_ptr -> nx_mdns_socket, packet_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, NX_MDNS_UDP_PORT, interface_index); + + /* If an error is detected, the packet was not sent and we have to release the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } +#else + + /* Release the packet. */ + nx_packet_release(packet_ptr); +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + + /* Check if send IPv6 packet. */ + if (ipv6_packet == NX_TRUE) + { + + /* Send the IPv6 mDNS message. */ + status = nxd_udp_socket_source_send(&mdns_ptr -> nx_mdns_socket, new_packet_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, NX_MDNS_UDP_PORT, address_index); + + /* If an error is detected, the packet was not sent and we have to release the packet. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + } + } +#endif /* NX_MDNS_ENABLE_IPV6 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_rr_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into the packet. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* packet_ptr Pointer to mDNS packet */ +/* rr Pointer to mDNS record */ +/* op RR adding Operation */ +/* packet_type Packet type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_name_string_encode Encode the name string */ +/* _nx_mdns_short_to_network_convert Convert and add the data */ +/* _nx_mdns_txt_string_encode Encode the txt string */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_announcing_send Send announcing message */ +/* _nx_mdns_probing_send Send probing message */ +/* _nx_mdns_query_send Send query message */ +/* _nx_mdns_response_send Send response message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_rr_add(NX_PACKET *packet_ptr, NX_MDNS_RR *rr, UINT op, UINT packet_type) +{ + +USHORT size = 0; +USHORT index = 0; +USHORT rr_size = 0; +USHORT rdata_length_index = 0; +UCHAR *data_ptr = packet_ptr -> nx_packet_append_ptr; +UINT rr_name_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)rr -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) + { + return (NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check whether set the resource record send flag. */ + if(op == NX_MDNS_PACKET_ADD_RR_QUESTION) + { + + /* The name size is should add the '.' and '\0', Calcuate the resource record size. QNAME, QTYPE, QCLASS. */ + rr_size = (USHORT)(rr_name_length + 2 + 4); + + if ((data_ptr + rr_size) > packet_ptr -> nx_packet_data_end) + { + return(NX_MDNS_PACKET_ERROR); + } + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr, rr -> nx_mdns_rr_name); + + /* Updat the index. */ + index = (USHORT)(index + size); + + /* Add the type. */ + if(packet_type == NX_MDNS_PACKET_PROBING) + { + _nx_mdns_short_to_network_convert(data_ptr + index, NX_MDNS_RR_TYPE_ALL); + } + else + { + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_type); + } + index = (USHORT)(index + 2); + + /* Add the class. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_class); + index = (USHORT)(index + 2); + } + + /* Check whether set the resource record send flag. */ + else + { + + /* Calcuate the resource record size. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ + rr_size = (USHORT)(rr_name_length + 2 + 10 + rr -> nx_mdns_rr_rdata_length); + + if ((data_ptr + rr_size) > packet_ptr -> nx_packet_data_end) + { + return(NX_MDNS_PACKET_ERROR); + } + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_name); + + /* Updat the index. */ + index = (USHORT)(index + size); + + /* Add the type and class. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_type); + index = (USHORT)(index + 2); + + /* Add the class. */ + if ((!(rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) && + (rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE)) + { + _nx_mdns_short_to_network_convert(data_ptr + index, ((rr -> nx_mdns_rr_class) | NX_MDNS_RR_CLASS_TOP_BIT)); + } + else + { + + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_class); + } + index = (USHORT)(index + 2); + + /* Add the ttl. */ + /* Check the resource record owner. */ + if (rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER) + { + /* Add the remaining ttl of peer resource reocrd. */ + _nx_mdns_long_to_network_convert(data_ptr + index, (rr -> nx_mdns_rr_remaining_ticks / NX_IP_PERIODIC_RATE)); + } + else + { + if (rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) + { + _nx_mdns_long_to_network_convert(data_ptr + index, 0); + } + else + { + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_ttl); + } + } + index = (USHORT)(index + 4); + + /* Compare the RDATA. */ + switch (rr -> nx_mdns_rr_type) + { + + case NX_MDNS_RR_TYPE_A: + { + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + index, 4); + index = (USHORT)(index + 2); + + /* Add the rdata. */ + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address); + index = (USHORT)(index + 4); + + break; + } + case NX_MDNS_RR_TYPE_AAAA: + { + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + index, 16); + index = (USHORT)(index + 2); + + /* Add the rdata. */ + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0]); + index = (USHORT)(index + 4); + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1]); + index = (USHORT)(index + 4); + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2]); + index = (USHORT)(index + 4); + _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3]); + index = (USHORT)(index + 4); + + break; + } + case NX_MDNS_RR_TYPE_PTR: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name); + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); + + break; + } + case NX_MDNS_RR_TYPE_SRV: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Add the prority. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority); + index = (USHORT)(index + 2); + + /* Add the weights. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights); + index = (USHORT)(index + 2); + + /* Add the port. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port); + index = (USHORT)(index + 2); + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target); + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 6)); + + break; + } + case NX_MDNS_RR_TYPE_TXT: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + if (rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data) + { + + /* Encode and add the text. */ + size = (USHORT)_nx_mdns_txt_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data); + } + else + { + + /* Encode the null. */ + *(data_ptr + index) = 0; + size = 1; + } + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); + + break; + } + +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + case NX_MDNS_RR_TYPE_CNAME: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_cname.nx_mdns_rr_cname_name); + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); + + break; + } + case NX_MDNS_RR_TYPE_NS: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ns.nx_mdns_rr_ns_name); + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); + + break; + } + case NX_MDNS_RR_TYPE_MX: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Add the preference. */ + _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference); + index = (USHORT)(index + 2); + + /* Encode and add the name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name); + index = (USHORT)(index + size); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 2)); + + break; + } +#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + case NX_MDNS_RR_TYPE_NSEC: + { + + /* Record the rdata length index then skip the rdata length. */ + rdata_length_index = index; + index = (USHORT)(index + 2); + + /* Encode and add the next domain name. */ + size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain); + index = (USHORT)(index + size); + + /* Add the window block. */ + *(data_ptr + index) = rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block; + index++; + + /* Add the bitmap length. */ + *(data_ptr + index) = rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length; + index++; + + /* Add the type bit maps. */ + memcpy(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length); + index = (USHORT)(index + rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length); + + /* Add the rdata length. */ + _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 2 + rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length)); + + break; + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + } + } + + /* Update the append pointer and packet length. */ + packet_ptr -> nx_packet_append_ptr += index; + packet_ptr -> nx_packet_length += index; + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_rr_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the resource record info from packet. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance. */ +/* packet_ptr Pointer to the packet. */ +/* data_ptr Pointer to the data. */ +/* rr_ptr Pointer to the record */ +/* op Operation: */ +/* set question or set answer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_name_string_decode Decode the name string */ +/* _nx_mdns_cache_add_string Add the name string */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_rr_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op, UINT interface_index) +{ + +UCHAR *cache_ptr; +UINT cache_size; +UINT cache_type; +USHORT record_class; +UINT status; +UINT temp_string_length; + + + /* Initialize. */ + memset(rr_ptr, 0, sizeof(NX_MDNS_RR)); + + /* Get cache type and size. */ + if ((op == NX_MDNS_RR_OP_LOCAL_SET_QUESTION) || + (op == NX_MDNS_RR_OP_LOCAL_SET_ANSWER)) + { + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; + cache_type = NX_MDNS_CACHE_TYPE_LOCAL; + } + else + { + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; + cache_type = NX_MDNS_CACHE_TYPE_PEER; + } + + /* Check cache pointer and cache size. */ + if ((cache_ptr == NX_NULL) || (cache_size == 0)) + { + return(NX_MDNS_ERROR); + } + + /* Set the interface. */ + rr_ptr -> nx_mdns_rr_interface_index = interface_index; + + /* Process the name string. */ + if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, + (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), + temp_string_buffer, NX_MDNS_NAME_MAX)) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the string . */ + if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, + (VOID **)(&rr_ptr -> nx_mdns_rr_name), NX_TRUE, NX_TRUE) != NX_MDNS_SUCCESS) + { + return(NX_MDNS_ERROR); + } + } + else + { + return(NX_MDNS_ERROR); + } + + /* Set the resource record type. */ + rr_ptr -> nx_mdns_rr_type = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr)); + + /* Get the resource record class.*/ + record_class = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 2); + + /* Remote RR, set the RR owner flag.*/ + if (cache_type == NX_MDNS_CACHE_TYPE_PEER) + rr_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_PEER; + + /* Unique RR, Set the RR set flag. */ + if (record_class & (~NX_MDNS_TOP_BIT_MASK)) + { + rr_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UNIQUE; + } + + /* Check the operation and update the record class. */ + if((op == NX_MDNS_RR_OP_LOCAL_SET_QUESTION) || (op == NX_MDNS_RR_OP_PEER_SET_QUESTION)) + { + rr_ptr -> nx_mdns_rr_class = record_class; + return(NX_MDNS_SUCCESS); + } + else + { + rr_ptr -> nx_mdns_rr_class = record_class & NX_MDNS_TOP_BIT_MASK; + } + + /* Set the rdata information for answer record. */ + status = _nx_mdns_packet_rr_data_set(mdns_ptr, packet_ptr, data_ptr, rr_ptr, op); + + /* Return success. */ + return (status); +} + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_rr_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the resource record of packet, and add the */ +/* record into peer cache. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance. */ +/* packet_ptr Pointer to the packet. */ +/* data_ptr Pointer to the data. */ +/* insert_ptr Pointer to the insert record */ +/* op Operation: add answer, set */ +/* question or set answer. */ +/* cache_ptr The record buffer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_name_string_decode Decode the name string */ +/* _nx_mdns_cache_add_string Add the name string */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_rr_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UINT interface_index) +{ + +UINT status; +USHORT record_class; +UCHAR is_present; +NX_MDNS_RR rr_ptr; +NX_MDNS_RR *insert_ptr; +NX_MDNS_RR *p; +ULONG *head; +UCHAR *service_name,*service_type,*service_domain; +UINT temp_string_length; +UINT rr_name_length; + + + /* Check the peer cache. */ + if ((mdns_ptr -> nx_mdns_peer_service_cache == NX_NULL) || + (mdns_ptr -> nx_mdns_peer_service_cache_size == 0)) + { + return(NX_MDNS_ERROR); + } + + /* Initialize. */ + memset(&rr_ptr, 0, sizeof(NX_MDNS_RR)); + + /* Process the name string. */ + if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, + (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), + temp_string_buffer, NX_MDNS_NAME_MAX)) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the string . */ + if(_nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_string_buffer, temp_string_length, + (VOID **)(&rr_ptr.nx_mdns_rr_name), NX_FALSE, NX_TRUE)) + { + return(NX_MDNS_ERROR); + } + } + else + { + return(NX_MDNS_ERROR); + } + + /* Set the resource record type. */ + rr_ptr.nx_mdns_rr_type = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr)); + + /* Get the resource record class.*/ + record_class = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 2); + + /* Set the resource record class. */ + rr_ptr.nx_mdns_rr_class = record_class & NX_MDNS_TOP_BIT_MASK; + + /* Remote RR, set the RR owner flag.*/ + rr_ptr.nx_mdns_rr_word |= NX_MDNS_RR_FLAG_PEER; + + /* Unique RR, Set the RR set flag. */ + if (record_class & (~NX_MDNS_TOP_BIT_MASK)) + { + rr_ptr.nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UNIQUE; + } + + /* Set the interface index. */ + rr_ptr.nx_mdns_rr_interface_index = interface_index; + + /* Set the rdata information for answer record. */ + status = _nx_mdns_packet_rr_data_set(mdns_ptr, packet_ptr, data_ptr, &rr_ptr, NX_MDNS_RR_OP_PEER_ADD_ANSWER); + + /* Check status. */ + if(status) + { + + /* Delete the name strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, rr_ptr.nx_mdns_rr_name, 0); + return (NX_MDNS_ERROR); + } + + /* Check if need to ignore this source reocrd. */ + if ((mdns_ptr -> nx_mdns_service_ignore_mask) && + ((rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || + (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || + (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR))) + { + + /* Get the service. */ + if (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)rr_ptr.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &rr_name_length, NX_MDNS_NAME_MAX)) + { + _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); + return(NX_MDNS_DATA_SIZE_ERROR); + } + memcpy((CHAR *)temp_string_buffer, (const char *)rr_ptr.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, rr_name_length + 1); + } + else + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)rr_ptr.nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) + { + _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); + return(NX_MDNS_DATA_SIZE_ERROR); + } + memcpy((CHAR *)temp_string_buffer, (const char *)rr_ptr.nx_mdns_rr_name, rr_name_length + 1); + } + + /* Resolve the service type. */ + if (_nx_mdns_service_name_resolve(temp_string_buffer, &service_name, &service_type, &service_domain)) + { + _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); + return (status); + } + + /* Check if this service type should be ignored. */ + if (_nx_mdns_service_mask_match(mdns_ptr, service_type, mdns_ptr -> nx_mdns_service_ignore_mask) == NX_MDNS_SUCCESS) + { + _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); + return (NX_MDNS_ERROR); + } + } + + /* Add the resource record into remote buffer. */ + if (_nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr, &insert_ptr, &is_present)) + { + + /* Delete the name strings. */ + _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); + return (NX_MDNS_ERROR); + } + + /* Check the ttl. */ + if (insert_ptr -> nx_mdns_rr_ttl) + { + + /* Step1. Process answer record. */ + /* Update the state. */ + insert_ptr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; + + /* Update the timer count. The querier should not include records in the Known-Answer list whose remaining TTL is less than half of their original TTL. */ + insert_ptr -> nx_mdns_rr_timer_count = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 50 / 100; + + /* Record the remaining ticks of resource record. */ + if (insert_ptr -> nx_mdns_rr_ttl >= NX_MDNS_RR_MAX_TTL) + { + /* If the ttl of resource resource record is outside the range, set as 0xFFFFFFFF. */ + insert_ptr -> nx_mdns_rr_remaining_ticks = 0xFFFFFFFF; + } + else + { + /* Convert units(seconds to ticks). */ + insert_ptr -> nx_mdns_rr_remaining_ticks = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE; + } + + /* Step2. Process query record. */ + /* Set the pointer. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + head = (ULONG*)(*head); + + /* Check the remote resource record state. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the state. */ + if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != insert_ptr -> nx_mdns_rr_interface_index) + continue; + + /* Check the name. */ + if (p -> nx_mdns_rr_name != insert_ptr -> nx_mdns_rr_name) + continue; + + /* Check the type. */ + if ((p -> nx_mdns_rr_type != insert_ptr -> nx_mdns_rr_type) && + (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL)) + continue; + + /* Check the class. */ + if (p -> nx_mdns_rr_class != insert_ptr -> nx_mdns_rr_class) + continue; + + /* Check the query type. */ + if (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_CONTINUOUS_QUERY)) + { + + /* Determine if we need to wake a thread suspended. */ + if (mdns_ptr -> nx_mdns_rr_receive_suspension_list) + { + + /* Resume suspended thread. */ + _nx_mdns_query_thread_resume(&(mdns_ptr -> nx_mdns_rr_receive_suspension_list), mdns_ptr, insert_ptr); + } + + /* Get the answer, we need not send the question again. Delete the resource record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); + + } + else + { + + /* There is no need for the querier to continue issuing a stream of queries when a mDNS response + is received containing a unique answer. mDNS querier should send the next query at 80%-82% of the + record's TTL. RFC6762, Section5.2,Page11. */ + if ((insert_ptr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) && (insert_ptr -> nx_mdns_rr_ttl)) + { + + /* Set the timer count. */ + p -> nx_mdns_rr_timer_count = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(80 + (NX_RAND() % 3)) / 100; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } + + /* Set the updating flag to update the resource record at 80% of the record's TTL. */ + insert_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UPDATING; + } + } + } + else + { + + /* Update the state to delete this record from peer cache. . */ + insert_ptr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_DELETE; + + /* Delete the resource record one second later. */ + insert_ptr -> nx_mdns_rr_timer_count = NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT; + } + + /* Set the mDNS timer for insert RR. */ + _nx_mdns_timer_set(mdns_ptr, insert_ptr, insert_ptr -> nx_mdns_rr_timer_count); + + /* Service name registered success, invoke the notify function. */ + if (mdns_ptr -> nx_mdns_service_change_notify) + { + + /* Process the service notify function. */ + _nx_mdns_service_change_notify_process(mdns_ptr, insert_ptr, is_present); + } + + /* Return success. */ + return (NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_rr_data_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the packet, and sets the data of */ +/* resource record. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance. */ +/* packet_ptr Pointer to the packet. */ +/* data_ptr Pointer to the data. */ +/* rr_ptr Pointer to the record */ +/* op Operation: */ +/* set answer in local cache. */ +/* or add answer in peer cache.*/ +/* cache_ptr The record buffer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_name_string_decode Decode the name string */ +/* _nx_mdns_cache_add_string Add the name string */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_rr_data_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op) +{ + +UCHAR *string_search = NX_NULL; +UINT cache_type; +UCHAR find_string; +UCHAR continue_process = NX_FALSE; +UINT status = NX_MDNS_UNSUPPORTED_TYPE; +UINT temp_string_length; + + + /* Get cache type and size. */ + if (op == NX_MDNS_RR_OP_LOCAL_SET_ANSWER) + { + cache_type = NX_MDNS_CACHE_TYPE_LOCAL; + find_string = NX_TRUE; + } + else + { + cache_type = NX_MDNS_CACHE_TYPE_PEER; + find_string = NX_FALSE; + } + + /* Set the resource record time to live.*/ + rr_ptr -> nx_mdns_rr_ttl = NX_MDNS_GET_ULONG_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 4); + + /* Set the resource record rdata length. */ + rr_ptr -> nx_mdns_rr_rdata_length = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 8);; + + /* Update the pointer to point at the resource data. */ + data_ptr = data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 10; + + /* Check the type. */ + switch (rr_ptr -> nx_mdns_rr_type) + { + case NX_MDNS_RR_TYPE_A: + { + + /* Get the rdata. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address = NX_MDNS_GET_ULONG_DATA(data_ptr); + rr_ptr -> nx_mdns_rr_rdata_length = 4; + + /* Update the status. */ + status = NX_MDNS_SUCCESS; + break; + } + case NX_MDNS_RR_TYPE_AAAA: + { + + /* Get the rdata. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0] = NX_MDNS_GET_ULONG_DATA(data_ptr); + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1] = NX_MDNS_GET_ULONG_DATA(data_ptr + 4); + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2] = NX_MDNS_GET_ULONG_DATA(data_ptr + 8); + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3] = NX_MDNS_GET_ULONG_DATA(data_ptr + 12); + rr_ptr -> nx_mdns_rr_rdata_length = 16; + + /* Update the status. */ + status = NX_MDNS_SUCCESS; + break; + } + case NX_MDNS_RR_TYPE_TXT: + { + + /* Process the txt string. An empty TXT record contaning zero strings is not allowed. RFC6763, Page12. */ + if (rr_ptr -> nx_mdns_rr_rdata_length == 1) + { + + /* Update the status. */ + status = NX_MDNS_SUCCESS; + } + else if (rr_ptr -> nx_mdns_rr_rdata_length > 1) + { + + /* Add the txt string. */ + if (_nx_mdns_txt_string_decode(data_ptr, rr_ptr -> nx_mdns_rr_rdata_length, temp_string_buffer, NX_MDNS_NAME_MAX) == NX_MDNS_SUCCESS) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Find the same string . */ + if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, + (VOID **)&string_search, find_string, NX_TRUE) == NX_MDNS_SUCCESS) + { + + /* Update the name pointer. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data = string_search; + + /* Calculate the text string.inlcude the one byte label. */ + rr_ptr -> nx_mdns_rr_rdata_length = (USHORT)(temp_string_length + 1); + + /* Update the status. */ + status = NX_MDNS_SUCCESS; + } + } + } + + break; + } + case NX_MDNS_RR_TYPE_SRV: + { + + /* Get the priority. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority = NX_MDNS_GET_USHORT_DATA(data_ptr); + data_ptr += 2; + + /* Get the weights. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights = NX_MDNS_GET_USHORT_DATA(data_ptr); + data_ptr += 2; + + /* Get the port. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port = NX_MDNS_GET_USHORT_DATA(data_ptr); + data_ptr += 2; + + /* Update the rdata length. */ + rr_ptr -> nx_mdns_rr_rdata_length = 6; + + /* Continue to process target name. */ + continue_process = NX_TRUE; + break; + } + case NX_MDNS_RR_TYPE_PTR: +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + case NX_MDNS_RR_TYPE_CNAME: + case NX_MDNS_RR_TYPE_NS: +#endif + { + + /* Update the rdata length. */ + rr_ptr -> nx_mdns_rr_rdata_length = 0; + + /* Continue to process the domain name. */ + continue_process = NX_TRUE; + break; + } +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + case NX_MDNS_RR_TYPE_MX: + { + + /* Set the preference. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference = NX_MDNS_GET_USHORT_DATA(data_ptr); + data_ptr += 2; + + /* Update the rdata length. */ + rr_ptr -> nx_mdns_rr_rdata_length = 2; + + /* Continue to process the domain name. */ + continue_process = NX_TRUE; + break; + } +#endif + } + + /* Check if need to continue process rdata. */ + if(continue_process == NX_TRUE) + { + + /* Process the target/domain name string. */ + if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, + (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), + temp_string_buffer, NX_MDNS_NAME_MAX)) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the string. */ + if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, + (VOID **)&string_search, find_string, NX_TRUE) == NX_MDNS_SUCCESS) + { + + /* Update the name pointer for SRV, PTR, etc. */ + rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target = string_search; + + /* Calculate the text string. Inlcude the one byte label '.' and null '\0'. */ + rr_ptr -> nx_mdns_rr_rdata_length = (USHORT)(rr_ptr -> nx_mdns_rr_rdata_length + (temp_string_length + 2)); + + /* Update the status. */ + status = NX_MDNS_SUCCESS; + } + } + } + + /* Return success. */ + return (status); +} + + +#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_packet_address_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks the IP address and port of received packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to mDNS packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_packet_address_check(NX_PACKET *packet_ptr) +{ + +USHORT mdns_flags; +UINT src_port; +ULONG *udp_header; + +#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 +NXD_ADDRESS src_address; +NXD_ADDRESS des_address; +#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ + +#ifndef NX_DISABLE_IPV4 +NX_IPV4_HEADER *ipv4_header; +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 +NX_IPV6_HEADER *ipv6_header; +#endif /* NX_MDNS_ENABLE_IPV6 */ + + + /* Extract the message type which should be the first byte. */ + mdns_flags = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET); + +#ifndef NX_DISABLE_IPV4 + /* Get the ip address. */ + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) + { + + /* Set the IPv4 header. */ + ipv4_header = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_ip_header; + + /* Set the source address. */ + src_address.nxd_ip_version = NX_IP_VERSION_V4; + src_address.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_source_ip; + + /* Set the destination address. */ + des_address.nxd_ip_version = NX_IP_VERSION_V4; + des_address.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_destination_ip; + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) + { + + /* Set the IPv6 header. */ + ipv6_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header; + + /* Set the source address. */ + src_address.nxd_ip_version = NX_IP_VERSION_V6; + COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_source_ip, src_address.nxd_ip_address.v6); + + /* Set the destination address. */ + des_address.nxd_ip_version = NX_IP_VERSION_V6; + COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_destination_ip, des_address.nxd_ip_address.v6); + } + else +#endif /* NX_MDNS_ENABLE_IPV6 */ + { + + /* Invalid IP version . */ + return(NX_MDNS_ERROR); + } + + /* Pickup the pointer to the head of the UDP packet. */ + udp_header = (ULONG *) (packet_ptr -> nx_packet_prepend_ptr - 8); + + /* Get the source port and destination port. */ + src_port = (UINT) ((*udp_header) >> NX_SHIFT_BY_16); + + /* Check the source UDP port. RFC6762, Section6, Page15. */ + if (src_port != NX_MDNS_UDP_PORT) + { + return(NX_MDNS_UDP_PORT_ERROR); + } + + /* Check the QR bit. */ + if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) + { + + /* Check the response code. */ + if (mdns_flags & NX_MDNS_ERROR_MASK) + { + + /* Release the source packet. */ + return(NX_MDNS_AUTH_ERROR); + } + + /* In response messages for Multicast domains, the AA bit Must be set to one, RFC6762, Page48. */ + if ((mdns_flags & NX_MDNS_AA_FLAG) != NX_MDNS_AA_FLAG) + { + return (NX_MDNS_ERROR); + } + +#ifndef NX_DISABLE_IPV4 + /* Check the interface and destination address. RFC6762, Section 11, Page38,39. */ + if (des_address.nxd_ip_version == NX_IP_VERSION_V4) + { + + /* Local link check, Multicast Address or (I & M) == (P & M). */ + if ((des_address.nxd_ip_address.v4 != NX_MDNS_IPV4_MULTICAST_ADDRESS) && + (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address & packet_ptr ->nx_packet_ip_interface -> nx_interface_ip_network_mask) != + (src_address.nxd_ip_address.v4 & packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) + { + return (NX_MDNS_NOT_LOCAL_LINK); + } + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + if(des_address.nxd_ip_version == NX_IP_VERSION_V6) + { + + /* Destination address is not FF02::FB address or source address not on link, RFC6762, Section 11, Page39. */ + /* Not check the source address. */ + if ((des_address.nxd_ip_address.v6[0] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0]) || + (des_address.nxd_ip_address.v6[1] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1]) || + (des_address.nxd_ip_address.v6[2] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2]) || + (des_address.nxd_ip_address.v6[3] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3])) + { + return (NX_MDNS_DEST_ADDRESS_ERROR); + } + } + else +#endif /* NX_MDNS_ENABLE_IPV6 */ + { + + /* Invalid IP version. */ + return(NX_MDNS_ERROR); + } + } + else + { + +#ifndef NX_DISABLE_IPV4 + /* Check the interface and destination address. RFC6762, Section 11, Page38,39. */ + if (des_address.nxd_ip_version == NX_IP_VERSION_V4) + { + if (des_address.nxd_ip_address.v4 != NX_MDNS_IPV4_MULTICAST_ADDRESS) + { + return (NX_MDNS_DEST_ADDRESS_ERROR); + } + } + else +#endif /* NX_DISABLE_IPV4 */ + +#ifdef NX_MDNS_ENABLE_IPV6 + if(des_address.nxd_ip_version == NX_IP_VERSION_V6) + { + if ((des_address.nxd_ip_address.v6[0] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0]) || + (des_address.nxd_ip_address.v6[1] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1]) || + (des_address.nxd_ip_address.v6[2] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2]) || + (des_address.nxd_ip_address.v6[3] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3])) + { + return (NX_MDNS_DEST_ADDRESS_ERROR); + } + } + else +#endif /* NX_MDNS_ENABLE_IPV6 */ + { + + /* Invalid IP version . */ + return(NX_MDNS_ERROR); + } + } + + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_address_change_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the address change event. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy the mDNS packet */ +/* nx_packet_release Release the mDNS packet */ +/* nx_udp_socket_send Send the udp packet */ +/* nxd_udp_socket_send Send the udp packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_thread_entry Processing thread for mDNS */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_address_change_process(NX_MDNS *mdns_ptr) +{ + +ULONG *head; +NX_MDNS_RR *p; +UINT i; + + + /* Register the host name. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Check if the interface is enabled. */ + if (!mdns_ptr -> nx_mdns_interface_enabled[i]) + continue; + + /* Get the local buffer head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + + if (head) + { + + /* Set the pointer. */ + head = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != i) + continue; + + /* If any of a host's IP addresses change, it MUST re-announce those address records. RFC6762, Section8.4, Page31. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) + { + + /* Send the "goodbye " announcement with RR TTL zero. RFC6762, Section8.4, Page31. */ + p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; + + /* Clear the retransmit count. */ + p -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; + + /* Set the timer count. 250ms. */ + p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; + + /* Set the delete flag. */ + p -> nx_mdns_rr_word = (p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DELETE); + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); + } + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) + _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + } + } + + /* Second register the host name, the host does not need to repeat the Probing step, Only Announcing the A/AAAA. */ + _nx_mdns_host_name_register(mdns_ptr, NX_FALSE, i); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_conflict_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function process the mDNS conflict. RFC6762, Section9, Page31 */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_rr The resource record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_add_string Add the string */ +/* _nx_mdns_cache_delete_string Delete the string */ +/* _nx_mdns_srv_name_resolve Reslove the service name */ +/* nx_mdns_rr_change_notify Resource record notify */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_conflict_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr) +{ + +UINT status; +UCHAR *old_name; +UCHAR *name; +UCHAR *type = NX_NULL; +UCHAR *domain = NX_NULL; +UINT i; +ULONG *head; +NX_MDNS_RR *p; +UCHAR is_host_type; +UINT temp_string_length; +UINT rr_name_length; + + + /* Initialize the value. */ + i = 0; + memset(&temp_string_buffer[0], 0, NX_MDNS_NAME_MAX + 1); + memset(&target_string_buffer[0], 0, NX_MDNS_NAME_MAX + 1); + + /* Get rr type. */ + if((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT)) + { + is_host_type = NX_FALSE; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(record_rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Store the service name. */ + memcpy((CHAR *)&target_string_buffer[0], (const char*)(record_rr -> nx_mdns_rr_name), rr_name_length + 1); + + /* Get Name, Type, Domain. */ + _nx_mdns_service_name_resolve(&target_string_buffer[0], &name, &type, &domain); + } + else if((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) + { + is_host_type = NX_TRUE; + name = mdns_ptr -> nx_mdns_host_name; + } + else + { + + /* This is an unsupported or unknown type. */ + return(NX_MDNS_UNSUPPORTED_TYPE); + } + + /* Check the conflict count. */ + if (record_rr -> nx_mdns_rr_conflict_count >= NX_MDNS_CONFLICT_COUNT) + { + + /* Yes, Receive the confilictiong mDNS, Probing failure. */ + if ((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A)) + { + + /* Service name has been registered , invoke the notify function. */ + if (mdns_ptr -> nx_mdns_probing_notify) + { + (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, name, NX_MDNS_LOCAL_SERVICE_REGISTERED_FAILURE); + } + } + + /* Return. */ + return (NX_MDNS_ERROR); + } + + /* Record the old name. */ + old_name = record_rr -> nx_mdns_rr_name; + + /* Set the new name and probing it. */ + while ((*name) != '\0') + { + temp_string_buffer[i++] = *name++; + } + + /* The first conflict, only add the " (2)". */ + if (record_rr -> nx_mdns_rr_conflict_count == 0) + { + temp_string_buffer[i++] = ' '; + temp_string_buffer[i++] = '('; + temp_string_buffer[i++] = '2'; + temp_string_buffer[i++] = ')'; + } + + /* Modify the count, eg: " (2)" change to " (3)". */ + else + { + temp_string_buffer[i-2] = (UCHAR)(temp_string_buffer[i-2] + 1); + } + + + if(is_host_type == NX_TRUE) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Construct the target host. */ + memcpy((CHAR *)(mdns_ptr -> nx_mdns_host_name), (CHAR *)(temp_string_buffer), temp_string_length); + + temp_string_buffer[i++] = '.'; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_domain_name, &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the domain. */ + memcpy((CHAR *)(&temp_string_buffer[i]), (CHAR *)mdns_ptr -> nx_mdns_domain_name, temp_string_length); + } + else + { + temp_string_buffer[i++] = '.'; + + /* Set the Type. */ + while ((*type) != '\0') + { + temp_string_buffer[i++] = *type++; + } + + temp_string_buffer[i++] = '.'; + + /* Set the Domain. */ + while ((*domain) != '\0') + { + temp_string_buffer[i++] = *domain++; + } + } + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)&temp_string_buffer[0], &temp_string_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Add the new resource records. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, + &temp_string_buffer[0], temp_string_length, + (VOID **)(&record_rr -> nx_mdns_rr_name), NX_FALSE, NX_TRUE); + + if (status ) + { + + /* No, return error status. */ + return(status); + } + + /* Update the state. */ + record_rr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; + record_rr -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; + record_rr -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; + record_rr -> nx_mdns_rr_conflict_count ++; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, record_rr, record_rr -> nx_mdns_rr_timer_count); + + /* Update the PTR/SRV data name. */ + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + if ((((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && (is_host_type == NX_FALSE)) || + ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && (is_host_type == NX_TRUE))) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == old_name)) + { + + /* Add the new resource records. */ + status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_string_buffer[0], temp_string_length, + (VOID **)(&(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name)), NX_FALSE, NX_TRUE); + + /* Delete the rdata name. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, old_name, 0); + } + } + + /* Delete the old name. */ + _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, old_name, 0); + + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_change_notify_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the mDNS service change operation, when the */ +/* service information change, notify the application. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_rr The resource record */ +/* is_present The service type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_service_change_notify_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *new_rr, UCHAR is_present) +{ + +UINT notify_status = 0; +ULONG *head; +NX_MDNS_RR *p; +NX_MDNS_SERVICE temp_service; +UINT rr_name_length; + + + /* Initialize the struct. */ + memset(&temp_service, 0, sizeof(NX_MDNS_SERVICE)); + + /* Compare the RDATA. */ + switch (new_rr -> nx_mdns_rr_type) + { + case NX_MDNS_RR_TYPE_A: + case NX_MDNS_RR_TYPE_AAAA: + { + + /* Get the remote buffer head. */ + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + head = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check whether the resource record is valid. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) + continue; + + /* Check the interface. */ + if (p -> nx_mdns_rr_interface_index != new_rr -> nx_mdns_rr_interface_index) + continue; + + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + { + if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target == new_rr -> nx_mdns_rr_name) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + break; + } + + /* Store the Service name. */ + memcpy((CHAR *)(&temp_string_buffer[0]), (CHAR *)(p -> nx_mdns_rr_name), rr_name_length + 1); + + /* Check if the address is updated. */ + if (((is_present == NX_FALSE) && (new_rr -> nx_mdns_rr_ttl != 0)) || + (((is_present == NX_TRUE) && (new_rr -> nx_mdns_rr_ttl == 0)))) + { + notify_status = NX_MDNS_PEER_SERVICE_UPDATED; + } + break; + } + } + } + + break; + } + case NX_MDNS_RR_TYPE_SRV: + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(new_rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + break; + } + + /* Store the Service name. */ + memcpy((CHAR *)&temp_string_buffer[0], (CHAR *)(new_rr -> nx_mdns_rr_name), rr_name_length + 1); + + /* Check if the service is new. */ + if ((is_present == NX_FALSE) && (new_rr -> nx_mdns_rr_ttl != 0)) + { + notify_status = NX_MDNS_PEER_SERVICE_RECEIVED; + } + else if ((is_present == NX_TRUE) && (new_rr -> nx_mdns_rr_ttl == 0)) + { + notify_status = NX_MDNS_PEER_SERVICE_DELETED; + } + break; + } + default: + { + + /* This is an unsupported or unknown type. */ + return; + } + } + + /* Check if need to call then notify function. */ + if (notify_status == 0) + return; + + /* Store the service name. */ + memcpy((CHAR *)(&temp_service.buffer[0]), (CHAR *)(&temp_string_buffer[0]), rr_name_length); + + /* Reslove the service name. */ + if (_nx_mdns_service_name_resolve(&temp_service.buffer[0], &(temp_service.service_name), &(temp_service.service_type), &(temp_service.service_domain))) + return; + + /* Compare the service change type. */ + if (_nx_mdns_service_mask_match(mdns_ptr, temp_service.service_type, mdns_ptr -> nx_mdns_service_notify_mask)) + return; + + /* Get the additional information. */ + _nx_mdns_service_addition_info_get(mdns_ptr, &temp_string_buffer[0], &temp_service, new_rr -> nx_mdns_rr_interface_index); + + /* Call the notify function. */ + (mdns_ptr -> nx_mdns_service_change_notify)(mdns_ptr, &temp_service, notify_status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_addition_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into remote buffer, */ +/* mDNS thread send the query message using continuous type. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The service instance */ +/* type The service type */ +/* domain The domain name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* _nx_mdns_query_check Check the query RR */ +/* _nx_mdns_cache_add_string Add the string into buffer */ +/* _nx_mdns_cache_delete_string Delete the string from buffer */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* into buffer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_service_addition_info_get(NX_MDNS *mdns_ptr, UCHAR *srv_name, NX_MDNS_SERVICE *service, UINT interface_index) +{ + +UINT index = 0; +ULONG current_time; +ULONG *head, *tail; +UCHAR i; +NX_MDNS_RR *p; +NX_MDNS_RR *p1; +UINT srv_name_length; +UINT temp_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)srv_name, &srv_name_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_ERROR); + } + + /* Get the current time. */ + current_time = tx_time_get(); + + for(i = 0; i < 2; i++) + { + + /* Set the pointer. */ + if(i == NX_MDNS_CACHE_TYPE_LOCAL) + { +#ifndef NX_MDNS_DISABLE_SERVER + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_SERVER */ + } + else + { +#ifndef NX_MDNS_DISABLE_CLIENT + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; +#else + continue; +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + + if(head == NX_NULL) + continue; + + /* Set the pointer. */ + tail = (ULONG*)(*head); + + /* Check the resource record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p < tail; p++) + { + + /* Check whether the resource record is valid. */ + if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Check the type and name. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, srv_name, srv_name_length))) + { + + /* Update the elasped timer. */ + p -> nx_mdns_rr_elapsed_time = current_time; + + /* Set the service priority, weight, port and target. */ + service -> service_priority = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority; + service -> service_weight = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights; + service -> service_port = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port; + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), &temp_length, NX_MDNS_HOST_NAME_MAX)) + { + return(NX_MDNS_ERROR); + } + + /* Store the target host. */ + memcpy((CHAR *)(service -> service_host), + (CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), + temp_length + 1); + + /* All address records (type "A" and "AAAA") named in the SRV rdata */ + for (p1 = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p1 < tail; p1++) + { + + /* Update the elasped timer. */ + p1 -> nx_mdns_rr_elapsed_time = current_time; + + /* Check the interface index. */ + if (p1 -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Find the "A" records. */ + if ((p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) && + (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) + { + + /* Set the IPv4 address. */ + service -> service_ipv4 = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address; + } + + /* Find the "AAAA" records. */ + if ((p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA) && + (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) + { + if (index < NX_MDNS_IPV6_ADDRESS_COUNT) + { + + /* Set the IPv6 address. */ + service -> service_ipv6[index][0] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0]; + service -> service_ipv6[index][1] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1]; + service -> service_ipv6[index][2] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2]; + service -> service_ipv6[index][3] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3]; + index ++; + } + } + } + } + + /* Check the type and name. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) && + (!_nx_mdns_name_match(p -> nx_mdns_rr_name, srv_name, srv_name_length))) + { + + /* Update the elasped timer. */ + p -> nx_mdns_rr_elapsed_time = current_time; + + /* Set the text valid flag. */ + service -> service_text_valid = 1; + + if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), &temp_length, NX_MDNS_NAME_MAX)) + { + continue; + } + + /* Store the txt. */ + memcpy((CHAR *)(service -> service_text), (const char*)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), temp_length + 1); + } + } + } + } + + /* Set the interface index. */ + service -> interface_index = (UCHAR)interface_index; + + /* Return a error status. */ + return(NX_MDNS_SUCCESS); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the mDNS remote buffer and local buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* local_cache_ptr Pointer to local cache */ +/* local_cache_size The size of local cache */ +/* peer_cache_ptr Pointer to peer cache */ +/* peer_cache_size The size of peer cache */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_create Initialize the mDNS structure */ +/* _nx_mdns_disable Disable the mDNS function */ +/* _nx_mdns_peer_cache_clear Clear the peer cache */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_initialize(NX_MDNS *mdns_ptr, VOID *local_cache_ptr, UINT local_cache_size, + VOID *peer_cache_ptr, UINT peer_cache_size) +{ + +ULONG *head; +ULONG *tail; + + +#ifndef NX_MDNS_DISABLE_SERVER + /* Check the cache. */ + if (local_cache_ptr) + { + + /* Zero out the cache. */ + memset(local_cache_ptr, 0, local_cache_size); + + /* Set the head. */ + head = (ULONG*)local_cache_ptr; + *head = (ULONG)((ULONG*)local_cache_ptr + 1); + + /* Set the tail. */ + tail = (ULONG*)local_cache_ptr + (local_cache_size >> 2) - 1; + *tail = (ULONG)tail; + + /* Record the info. */ + mdns_ptr -> nx_mdns_local_service_cache = (UCHAR*)local_cache_ptr; + mdns_ptr -> nx_mdns_local_service_cache_size = local_cache_size; + + /* Clear the count. */ + mdns_ptr -> nx_mdns_local_rr_count = 0; + mdns_ptr -> nx_mdns_local_string_count = 0; + mdns_ptr -> nx_mdns_local_string_bytes = 0; + } +#else + NX_PARAMETER_NOT_USED(local_cache_ptr); + NX_PARAMETER_NOT_USED(local_cache_size); +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Check the cache. */ + if (peer_cache_ptr) + { + + /* Zero out the cache. */ + memset(peer_cache_ptr, 0, peer_cache_size); + + /* Set the head. */ + head = (ULONG*)peer_cache_ptr; + *head = (ULONG)((ULONG*)peer_cache_ptr + 1); + + /* Set the tail. */ + tail = (ULONG*)peer_cache_ptr + (peer_cache_size >> 2) - 1; + *tail = (ULONG)tail; + + /* Record the info. */ + mdns_ptr -> nx_mdns_peer_service_cache = (UCHAR*)peer_cache_ptr; + mdns_ptr -> nx_mdns_peer_service_cache_size = peer_cache_size; + + /* Clear the count. */ + mdns_ptr -> nx_mdns_peer_rr_count = 0; + mdns_ptr -> nx_mdns_peer_string_count = 0; + mdns_ptr -> nx_mdns_peer_string_bytes = 0; + } +#else + NX_PARAMETER_NOT_USED(peer_cache_ptr); + NX_PARAMETER_NOT_USED(peer_cache_size); +#endif /* NX_MDNS_DISABLE_CLIENT */ + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_add_resource_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the mDNS resource record into record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_type Cache type: local or peer */ +/* record_ptr Pointer to resource record */ +/* insert_rr Pointer to insert resource */ +/* record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_find_resource_record Find the resource record */ +/* _nx_mdns_cache_delete_string Delete the string from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ +/* _nx_mdns_rr_ptr_add Add PTR resource record */ +/* _nx_mdns_rr_srv_add Add SRV resource record */ +/* _nx_mdns_rr_txt_add Add TXT resource record */ +/* _nx_mdns_query Send query */ +/* _nx_mdns_cache_delete_rr_string Delete the rr string */ +/* _nx_mdns_packet_rr_process Process resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_add_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, NX_MDNS_RR **insert_ptr, UCHAR *is_present) +{ + +UCHAR *cache_ptr; +UINT cache_size; +ULONG *tail; +ULONG *head; +NX_MDNS_RR *p; +NX_MDNS_RR *rr; +UINT rr_name_length; + +#ifndef NX_MDNS_DISABLE_CLIENT +ULONG elapsed_time; +ULONG current_time; +ULONG min_elapsed_time; +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Initialize the parameters. */ + min_elapsed_time = 0; + current_time = tx_time_get(); +#endif /* NX_MDNS_DISABLE_CLIENT */ + + /* Initialize. */ + if (is_present) + *is_present = NX_FALSE; + + /* Check the RR with same rname, rtype, rclass and rdata. */ + if (_nx_mdns_cache_find_resource_record(mdns_ptr, cache_type, record_ptr, NX_MDNS_RR_MATCH_ALL, &rr) == NX_MDNS_SUCCESS) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Copy other informations of record_ptr into insert_rr resource record. */ + memcpy(rr, record_ptr, sizeof(NX_MDNS_RR)); + + /* Special process for _services._dns-sd._udp.local which pointer to same service type. */ + if ((rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && + (!_nx_mdns_name_match(rr -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length))) + { + rr -> nx_mdns_rr_count ++; + } + + /* Delete the resource record same strings. */ + _nx_mdns_cache_delete_rr_string(mdns_ptr, cache_type, rr); + + /* Set the insert ptr. */ + if(insert_ptr != NX_NULL) + *insert_ptr = rr; + + /* Set the flag. */ + if (is_present) + *is_present = NX_TRUE; + + return(NX_MDNS_SUCCESS); + } + + /* Check the cache type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; + } + else + { + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; + } + + /* Check cache pointer and cache size. */ + if ((cache_ptr == NX_NULL) || (cache_size == 0)) + { + return(NX_MDNS_ERROR); + } + + /* Get head and tail. */ + tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; + tail = (ULONG*)(*tail); + head = (ULONG*)cache_ptr; + head = (ULONG*)(*head); + + /* Set the pointer. */ + rr = NX_NULL; + + /* Find an empty entry before head. */ + for(p = (NX_MDNS_RR*)((ULONG*)cache_ptr + 1); p < (NX_MDNS_RR*)head; p++) + { + if(p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + { + rr = p; + break; + } + } + + if (!rr) + { + + /* Check whether the cache is full. */ + if((head + (sizeof(NX_MDNS_RR) >> 2)) > tail) + { + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + return(NX_MDNS_CACHE_ERROR); + } + else + { + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Find an aging resource reocrd and repalce it. */ + for(p = (NX_MDNS_RR*)((ULONG*)cache_ptr + 1); p < (NX_MDNS_RR*)head; p++) + { + + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) + continue; + + /* Calculate the elapsed time. */ + elapsed_time = current_time - p -> nx_mdns_rr_elapsed_time; + + /* Check the elapsed time to find the aging resource record. */ + if (elapsed_time >= min_elapsed_time) + { + rr = p; + min_elapsed_time = elapsed_time; + } + } + + if (rr) + { + + /* Delete this record. */ + _nx_mdns_cache_delete_resource_record(mdns_ptr, cache_type, rr); + + /* Update the head. */ + head = (ULONG*)cache_ptr; + head = (ULONG*)(*head); + } + else + { + return(NX_MDNS_CACHE_ERROR); + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + } + } + else + { + rr = (NX_MDNS_RR*)head; + } + } + + /* Just copy it to cache_ptr. */ + memcpy(rr, record_ptr, sizeof(NX_MDNS_RR)); + + /* Check the type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + + /* Increase the count. */ + mdns_ptr -> nx_mdns_local_rr_count ++; + } + else + { + + /* Increase the count. */ + mdns_ptr -> nx_mdns_peer_rr_count ++; + } + +#ifndef NX_MDNS_DISABLE_CLIENT + /* Update the peer resource record elapsed time. */ + if (cache_type == NX_MDNS_CACHE_TYPE_PEER) + { + + /* Get the current time to set the elapsed time. */ + rr -> nx_mdns_rr_elapsed_time = current_time; + } +#endif /* NX_MDNS_DISABLE_CLIENT */ + + /* Set the insert ptr. */ + if(insert_ptr != NX_NULL) + *insert_ptr = rr; + + if((ULONG*)rr >= head) + { + + /* Update HEAD when new record is added. */ + head = (ULONG*)cache_ptr; + *head = (ULONG)(rr + 1); + } + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_delete_resource_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS resource record from record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance. */ +/* cache_type Cache type: local or peer */ +/* record_ptr Pointer to resource record. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_delete_string Delete the string from buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_rr_delete Delete the resource record */ +/* _nx_mdns_query Send the one-shot query */ +/* _nx_mdns_timer_event_process Process the timer event */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* _nx_mdns_cache_delete_rr_string Delete the rr string */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_delete_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr) +{ + +UCHAR *cache_ptr; +ULONG *head; + + + /* Delete the resource record strings. */ + _nx_mdns_cache_delete_rr_string(mdns_ptr, cache_type, record_ptr); + + /* Zero out the record. */ + memset(record_ptr, 0, sizeof(NX_MDNS_RR)); + + /* Check the type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + + /* Decrease the count. */ + mdns_ptr -> nx_mdns_local_rr_count --; + + /* Set the cache. */ + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + } + else + { + + /* Decrease the count. */ + mdns_ptr -> nx_mdns_peer_rr_count --; + + /* Set the cache. */ + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + } + + if (cache_ptr == NX_NULL) + { + return(NX_MDNS_CACHE_ERROR); + } + + /* Get head. */ + head = (ULONG*)cache_ptr; + head = (ULONG*)(*head); + + /* Move HEAD if the last RR is deleted. */ + if(record_ptr == ((NX_MDNS_RR*)head - 1)) + { + while(record_ptr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + { + record_ptr--; + if(record_ptr < (NX_MDNS_RR*)cache_ptr) + break; + } + *((ULONG*)cache_ptr) = (ULONG)(record_ptr + 1); + } + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_find_resource_record PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the mDNS resource record in record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance. */ +/* cache_type Cache type: local or peer */ +/* record_ptr Resource record. */ +/* match_type Match type. */ +/* search_rr The search resource record. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_find_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, UINT match_type, NX_MDNS_RR **search_rr) +{ + +UCHAR *cache_ptr; +ULONG *head; +NX_MDNS_RR *p; +UINT same_rdata; + + + /* Check the cache type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + } + else + { + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + } + + /* Get head. */ + head = (ULONG*)cache_ptr; + head = (ULONG*)(*head); + + /* Find the same record. */ + for(p = (NX_MDNS_RR*)((UCHAR*)cache_ptr + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) + continue; + + /* Check whether the resource record is valid. */ + if(p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check whether the same record it is. RFC6762, Section6, Page13. */ + /* The rules: rrname must match the question name. + rrtype must match the question qtype unless the qtype is "ANY" or the rrtype is "CNAME". + rrclass must match the question qclass unless the qclass is "ANY". */ + if (p -> nx_mdns_rr_name != record_ptr -> nx_mdns_rr_name) + continue; + + /* In the probing state, we need not match the type. */ + if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) + { + if ((p -> nx_mdns_rr_type != record_ptr -> nx_mdns_rr_type) && + (record_ptr -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL) && + (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_CNAME)) + continue; + } + + /* Check the RR class, Ignore the top bit. */ + if ((p -> nx_mdns_rr_class != (record_ptr -> nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)) && + ((record_ptr -> nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK) != NX_MDNS_RR_CLASS_ALL)) + continue; + + /* Check if just match the basic info. */ + if (match_type == NX_MDNS_RR_MATCH_EXCEPT_RDATA) + { + + /* Find the same record. */ + *search_rr = p; + return(NX_MDNS_SUCCESS); + } + else + { + + /* Yes, match all information of resource record. */ + + /* Check the state. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) + continue; + + /* Reset the value. */ + same_rdata = NX_FALSE; + + /* Compare the RDATA. */ + switch (p -> nx_mdns_rr_type) + { + case NX_MDNS_RR_TYPE_A: + { + if(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address) + { + same_rdata = NX_TRUE; + } + break; + } + case NX_MDNS_RR_TYPE_SRV: + { + if((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) + { + same_rdata = NX_TRUE; + } + break; + } + case NX_MDNS_RR_TYPE_AAAA: + { + if(!memcmp(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address, record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address, 16)) + { + same_rdata = NX_TRUE; + } + break; + } + case NX_MDNS_RR_TYPE_PTR: + case NX_MDNS_RR_TYPE_TXT: + +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + case NX_MDNS_RR_TYPE_CNAME: + case NX_MDNS_RR_TYPE_NS: +#endif + { + + /* Check the rdata. */ + if(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) + { + same_rdata = NX_TRUE; + } + break; + } +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + case NX_MDNS_RR_TYPE_MX: + { + if((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference)) + { + same_rdata = NX_TRUE; + } + break; + } +#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + case NX_MDNS_RR_TYPE_NSEC: + { + if ((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain == record_ptr ->nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block) && + (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length) && + (!memcmp(&(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0]), + &(record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0]), + record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length))) + { + same_rdata = NX_TRUE; + } + break; + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + default: + { + + /* This is an unsupported or unknown type. */ + return(NX_MDNS_UNSUPPORTED_TYPE); + } + } + + /* Check the same RR. */ + if (same_rdata == NX_TRUE) + { + + /* Find the same record. */ + *search_rr = p; + return(NX_MDNS_SUCCESS); + } + } + } + + return(NX_MDNS_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_add_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds or finds the mDNS string in the record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_type Cache type: local or peer */ +/* memory_ptr Pointer to the string */ +/* memory_size The size of string. */ +/* insert_rr Pointer to insert string. */ +/* find_string If set, just find the existed */ +/* string, otherwise, insert */ +/* this string if it does not */ +/* exist. */ +/* add_name If set, use name match */ +/* to check the string, */ +/* otherwise, use memcmp. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ +/* _nx_mdns_rr_ptr_add Add PTR resource record */ +/* _nx_mdns_rr_srv_add Add SRV resource record */ +/* _nx_mdns_rr_txt_add Add TXT resource record */ +/* _nx_mdns_query Send query */ +/* _nx_mdns_conflict_process Process the conflict */ +/* _nx_mdns_packet_rr_process Process resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_add_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *memory_ptr, UINT memory_size, VOID **insert_ptr, UCHAR find_string, UCHAR add_name) +{ + +UCHAR *cache_ptr; +UINT cache_size; +ULONG *tail; +ULONG *head; +UINT memory_len; +UINT used_cache_size; +USHORT len, cnt; +USHORT min_len = 0xFFFF; +UCHAR *p, *available, *start; + + + /* Check the cache type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; + } + else + { + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; + } + + /* Check cache pointer and cache size. */ + if ((cache_ptr == NX_NULL) || (cache_size == 0)) + { + return(NX_MDNS_ERROR); + } + + /* Get head and tail. */ + tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; + p = (UCHAR*)tail; + tail = (ULONG*)(*tail); + head = (ULONG*)cache_ptr; + head = (ULONG*)(*head); + + /* Calculate the amount of memory needed to store this string, including CNT and LEN fields. */ + + /* Make the length 4 bytes align. */ + memory_len = memory_size; + + /* Add the length of CNT and LEN fields. */ + memory_len = ((memory_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + available = (UCHAR*)tail; + while(p > (UCHAR*)tail) + { + + /* Get len and cnt. */ + len = *((USHORT*)(p - 2)); + cnt = *((USHORT*)(p - 4)); + start = p - len; + + if((len == memory_len) && + (((add_name == NX_TRUE) && + (!_nx_mdns_name_match(start, memory_ptr, memory_size))) || + ((add_name == NX_FALSE) && + (!memcmp(start, memory_ptr, memory_size))))) + { + + /* The same string exists in the string table. */ + if(insert_ptr) + *insert_ptr = start; + + if(find_string == NX_FALSE) + { + + /* Increase the use count CNT. */ + cnt++; + *((USHORT*)(p - 4)) = cnt; + } + + return(NX_MDNS_SUCCESS); + } + + /* This slot is not being used. The size of the slot is a smaller + fit for this string. */ + if((cnt == 0) && (len >= memory_len) && (len < min_len)) + { + + /* This place is better to insert. */ + available = p; + min_len = len; + } + + /* Move to the next string. */ + p = start; + } + + if(find_string == NX_TRUE) + return(NX_MDNS_ERROR); + + /* If we reach this point, the string needs to be added to the string table. */ + if(available == (UCHAR*)tail) + { + + /* Make sure the service cache still has room to add this string + (without overwriting the RR area.) */ + if(((UCHAR*)tail - memory_len) < (UCHAR*)head ) + { + + /* This service cache does not have room for the string table to grow. */ + /* Invoke user-installed cache full notify function .*/ + if(mdns_ptr -> nx_mdns_cache_full_notify) + { + + /* Calculate the fragment size, RR size, string size, Head and Tail. */ + if(cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + used_cache_size = mdns_ptr -> nx_mdns_local_rr_count * sizeof(NX_MDNS_RR) + mdns_ptr -> nx_mdns_local_string_bytes + 2 * sizeof(ULONG); + } + else + { + used_cache_size = mdns_ptr -> nx_mdns_peer_rr_count * sizeof(NX_MDNS_RR) + mdns_ptr -> nx_mdns_peer_string_bytes + 2 * sizeof(ULONG); + } + + /* Check the cache. */ + if ((used_cache_size + memory_len) <= cache_size) + { + (mdns_ptr -> nx_mdns_cache_full_notify)(mdns_ptr, NX_MDNS_CACHE_STATE_FRAGMENTED, cache_type); + } + else + { + (mdns_ptr -> nx_mdns_cache_full_notify)(mdns_ptr, NX_MDNS_CACHE_STATE_FULL, cache_type); + } + } + + /* The buffer is full. */ + return(NX_MDNS_CACHE_ERROR); + } + + /* Update TAIL. */ + *((ULONG*)cache_ptr + (cache_size >> 2) - 1) = (ULONG)(available - memory_len); + + } + else if(memory_len < min_len) + { + + /* Set the LEN for remaining space. */ + *((USHORT*)(available - 2 - memory_len)) = (USHORT)(min_len - memory_len); + } + + /* Set LEN and CNT. */ + *((USHORT*)(available - 2)) = (USHORT)memory_len; + *((USHORT*)(available - 4)) = 1; + + /* Clear last 4 bytes. */ + *((ULONG*)(available - 8)) = 0; + + /* Insert string to cache. */ + memcpy(available - memory_len, memory_ptr, memory_size); + + /* Set end character 0. */ + *(available - memory_len + memory_size) = 0; + + + /* Check the type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + + /* Increase the count and bytes. */ + mdns_ptr -> nx_mdns_local_string_count ++; + mdns_ptr -> nx_mdns_local_string_bytes += memory_len; + } + else + { + + /* Increase the count and bytes. */ + mdns_ptr -> nx_mdns_peer_string_count ++; + mdns_ptr -> nx_mdns_peer_string_bytes += memory_len; + } + + if(insert_ptr) + *insert_ptr = available - memory_len; + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_delete_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS string from the record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_type Cache type: local or peer */ +/* string_ptr Pointer to the string */ +/* string_len The length of string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ +/* _nx_mdns_rr_ptr_add Add PTR resource record */ +/* _nx_mdns_rr_srv_add Add SRV resource record */ +/* _nx_mdns_rr_txt_add Add TXT resource record */ +/* _nx_mdns_query Send query */ +/* _nx_mdns_conflict_process Process the conflict */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* _nx_mdns_packet_rr_process Process resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_cache_delete_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len) +{ + +UCHAR *cache_ptr; +UINT cache_size; +ULONG *tail; +ULONG *end; +USHORT cnt; + + + /* Check the cache type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; + cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; + } + else + { + cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; + cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; + } + + /* Check cache pointer and cache size. */ + if ((cache_ptr == NX_NULL) || (cache_size == 0)) + { + return(NX_MDNS_ERROR); + } + + /* Validate input parameter. */ + if(string_ptr == NX_NULL) + return(NX_MDNS_PARAM_ERROR); + + /* Check if input the string length. */ + if (string_len == 0) + { + + /* Check string length. */ + if (_nx_utility_string_length_check(string_ptr, &string_len, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + } + + /* Add the length of CNT and LEN fields. */ + /* Also make the total length 4 bytes align. */ + string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + end = (ULONG*)((UCHAR*)string_ptr + string_len); + + /* Get tail. */ + + /* Validate the string table. */ + tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; + if(end > tail) + { + + /* The end of string exceeds cache_ptr. */ + return(NX_MDNS_CACHE_ERROR); + } + tail = (ULONG*)(*tail); + if((UCHAR*)string_ptr < (UCHAR*)tail) + { + + /* The end of string exceeds cache_ptr. */ + return(NX_MDNS_CACHE_ERROR); + } + + /* Decrease the usage counter value. */ + cnt = *((USHORT*)((UCHAR*)end - 4)); + cnt--; + *((USHORT*)((UCHAR*)end - 4)) = cnt; + + /* Clear the memory if cnt is zero. */ + if(cnt == 0) + { + memset(string_ptr, 0, string_len - 2); + + /* Check the type. */ + if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) + { + + /* Increase the count and bytes. */ + mdns_ptr -> nx_mdns_local_string_count --; + mdns_ptr -> nx_mdns_local_string_bytes -= string_len; + } + else + { + + /* Increase the count and bytes. */ + mdns_ptr -> nx_mdns_peer_string_count --; + mdns_ptr -> nx_mdns_peer_string_bytes -= string_len; + } + + /* Update the tail pointer if the string at the tail is deleted. */ + if(string_ptr == tail) + { + tail = end; + + while((end < ((ULONG*)cache_ptr + (cache_size >> 2) - 1))) + { + + /* Set the string pt and string length. */ + string_ptr = end; + + /* Check string length. */ + if (_nx_utility_string_length_check(string_ptr, &string_len, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Check the string length. */ + if(string_len == 0) + { + + /* This slot is cleared. */ + while(*((ULONG*)string_ptr) == 0) + string_ptr = (UCHAR*)string_ptr + 4; + + end = (ULONG*)string_ptr + 1; + cnt = *((USHORT*)string_ptr); + } + else + { + + /* Make the length 4 bytes align and add the length of CNT and LEN fields. */ + string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; + + end = (ULONG*)((UCHAR*)string_ptr + string_len); + cnt = *((USHORT*)((UCHAR*)end - 4)); + } + + /* Check whether this slot is never referenced. */ + if(cnt == 0) + tail = end; + else + break; + } + *((ULONG*)cache_ptr + (cache_size >> 2) - 1) = (ULONG)tail; + } + } + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_cache_delete_rr_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the mDNS string from the record buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* cache_type Cache type: local or peer */ +/* string_ptr Pointer to the string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_mdns_cache_delete_string Delete the string from cache */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_cache_add_resource_record Add the resource record */ +/* _nx_mdns_cache_delete_resource_record Delete the resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_mdns_cache_delete_rr_string(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_rr) +{ + + /* Delete the name strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, cache_type, record_rr -> nx_mdns_rr_name, 0); + + /* Check if need to release the rdata string. */ + if (record_rr -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) + { + + if (((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_CNAME) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NS) || + (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_MX) +#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ + ) && + (record_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) + { + + /* Delete the same strings. */ + _nx_mdns_cache_delete_string(mdns_ptr, cache_type, record_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, 0); + } + } +} + + +#ifndef NX_MDNS_DISABLE_SERVER +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_additional_resource_record_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function find the mDNS additional resource record. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_ptr Pointer to record instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_response_send Send response message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_mdns_additional_resource_record_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr) +{ + +ULONG *head; +NX_MDNS_RR *p; + + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + /* Find the additional resource records according to the type. */ + switch (record_ptr -> nx_mdns_rr_type ) + { + + case NX_MDNS_RR_TYPE_A: + case NX_MDNS_RR_TYPE_AAAA: + { + + /* Recommends AAAA records in the additional section when responding + to rrtype "A" queries, and vice versa. RFC6762, Section19, Page51. */ + _nx_mdns_additional_a_aaaa_find(mdns_ptr, record_ptr -> nx_mdns_rr_name, record_ptr -> nx_mdns_rr_interface_index); + + break; + } + + case NX_MDNS_RR_TYPE_PTR: + { + + /* Find the additional resource record. */ + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface. */ + if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) + continue; + + /* The SRV record(s) named in the PTR rdata. + The TXT record(s) named in the PTR rdata. + All address records (type "A" and "AAAA") named in the SRV rdata. RFC6763, Section12.1, Page30.*/ + + /* The SRV records named in the PTR rdata */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && + (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) && + ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && + (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && + (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) + { + + /* Set the flag to add this resource records into additional records. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; + + /* All address records (type "A" and "AAAA") named in the SRV rdata */ + _nx_mdns_additional_a_aaaa_find(mdns_ptr, p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, record_ptr -> nx_mdns_rr_interface_index); + } + + /* The TXT records named in the PTR rdata */ + if (((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || + (p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC)) && + (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) && + ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && + (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && + (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) + { + + /* Set the flag to add this resource records into additional records. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; + } + } + + break; + } + + case NX_MDNS_RR_TYPE_SRV: + case NX_MDNS_RR_TYPE_TXT: + { + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + /* Find the additional resource record. */ + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface. */ + if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) + continue; + + /* The NSEC records named same as SRV/TXT name. */ + if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) && + (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_name) && + ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && + (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && + (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) + { + + /* Set the flag to add this resource records into additional records. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; + } + } +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + + /* All address records (type "A" and "AAAA") named in the SRV rdata */ + if (record_ptr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + _nx_mdns_additional_a_aaaa_find(mdns_ptr, record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, record_ptr -> nx_mdns_rr_interface_index); + break; + } + } + + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_additional_a_aaaa_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function find the mDNS additional A/AAAA resource record. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_ptr Pointer to record instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_additional_resource_record_find */ +/* Find additional record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_mdns_additional_a_aaaa_find(NX_MDNS *mdns_ptr, UCHAR *name, UINT interface_index) +{ + +ULONG *head; +NX_MDNS_RR *p; + + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + head = (ULONG*)(*head); + + /* Recommends AAAA records in the additional section when responding + to rrtype "A" queries, and vice versa. RFC6762, Section19, Page51. */ + for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) + { + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + /* Find the "A" records. */ + if (((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA || + (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC))) && + (p -> nx_mdns_rr_name == name) && + ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || + (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && + (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && + (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) + { + + /* Set the flag to add this resource records into additional records. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; + } + } +} +#endif /* NX_MDNS_DISABLE_SERVER */ + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_known_answer_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the mDNS known answer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* record_ptr Pointer to record instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_query_send Send query message */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_known_answer_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr) +{ + +UINT status = NX_MDNS_NO_KNOWN_ANSWER; +ULONG *head, *tail; +NX_MDNS_RR *p; +UINT i; +UINT name_length; +#ifndef NX_MDNS_DISABLE_SERVER +UINT cache_count = 2; +#else +UINT cache_count = 1; +#endif + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_mdns_rr_name), &name_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Loop to find the known answer in cache. */ + for (i = 0; i < cache_count; i++) + { + + /* Set the pointer. */ + if (i == 0) + { + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + } +#ifndef NX_MDNS_DISABLE_SERVER + else + { + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + } +#endif /* NX_MDNS_DISABLE_SERVER */ + tail = (ULONG*)(*head); + + /* Whether this mDNS message response to query. */ + for(p = (NX_MDNS_RR*)(head + 1); (ULONG*)p < tail; p++) + { + + /* Check the state. */ + if(p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_VALID) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) + continue; + + /* Check whether the Known Answer record it is. */ + if ((!_nx_mdns_name_match(p -> nx_mdns_rr_name, record_ptr -> nx_mdns_rr_name, name_length)) && + (p -> nx_mdns_rr_class == record_ptr -> nx_mdns_rr_class)) + { + + if ((record_ptr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_ALL) || + (p -> nx_mdns_rr_type == record_ptr -> nx_mdns_rr_type)) + { + + /* Set the additional flag. */ + p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_KNOWN_ANSWER; + + /* Yes, find the known answer. */ + status = NX_MDNS_SUCCESS; + } + } + } + } + + return(status); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +#ifndef NX_MDNS_DISABLE_CLIENT +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_query_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks whether mDNS querier already has one Unique */ +/* record in the local buffer/remote buffer or one same query in the */ +/* remote buffer. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* name The resource record name */ +/* type The resource record type */ +/* interface_index The interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_query Send the query */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_query_check(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT one_shot, NX_MDNS_RR **search_rr, UINT interface_index) +{ + +ULONG *head; +NX_MDNS_RR *p; +UCHAR i; +UCHAR same_query = NX_FALSE; +NX_MDNS_RR *rr = NX_NULL; +UCHAR srv_flag = NX_FALSE; +UCHAR txt_flag = NX_FALSE; +UINT name_length; + + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + for(i = 0; i < 2; i++) + { + if(i == NX_MDNS_CACHE_TYPE_LOCAL) + head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; + else + head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; + + if(head) + { + for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) + { + + /* Check whether the resource record is valid. */ + if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) + continue; + + /* Check the interface index. */ + if (p -> nx_mdns_rr_interface_index != interface_index) + continue; + + if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, name, name_length)) + { + if ((p -> nx_mdns_rr_type == type) && (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) + { + + /* Set the query. */ + same_query = NX_TRUE; + + /* Record the RR potiner. */ + rr = p; + } + + /* Check the rr type. */ + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) + srv_flag = NX_TRUE; + if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) + txt_flag = NX_TRUE; + + if ((p -> nx_mdns_rr_type == type) || + ((type == NX_MDNS_RR_TYPE_ALL) && (srv_flag == NX_TRUE) && (txt_flag == NX_TRUE))) + { + if (search_rr) + *search_rr = p; + + /* Check the query type. */ + if (one_shot == NX_TRUE) + return(NX_MDNS_EXIST_SHARED_RR); + + if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) + return(NX_MDNS_EXIST_UNIQUE_RR); + } + } + } + } + } + + /* Check the same query. */ + if (same_query == NX_TRUE) + { + + /* A multicast DNS querier should also delay the first query of the series by + a randomly chosen amount in the range 20-120ms. */ + rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); + rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; + + /* Set the mDNS timer. */ + _nx_mdns_timer_set(mdns_ptr, rr, rr -> nx_mdns_rr_timer_count); + + return (NX_MDNS_EXIST_SAME_QUERY); + } + + /* Return a successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_query_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes mDNS One-shot query timeout and thread */ +/* terminate actions that require the mDNS data structures to be */ +/* cleaned up. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to suspended thread's */ +/* control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume thread service */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_timeout Thread timeout processing */ +/* _tx_thread_terminate Thread terminate processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_mdns_query_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_MDNS *mdns_ptr; + + + NX_CLEANUP_EXTENSION + + /* Setup pointer to UDP socket control block. */ + mdns_ptr = (NX_MDNS *) thread_ptr -> tx_thread_suspend_control_block; + + /* Disable interrupts to remove the suspended thread from the UDP socket. */ + TX_DISABLE + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (mdns_ptr) && + (mdns_ptr -> nx_mdns_id == NX_MDNS_ID)) + { + + /* Yes, we still have thread suspension! */ + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Remove the suspended thread from the list. */ + + /* See if this is the only suspended thread on the list. */ + if (thread_ptr == thread_ptr -> tx_thread_suspended_next) + { + + /* Yes, the only suspended thread. */ + + /* Update the head pointer. */ + mdns_ptr -> nx_mdns_rr_receive_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + mdns_ptr -> nx_mdns_rr_receive_suspension_list = thread_ptr -> tx_thread_suspended_next; + + /* Update the links of the adjacent threads. */ + (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = thread_ptr -> tx_thread_suspended_previous; + (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr -> tx_thread_suspended_next; + } + + /* Decrement the suspension count. */ + mdns_ptr -> nx_mdns_rr_receive_suspended_count--; + + /* Now we need to determine if this cleanup is from a terminate, timeout, + or from a wait abort. */ + if (thread_ptr -> tx_thread_state == TX_TCP_IP) + { + + /* Thread still suspended on the UDP socket. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_MDNS_NO_RR; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume the thread! Check for preemption even though we are executing + from the system timer thread right now which normally executes at the + highest priority. */ + _tx_thread_system_resume(thread_ptr); + + /* Finished, just return. */ + return; + } + } + + /* Restore interrupts. */ + TX_RESTORE +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_query_thread_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends a thread on a mDNS client query service */ +/* */ +/* INPUT */ +/* */ +/* suspension_list_head Pointer to the suspension list*/ +/* mutex_ptr Pointer to mutex to release */ +/* suspend_cleanup Suspension cleanup routine */ +/* wait_option Optional timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_put Release protection */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_mdns_query_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), + NX_MDNS *mdns_ptr, NX_MDNS_RR **rr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; + + + /* Lockout interrupts. */ + TX_DISABLE + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup suspension list. */ + if (*suspension_list_head) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = *suspension_list_head; + thread_ptr -> tx_thread_suspended_previous = (*suspension_list_head) -> tx_thread_suspended_previous; + ((*suspension_list_head) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr; + (*suspension_list_head) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + *suspension_list_head = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_MDNS_NO_RR; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = suspend_cleanup; + + /* Setup cleanup information, i.e. this pool control block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)mdns_ptr; + + /* Save the return RR pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)rr; + + /* Increment the suspended thread count. */ + mdns_ptr -> nx_mdns_rr_receive_suspended_count++; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_TCP_IP; + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Save the timeout value. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Restore interrupts. */ + TX_RESTORE + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_query_thread_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes a thread suspended on a mDNS Client query */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to suspended thread's */ +/* control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume thread service */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_timeout Thread timeout processing */ +/* _tx_thread_terminate Thread terminate processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_mdns_query_thread_resume(TX_THREAD **suspension_list_head, NX_MDNS *mdns_ptr, NX_MDNS_RR *rr) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the thread pointer. */ + thread_ptr = *suspension_list_head; + + /* Determine if there still is a thread suspended. */ + if (thread_ptr) + { + + /* Remove the suspended thread from the list. */ + + /* See if this is the only suspended thread on the list. */ + if (thread_ptr == thread_ptr -> tx_thread_suspended_next) + { + + /* Yes, the only suspended thread. */ + + /* Update the head pointer. */ + *suspension_list_head = TX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + *suspension_list_head = thread_ptr -> tx_thread_suspended_next; + + /* Update the links of the adjacent threads. */ + (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = thread_ptr -> tx_thread_suspended_previous; + (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr -> tx_thread_suspended_next; + } + + /* Decrement the suspension count. */ + mdns_ptr -> nx_mdns_rr_receive_suspended_count--; + + /* Prepare for resumption of the first thread. */ + + /* Clear cleanup routine to avoid timeout. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Return this block pointer to the suspended thread waiting for + a block. */ + *((NX_MDNS_RR **) thread_ptr -> tx_thread_additional_suspend_info) = rr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_MDNS_SUCCESS; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_service_mask_match PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function matchs the mDNS service mask to listen the service */ +/* and notify the application, or ignore the service. */ +/* */ +/* INPUT */ +/* */ +/* mdns_ptr Pointer to mDNS instance */ +/* service_type Pointer to Service type */ +/* service_mask The Service mask */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the mDNS mutex */ +/* tx_mutex_put Put the mDNS mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_service_mask_match(NX_MDNS *mdns_ptr, UCHAR *service_type, ULONG service_mask) +{ + +UINT i; +UINT found; +ULONG mask; +UINT type_length; + + + NX_PARAMETER_NOT_USED(mdns_ptr); + + /* Initialize the parameters. */ + i = 0; + found = 0; + mask = 0x00000001; + + /* Compare the service type. */ + while (nx_mdns_service_types[i]) + { + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)nx_mdns_service_types[i], &type_length, NX_MDNS_TYPE_MAX)) + { + return(NX_MDNS_DATA_SIZE_ERROR); + } + + /* Find the same service type. */ + if (!_nx_mdns_name_match(service_type, (UCHAR *)(nx_mdns_service_types[i]), type_length)) + { + found = 1; + break; + } + i ++; + } + + /* Check the result. */ + if (found) + { + + /* Check service mask. */ + if (service_mask & (mask << i)) + { + return(NX_MDNS_SUCCESS); + } + } + + /* Return status. */ + return(NX_MDNS_SERVICE_TYPE_MISMATCH); +} +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_name_match PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function name string match, the lowercase letters "a" to "z" */ +/* match their uppercase equivalents "A" to "Z". */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_rr_add Add the RR into packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_name_match(UCHAR *src, UCHAR *dst, UINT length) +{ + +UINT index = 0; + + + /* Check the name. */ + while (*dst != '\0') + { + if((*src) != (*dst)) + { + if((((*src) | 0x20) >= 'a') && (((*src) | 0x20) <= 'z')) + { + /* Match the characters, case in-sensitive. */ + if(((*src) | 0x20) != ((*dst) | 0x20)) + return(NX_MDNS_NAME_MISMATCH); + } + else + { + return(NX_MDNS_NAME_MISMATCH); + } + } + src ++; + dst ++; + index ++; + } + + /* Check the scan length. */ + if (index != length) + { + return (NX_MDNS_NAME_MISMATCH); + } + + /* Return success. */ + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_txt_string_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the txt string and adds the txt string into */ +/* packet.the TXT records are formatted in a "key=value" notation */ +/* with ";" acting as separator when more then one key is available. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_rr_add Add the RR into packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_txt_string_encode(UCHAR *ptr, UCHAR *txt) +{ + +UCHAR *length; +UINT count = 1; + + + /* Point to the first character position in the buffer. This will point + to the length of the following name. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + + /* Move through string, copying bytes and updating length. + Whenever a "." is found, start a new string by updating the + pointer to the length and setting the length to zero. */ + while (*txt) + { + + /* Is a dot been found? */ + if (*txt == ';') + { + + + /* Yes, setup a new length pointer. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + txt++; + } + else + { + + /* Copy a character to the destination. */ + *ptr++ = *txt++; + + /* Adjust the length of the current segment. */ + (*length)++; + } + + /* Increment the total count here. */ + count++; + } + + /* Return the count. */ + return(count); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_txt_string_decode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decode the txt string and adds the txt string into */ +/* buffer.the TXT records are formatted in a "key=value" notation */ +/* with ";" acting as separator when more then one key is available. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer to decode */ +/* data_length The length of data */ +/* buffer Pointer to decoded data */ +/* size Size of data buffer to decode */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_mdns_packet_process Process mDNS packet */ +/* _nx_mdns_packet_rr_process Process resource record */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_txt_string_decode(UCHAR *data, UINT data_length, UCHAR *buffer, UINT size) +{ + + + /* Check the buffer size. */ + if (data_length >= size) + { + return (NX_MDNS_CACHE_ERROR); + } + + /* decode the data. */ + while (data_length) + { + + UINT labelSize = *data++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_MDNS_LABEL_MAX) + { + + /* Simple count, check for space and copy the label. */ + while (labelSize > 0) + { + + *buffer++ = *data++; + labelSize--; + data_length--; + } + + /* Now add the ';' */ + *buffer++ = ';'; + data_length--; + } + else + { + return(NX_MDNS_EXCEED_MAX_LABEL); + } + } + + /* Done copying the data, set the last . to a trailing null */ + if (*(buffer - 1) == ';') + { + + buffer--; + } + + /* Null terminate name. */ + *buffer = '\0'; + + /* Return name size. */ + return(NX_MDNS_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_name_size_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the size of the name. */ +/* */ +/* INPUT */ +/* */ +/* name Pointer to the name */ +/* */ +/* OUTPUT */ +/* */ +/* UINT Size of name */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_name_size_calculate(UCHAR *name) +{ + +UINT size = 0; + + + /* As long as we haven't found a zero length terminating label */ + while (*name != '\0') + { + + UINT labelSize = *name++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_MDNS_LABEL_MAX) + { + + /* Simple count, adjust size and skip the label. */ + size += labelSize + 1; + name += labelSize; + } + else if ((labelSize & NX_MDNS_COMPRESS_MASK) == NX_MDNS_COMPRESS_VALUE) + { + + /* This is a pointer size is 2 bytes and this is the end of this name */ + return(size + 2); + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + + /* Adjust size for the final NULL. */ + return(size + 1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_name_string_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a string containing the name as a list of */ +/* labels separated by dots to the encoded list of labels specified */ +/* in RFC1035 for DNS servers. This conversion doesn't handle */ +/* compression and doesn't check on the lengths of the labels or the */ +/* entire name. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to destination */ +/* name Source name string */ +/* */ +/* OUTPUT */ +/* */ +/* count Count of characters encoded */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_name_string_encode(UCHAR *ptr, UCHAR *name) +{ + +UCHAR *length; +UINT count = 1; + + + /* Point to the first character position in the buffer. This will point + to the length of the following name. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + + /* Move through string, copying bytes and updating length. + Whenever a "." is found, start a new string by updating the + pointer to the length and setting the length to zero. */ + while (*name) + { + + /* Is a dot been found? */ + if (*name == '.') + { + + /* Yes, setup a new length pointer. */ + length = ptr++; + + /* Default the length to zero. */ + *length = 0; + name++; + } + else + { + + /* Copy a character to the destination. */ + *ptr++ = *name++; + + /* Adjust the length of the current segment. */ + (*length)++; + } + + /* Increment the total count here. */ + count++; + } + + /* Add the final zero length, like a NULL terminator. */ + *ptr = 0; + + /* Increment the total count. */ + count++; + + /* Return the count. */ + return(count); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_name_string_decode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts from the encoded list of labels as specified */ +/* in RFC 1035 to a string containing the name as a list of labels */ +/* separated by dots. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer to decode */ +/* start Location of start of data */ +/* buffer Pointer to decoded data */ +/* size Size of data buffer to decode */ +/* */ +/* OUTPUT */ +/* */ +/* Size of decoded data */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_name_string_decode(UCHAR *data, UINT start, UCHAR *buffer, UINT size) +{ + +UCHAR *character = data + start; +UINT length = 0; + + + /* As long as there is space in the buffer and we haven't + found a zero terminating label */ + while ((size > length) && (*character != '\0')) + { + + UINT labelSize = *character++; + + /* Is this a compression pointer or a count. */ + if (labelSize <= NX_MDNS_LABEL_MAX) + { + + /* Simple count, check for space and copy the label. */ + while ((size > length) && (labelSize > 0)) + { + + *buffer++ = *character++; + length++; + labelSize--; + } + + /* Now add the '.' */ + *buffer++ = '.'; + length++; + } + else if ((labelSize & NX_MDNS_COMPRESS_MASK) == NX_MDNS_COMPRESS_VALUE) + { + + /* This is a pointer, just adjust the source. */ + character = data + ((labelSize & NX_MDNS_LABEL_MAX) << 8) + *character; + } + else + { + + /* Not defined, just fail */ + return(0); + } + } + + /* Done copying the data, set the last . to a trailing null */ + if (*(buffer - 1) == '.') + { + + buffer--; + length --; + } + + /* Null terminate name. */ + *buffer = '\0'; + + /* Return name size. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_rr_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the size of resource record. */ +/* */ +/* INPUT */ +/* */ +/* resource Pointer to the resource */ +/* */ +/* OUTPUT */ +/* */ +/* size of data */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_mdns_rr_size_get(UCHAR *resource) +{ + +UINT name_size; +UINT data_size; + + /* Resource size is + name size + data size + 2 bytes for type, 2 for class, 4 for time to live and 2 for data length + i.e. name size + data size + 10 bytes overhead. + */ + name_size = _nx_mdns_name_size_calculate(resource); + data_size = NX_MDNS_GET_USHORT_DATA(resource + name_size + 8); + + /* Return resource size. */ + return(name_size + data_size + 10); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_short_to_network_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an unsigned short to network byte order, */ +/* which is big endian. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to the destination */ +/* value Source value */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* DNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static void _nx_mdns_short_to_network_convert(UCHAR *ptr, USHORT value) +{ + + *ptr++ = (UCHAR)(value >> 8); + *ptr = (UCHAR)value; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_mdns_long_to_network_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an unsigned long to network format, which */ +/* big endian. */ +/* */ +/* INPUT */ +/* */ +/* ptr Pointer to the destination */ +/* value Source value */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* DNS component */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static void _nx_mdns_long_to_network_convert(UCHAR *ptr, ULONG value) +{ + + *ptr++ = (UCHAR)(value >> 24); + *ptr++ = (UCHAR)(value >> 16); + *ptr++ = (UCHAR)(value >> 8); + *ptr = (UCHAR)value; +} diff --git a/addons/mdns/nxd_mdns.h b/addons/mdns/nxd_mdns.h new file mode 100644 index 00000000..41eaf2f1 --- /dev/null +++ b/addons/mdns/nxd_mdns.h @@ -0,0 +1,1316 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Multicast Domain Name System (mDNS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_mdns.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Multicast Domain Name System (mDNS) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_MDNS_H +#define NXD_MDNS_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + + + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_ip.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_ipv6.h" +#endif /* FEATURE_NX_IPV6 */ + + +/* Define the Multicast DNS ID. */ +#define NX_MDNS_ID 0x4d444e53UL + +/* Define macros that get the data on unaligned address. */ +#define NX_MDNS_GET_USHORT_DATA(data) (USHORT)((*(data) << 8) | (*(data + 1))) +#define NX_MDNS_GET_ULONG_DATA(data) (ULONG)((*(data) << 24) | (*(data + 1) << 16) | (*(data + 2) << 8) | (*(data + 3))) + +/* Disable the mDNS Server functionality. By default mDNS server + function is enabled. To remove the mDNS server function from + the mDNS library, uncomment the following line. */ +/* +#define NX_MDNS_DISABLE_SERVER +*/ + +/* Disable the mDNS Client functionality. By default mDNS client + function is enabled. To remove the mDNS client function from + the mDNS library, uncomment the following line. */ +/* +#define NX_MDNS_DISABLE_CLIENT +*/ + +/* Enable the feature to check the address and port of mDNS message. + By default is enabled. To remove it from the mDNS library, + comment the following line. */ +#define NX_MDNS_ENABLE_ADDRESS_CHECK + +/* Enable the Passive Observation Of Failures feature for Client. + By default is enabled. To remove it from the mDNS library, + comment the following line. + Note: This will have no effect if NX_MDNS_DISABLE_CLIENT is defined. */ +#define NX_MDNS_ENABLE_CLIENT_POOF + +/* Enable the feature for Server to generate the Negative Responses. + By default is enabled. To remove it from the mDNS library, + comment the following line. + Note: This will have no effect if NX_MDNS_DISABLE_SERVER is defined. */ +#define NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + + +/* Enable mDNS IPv6 feature, send/process mDNS message over IPv6 address. + By default mDNS IPv6 function is disabled. To enable this feature, + uncomment the following line. */ +/* +#define NX_MDNS_ENABLE_IPV6 +*/ + +#ifdef NX_MDNS_ENABLE_IPV6 + +#ifndef FEATURE_NX_IPV6 +#error "mDNS IPv6 is not supported if IPv6 is not enabled." +#endif /* FEATURE_NX_IPV6 */ + +#ifndef NX_IPV6_MULTICAST_ENABLE +#error "mDNS IPv6 is not supported if IPv6 multicast is not enabled." +#endif /* NX_IPV6_MULTICAST_ENABLE */ + +#ifndef NX_MDNS_DISABLE_SERVER +#ifndef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY +#error "mDNS IPv6 is not supported if IPv6 address change notify is not enabled." +#endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */ +#endif /* NX_MDNS_DISABLE_SERVER */ + +#endif /* NX_MDNS_ENABLE_IPV6 */ + + +/* Define the IPV6 address count of the host name. */ +#ifndef NX_MDNS_IPV6_ADDRESS_COUNT +#define NX_MDNS_IPV6_ADDRESS_COUNT 2 +#endif /* NX_MDNS_IPV6_ADDRESS_COUNT */ + + +/* Define message and name limits. */ +#define NX_MDNS_TYPE_MAX 21 /* Maximum Type size, ._tcp, may be up to 15 bytes, + plus the underscore and length byte. Including the "_udp" or "_tcp". */ +#define NX_MDNS_LABEL_MAX 63 /* Maximum Label (between two dots) size */ +#define NX_MDNS_NAME_MAX 255 /* Maximum Name size */ +#define NX_MDNS_IP_LOOKUP_SIZE 75 /* IPv6 needs 66 characters for the address plus 8 for the ip6.arpa plus null */ + /* IPv4 needs 12 characters max for the address plus 12 for the IN-ADDR.ARPA plus null */ + + +/* Define the mDNS's host name cache size. Keep four-byte alignment. */ +/* Note: The real host name size plus conflict size (4) + must not exceed NX_MDNS_LABEL_MAX and NX_MDNS_HOST_NAME_MAX. + such as: + the real host name: "NETX-MDNS-HOST" + the conflict name: " (2)" + the final name: "NETX-MDNS-HOST (2)". */ +#ifndef NX_MDNS_HOST_NAME_MAX +#define NX_MDNS_HOST_NAME_MAX 64 +#endif /* NX_MDNS_HOST_NAME_MAX */ + + +/* Define the mDNS's service name cache size. Keep four-byte alignment. */ +/* Note: The real service name size plus conflict size (4) + must not exceed NX_MDNS_LABEL_MAX and NX_MDNS_SERVICE_NAME_MAX. + such as: + the real service name: "NETX-MDNS-SERVICE" + the conflict name: " (2)" + the final service name: "NETX-MDNS-SERVICE (2)". */ +#ifndef NX_MDNS_SERVICE_NAME_MAX +#define NX_MDNS_SERVICE_NAME_MAX 64 +#endif /* NX_MDNS_SERVICE_NAME_MAX */ + + +/* Define the mDNS's domain name max size. */ +#ifndef NX_MDNS_DOMAIN_NAME_MAX +#define NX_MDNS_DOMAIN_NAME_MAX 16 +#endif /* NX_MDNS_DOMAIN_NAME_MAX */ + +/* NX_MDNS_DOMAIN_NAME_MAX must be at leat 5 bytes to hold "local". */ +#if (NX_MDNS_DOMAIN_NAME_MAX < 5) +#error "NX_MDNS_DOMAIN_NAME_MAX must be at least 5 bytes!" +#endif /* (NX_MDNS_DOMAIN_NAME_MAX < 5) */ + + +/* Define the conflict count of service name or host name. */ +/* Note: the confilict count should be less than 8, since we just append " (x)" + between " (2)" and " (9)" during the conflict resolution process. */ +#ifndef NX_MDNS_CONFLICT_COUNT +#define NX_MDNS_CONFLICT_COUNT 8 +#endif/* NX_MDNS_CONFLICT_COUNT */ + + +/* Define the DNS-SD buffer size for storing "_services._dns-sd._udp.local" */ +/* Note: the domain can be updated, so the max size should be NX_MDNS_DOMAIN_NAME_MAX + 23. + "_services._dns-sd._udp." (23) + NX_MDNS_DOMAIN_NAME_MAX. */ +#define NX_MDNS_DNS_SD_MAX (NX_MDNS_DOMAIN_NAME_MAX + 23) + + +/* Define mDNS Multicast Address. */ +#define NX_MDNS_IPV4_MULTICAST_ADDRESS (IP_ADDRESS(224,0,0,251)) + + +/* Define mDNS port. */ +#define NX_MDNS_UDP_PORT 5353 + + +/* Define UDP socket create options. */ +#ifndef NX_MDNS_UDP_TYPE_OF_SERVICE +#define NX_MDNS_UDP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif /* NX_MDNS_UDP_TYPE_OF_SERVICE */ + +#ifndef NX_MDNS_UDP_FRAGMENT_OPTION +#define NX_MDNS_UDP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif /* NX_MDNS_UDP_FRAGMENT_OPTION */ + +#ifndef NX_MDNS_UDP_TIME_TO_LIVE +#define NX_MDNS_UDP_TIME_TO_LIVE 0xFF +#endif /* NX_MDNS_UDP_TIME_TO_LIVE */ + +#ifndef NX_MDNS_UDP_QUEUE_DEPTH +#define NX_MDNS_UDP_QUEUE_DEPTH 4 +#endif /* NX_MDNS_UDP_QUEUE_DEPTH */ + + +/* Define the resource record TTL. In second. */ +/* The recommended TTL value for Multicast DNS resource records with a host name as the resource record's name + (e.g., A, AAAA, HINFO) or a host name contaned within the resource record's rdata (e.g., SRV, reverse mapping PTR record) + should be 120 seconds. The recommended TTL value for other Multicast DNS resource records is 75 minutes. + RFC6762, Section10, Page33. */ +#ifndef NX_MDNS_RR_TTL_HOST +#define NX_MDNS_RR_TTL_HOST 120 +#endif /* NX_MDNS_RR_TTL_HOST */ + +#ifndef NX_MDNS_RR_TTL_OTHER +#define NX_MDNS_RR_TTL_OTHER 4500 /* 75 minutes. */ +#endif /* NX_MDNS_RR_TTL_OTHER */ + + +/* Define the mDNS's probing timer interval, default 250ms in spec. In tick. + should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ +#ifndef NX_MDNS_PROBING_TIMER_COUNT +#define NX_MDNS_PROBING_TIMER_COUNT 25 +#endif /* NX_MDNS_PROBING_TIMER_COUNT */ + + +/* Define the mDNS's announcing timer interval, default 250ms in spec. In tick. + should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ +#ifndef NX_MDNS_ANNOUNCING_TIMER_COUNT +#define NX_MDNS_ANNOUNCING_TIMER_COUNT 25 +#endif /* NX_MDNS_ANNOUNCING_TIMER_COUNT */ + + +/* Define the mDNS's goodbye timer interval, default 250ms in spec. In tick. + should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ +#ifndef NX_MDNS_GOODBYE_TIMER_COUNT +#define NX_MDNS_GOODBYE_TIMER_COUNT 25 +#endif /* NX_MDNS_GOODBYE_TIMER_COUNT */ + + +/* Define the mDNS's min query timer interval between two queries, 1 second. In tick. */ +#ifndef NX_MDNS_QUERY_MIN_TIMER_COUNT +#define NX_MDNS_QUERY_MIN_TIMER_COUNT NX_IP_PERIODIC_RATE +#endif /* NX_MDNS_QUERY_MIN_TIMER_COUNT */ + + +/* Define the mDNS's max query timer interval between first two queries, 60 minutes. In tick. */ +#ifndef NX_MDNS_QUERY_MAX_TIMER_COUNT +#define NX_MDNS_QUERY_MAX_TIMER_COUNT (3600 * NX_IP_PERIODIC_RATE) +#endif /* NX_MDNS_QUERY_MAX_TIMER_COUNT */ + + +/* Define the mDNS's query delay timer interval, 20-120ms. In tick. */ +#ifndef NX_MDNS_QUERY_DELAY_MIN +#define NX_MDNS_QUERY_DELAY_MIN 2 +#endif /* NX_MDNS_QUERY_DELAY_MIN */ + +#ifndef NX_MDNS_QUERY_DELAY_RANGE +#define NX_MDNS_QUERY_DELAY_RANGE 10 +#endif /* NX_MDNS_QUERY_DELAY_RANGE */ + + +/* Define the mDNS's response delay time interval for multicast query. */ +/* The time interval, in ticks, in responding to a query to ensure an interval of at least 1s + since the last time the record was multicast. The default value is 100 ticks. */ +#ifndef NX_MDNS_RESPONSE_INTERVAL +#define NX_MDNS_RESPONSE_INTERVAL NX_IP_PERIODIC_RATE +#endif /* NX_MDNS_RESPONSE_INTERVAL */ + + +/* Define the mDNS's response delay time interval for probe message. */ +/* The time interval, in ticks, in responding to a probe queries to ensure an interval of + at least 250ms since the last time the record was multicast. The default value is 25 ticks. */ +#ifndef NX_MDNS_RESPONSE_PROBING_TIMER_COUNT +#define NX_MDNS_RESPONSE_PROBING_TIMER_COUNT 25 +#endif /* NX_MDNS_RESPONSE_PROBING_TIMER_COUNT */ + + +/* Define the mDNS's response delay time interval for unicast query, 10 ms. In tick. */ +#ifndef NX_MDNS_RESPONSE_UNIQUE_DELAY +#define NX_MDNS_RESPONSE_UNIQUE_DELAY 1 +#endif /* NX_MDNS_RESPONSE_UNIQUE_DELAY */ + + +/* Define the mDNS's response delay time interval for shared message, 20-120ms. In tick. */ +#ifndef NX_MDNS_RESPONSE_SHARED_DELAY_MIN +#define NX_MDNS_RESPONSE_SHARED_DELAY_MIN 2 +#endif /* NX_MDNS_RESPONSE_SHARED_DELAY_MIN */ + +#ifndef NX_MDNS_RESPONSE_SHARED_DELAY_RANGE +#define NX_MDNS_RESPONSE_SHARED_DELAY_RANGE 10 +#endif /* NX_MDNS_RESPONSE_SHARED_DELAY_RANGE */ + + +/* Define the mDNS's response delay time interval for query with TC, 400-500 ms. In tick. */ +#ifndef NX_MDNS_RESPONSE_TC_DELAY_MIN +#define NX_MDNS_RESPONSE_TC_DELAY_MIN 40 +#endif /* NX_MDNS_RESPONSE_TC_DELAY_MIN */ + +#ifndef NX_MDNS_RESPONSE_TC_DELAY_RANGE +#define NX_MDNS_RESPONSE_TC_DELAY_RANGE 10 +#endif /* NX_MDNS_RESPONSE_TC_DELAY_RANGE */ + + +/* Define the mDNS's random delay timer count, 120 ms. In tick. */ +/* This value allows a response to include messages that would be sent within + the next 120ms range. */ +#ifndef NX_MDNS_TIMER_COUNT_RANGE +#define NX_MDNS_TIMER_COUNT_RANGE 12 +#endif /* NX_MDNS_TIMER_COUNT_RANGE */ + + +/* Define the mDNS's probing retransmit count. The defaul value is 3. */ +#ifndef NX_MDNS_PROBING_RETRANSMIT_COUNT +#define NX_MDNS_PROBING_RETRANSMIT_COUNT 3 +#endif /* NX_MDNS_PROBING_RETRANSMIT_COUNT */ + + +/* Define the mDNS's goodbye retransmit count. The defaul value is 1. */ +#ifndef NX_MDNS_GOODBYE_RETRANSMIT_COUNT +#define NX_MDNS_GOODBYE_RETRANSMIT_COUNT 1 +#endif /* NX_MDNS_GOODBYE_RETRANSMIT_COUNT */ + + +/* Passive Observation Of Failures. + If a host sees queries, for which a record in its cache would be + expected to be given as an answer in a multicast response, but no + such answer is seen, then the host may take this as an indication + that the record may no longer be valid. + After seesing NX_MDNS_POOF_MIN_COUNT of these queries, and seeing + no multicast response containing the expected answer with in + NX_MDNS_POOF_TIMER_COUNT, delete the RR from the cache. + RFC6762, Section10.5, Page38. */ + +/* Define the Passive Observation Of Failures min count. The defaul value is 2. */ +#ifndef NX_MDNS_POOF_MIN_COUNT +#define NX_MDNS_POOF_MIN_COUNT 2 +#endif /* NX_MDNS_POOF_MIN_COUNT */ + +/* Define the Passive Observation Of Failures timer count, 10 seconds in spec. In tick. */ +#ifndef NX_MDNS_POOF_TIMER_COUNT +#define NX_MDNS_POOF_TIMER_COUNT (10 * NX_IP_PERIODIC_RATE) +#endif /* NX_MDNS_POOF_TIMER_COUNT */ + + +/* Define the RR delete delay timer. */ +/* Queriers receiving a Multicast DNS response with a TTL of zero SHOULD + NOT immediately delete the record from the cache, but instead record + a TTL of 1 and then delete the record one second later. In tick. */ +#ifndef NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT +#define NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT NX_IP_PERIODIC_RATE +#endif /* NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT */ + + +/* Define the default mDNS's announcing value. */ +#define NX_MDNS_ANNOUNCING_PERIOD NX_IP_PERIODIC_RATE +#define NX_MDNS_ANNOUNCING_COUNT 1 +#define NX_MDNS_ANNOUNCING_FACTOR 1 +#define NX_MDNS_ANNOUNCING_RETRANS_INTERVAL 0 +#define NX_MDNS_ANNOUNCING_PERIOD_INTERVAL 0xFFFFFFFF +#define NX_MDNS_ANNOUNCING_MAX_TIME 3 +#define NX_MDNS_ANNOUNCING_FOREVER 0xFF + + +/* Define the max ttl. In second. */ +#define NX_MDNS_RR_MAX_TTL 0xFFFFFFFF/NX_IP_PERIODIC_RATE + + +/* Define the RR update retransmit count. + The querier should plan to issure a query at 80%, 85%, 90%, 95% of the record lifetime. */ +#define NX_MDNS_RR_UPDATE_COUNT 4 + + +/* Define the Address length. */ +#define NX_MDNS_IPV4_ADDRESS_LENGTH 4 +#define NX_MDNS_IPV6_ADDRESS_LENGTH 16 + + +/* Define mDNS event flags. */ +#define NX_MDNS_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags. */ +#define NX_MDNS_PKT_RX_EVENT ((ULONG) 0x00000001) /* Receive the mDNS packet. */ +#define NX_MDNS_QUERY_SEND_EVENT ((ULONG) 0x00000002) /* Send the mDNS Query packet. */ +#define NX_MDNS_RESPONSE_SEND_EVENT ((ULONG) 0x00000004) /* Send the mDNS Response packet. */ +#define NX_MDNS_PROBING_SEND_EVENT ((ULONG) 0x00000008) /* Send the mDNS Probing packet. */ +#define NX_MDNS_ANNOUNCING_SEND_EVENT ((ULONG) 0x00000010) /* Send the mDNS Announcing packet. */ +#define NX_MDNS_GOODBYE_SEND_EVENT ((ULONG) 0x00000020) /* Send the mDNS Goodbye packet. */ +#define NX_MDNS_TIMER_EVENT ((ULONG) 0x00000040) /* Process the mDNS timer event. */ +#define NX_MDNS_ADDRESS_CHANGE_EVENT ((ULONG) 0x00000080) /* Process the mDNS address change event. */ +#define NX_MDNS_RR_ELAPSED_TIMER_EVENT ((ULONG) 0x00000100) /* Process the mDNS rr elapsed tiemr event. */ + + +/* Define return code constants. */ +#define NX_MDNS_SUCCESS 0x00 /* mDNS Success. */ +#define NX_MDNS_ERROR 0xA1 /* mDNS internal error. */ +#define NX_MDNS_PARAM_ERROR 0xA2 /* mDNS parameters error. */ +#define NX_MDNS_CACHE_ERROR 0xA3 /* The Cache size is not enough. */ +#define NX_MDNS_UNSUPPORTED_TYPE 0xA4 /* The unsupported resource record type. */ +#define NX_MDNS_DATA_SIZE_ERROR 0xA5 /* The data size is too big. */ +#define NX_MDNS_AUTH_ERROR 0xA6 /* Attempting to parse too large a data. */ +#define NX_MDNS_PACKET_ERROR 0xA7 /* The packet can not add the resource record. */ +#define NX_MDNS_DEST_ADDRESS_ERROR 0xA9 /* The destination address error. */ +#define NX_MDNS_UDP_PORT_ERROR 0xB0 /* The udp port error. */ +#define NX_MDNS_NOT_LOCAL_LINK 0xB1 /* The message that not originate from the local link. */ +#define NX_MDNS_EXCEED_MAX_LABEL 0xB2 /* The data exceed the max laber size. */ +#define NX_MDNS_EXIST_UNIQUE_RR 0xB3 /* At least one Unqiue record in the cache. */ +#define NX_MDNS_EXIST_SHARED_RR 0xB4 /* At least one shared record in the cache. */ +#define NX_MDNS_EXIST_SAME_QUERY 0xB5 /* Exist the same query record in the cache. */ +#define NX_MDNS_EXIST_SAME_SERVICE 0xB6 /* Exist the same service. */ +#define NX_MDNS_NO_RR 0xB7 /* No response for one-shot query. */ +#define NX_MDNS_NO_KNOWN_ANSWER 0xB8 /* No known answer for query. */ +#define NX_MDNS_NAME_MISMATCH 0xB9 /* The name mismatch. */ +#define NX_MDNS_NOT_STARTED 0xC0 /* mDNS does not start. */ +#define NX_MDNS_HOST_NAME_ERROR 0xC1 /* mDNS host name error. */ +#define NX_MDNS_NO_MORE_ENTRIES 0xC2 /* No more entries be found. */ +#define NX_MDNS_SERVICE_TYPE_MISMATCH 0xC3 /* The service type mismatch */ +#define NX_MDNS_NOT_ENABLED 0xC4 /* mDNS does not enable. */ +#define NX_MDNS_ALREADY_ENABLED 0xC5 /* mDNS already enabled. */ + + +/* Define the local host/service register notify state. */ +#define NX_MDNS_LOCAL_HOST_REGISTERED_SUCCESS 1 /* mDNS Server: Local host registered success. */ +#define NX_MDNS_LOCAL_HOST_REGISTERED_FAILURE 2 /* mDNS Server: Local host registered failure. */ +#define NX_MDNS_LOCAL_SERVICE_REGISTERED_SUCCESS 3 /* mDNS Server: Local service registered success. */ +#define NX_MDNS_LOCAL_SERVICE_REGISTERED_FAILURE 4 /* mDNS Server: Local service registered failure. */ + +/* Define the peer service change notify state. */ +#define NX_MDNS_PEER_SERVICE_RECEIVED 1 /* mDNS Client: Peer service received. */ +#define NX_MDNS_PEER_SERVICE_DELETED 2 /* mDNS Client: Peer service deleted. */ +#define NX_MDNS_PEER_SERVICE_UPDATED 3 /* mDNS Client: Peer service address updated. */ + +/* Define the cache notify state. */ +#define NX_MDNS_CACHE_STATE_FULL 1 /* mDNS Cache is full, and cannot fill the RR. */ +#define NX_MDNS_CACHE_STATE_FRAGMENTED 2 /* mDNS Cache is fragmented, and cannot fill the RR. */ + +/* Define cache type. */ +#define NX_MDNS_CACHE_TYPE_LOCAL 0 /* Local cache. */ +#define NX_MDNS_CACHE_TYPE_PEER 1 /* Peer cache. */ + + +/* Define offsets into the DNS message buffer. */ +#define NX_MDNS_ID_OFFSET 0 /* Offset to ID code in DNS buffer */ +#define NX_MDNS_FLAGS_OFFSET 2 /* Offset to flags in DNS buffer */ +#define NX_MDNS_QDCOUNT_OFFSET 4 /* Offset to Question Count in DNS buffer */ +#define NX_MDNS_ANCOUNT_OFFSET 6 /* Offset to Answer Count in DNS buffer */ +#define NX_MDNS_NSCOUNT_OFFSET 8 /* Offset to Authority Count in DNS buffer */ +#define NX_MDNS_ARCOUNT_OFFSET 10 /* Offset to Additional Info. Count in DNS buffer */ +#define NX_MDNS_QDSECT_OFFSET 12 /* Offset to Question Section in DNS buffer */ + + +/* Define constants for the flags word. */ +#define NX_MDNS_QUERY_MASK 0x0000 +#define NX_MDNS_QUERY_FLAG 0x0000 +#define NX_MDNS_RESPONSE_FLAG 0x8000 +#define NX_MDNS_ERROR_MASK 0x000F +#define NX_MDNS_TOP_BIT_MASK 0x7FFF + +#define NX_MDNS_OPCODE_QUERY (0 << 12) /* Shifted right 12 is still 0 */ +#define NX_MDNS_OPCODE_IQUERY (1 << 12) /* 1 shifted right by 12 */ +#define NX_MDNS_OPCODE_STATUS (2 << 12) /* 2 shifted right by 12 */ + +#define NX_MDNS_AA_FLAG 0x0400 /* Authoritative Answer */ +#define NX_MDNS_TC_FLAG 0x0200 /* Truncated */ +#define NX_MDNS_RD_FLAG 0x0100 /* Recursive Query */ +#define NX_MDNS_RA_FLAG 0x0080 /* Recursion Available */ +#define NX_MDNS_FA_FLAG 0x0010 /* Force Authentication */ + +/* Define name compression masks. */ +#define NX_MDNS_COMPRESS_MASK 0xc0 +#define NX_MDNS_COMPRESS_VALUE 0xc0 +#define NX_MDNS_POINTER_MASK 0xc000 + +/* Define resource record types. */ +#define NX_MDNS_RR_TYPE_A 1 /* Host address */ +#define NX_MDNS_RR_TYPE_NS 2 /* Authoritative name server */ +#define NX_MDNS_RR_TYPE_MD 3 /* Mail destination (Obsolete - use MX) */ +#define NX_MDNS_RR_TYPE_MF 4 /* Mail forwarder (Obsolete - use MX) */ +#define NX_MDNS_RR_TYPE_CNAME 5 /* Canonical name for an alias */ +#define NX_MDNS_RR_TYPE_SOA 6 /* Marks the start of a zone of authority */ +#define NX_MDNS_RR_TYPE_MB 7 /* Mailbox domain name (EXPERIMENTAL) */ +#define NX_MDNS_RR_TYPE_MG 8 /* Mail group member (EXPERIMENTAL) */ +#define NX_MDNS_RR_TYPE_MR 9 /* Mail rename domain name (EXPERIMENTAL) */ +#define NX_MDNS_RR_TYPE_NULL 10 /* Null RR (EXPERIMENTAL) */ +#define NX_MDNS_RR_TYPE_WKS 11 /* Well known service description */ +#define NX_MDNS_RR_TYPE_PTR 12 /* Domain name pointer */ +#define NX_MDNS_RR_TYPE_HINFO 13 /* Host information */ +#define NX_MDNS_RR_TYPE_MINFO 14 /* Mailbox or mail list information */ +#define NX_MDNS_RR_TYPE_MX 15 /* Mail exchange */ +#define NX_MDNS_RR_TYPE_TXT 16 /* Text strings */ +#define NX_MDNS_RR_TYPE_AAAA 28 /* IPv6 Host address */ +#define NX_MDNS_RR_TYPE_SRV 33 /* The location of services */ +#define NX_MDNS_RR_TYPE_NSEC 47 /* The type of NSEC RR. */ + + +/* Define constants for Qtypes (queries). */ +#define NX_MDNS_RR_TYPE_AXFR 252 /* Request for a transfer of an entire zone */ +#define NX_MDNS_RR_TYPE_MAILB 253 /* Request for mailbox-related records (MB, MG or MR) */ +#define NX_MDNS_RR_TYPE_MAILA 254 /* Request for mail agent RRs (Obsolete - see MX) */ +#define NX_MDNS_RR_TYPE_ALL 255 /* Request for all records */ + + +/* Define resource record classes. */ +#define NX_MDNS_RR_CLASS_IN 1 /* Internet */ +#define NX_MDNS_RR_CLASS_CS 2 /* CSNET class (Obsolete) */ +#define NX_MDNS_RR_CLASS_CH 3 /* CHAOS class */ +#define NX_MDNS_RR_CLASS_HS 4 /* Hesiod [Dyer 87] */ +#define NX_MDNS_RR_CLASS_ALL 255 /* Any class */ +#define NX_MDNS_RR_CLASS_TOP_BIT 0x8000 /* The top bit of class. */ + + +/* Define the resource record state value. */ +#define NX_MDNS_RR_STATE_INVALID 0 /* Invalid resource records. */ +#define NX_MDNS_RR_STATE_PROBING 1 /* mDNS Server probing the resource records. */ +#define NX_MDNS_RR_STATE_ANNOUNCING 2 /* mDNS Server announcing the resource records. */ +#define NX_MDNS_RR_STATE_GOODBYE 3 /* mDNS Server send the Goodbye. */ +#define NX_MDNS_RR_STATE_SUSPEND 4 /* mDNS Server suspend the resource record. */ +#define NX_MDNS_RR_STATE_QUERY 5 /* mDNS Client send the initial query. */ +#define NX_MDNS_RR_STATE_UPDATING 6 /* mDNS Client send the query to update the RR. */ +#define NX_MDNS_RR_STATE_DELETE 7 /* mDNS Client delete the resource records. */ +#define NX_MDNS_RR_STATE_POOF_DELETE 8 /* mDNS Client delete the resource records by Passive Observation Of Failures.*/ +#define NX_MDNS_RR_STATE_VALID 9 /* Valid resource records. */ + + +/* Define the sending type of resource records. */ +#define NX_MDNS_RR_SEND_FLAG_CLEAR 0x00 /* Response should not send the Resource records. */ +#define NX_MDNS_RR_SEND_MULTICAST 0x01 /* Send the Resource records via multicast. */ +#define NX_MDNS_RR_SEND_UNICAST 0x02 /* Send the Resource records via unicast. */ +#define NX_MDNS_RR_SEND_FLAG_MASK 0xF0 /* The mask of send flag. */ + + +/* Define resource record owner. */ +#define NX_MDNS_RR_OWNER_LOCAL 0 /* Local Resource records. */ +#define NX_MDNS_RR_OWNER_REMOTE 1 /* Remote Resource records. */ + + +/* Define resource record set. */ +#define NX_MDNS_RR_SET_SHARED 0 /* Shared Resource records. */ +#define NX_MDNS_RR_SET_UNIQUE 1 /* Unique Resource records. */ + + +/* Define the resource record state mask. */ +#define NX_MDNS_RR_FLAG_PEER 0x0001 /* RR owner flag. */ +#define NX_MDNS_RR_FLAG_UNIQUE 0x0002 /* RR set flag. */ +#define NX_MDNS_RR_FLAG_CONTINUOUS_QUERY 0x0004 /* RR query type flag. */ +#define NX_MDNS_RR_FLAG_DUPLICATE_QUERY 0x0008 /* RR duplicate query flag. */ +#define NX_MDNS_RR_FLAG_ADDITIONAL 0x0010 /* RR additional flag. */ +#define NX_MDNS_RR_FLAG_UPDATING 0x0020 /* RR updating flag. */ +#define NX_MDNS_RR_FLAG_DELETE 0x0040 /* RR delete flag. */ +#define NX_MDNS_RR_FLAG_ANSWER 0x0080 /* RR answer flag. */ +#define NX_MDNS_RR_FLAG_KNOWN_ANSWER 0x0100 /* RR known answer flag. */ +#define NX_MDNS_RR_FLAG_AUTHORIY_ANSWER 0x0200 /* RR authority answer flag. */ + + +/* Define the type to search the same resource record. */ +#define NX_MDNS_RR_MATCH_ALL 1 /* Match all data: name, type, class, rdata. */ +#define NX_MDNS_RR_MATCH_EXCEPT_RDATA 2 /* Match the name, type, class, except rdata. */ + + +/* Define the type to set/add the resource record in cache from packet. */ +#define NX_MDNS_RR_OP_LOCAL_SET_QUESTION 0 /* Set resource record question in local cache. */ +#define NX_MDNS_RR_OP_LOCAL_SET_ANSWER 1 /* Set resource record answer in local cache. */ +#define NX_MDNS_RR_OP_PEER_SET_QUESTION 2 /* Set resource record question in peer cache. */ +#define NX_MDNS_RR_OP_PEER_ADD_ANSWER 3 /* Add resource record answer in peer cache. */ + + +/* Define the type for adding question/answer RR into the packet. */ +#define NX_MDNS_PACKET_ADD_RR_QUESTION 1 /* Add the question resource record into packet. */ +#define NX_MDNS_PACKET_ADD_RR_ANSWER 2 /* Add the answer resource record into packet. */ + + +/* Define mDNS packet type. */ +#define NX_MDNS_PACKET_QUERY 1 /* Query packet. */ +#define NX_MDNS_PACKET_PROBING 2 /* Probing packet. Is specific query. */ +#define NX_MDNS_PACKET_RESPONSE 3 /* Response packet. */ + + +/* Define the Add NSEC type. */ +#define NX_MDNS_ADD_NSEC_FOR_HOST 0 /* Add the NSEC for host name. */ +#define NX_MDNS_ADD_NSEC_FOR_SERVICE 1 /* Add the NSEC for service. */ + + +/* Define the RDATA structure. */ + +/* A RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | ADDRESS | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_A_STRUCT +{ + ULONG nx_mdns_rr_a_address; +} NX_MDNS_RR_A; + + +/* NS RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / NSDNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_NS_STRUCT +{ + UCHAR* nx_mdns_rr_ns_name; +} NX_MDNS_RR_NS; + +/* MD RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MADNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MD_STRUCT +{ + UCHAR* nx_mdns_rr_md_name; +} NX_MDNS_RR_MD; + +/* MF RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MADNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MF_STRUCT +{ + UCHAR* nx_mdns_rr_mf_name; +} NX_MDNS_RR_MF; + +/* CNMAE RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / CNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_CNAME_STRUCT +{ + UCHAR* nx_mdns_rr_cname_name; +} NX_MDNS_RR_CNAME; + +/* SOA RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RNAME / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | SERIAL | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | REFRESH | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | RETRY | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | EXPIRE | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | MINMUM | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_SOA_STRUCT +{ + UCHAR* nx_mdns_rr_soa_mname; + UCHAR* nx_mdns_rr_soa_rname; + ULONG nx_mdns_rr_soa_serial; + ULONG nx_mdns_rr_soa_refresh; + ULONG nx_mdns_rr_soa_retry; + ULONG nx_mdns_rr_soa_expire; + ULONG nx_mdns_rr_soa_minmum; +} NX_MDNS_RR_SOA; + +/* MB RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MADNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MB_STRUCT +{ + UCHAR* nx_mdns_rr_mb_name; +} NX_MDNS_RR_MB; + +/* MG RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / MGMNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MG_STRUCT +{ + UCHAR* nx_mdns_rr_mg_name; +} NX_MDNS_RR_MG; + +/* MR RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / NEWNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MR_STRUCT +{ + UCHAR* nx_mdns_rr_mr_name; +} NX_MDNS_RR_MR; + +/* NULL RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_NULL_STRUCT +{ + UCHAR* nx_mdns_rr_null_ptr; +} NX_MDNS_RR_NULL; + +/* WKS RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | ADDRESS | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PROTOCOL | | + |--+--+--+--+--+--+--+--+ | + / / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_WKS_STRUCT +{ + ULONG nx_mdns_rr_wks_address; + UCHAR nx_mdns_rr_wks_protocol; + UCHAR nx_mdns_rr_wks_reserved[3]; + UCHAR* nx_mdns_rr_wks_bit_map; +} NX_MDNS_RR_WKS; + +/* PTR RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / PTRDNAME / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_PTR_STRUCT +{ + UCHAR* nx_mdns_rr_ptr_name; +} NX_MDNS_RR_PTR; + +/* HINFO RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / CPU / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / OS / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_HINFO_STRUCT +{ + UCHAR* nx_mdns_rr_hinfo_cpu; + UCHAR* nx_mdns_rr_hinfo_os; +} NX_MDNS_RR_HINFO; + +/* MINFO RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RMAILBX / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / EMAILBX / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MINFO_STRUCT +{ + UCHAR* nx_mdns_rr_minfo_cpu; + UCHAR* nx_mdns_rr_minfo_os; +} NX_MDNS_RR_MINFO; + +/* MX RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PREFERENCE | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / NEWNAME / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_MX_STRUCT +{ + UCHAR* nx_mdns_rr_mx_name; + USHORT nx_mdns_rr_mx_preference; + USHORT nx_mdns_rr_mx_reserved; +} NX_MDNS_RR_MX; + +/* TXT RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / TXT-DATA / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_TXT_STRUCT +{ + UCHAR* nx_mdns_rr_txt_data; +} NX_MDNS_RR_TXT; + +/* AAAA RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | | + | | + | | + | IPv6 ADDRESS | + | | + | | + | | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_AAAA_STRUCT +{ + ULONG nx_mdns_rr_aaaa_address[4]; +} NX_MDNS_RR_AAAA; + +/* SRV RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PRIORITY | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | WEIGHTS | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | PORT | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / TARGET / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_SRV_STRUCT +{ + UCHAR* nx_mdns_rr_srv_target; + USHORT nx_mdns_rr_srv_priority; + USHORT nx_mdns_rr_srv_weights; + USHORT nx_mdns_rr_srv_port; + USHORT nx_mdns_rr_srv_reserved; +} NX_MDNS_RR_SRV; + + +/* NSEC RDATA format + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / Next Domain Name / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / Type Bit Maps / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +typedef struct NX_MDNS_RR_NSEC_STRUCT +{ + UCHAR* nx_mdns_rr_nsec_next_domain; + UCHAR nx_mdns_rr_nsec_window_block; + UCHAR nx_mdns_rr_nsec_bitmap_length; + UCHAR nx_mdns_rr_nsec_bitmap[5]; /* Can match the max rr type 6 * 7 = 42. */ + UCHAR nx_mdns_rr_nsec_additional_send; /* 0 indicate answer, 1 indicate additional. */ +} NX_MDNS_RR_NSEC; + + +/* RR definitions. RFC1035. */ +/* RR Format. + 0 1 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | | + / NAME / + / / + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | TYPE | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | CLASS | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | TTL | + | | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + | RDLENGTH | + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| + / RDATA / + / / + |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| +*/ + +/* The following data structure is used to store the resource records(RRs). */ +typedef struct NX_MDNS_RR_STRUCT +{ + + UCHAR* nx_mdns_rr_name; /* Owner's name,i.e., the name of the node to + which this resource record pertains. */ + + USHORT nx_mdns_rr_type; /* RR TYPE. */ + + USHORT nx_mdns_rr_class; /* RR CLASS. */ + + ULONG nx_mdns_rr_ttl; /* The time interval that the RR may be cached before the source of + the information should again be consulted. */ + + UINT nx_mdns_rr_interface_index; /* RR interface index. */ + + USHORT nx_mdns_rr_rdata_length; /* The length of rdata. nx_mdns_rr_rdata */ + + UCHAR nx_mdns_rr_state; /* The resource records state, Probing, Annoncing, Valid. */ + + UCHAR nx_mdns_rr_retransmit_count; /* Define the count for the retransmit the RR. */ + + ULONG nx_mdns_rr_retransmit_lifetime; /* Define the lifetime for retransmit the RR. */ + + ULONG nx_mdns_rr_timer_count; /* Define the timer count for the retransmit the RR. */ + + ULONG nx_mdns_rr_elapsed_time; /* Define the time elasped for the peer RR. */ + + ULONG nx_mdns_rr_remaining_ticks; /* Define the remaining ticks of the peer RR. */ + + UCHAR nx_mdns_rr_announcing_max_time; /* RR announcing max time. Local RR. */ + + UCHAR nx_mdns_rr_response_interval; /* Define the time interval for two responses. Local RR. */ + + UCHAR nx_mdns_rr_conflict_count; /* The conflict count of service name or host name. Local RR. */ + + UCHAR nx_mdns_rr_poof_count; /* The Passive Observation Of Failures count of resource record. Peer RR.*/ + + UCHAR nx_mdns_rr_count; /* The count of same _services._dns-sd._udp.local PTR resource reocrd. */ + + UCHAR nx_mdns_rr_send_flag; /* The flag for seding resource record. */ + + USHORT nx_mdns_rr_word; + + /* Define the state, owner, flag, set of the resource records. This word contains + the following information: + + bits 0 RR Owner, the owner of resource record, + 0 indicates local RR, 1 indicates peer RR. + bits 1 RR Set, the set of resource record, + 0 indicates shared RR, 1 indicates unique RR. + bits 2 RR query type, the query type of resource record, + 0 indicates query the RR use One-shot method, 1 indicates query the RR use Continuous method. + bits 3 RR additional flag, send this resource record as the additional RR. + bits 4 RR query duplicate flag, this resource record is the duplicate quesiton. + bits 5 RR updating flag, this resource record need to be maintenance. + bits 6 RR delete flag, this resource record need to be deleted. + bits 7 RR answer flag, this resource record has been added in answer section. + bits 8 RR known answer flag, send this resource record as the known answer. + bits 9 RR authority answer flag, send this resource record as the authority answer. + */ + + /* Union that holds resource record data. */ + union nx_mdns_rr_rdata_union + { + NX_MDNS_RR_A nx_mdns_rr_rdata_a; + NX_MDNS_RR_AAAA nx_mdns_rr_rdata_aaaa; + NX_MDNS_RR_PTR nx_mdns_rr_rdata_ptr; + NX_MDNS_RR_SRV nx_mdns_rr_rdata_srv; + NX_MDNS_RR_TXT nx_mdns_rr_rdata_txt; + +#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES + NX_MDNS_RR_NSEC nx_mdns_rr_rdata_nsec; +#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ + +#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES + NX_MDNS_RR_CNAME nx_mdns_rr_rdata_cname; + NX_MDNS_RR_NS nx_mdns_rr_rdata_ns; + NX_MDNS_RR_MX nx_mdns_rr_rdata_mx; +#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ + } nx_mdns_rr_rdata; + +}NX_MDNS_RR; + +/* Buffer usage. */ +/* + + |-----------+-----------+-----------+-----------+-----------+------------+-----------+------------+------------| + | HEAD |NX_MDNS_RR |NX_MDNS_RR | ..........| STRING | CNT | LEN | STRING | CNT | LEN | TAIL | + |-----------+-----------+-----------+-----------+-----------+------------+-----------+------------+------------| + + HEAD: First unused memory at the front of cache. The size is 4 bytes. + NX_MDNS_RR: The Resource Record struct, the size is sizeof(NX_MDNS_RR). + TAIL: It points to the last used memory at the back of cache. Its size is 4 bytes. + LEN: It is the length of STRING, plus the CNT and LEN fields. This field takes 2 bytes. + CNT: It is the reference count of STRING. It takes 2 bytes. + STRING: The content of name string and rdata string, must be null-terminated. Padded with 0s to be 4 byte aligned. +*/ + + +/* Define the Service structure. */ +typedef struct NX_MDNS_SERVICE_STRUCT +{ + + UCHAR* service_name; /* Service instance. */ + + UCHAR* service_type; /* Service type. */ + + UCHAR* service_domain; /* Service domain. */ + + UCHAR service_text[NX_MDNS_NAME_MAX+1]; /* Service txt information. */ + + UCHAR service_host[NX_MDNS_HOST_NAME_MAX + 1]; /* The target host of the service. */ + + USHORT service_port; /* Service port. */ + + USHORT service_weight; /* Service weight. */ + + USHORT service_priority; /* Service priority. */ + + UCHAR interface_index; /* Service interface idnex. */ + + UCHAR service_text_valid; /* Flag indicating text fields are valid. */ + + ULONG service_ipv4; /* The IPv4 address for service. */ + + ULONG service_ipv6[NX_MDNS_IPV6_ADDRESS_COUNT][4]; /* The IPv6 address for service.*/ + + UCHAR buffer[NX_MDNS_NAME_MAX+1]; /* The buffer for service instance, type and domain.*/ + +} NX_MDNS_SERVICE; + + +/* Define the basic Multicast DNS data structure. */ + +typedef struct NX_MDNS_STRUCT +{ + ULONG nx_mdns_id; /* Multicast DNS ID. */ + + NX_IP* nx_mdns_ip_ptr; /* Pointer to associated IP structure. */ + + NX_UDP_SOCKET nx_mdns_socket; /* Multicast DNS Socket. */ + + TX_MUTEX nx_mdns_mutex; /* Multicast DNS Mutex. */ + + TX_TIMER nx_mdns_timer; /* Multicast DNS TIMER. */ + + TX_THREAD nx_mdns_thread; /* Multicast DNS processing thread. */ + + TX_EVENT_FLAGS_GROUP nx_mdns_events; /* Multicast DNS event. */ + + NX_PACKET_POOL* nx_mdns_packet_pool_ptr; /* Pointer to the packet pool. */ + + UCHAR nx_mdns_host_name[NX_MDNS_HOST_NAME_MAX]; /* The Embedded Device name supplied at create. */ + + UCHAR nx_mdns_domain_name[NX_MDNS_DOMAIN_NAME_MAX + 1]; /* The mDNS domain name. */ + + UINT nx_mdns_interface_enabled[NX_MAX_PHYSICAL_INTERFACES]; /* Interface enable status. */ + +#ifdef NX_MDNS_ENABLE_IPV6 + UINT nx_mdns_ipv6_address_index[NX_MAX_PHYSICAL_INTERFACES]; /* IPv6 link local address index. */ +#endif /* NX_MDNS_ENABLE_IPV6 */ + + /* Define the UDP receive suspension list head associated with a count of + how many threads are suspended attempting to receive from the same TCP port. */ + TX_THREAD* nx_mdns_rr_receive_suspension_list; /* The suspended thread. */ + + ULONG nx_mdns_rr_receive_suspended_count; /* The suspended count. */ + + UCHAR* nx_mdns_local_service_cache; /* Pointer to the cache. */ + + UINT nx_mdns_local_service_cache_size; /* The size of cache. */ + + UCHAR* nx_mdns_peer_service_cache; /* Pointer to the cache. */ + + UINT nx_mdns_peer_service_cache_size; /* The size of cache. */ + + ULONG nx_mdns_service_ignore_mask; /* The mask specifying services types to be ignored. */ + + ULONG nx_mdns_service_notify_mask; /* The service mask for listen the service and notify the applicaiton. */ + + ULONG nx_mdns_timer_min_count; /* The minimum timer count indicate the intervals between last timer event and next timer event. */ + + USHORT nx_mdns_announcing_period; /* Number of ticks for the initial period. Default value is 1 second. */ + + USHORT nx_mdns_announcing_retrans_interval; /* Number of ticks to wait ticks before sending out repeated announcement message. */ + + ULONG nx_mdns_announcing_period_interval; /* Number of ticks between two announcing period. */ + + UCHAR nx_mdns_announcing_count; /* Number of repetitions between one announcing period. Default value is 1. */ + + UCHAR nx_mdns_announcing_factor; /* Telescopic factor, default value is 0. 2^k. */ + + UCHAR nx_mdns_announcing_max_time; /* Max time of Announcing period, default value is 3. */ + + UCHAR nx_mdns_started; /* mDNS task has been started. */ + + ULONG nx_mdns_local_rr_count; /* The number of resource records in the local cache. */ + + ULONG nx_mdns_local_string_count; /* The number of strings in the local cache. */ + + ULONG nx_mdns_local_string_bytes; /* The number of total bytes in string table in the local cache. */ + + ULONG nx_mdns_peer_rr_count; /* The number of resource records in the peer cache. */ + + ULONG nx_mdns_peer_string_count; /* The number of strings in the peer cache. */ + + ULONG nx_mdns_peer_string_bytes; /* The number of total bytes in string table in the peer cache. */ + + ULONG nx_mdns_first_probing_delay; /* The delay of first probing for unique RR. */ + + VOID (*nx_mdns_probing_notify)(struct NX_MDNS_STRUCT *, UCHAR *, UINT); + + VOID (*nx_mdns_service_change_notify)(struct NX_MDNS_STRUCT *, struct NX_MDNS_SERVICE_STRUCT *, UINT); + + VOID (*nx_mdns_cache_full_notify)(struct NX_MDNS_STRUCT *, UINT, UINT); + +} NX_MDNS; + + +#ifndef NX_MDNS_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map mDNS API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_mdns_create _nx_mdns_create +#define nx_mdns_delete _nx_mdns_delete +#define nx_mdns_enable _nx_mdns_enable +#define nx_mdns_disable _nx_mdns_disable +#define nx_mdns_cache_notify_set _nx_mdns_cache_notify_set +#define nx_mdns_cache_notify_clear _nx_mdns_cache_notify_clear +#define nx_mdns_domain_name_set _nx_mdns_domain_name_set + +#ifndef NX_MDNS_DISABLE_SERVER +#define nx_mdns_service_announcement_timing_set _nx_mdns_service_announcement_timing_set +#define nx_mdns_service_add _nx_mdns_service_add +#define nx_mdns_service_delete _nx_mdns_service_delete +#define nx_mdns_local_cache_clear _nx_mdns_local_cache_clear +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT +#define nx_mdns_service_one_shot_query _nx_mdns_service_one_shot_query +#define nx_mdns_service_continuous_query _nx_mdns_service_continuous_query +#define nx_mdns_service_query_stop _nx_mdns_service_query_stop +#define nx_mdns_service_lookup _nx_mdns_service_lookup +#define nx_mdns_service_ignore_set _nx_mdns_service_ignore_set +#define nx_mdns_service_notify_set _nx_mdns_service_notify_set +#define nx_mdns_service_notify_clear _nx_mdns_service_notify_clear +#define nx_mdns_host_address_get _nx_mdns_host_address_get +#define nx_mdns_peer_cache_clear _nx_mdns_peer_cache_clear +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#else + +#define nx_mdns_create _nxe_mdns_create +#define nx_mdns_delete _nxe_mdns_delete +#define nx_mdns_enable _nxe_mdns_enable +#define nx_mdns_disable _nxe_mdns_disable +#define nx_mdns_cache_notify_set _nxe_mdns_cache_notify_set +#define nx_mdns_cache_notify_clear _nxe_mdns_cache_notify_clear +#define nx_mdns_domain_name_set _nxe_mdns_domain_name_set + +#ifndef NX_MDNS_DISABLE_SERVER +#define nx_mdns_service_announcement_timing_set _nxe_mdns_service_announcement_timing_set +#define nx_mdns_service_add _nxe_mdns_service_add +#define nx_mdns_service_delete _nxe_mdns_service_delete +#define nx_mdns_local_cache_clear _nxe_mdns_local_cache_clear +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT +#define nx_mdns_service_one_shot_query _nxe_mdns_service_one_shot_query +#define nx_mdns_service_continuous_query _nxe_mdns_service_continuous_query +#define nx_mdns_service_query_stop _nxe_mdns_service_query_stop +#define nx_mdns_service_lookup _nxe_mdns_service_lookup +#define nx_mdns_service_ignore_set _nxe_mdns_service_ignore_set +#define nx_mdns_service_notify_set _nxe_mdns_service_notify_set +#define nx_mdns_service_notify_clear _nxe_mdns_service_notify_clear +#define nx_mdns_host_address_get _nxe_mdns_host_address_get +#define nx_mdns_peer_cache_clear _nxe_mdns_peer_cache_clear +#endif /* NX_MDNS_DISABLE_CLIENT */ + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +#endif /* NX_MDNS_SOURCE_CODE */ + + +/* Define Thread function prototypes. */ +UINT _nx_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, + UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, + VOID *local_cache_ptr, UINT local_cache_size, + VOID *peer_cache_ptr, UINT peer_cache_size, + VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)); +UINT _nxe_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, + UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, + VOID *local_cache_ptr, UINT local_cache_size, + VOID *peer_cache_ptr, UINT peer_cache_size, + VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)); +UINT _nx_mdns_delete(NX_MDNS *mdns_ptr); +UINT _nxe_mdns_delete(NX_MDNS *mdns_ptr); +UINT _nx_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index); +UINT _nxe_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index); +UINT _nx_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index); +UINT _nxe_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index); +UINT _nx_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT state, UINT cache_type)); +UINT _nxe_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT state, UINT cache_type)); +UINT _nx_mdns_cache_notify_clear(NX_MDNS *mdns_ptr); +UINT _nxe_mdns_cache_notify_clear(NX_MDNS *mdns_ptr); +UINT _nx_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name); +UINT _nxe_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name); + +#ifndef NX_MDNS_DISABLE_SERVER +UINT _nx_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time); +UINT _nxe_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time); +UINT _nx_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, + USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index); +UINT _nxe_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, + USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index); +UINT _nx_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nxe_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nx_mdns_local_cache_clear(NX_MDNS *mdns_ptr); +UINT _nxe_mdns_local_cache_clear(NX_MDNS *mdns_ptr); +#endif /* NX_MDNS_DISABLE_SERVER */ + +#ifndef NX_MDNS_DISABLE_CLIENT +UINT _nx_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout); +UINT _nxe_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout); +UINT _nx_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nxe_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nx_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nxe_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); +UINT _nx_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service); +UINT _nxe_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service); +UINT _nx_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask); +UINT _nxe_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask); +UINT _nx_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, + VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)); +UINT _nxe_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, + VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)); +UINT _nx_mdns_service_notify_clear(NX_MDNS *mdns_ptr); +UINT _nxe_mdns_service_notify_clear(NX_MDNS *mdns_ptr); +UINT _nx_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout); +UINT _nxe_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout); +UINT _nx_mdns_peer_cache_clear(NX_MDNS *mdns_ptr); +UINT _nxe_mdns_peer_cache_clear(NX_MDNS *mdns_ptr); +#endif /* NX_MDNS_DISABLE_CLIENT */ + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_MDNS_H */ + diff --git a/addons/mqtt/nxd_mqtt_client.c b/addons/mqtt/nxd_mqtt_client.c new file mode 100644 index 00000000..64b9349d --- /dev/null +++ b/addons/mqtt/nxd_mqtt_client.c @@ -0,0 +1,5964 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** MQTT (MQTT) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NXD_MQTT_CLIENT_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_mqtt_client.h" + +/* Bring in externals for caller checking code. */ + +#define MQTT_ALL_EVENTS ((ULONG)0xFFFFFFFF) +#define MQTT_TIMEOUT_EVENT ((ULONG)0x00000001) +#define MQTT_PACKET_RECEIVE_EVENT ((ULONG)0x00000002) +#define MQTT_START_EVENT ((ULONG)0x00000004) +#define MQTT_DELETE_EVENT ((ULONG)0x00000008) +#define MQTT_PING_TIMEOUT_EVENT ((ULONG)0x00000010) +#define MQTT_NETWORK_DISCONNECT_EVENT ((ULONG)0x00000020) +#define MQTT_TCP_ESTABLISH_EVENT ((ULONG)0x00000040) + +static UINT _nxd_mqtt_client_create_internal(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, + CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority); +static UINT _nxd_mqtt_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr); +static UINT _nxd_mqtt_copy_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + USHORT packet_id, UCHAR set_duplicate_flag, UINT wait_option); +static VOID _nxd_mqtt_release_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr); +static VOID _nxd_mqtt_release_receive_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr); +static UINT _nxd_mqtt_client_retransmit_message(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); +static UINT _nxd_mqtt_client_connect_packet_send(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_set_fixed_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes the fixed header filed in the outgoing */ +/* MQTT packet. */ +/* */ +/* This function follows the logic outlined in 2.2 in MQTT */ +/* specification. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Outgoing MQTT packet */ +/* control_header Control byte */ +/* length Remaining length in bytes */ +/* wait_option Wait option */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_sub_unsub */ +/* _nxd_mqtt_client_connect */ +/* _nxd_mqtt_client_publish */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, UCHAR control_header, UINT length, UINT wait_option) +{ +UCHAR fixed_header[5]; +UCHAR *byte = fixed_header; +UINT count = 0; +UINT ret; + + *byte = control_header; + byte++; + + do + { + if (length & 0xFFFFFF80) + { + *(byte + count) = (UCHAR)((length & 0x7F) | 0x80); + } + else + { + *(byte + count) = length & 0x7F; + } + length = length >> 7; + + count++; + } while (length != 0); + + ret = nx_packet_data_append(packet_ptr, fixed_header, count + 1, + client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + + return(ret); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_read_remaining_length PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the remaining length filed in the incoming */ +/* MQTT packet. */ +/* */ +/* This function follows the logic outlined in 2.2.3 in MQTT */ +/* specification */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Incoming MQTT packet. */ +/* remaining_length remaining length in bytes, */ +/* this is the return value. */ +/* offset Pointer to offset of the */ +/* remaining data */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_process_publish */ +/* _nxd_mqtt_client_message_get */ +/* _nxd_mqtt_process_sub_unsub_ack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_read_remaining_length(NX_PACKET *packet_ptr, UINT *remaining_length, ULONG *offset_ptr) +{ +UINT value = 0; +UCHAR bytes[4] = {0}; +UINT multiplier = 1; +UINT byte_count = 0; +ULONG bytes_copied; + + if (nx_packet_data_extract_offset(packet_ptr, 1, &bytes, sizeof(bytes), &bytes_copied)) + { + + /* Packet is incomplete. */ + return(NXD_MQTT_PARTIAL_PACKET); + } + + do + { + if (byte_count >= bytes_copied) + { + if (byte_count == 4) + { + return(NXD_MQTT_INTERNAL_ERROR); + } + else + { + + /* Packet is incomplete. */ + return(NXD_MQTT_PARTIAL_PACKET); + } + } + value += (((bytes[byte_count]) & 0x7F) * multiplier); + multiplier = multiplier << 7; + } while ((bytes[byte_count++]) & 0x80); + + if ((1 + byte_count + value) > packet_ptr -> nx_packet_length) + { + + /* Packet is incomplete. */ + /* Remaining length is larger than packet size. */ + return(NXD_MQTT_PARTIAL_PACKET); + } + + *remaining_length = value; + *offset_ptr = (1 + byte_count); + + return(NXD_MQTT_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_sub_unsub PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a subscribe or unsubscribe message to the */ +/* broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* op Subscribe or Unsubscribe */ +/* topic_name Pointer to the topic string */ +/* to subscribe to */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* QoS Expected QoS level */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* _nxd_mqtt_packet_allocate */ +/* _nxd_mqtt_client_set_fixed_header */ +/* _nxd_mqtt_client_append_message */ +/* tx_mutex_put */ +/* nx_tcp_socket_send */ +/* nx_secure_tls_session_send */ +/* nx_packet_release */ +/* _nxd_mqtt_copy_transmit_packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_subscribe */ +/* _nxd_mqtt_client_unsubscribe */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_sub_unsub(NXD_MQTT_CLIENT *client_ptr, UINT op, + CHAR *topic_name, UINT topic_name_length, UINT QoS) +{ + + +NX_PACKET *packet_ptr; +NX_PACKET *transmit_packet_ptr; +UINT status; +UINT length = 0; +UINT ret = NXD_MQTT_SUCCESS; +UCHAR temp_data[2]; + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + + /* Do nothing if the client is already connected. */ + if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED) + { + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_NOT_CONNECTED); + } + + status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); + if (status) + { + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(status); + } + + /* Compute the remaining length field, starting with 2 bytes of packet ID */ + length = 2; + + /* Count the topic. */ + length += (2 + topic_name_length); + + if (op == ((MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02)) + { + /* Count one byte for QoS */ + length++; + } + + /* Write out the control header and remaining length field. */ + ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, (UCHAR )op, length, NX_WAIT_FOREVER); + + if (ret) + { + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + temp_data[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8); + temp_data[1] = (client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF); + + /* Append packet ID. */ + ret = nx_packet_data_append(packet_ptr, temp_data, 2, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_WAIT_FOREVER); + + if (ret) + { + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Append topic name */ + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, topic_name, topic_name_length, NX_WAIT_FOREVER); + + if (ret) + { + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + if (op == ((MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02)) + { + /* Fill in QoS value. */ + temp_data[0] = QoS & 0x3; + + ret = nx_packet_data_append(packet_ptr, temp_data, 1, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_WAIT_FOREVER); + + if (ret) + { + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + } + + /* Copy packet for retransmission. */ + if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, + (USHORT)(client_ptr -> nxd_mqtt_client_packet_identifier), + NX_FALSE, NX_WAIT_FOREVER)) + { + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + if (client_ptr -> message_transmit_queue_head == NX_NULL) + { + client_ptr -> message_transmit_queue_head = transmit_packet_ptr; + } + else + { + client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; + } + client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; + + client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF; + + /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ + if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) + client_ptr -> nxd_mqtt_client_packet_identifier = 1; + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Ready to send the connect message to the server. */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); + } +#else + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); +#endif /* NX_SECURE_ENABLE */ + + + if (status) + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + + ret = NXD_MQTT_COMMUNICATION_FAILURE; + } + + return(ret); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a packet for transmitting MQTT message. */ +/* Special care has to be taken for accommodating IPv4/IPv6 header, */ +/* and possibly TLS record if TLS is being used. On failure, the */ +/* TLS mutex is released and the caller can simply return. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Allocated packet to be */ +/* returned to the caller. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_packet_allocate Allocate packet for MQTT */ +/* over TLS socket */ +/* nx_packet_allocate Allocate a packet for MQTT */ +/* over regular TCP socket */ +/* tx_mutex_put Release a mutex */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_process_publish */ +/* _nxd_mqtt_client_connect */ +/* _nxd_mqtt_client_publish */ +/* _nxd_mqtt_client_subscribe */ +/* _nxd_mqtt_client_unsubscribe */ +/* _nxd_mqtt_client_send_simple_message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr) +{ +UINT status = NXD_MQTT_SUCCESS; + +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + /* Use TLS packet allocate. The TLS packet allocate is able to count for + TLS-related header space including crypto initial vector area. */ + status = nx_secure_tls_packet_allocate(&client_ptr -> nxd_mqtt_tls_session, client_ptr -> nxd_mqtt_client_packet_pool_ptr, + packet_ptr, TX_WAIT_FOREVER); + } + /* Allocate a packet */ + else + { +#endif + if (client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(client_ptr -> nxd_mqtt_client_packet_pool_ptr, packet_ptr, NX_IPv4_TCP_PACKET, + TX_WAIT_FOREVER); + } + else + { + status = nx_packet_allocate(client_ptr -> nxd_mqtt_client_packet_pool_ptr, packet_ptr, NX_IPv6_TCP_PACKET, + TX_WAIT_FOREVER); + } +#ifdef NX_SECURE_ENABLE + } +#endif + + if (status != NX_SUCCESS) + { + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + return(NXD_MQTT_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_tcp_establish_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is installed as TCP connection establish */ +/* callback function. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr The socket that receives */ +/* the message. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_thread_entry */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr) +{ +NXD_MQTT_CLIENT *client_ptr; + + client_ptr = (NXD_MQTT_CLIENT *)socket_ptr -> nx_tcp_socket_reserved_ptr; + + if (&(client_ptr -> nxd_mqtt_client_socket) == socket_ptr) + { + + /* Set the event flag. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_TCP_ESTABLISH_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_TCP_ESTABLISH_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_receive_callback PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is installed as TCP receive callback */ +/* function. On receiving a TCP message, the callback function */ +/* sets an event flag to trigger MQTT client to process received */ +/* message. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr The socket that receives */ +/* the message. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_thread_entry */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_receive_callback(NX_TCP_SOCKET *socket_ptr) +{ +NXD_MQTT_CLIENT *client_ptr; + + client_ptr = (NXD_MQTT_CLIENT *)socket_ptr -> nx_tcp_socket_reserved_ptr; + + if (&(client_ptr -> nxd_mqtt_client_socket) == socket_ptr) + { + /* Set the event flag. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_PACKET_RECEIVE_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PACKET_RECEIVE_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_copy_transmit_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function saves a transmit packet. */ +/* A transmit packet is allocated to store QoS 1 and 2 messages. */ +/* Upon a message being properly acknowledged, the packet will */ +/* be released. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the MQTT message */ +/* packet to be saved */ +/* new_packet_ptr Return a copied packet */ +/* packet_id Current packet ID */ +/* set_duplicate_flag Set duplicate flag for fixed */ +/* header or not */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_sub_unsub */ +/* _nxd_mqtt_process_publish */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_copy_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + USHORT packet_id, UCHAR set_duplicate_flag, UINT wait_option) +{ +UINT status; + + /* Copy current packet. */ + status = nx_packet_copy(packet_ptr, new_packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + if (status) + { + + /* No available packet to be stored. */ + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Save packet_id at the beginning of packet. */ + *((USHORT *)(*new_packet_ptr) -> nx_packet_data_start) = packet_id; + + if (set_duplicate_flag) + { + + /* Update duplicate flag in fixed header. */ + *((*new_packet_ptr) -> nx_packet_prepend_ptr) = (*((*new_packet_ptr) -> nx_packet_prepend_ptr)) | MQTT_PUBLISH_DUP_FLAG; + } + + return(NXD_MQTT_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_release_transmit_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function releases a transmit packet. */ +/* A transmit packet is allocated to store QoS 1 and 2 messages. */ +/* Upon a message being properly acknowledged, the packet can */ +/* be released. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the MQTT message */ +/* packet to be removed */ +/* previous_packet_ptr Pointer to the previous packet*/ +/* or NULL if none exists */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_thread_entry */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_release_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr) +{ + + if (previous_packet_ptr) + { + previous_packet_ptr -> nx_packet_queue_next = packet_ptr -> nx_packet_queue_next; + } + else + { + client_ptr -> message_transmit_queue_head = packet_ptr -> nx_packet_queue_next; + } + + if (packet_ptr == client_ptr -> message_transmit_queue_tail) + { + client_ptr -> message_transmit_queue_tail = previous_packet_ptr; + } + nx_packet_release(packet_ptr); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_release_receive_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function releases a receive packet. */ +/* A receive packet is allocated to store QoS 1 and 2 messages. */ +/* Upon a message being properly acknowledged, the packet can */ +/* be released. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the MQTT message */ +/* packet to be removed */ +/* previous_packet_ptr Pointer to the previous packet*/ +/* or NULL if none exists */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_thread_entry */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_release_receive_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr) +{ + + if (previous_packet_ptr) + { + previous_packet_ptr -> nx_packet_queue_next = packet_ptr -> nx_packet_queue_next; + } + else + { + client_ptr -> message_receive_queue_head = packet_ptr -> nx_packet_queue_next; + } + + if (packet_ptr == client_ptr -> message_receive_queue_tail) + { + client_ptr -> message_receive_queue_tail = previous_packet_ptr; + } + + client_ptr -> message_receive_queue_depth--; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_connack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function processes a CONNACK message from the broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* [nxd_mqtt_connect_notify] User supplied connect */ +/* callback function */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* _nxd_mqtt_client_retransmit_message */ +/* _nxd_mqtt_client_connection_end */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_process_connack(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT ret = NXD_MQTT_COMMUNICATION_FAILURE; +MQTT_PACKET_CONNACK *connack_packet_ptr = (MQTT_PACKET_CONNACK *)(packet_ptr -> nx_packet_prepend_ptr); + + + /* Check the length. */ + if ((packet_ptr -> nx_packet_length != sizeof(MQTT_PACKET_CONNACK)) || + (connack_packet_ptr -> mqtt_connack_packet_header >> 4 != MQTT_CONTROL_PACKET_TYPE_CONNACK)) + { + /* Invalid packet length. Free the packet and process error. */ + ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; + } + else + { + + /* Check remaining length. */ + if (connack_packet_ptr -> mqtt_connack_packet_remaining_length != 2) + { + ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; + } + /* Follow MQTT-3.2.2-1 rule. */ + else if ((client_ptr -> nxd_mqtt_clean_session) && (connack_packet_ptr -> mqtt_connack_packet_ack_flags & MQTT_CONNACK_CONNECT_FLAGS_SP)) + { + + /* Client requested clean session, and server responded with Session Present. This is a violation. */ + ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; + } + else if (connack_packet_ptr -> mqtt_connack_packet_return_code > MQTT_CONNACK_CONNECT_RETURN_CODE_NOT_AUTHORIZED) + { + ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; + } + else if (connack_packet_ptr -> mqtt_connack_packet_return_code > 0) + { + + /* Pass the server return code to the application. */ + ret = (UINT)(NXD_MQTT_ERROR_CONNECT_RETURN_CODE + connack_packet_ptr -> mqtt_connack_packet_return_code); + } + else + { + ret = NXD_MQTT_SUCCESS; + + /* Obtain mutex before we modify client control block. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED; + + /* Initialize the packet identification field. */ + client_ptr -> nxd_mqtt_client_packet_identifier = NXD_MQTT_INITIAL_PACKET_ID_VALUE; + + /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ + if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) + client_ptr -> nxd_mqtt_client_packet_identifier = 1; + + /* Release mutex */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + } + } + + /* Check callback function. */ + if (client_ptr -> nxd_mqtt_connect_notify) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, ret, client_ptr -> nxd_mqtt_connect_context); + } + + if (ret == NXD_MQTT_SUCCESS) + { + + /* If client doesn't start with Clean Session, and there are un-acked PUBLISH messages, + we shall re-publish these messages. */ + if ((client_ptr -> nxd_mqtt_clean_session != NX_TRUE) && (client_ptr -> message_transmit_queue_head)) + { + + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + /* There are messages from the previous session that has not been acknowledged. */ + ret = _nxd_mqtt_client_retransmit_message(client_ptr, wait_option); + + /* Release mutex */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + } + } + else + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + } + + return(ret); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_publish_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function processes a packet and parses topic and */ +/* message. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to the packet */ +/* topic_offset_ptr Return topic offset */ +/* topic_length_ptr Return topic length */ +/* message_offset_ptr Return message offset */ +/* message_length_ptr Return message length */ +/* */ +/* OUTPUT */ +/* */ +/* Status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_read_remaining_length */ +/* nx_packet_data_extract_offset */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_process_publish */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_process_publish_packet(NX_PACKET *packet_ptr, ULONG *topic_offset_ptr, USHORT *topic_length_ptr, + ULONG *message_offset_ptr, ULONG *message_length_ptr) +{ +UCHAR QoS; +UINT remaining_length = 0; +UINT topic_length; +ULONG offset; +UCHAR bytes[2]; +ULONG bytes_copied; + + + QoS = (UCHAR)((*(packet_ptr -> nx_packet_prepend_ptr) & MQTT_PUBLISH_QOS_LEVEL_FIELD) >> 1); + + if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) + { + return(NXD_MQTT_INVALID_PACKET); + } + + if (remaining_length < 2) + { + return(NXD_MQTT_INVALID_PACKET); + } + + /* Get topic length fields. */ + if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || + (bytes_copied != sizeof(bytes))) + { + return(NXD_MQTT_INVALID_PACKET); + } + + topic_length = (UINT)(*(bytes) << 8) | (*(bytes + 1)); + + if (topic_length > remaining_length - 2u) + { + return(NXD_MQTT_INVALID_PACKET); + } + + *topic_offset_ptr = offset + 2; + *topic_length_ptr = (USHORT)topic_length; + + remaining_length = remaining_length - topic_length - 2; + if ((QoS == 1) || (QoS == 2)) + { + offset += 2 + 2 + topic_length; + + if (remaining_length < 2) + { + return(NXD_MQTT_INVALID_PACKET); + } + remaining_length = remaining_length - 2; + } + else + { + offset += 2 + topic_length; + } + + *message_offset_ptr = offset; + *message_length_ptr = (ULONG)remaining_length; + + /* Return */ + return(NXD_MQTT_SUCCESS); +} +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_publish PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process a publish message from the broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE - packet is consumed */ +/* NX_FALSE - packet is not consumed */ +/* */ +/* CALLS */ +/* */ +/* [receive_notify] User supplied receive */ +/* callback function */ +/* _nxd_mqtt_packet_allocate */ +/* nx_tcp_socket_send */ +/* nx_packet_release */ +/* nx_secure_tls_session_send */ +/* _nxd_mqtt_process_publish_packet */ +/* _nxd_mqtt_copy_transmit_packet */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_process_publish(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ +MQTT_PACKET_PUBLISH_RESPONSE *pubresp_ptr; +UINT status; +USHORT packet_id = 0; +UCHAR QoS; +UINT enqueue_message = 0; +NX_PACKET *transmit_packet_ptr; +UINT remaining_length = 0; +UINT packet_consumed = NX_FALSE; +UCHAR fixed_header; +USHORT transmit_packet_id; +UINT topic_length; +ULONG offset; +UCHAR bytes[2]; +ULONG bytes_copied; + + QoS = (UCHAR)((*(packet_ptr -> nx_packet_prepend_ptr) & MQTT_PUBLISH_QOS_LEVEL_FIELD) >> 1); + + if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) + { + return(NX_FALSE); + } + + if (remaining_length < 2) + { + return(NXD_MQTT_INVALID_PACKET); + } + + /* Get topic length fields. */ + if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || + (bytes_copied != sizeof(bytes))) + { + return(NXD_MQTT_INVALID_PACKET); + } + + topic_length = (UINT)(*(bytes) << 8) | (*(bytes + 1)); + + if (topic_length > remaining_length - 2u) + { + return(NXD_MQTT_INVALID_PACKET); + } + + if (QoS == 0) + { + enqueue_message = 1; + } + else + { + /* QoS 1 or QoS 2 messages. */ + /* Get packet id fields. */ + if (nx_packet_data_extract_offset(packet_ptr, offset + 2 + topic_length, &bytes, sizeof(bytes), &bytes_copied)) + { + return(NXD_MQTT_INVALID_PACKET); + } + + packet_id = (USHORT)(((*bytes) << 8) | (*(bytes + 1))); + + /* Look for an existing transmit packets with the same packet id */ + transmit_packet_ptr = client_ptr -> message_transmit_queue_head; + + while (transmit_packet_ptr) + { + fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); + transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); + if ((transmit_packet_id == packet_id) && + ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_PUBREC << 4))) + { + + /* Found a packet containing the packet_id */ + break; + } + transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; + } + + if (transmit_packet_ptr) + { + /* This published data is already in our system. No need to deliver this message to the application. */ + enqueue_message = 0; + } + else + { + enqueue_message = 1; + } + } + + if (enqueue_message) + { + if (packet_ptr -> nx_packet_length > (offset + remaining_length)) + { + + /* This packet contains multiple messages. */ + if (nx_packet_copy(packet_ptr, &packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_NO_WAIT)) + { + + /* No packet is available. */ + return(NX_FALSE); + } + } + else + { + packet_consumed = NX_TRUE; + } + + /* Increment the queue depth counter. */ + client_ptr -> message_receive_queue_depth++; + + if (client_ptr -> message_receive_queue_head == NX_NULL) + { + client_ptr -> message_receive_queue_head = packet_ptr; + } + else + { + client_ptr -> message_receive_queue_tail -> nx_packet_queue_next = packet_ptr; + } + client_ptr -> message_receive_queue_tail = packet_ptr; + + /* Invoke the user-defined receive notify function if it is set. */ + if (client_ptr -> nxd_mqtt_client_receive_notify) + { + (*(client_ptr -> nxd_mqtt_client_receive_notify))(client_ptr, client_ptr -> message_receive_queue_depth); + } + } + + /* If the message QoS level is 0, we are done. */ + if (QoS == 0) + { + /* Return */ + return(packet_consumed); + } + + /* Send out proper ACKs for QoS 1 and 2 messages. */ + /* Allocate a new packet so we can send out a response. */ + status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); + if (status) + { + /* Packet allocation fails. */ + return(packet_consumed); + } + + /* Fill in the packet ID */ + pubresp_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)(packet_ptr -> nx_packet_prepend_ptr); + pubresp_ptr -> mqtt_publish_response_packet_remaining_length = 2; + pubresp_ptr -> mqtt_publish_response_packet_packet_identifier_msb = (UCHAR)(packet_id >> 8); + pubresp_ptr -> mqtt_publish_response_packet_packet_identifier_lsb = (UCHAR)(packet_id & 0xFF); + + if (QoS == 1) + { + + pubresp_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBACK << 4; + } + else + { + pubresp_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBREC << 4; + } + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(MQTT_PACKET_PUBLISH_RESPONSE); + packet_ptr -> nx_packet_length = sizeof(MQTT_PACKET_PUBLISH_RESPONSE); + + if (QoS == 2) + { + + /* Copy packet for checking duplicate publish packet. */ + if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, + packet_id, NX_FALSE, NX_WAIT_FOREVER)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(packet_consumed); + } + if (client_ptr -> message_transmit_queue_head == NX_NULL) + { + client_ptr -> message_transmit_queue_head = transmit_packet_ptr; + } + else + { + client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; + } + client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; + } + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); + } +#else + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); + +#endif /* NX_SECURE_ENABLE */ + + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + else + { + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + } + + /* Return */ + return(packet_consumed); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_publish_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process a publish response messages. */ +/* Publish Response messages are: PUBACK, PUBREC, PUBREL */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* Status */ +/* */ +/* CALLS */ +/* */ +/* [nxd_mqtt_client_receive_notify] User supplied publish */ +/* callback function */ +/* _nxd_mqtt_release_transmit_packet */ +/* nx_tcp_socket_send */ +/* nx_secure_tls_session_send */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_process_publish_response(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ +MQTT_PACKET_PUBLISH_RESPONSE *response_ptr; +USHORT packet_id; +NX_PACKET *previous_packet_ptr; +NX_PACKET *transmit_packet_ptr; +NX_PACKET *response_packet; +UINT ret; +UCHAR fixed_header; +USHORT transmit_packet_id; + + response_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Validate the packet. */ + if (response_ptr -> mqtt_publish_response_packet_remaining_length != 2) + { + /* Invalid remaining_length value. Return 1 so the caller can release + the packet. */ + + return(1); + } + + packet_id = (USHORT)((response_ptr -> mqtt_publish_response_packet_packet_identifier_msb << 8) | + (response_ptr -> mqtt_publish_response_packet_packet_identifier_lsb)); + + /* Search all the outstanding transmitted packets for a match. */ + previous_packet_ptr = NX_NULL; + transmit_packet_ptr = client_ptr -> message_transmit_queue_head; + while (transmit_packet_ptr) + { + fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); + transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); + if (transmit_packet_id == packet_id) + { + + /* Found the matching packet id */ + if (((response_ptr -> mqtt_publish_response_packet_header) >> 4) == MQTT_CONTROL_PACKET_TYPE_PUBACK) + { + + /* PUBACK is the response to a PUBLISH packet with QoS Level 1*/ + /* Therefore we verify that packet contains PUBLISH packet with QoS level 1*/ + if ((fixed_header & 0xF6) == ((MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4) | MQTT_PUBLISH_QOS_LEVEL_1)) + { + /* QoS Level1 message receives an ACK. */ + /* This message can be released. */ + _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); + + /* Return with value 1, so the caller will release packet_ptr */ + return(1); + } + } + else if (((response_ptr -> mqtt_publish_response_packet_header) >> 4) == MQTT_CONTROL_PACKET_TYPE_PUBREL) + { + + /* QoS 2 publish Release received, part 2. */ + /* Therefore we verify that packet contains PUBLISH packet with QoS level 2*/ + if ((fixed_header & 0xF6) == (MQTT_CONTROL_PACKET_TYPE_PUBREC << 4)) + { + + /* QoS Level2 message receives an ACK. */ + /* This message can be released. */ + /* Send PUBCOMP */ + + /* Allocate a packet to send the response. */ + ret = _nxd_mqtt_packet_allocate(client_ptr, &response_packet); + if (ret) + { + return(1); + } + + if (4u > ((ULONG)(response_packet -> nx_packet_data_end) - (ULONG)(response_packet -> nx_packet_append_ptr))) + { + nx_packet_release(response_packet); + + /* Packet buffer is too small to hold the message. */ + return(NX_SIZE_ERROR); + } + + response_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)response_packet -> nx_packet_prepend_ptr; + + response_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBCOMP << 4; + response_ptr -> mqtt_publish_response_packet_remaining_length = 2; + + /* Fill in packet ID */ + response_packet -> nx_packet_prepend_ptr[3] = packet_ptr -> nx_packet_prepend_ptr[3]; + response_packet -> nx_packet_prepend_ptr[4] = packet_ptr -> nx_packet_prepend_ptr[4]; + response_packet -> nx_packet_append_ptr = response_packet -> nx_packet_prepend_ptr + 4; + response_packet -> nx_packet_length = 4; + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + ret = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), response_packet, NX_WAIT_FOREVER); + } + else + { + ret = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, response_packet, NX_WAIT_FOREVER); + } +#else + ret = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, response_packet, NX_WAIT_FOREVER); + +#endif /* NX_SECURE_ENABLE */ + + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + if (ret) + { + nx_packet_release(response_packet); + } + + /* This packet can be released. */ + _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); + + /* Return with value 1, so the caller will release packet_ptr */ + return(1); + } + } + } + + /* Move on to the next packet */ + previous_packet_ptr = transmit_packet_ptr; + transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; + } + + /* nothing is found. Return 1 to release the packet.*/ + return(1); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_sub_unsub_ack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process an ACK message for subscribe */ +/* or unsubscribe request. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* Status */ +/* */ +/* CALLS */ +/* */ +/* [nxd_mqtt_client_receive_notify] User supplied publish */ +/* callback function */ +/* _nxd_mqtt_release_transmit_packet */ +/* Release the memory block */ +/* _nxd_mqtt_read_remaining_length Skip the remaining length */ +/* field */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_process_sub_unsub_ack(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ + +USHORT packet_id; +NX_PACKET *previous_packet_ptr; +NX_PACKET *transmit_packet_ptr; +UCHAR response_header; +UCHAR fixed_header; +USHORT transmit_packet_id; +UINT remaining_length; +ULONG offset; +UCHAR bytes[2]; +ULONG bytes_copied; + + + response_header = *(packet_ptr -> nx_packet_prepend_ptr); + + if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) + { + + /* Unable to process the sub/unsub ack. Simply return and release the packet. */ + return(NXD_MQTT_INVALID_PACKET); + } + + /* Get packet id fields. */ + if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || + (bytes_copied != sizeof(bytes))) + { + return(NXD_MQTT_INVALID_PACKET); + } + + packet_id = (USHORT)(((*bytes) << 8) | (*(bytes + 1))); + + /* Search all the outstanding transmitted packets for a match. */ + previous_packet_ptr = NX_NULL; + transmit_packet_ptr = client_ptr -> message_transmit_queue_head; + while (transmit_packet_ptr) + { + fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); + transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); + if (transmit_packet_id == packet_id) + { + + /* Found the matching packet id */ + if (((response_header >> 4) == MQTT_CONTROL_PACKET_TYPE_SUBACK) && + ((fixed_header >> 4) == MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE)) + { + /* Validate the packet. */ + if (remaining_length != 3) + { + /* Invalid remaining_length value. */ + return(1); + } + + /* Release the transmit packet. */ + _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); + + return(1); + } + else if (((response_header >> 4) == MQTT_CONTROL_PACKET_TYPE_UNSUBACK) && + ((fixed_header >> 4) == MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE)) + { + /* Validate the packet. */ + if (remaining_length != 2) + { + /* Invalid remaining_length value. */ + return(1); + } + + /* Unsubscribe succeeded. */ + /* Release the transmit packet. */ + _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); + + return(1); + } + } + + /* Move on to the next packet */ + previous_packet_ptr = transmit_packet_ptr; + transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; + } + return(1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_pingresp PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process a PINGRESP message. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* Status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* callback function */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_process_pingresp(NXD_MQTT_CLIENT *client_ptr) +{ + + + /* If there is an outstanding ping, mark it as responded. */ + if (client_ptr -> nxd_mqtt_ping_not_responded == NX_TRUE) + { + client_ptr -> nxd_mqtt_ping_not_responded = NX_FALSE; + + client_ptr -> nxd_mqtt_ping_sent_time = 0; + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_process_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process a DISCONNECT message. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_send */ +/* nx_tcp_socket_disconnect */ +/* nx_tcp_client_socket_unbind */ +/* _nxd_mqtt_release_transmit_packet */ +/* _nxd_mqtt_release_receive_packet */ +/* _nxd_mqtt_client_connection_end */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_packet_receive_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_process_disconnect(NXD_MQTT_CLIENT *client_ptr) +{ +NX_PACKET *previous = NX_NULL; +NX_PACKET *current; +NX_PACKET *next; +UINT disconnect_callback = NX_FALSE; +UINT status; +UCHAR fixed_header; + + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) + { + /* State changes from CONNECTED TO IDLE. Call disconnect notify callback + if the function is set. */ + disconnect_callback = NX_TRUE; + } + else if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTING) + { + + /* If state isn't CONNECTED or CONNECTING, just return. */ + return; + } + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NXD_MQTT_SOCKET_TIMEOUT); + + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); + + /* Free up sub/unsub packets on the transmit queue. */ + current = client_ptr -> message_transmit_queue_head; + + while (current) + { + next = current -> nx_packet_queue_next; + fixed_header = *(current -> nx_packet_prepend_ptr); + + if (((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4)) || + ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE << 4))) + { + _nxd_mqtt_release_transmit_packet(client_ptr, current, previous); + } + else + { + previous = current; + } + current = next; + } + + /* If a callback notification is defined, call it now. */ + if ((disconnect_callback == NX_TRUE) && (client_ptr -> nxd_mqtt_disconnect_notify)) + { + client_ptr -> nxd_mqtt_disconnect_notify(client_ptr); + } + + /* If a connect callback notification is defined and is still in connecting stage, call it now. */ + if ((disconnect_callback == NX_FALSE) && (client_ptr -> nxd_mqtt_connect_notify)) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, NXD_MQTT_CONNECT_FAILURE, client_ptr -> nxd_mqtt_connect_context); + } + + if (status == TX_SUCCESS) + { + /* Remove all the packets in the receive queue. */ + while (client_ptr -> message_receive_queue_head) + { + _nxd_mqtt_release_receive_packet(client_ptr, client_ptr -> message_receive_queue_head, NX_NULL); + } + client_ptr -> message_receive_queue_depth = 0; + + /* Clear the MQTT_PACKET_RECEIVE_EVENT */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, ~MQTT_PACKET_RECEIVE_EVENT, TX_AND); +#else + nx_cloud_module_event_clear(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PACKET_RECEIVE_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + } + + /* Clear flags if keep alive is enabled. */ + if (client_ptr -> nxd_mqtt_keepalive) + { + client_ptr -> nxd_mqtt_ping_not_responded = 0; + client_ptr -> nxd_mqtt_ping_sent_time = 0; + } + + /* Clean up the information when disconnecting. */ + client_ptr -> nxd_mqtt_client_username = NX_NULL; + client_ptr -> nxd_mqtt_client_password = NX_NULL; + client_ptr -> nxd_mqtt_client_will_topic = NX_NULL; + client_ptr -> nxd_mqtt_client_will_message = NX_NULL; + client_ptr -> nxd_mqtt_client_will_qos_retain = 0; + + /* Release current processing packet. */ + if (client_ptr -> nxd_mqtt_client_processing_packet) + { + nx_packet_release(client_ptr -> nxd_mqtt_client_processing_packet); + client_ptr -> nxd_mqtt_client_processing_packet = NX_NULL; + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_packet_receive_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function process MQTT message. */ +/* NOTE: MQTT Mutex is NOT obtained on entering this function. */ +/* Therefore it shouldn't hold the mutex when it exists this function. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_receive */ +/* nx_tcp_socket_receive */ +/* _nxd_mqtt_process_publish */ +/* _nxd_mqtt_process_publish_response */ +/* _nxd_mqtt_process_sub_unsub_ack */ +/* _nxd_mqtt_process_pingresp */ +/* _nxd_mqtt_process_disconnect */ +/* nx_packet_release */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_packet_receive_process(NXD_MQTT_CLIENT *client_ptr) +{ +NX_PACKET *packet_ptr; +NX_PACKET *previous_packet_ptr; +UINT status; +UCHAR packet_type; +UINT remaining_length; +UINT packet_consumed; +ULONG offset; +ULONG bytes_copied; +ULONG packet_length; + + for (;;) + { + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Make a receive call. */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_receive(&(client_ptr -> nxd_mqtt_tls_session), &packet_ptr, NX_NO_WAIT); + } + else + { + status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, NX_NO_WAIT); + } +#else + status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, NX_NO_WAIT); +#endif /* NX_SECURE_ENABLE */ + + if (status != NX_SUCCESS) + { + if (status != NX_NO_PACKET) + { + + /* Network issue. Close the MQTT session. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_NETWORK_DISCONNECT_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_NETWORK_DISCONNECT_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + } + + break; + } + + /* Obtain the mutex. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + /* Is there a packet waiting for processing? */ + if (client_ptr -> nxd_mqtt_client_processing_packet) + { + + /* Yes. Link received packet to existing one. */ + if (client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last) + { + client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last -> nx_packet_next = packet_ptr; + } + else + { + client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_next = packet_ptr; + } + if (packet_ptr -> nx_packet_last) + { + client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last = packet_ptr -> nx_packet_last; + } + else + { + client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last = packet_ptr; + } + client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_length += packet_ptr -> nx_packet_length; + + /* Start to process existing packet. */ + packet_ptr = client_ptr -> nxd_mqtt_client_processing_packet; + client_ptr -> nxd_mqtt_client_processing_packet = NX_NULL; + } + + /* Check notify function. */ + if (client_ptr -> nxd_mqtt_packet_receive_notify) + { + + /* Call notify function. Return NX_TRUE if the packet has been consumed. */ + if (client_ptr -> nxd_mqtt_packet_receive_notify(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_packet_receive_context) == NX_TRUE) + { + continue; + } + } + + packet_consumed = NX_FALSE; + while (packet_ptr) + { + /* Parse the incoming packet. */ + status = _nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset); + if (status == NXD_MQTT_PARTIAL_PACKET) + { + + /* We only have partial MQTT message. + * Put it to waiting list for more packets. */ + client_ptr -> nxd_mqtt_client_processing_packet = packet_ptr; + packet_consumed = NX_TRUE; + break; + } + else if (status) + { + + /* Invalid packet. */ + break; + } + + /* Get packet type. */ + if (nx_packet_data_extract_offset(packet_ptr, 0, &packet_type, 1, &bytes_copied)) + { + + /* Unable to read packet type. */ + break; + } + + /* Right shift 4 bits to get the packet type. */ + packet_type = packet_type >> 4; + + /* Process based on packet type. */ + switch (packet_type) + { + case MQTT_CONTROL_PACKET_TYPE_CONNECT: + /* Client does not accept connections. Nothing needs to be done. */ + break; + case MQTT_CONTROL_PACKET_TYPE_CONNACK: + _nxd_mqtt_process_connack(client_ptr, packet_ptr, NX_NO_WAIT); + break; + + case MQTT_CONTROL_PACKET_TYPE_PUBLISH: + packet_consumed = _nxd_mqtt_process_publish(client_ptr, packet_ptr); + break; + + case MQTT_CONTROL_PACKET_TYPE_PUBACK: + case MQTT_CONTROL_PACKET_TYPE_PUBREL: + _nxd_mqtt_process_publish_response(client_ptr, packet_ptr); + break; + + case MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE: + case MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE: + /* Client should not process subscribe or unsubscribe message. */ + break; + + case MQTT_CONTROL_PACKET_TYPE_SUBACK: + case MQTT_CONTROL_PACKET_TYPE_UNSUBACK: + _nxd_mqtt_process_sub_unsub_ack(client_ptr, packet_ptr); + break; + + + case MQTT_CONTROL_PACKET_TYPE_PINGREQ: + /* Client is not supposed to receive ping req. Ignore it. */ + break; + + case MQTT_CONTROL_PACKET_TYPE_PINGRESP: + _nxd_mqtt_process_pingresp(client_ptr); + break; + + case MQTT_CONTROL_PACKET_TYPE_DISCONNECT: + _nxd_mqtt_process_disconnect(client_ptr); + break; + + /* Publisher sender message type for QoS 2. Not supported. */ + case MQTT_CONTROL_PACKET_TYPE_PUBREC: + case MQTT_CONTROL_PACKET_TYPE_PUBCOMP: + default: + /* Unknown type. */ + break; + } + + if (packet_consumed) + { + break; + } + + /* Trim current packet. */ + offset += remaining_length; + packet_length = packet_ptr -> nx_packet_length; + if (packet_length > offset) + { + + /* Multiple MQTT message in one packet. */ + packet_length = packet_ptr -> nx_packet_length - offset; + while ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) <= offset) + { + offset -= (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); + + /* Current packet can be released. */ + previous_packet_ptr = packet_ptr; + packet_ptr = packet_ptr -> nx_packet_next; + previous_packet_ptr -> nx_packet_next = NX_NULL; + nx_packet_release(previous_packet_ptr); + if (packet_ptr == NX_NULL) + { + + /* Invalid packet. */ + break; + } + } + + if (packet_ptr) + { + + /* Adjust current packet. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + offset; + packet_ptr -> nx_packet_length = packet_length; + } + } + else + { + + /* All messages in current packet is processed. */ + break; + } + } + + if (!packet_consumed) + { + nx_packet_release(packet_ptr); + } + } + + /* No more data in the receive queue. Return. */ + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_tcp_establish_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes MQTT TCP connection establish event. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_start */ +/* _nxd_mqtt_client_connection_end */ +/* _nxd_mqtt_client_connect_packet_send */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_tcp_establish_process(NXD_MQTT_CLIENT *client_ptr) +{ +UINT status; + + + /* TCP connection is established. */ + + /* If TLS is enabled, start TLS */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_start(&(client_ptr -> nxd_mqtt_tls_session), &(client_ptr -> nxd_mqtt_client_socket), NX_NO_WAIT); + + if (status != NX_CONTINUE) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + /* Check callback function. */ + if (client_ptr -> nxd_mqtt_connect_notify) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); + } + + return; + } + + /* TLS in progress. */ + client_ptr -> nxd_mqtt_tls_in_progress = NX_TRUE; + + return; + } +#endif /* NX_SECURE_ENABLE */ + + /* Start to send MQTT connect packet. */ + status = _nxd_mqtt_client_connect_packet_send(client_ptr, NX_NO_WAIT); + + /* Check status. */ + if (status) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + /* Check callback function. */ + if (client_ptr -> nxd_mqtt_connect_notify) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); + } + } +} + + +#ifdef NX_SECURE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_tls_establish_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TLS connection establish event. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_secure_tls_handshake_process */ +/* _nxd_mqtt_client_connect_packet_send */ +/* _nxd_mqtt_client_connection_end */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_tls_establish_process(NXD_MQTT_CLIENT *client_ptr) +{ +UINT status; + + + /* Directly call handshake process for async mode. */ + status = _nx_secure_tls_handshake_process(&(client_ptr -> nxd_mqtt_tls_session), NX_NO_WAIT); + if (status == NX_SUCCESS) + { + + /* TLS session established. */ + client_ptr -> nxd_mqtt_tls_in_progress= NX_FALSE; + + /* Start to send MQTT connect packet. */ + status = _nxd_mqtt_client_connect_packet_send(client_ptr, NX_NO_WAIT); + + /* Check status. */ + if (status) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + /* Check callback function. */ + if (client_ptr -> nxd_mqtt_connect_notify) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); + } + } + } + else if (status != NX_CONTINUE) + { + + /* Error. */ + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + /* Check callback function. */ + if (client_ptr -> nxd_mqtt_connect_notify) + { + client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); + } + } + + return; +} +#endif /* NX_SECURE_ENABLE */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_append_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes the message length and message in the outgoing */ +/* MQTT packet. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Outgoing MQTT packet */ +/* message Pointer to the message */ +/* length Length of the message */ +/* wait_option Wait option */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_sub_unsub */ +/* _nxd_mqtt_client_connect */ +/* _nxd_mqtt_client_publish */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_append_message(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, CHAR *message, UINT length, ULONG wait_option) +{ +UINT ret = 0; +UCHAR len[2]; + + len[0] = (length >> 8) & 0xFF; + len[1] = length & 0xFF; + + /* Append message length field. */ + ret = nx_packet_data_append(packet_ptr, len, 2, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + + if (ret) + { + return(ret); + } + + if (length) + { + /* Copy the string into the packet. */ + ret = nx_packet_data_append(packet_ptr, message, length, + client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + } + + return(ret); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_connection_end PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used to end the MQTT connection. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* wait_option Wait option */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_end End TLS session */ +/* nx_secure_tls_session_delete Delete TLS session */ +/* nx_tcp_socket_disconnect Close TCP connection */ +/* nx_tcp_client_socket_unbind Unbind TCP socket */ +/* tx_timer_delete Delete timer */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_connect */ +/* _nxd_mqtt_process_disconnect */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nxd_mqtt_client_connection_end(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) +{ + + /* Obtain the mutex. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + /* Mark the session as terminated. */ + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_end(&(client_ptr -> nxd_mqtt_tls_session), wait_option); + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif + nx_tcp_socket_disconnect(&(client_ptr -> nxd_mqtt_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nxd_mqtt_client_socket)); + + /* Disable timer if timer has been started. */ + if (client_ptr -> nxd_mqtt_keepalive) + { + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + } +} + + +static UINT _nxd_mqtt_send_simple_message(NXD_MQTT_CLIENT *client_ptr, UCHAR header_value); + + +/* MQTT internal function */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is passed to MQTT client socket create call. */ +/* This callback function notifies MQTT client thread when the TCP */ +/* connection is lost. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket that */ +/* disconnected. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* TCP socket disconnect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_periodic_timer_entry(ULONG client) +{ +/* Check if it is time to send out a ping message. */ +NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)client; + + /* If an outstanding ping response has not been received, and the client exceeds the time waiting for ping response, + the client shall disconnect from the server. */ + if (client_ptr -> nxd_mqtt_ping_not_responded) + { + /* If current time is greater than the ping timeout */ + if ((tx_time_get() - client_ptr -> nxd_mqtt_ping_sent_time) >= client_ptr -> nxd_mqtt_ping_timeout) + { + /* Ping timed out. Need to terminate the connection. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_PING_TIMEOUT_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PING_TIMEOUT_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + return; + } + } + + /* About to timeout? */ + if ((client_ptr -> nxd_mqtt_timeout - tx_time_get()) <= client_ptr -> nxd_mqtt_timer_value) + { + /* Set the flag so the MQTT thread can send the ping. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_TIMEOUT_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_TIMEOUT_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + } + + /* If keepalive is not enabled, just return. */ + return; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_event_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function serves as the entry point for the MQTT */ +/* client thread. */ +/* */ +/* INPUT */ +/* */ +/* mqtt_client Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_release_transmit_packet */ +/* _nxd_mqtt_release_receive_packet */ +/* _nxd_mqtt_send_simple_message */ +/* _nxd_mqtt_process_disconnect */ +/* _nxd_mqtt_packet_receive_process */ +/* tx_timer_delete */ +/* tx_event_flags_delete */ +/* nx_tcp_socket_delete */ +/* tx_timer_delete */ +/* tx_mutex_delete */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_create */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_client_event_process(VOID *mqtt_client, ULONG common_events, ULONG module_own_events) +{ +NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)mqtt_client; + + + /* Obtain the mutex. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); + + /* Process common events. */ + NX_PARAMETER_NOT_USED(common_events); + + /* Process module own events. */ + if (module_own_events & MQTT_START_EVENT) + { + + /* Move MQTT Client state to STARTED */ + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; + } + + if (module_own_events & MQTT_TIMEOUT_EVENT) + { + /* Send out PING only if the client is connected. */ + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) + { + _nxd_mqtt_send_simple_message(client_ptr, MQTT_CONTROL_PACKET_TYPE_PINGREQ); + } + } + + if (module_own_events & MQTT_TCP_ESTABLISH_EVENT) + { + _nxd_mqtt_tcp_establish_process(client_ptr); + } + + if (module_own_events & MQTT_PACKET_RECEIVE_EVENT) + { +#ifdef NX_SECURE_ENABLE + /* TLS in progress on async mode. */ + if (client_ptr -> nxd_mqtt_tls_in_progress) + { + _nxd_mqtt_tls_establish_process(client_ptr); + } + else +#endif /* NX_SECURE_ENABLE */ + + _nxd_mqtt_packet_receive_process(client_ptr); + } + + if (module_own_events & MQTT_PING_TIMEOUT_EVENT) + { + /* The server/broker didn't respond to our ping request message. Disconnect from the server. */ + _nxd_mqtt_process_disconnect(client_ptr); + } + if (module_own_events & MQTT_NETWORK_DISCONNECT_EVENT) + { + /* The server closed TCP socket. We shall go through the disconnect code path. */ + _nxd_mqtt_process_disconnect(client_ptr); + } + + if (module_own_events & MQTT_DELETE_EVENT) + { + + /* Stop the client and disconnect from the server. */ + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) + { + _nxd_mqtt_process_disconnect(client_ptr); + } + + /* Delete the timer. Check first if it is already deleted. */ + if ((client_ptr -> nxd_mqtt_timer).tx_timer_id != 0) + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + +#ifndef NXD_MQTT_CLOUD_ENABLE + /* Delete the event flag. Check first if it is already deleted. */ + if ((client_ptr -> nxd_mqtt_events).tx_event_flags_group_id != 0) + tx_event_flags_delete(&client_ptr -> nxd_mqtt_events); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Release all the messages on the receive queue. */ + while (client_ptr -> message_receive_queue_head) + { + _nxd_mqtt_release_receive_packet(client_ptr, client_ptr -> message_receive_queue_head, NX_NULL); + } + client_ptr -> message_receive_queue_depth = 0; + + /* Delete all the messages sitting in the receive and transmit queue. */ + while (client_ptr -> message_transmit_queue_head) + { + _nxd_mqtt_release_transmit_packet(client_ptr, client_ptr -> message_transmit_queue_head, NX_NULL); + } + + /* Release mutex */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + +#ifndef NXD_MQTT_CLOUD_ENABLE + /* Delete the mutex. */ + tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Deleting the socket, (the socket ID is cleared); this signals it is ok to delete this thread. */ + nx_tcp_socket_delete(&client_ptr -> nxd_mqtt_client_socket); + } + else + { + + /* Release mutex */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + } +} + + +#ifndef NXD_MQTT_CLOUD_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function serves as the entry point for the MQTT */ +/* client thread. */ +/* */ +/* INPUT */ +/* */ +/* mqtt_client Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get */ +/* _nxd_mqtt_client_event_process */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_create */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nxd_mqtt_thread_entry(ULONG mqtt_client) +{ +NXD_MQTT_CLIENT *client_ptr; +ULONG events; + + client_ptr = (NXD_MQTT_CLIENT *)mqtt_client; + + /* Loop to process events on the MQTT client */ + for (;;) + { + + tx_event_flags_get(&client_ptr -> nxd_mqtt_events, MQTT_ALL_EVENTS, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Call the event processing routine. */ + _nxd_mqtt_client_event_process(client_ptr, NX_NULL, events); + + if (events & MQTT_DELETE_EVENT) + { + break; + } + } +} +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _mqtt_client_disconnect_callback PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is passed to MQTT client socket create call. */ +/* This callback function notifies MQTT client thread when the TCP */ +/* connection is lost. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket that */ +/* disconnected. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* TCP socket disconnect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _mqtt_client_disconnect_callback(NX_TCP_SOCKET *socket_ptr) +{ +NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)(socket_ptr -> nx_tcp_socket_reserved_ptr); + + /* Set the MQTT_NETWORK_DISCONNECT event. This event indicates + that the disconnect is initiated from the network. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_NETWORK_DISCONNECT_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_NETWORK_DISCONNECT_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an instance for MQTT Client. It initializes */ +/* MQTT Client control block, creates a thread, mutex and event queue */ +/* for MQTT Client, and creates the TCP socket for MQTT messaging. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* client_id Client ID for this instance */ +/* client_id_length Length of Client ID, in bytes */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* stack_ptr Client thread's stack pointer */ +/* stack_size Client thread's stack size */ +/* mqtt_thread_priority Priority for MQTT thread */ +/* memory_ptr Deprecated and not used */ +/* memory_size Deprecated and not used */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_create_internal Create mqtt client */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, + CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, + VOID *memory_ptr, ULONG memory_size) +{ + +UINT status; + + + NX_PARAMETER_NOT_USED(memory_ptr); + NX_PARAMETER_NOT_USED(memory_size); + + /* Create MQTT client. */ + status = _nxd_mqtt_client_create_internal(client_ptr, client_name, client_id, client_id_length, ip_ptr, + pool_ptr, stack_ptr, stack_size, mqtt_thread_priority); + + /* Check status. */ + if (status) + { + return(status); + } + +#ifdef NXD_MQTT_CLOUD_ENABLE + + /* Create cloud helper. */ + status = nx_cloud_create(&(client_ptr -> nxd_mqtt_client_cloud), "Cloud Helper", stack_ptr, stack_size, mqtt_thread_priority); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ + + /* Delete socket. */ + nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); + + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Save the cloud pointer. */ + client_ptr -> nxd_mqtt_client_cloud_ptr = &(client_ptr -> nxd_mqtt_client_cloud); + + /* Save the mutex pointer. */ + client_ptr -> nxd_mqtt_client_mutex_ptr = &(client_ptr -> nxd_mqtt_client_cloud.nx_cloud_mutex); + + /* Register MQTT on cloud helper. */ + status = nx_cloud_module_register(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module), client_name, NX_CLOUD_MODULE_MQTT_EVENT, + _nxd_mqtt_client_event_process, client_ptr); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Delete own created cloud. */ + nx_cloud_delete(&(client_ptr -> nxd_mqtt_client_cloud)); + + /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ + + /* Delete socket. */ + nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); + + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Set start event to start MQTT. */ + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_START_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Return. */ + return(NXD_MQTT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_create_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an instance for MQTT Client. It initializes */ +/* MQTT Client control block, creates a thread, mutex and event queue */ +/* for MQTT Client, and creates the TCP socket for MQTT messaging. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* client_id Client ID for this instance */ +/* client_id_length Length of Client ID, in bytes */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* stack_ptr Client thread's stack pointer */ +/* stack_size Client thread's stack size */ +/* mqtt_thread_priority Priority for MQTT thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_create Create a thread */ +/* tx_mutex_create Create mutex */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* tx_event_flag_create Create event flag */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_client_create_internal(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, + CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority) +{ +UINT status; + +#ifdef NXD_MQTT_CLOUD_ENABLE + NX_PARAMETER_NOT_USED(stack_ptr); + NX_PARAMETER_NOT_USED(stack_size); + NX_PARAMETER_NOT_USED(mqtt_thread_priority); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Clear the MQTT Client control block. */ + NXD_MQTT_SECURE_MEMSET((void *)client_ptr, 0, sizeof(NXD_MQTT_CLIENT)); + +#ifndef NXD_MQTT_CLOUD_ENABLE + + /* Create MQTT mutex. */ + status = tx_mutex_create(&client_ptr -> nxd_mqtt_protection, client_name, TX_NO_INHERIT); + + /* Determine if an error occurred. */ + if (status != TX_SUCCESS) + { + + return(NXD_MQTT_INTERNAL_ERROR); + } + client_ptr -> nxd_mqtt_client_mutex_ptr = &(client_ptr -> nxd_mqtt_protection); + + /* Now create MQTT client thread */ + status = tx_thread_create(&(client_ptr -> nxd_mqtt_thread), client_name, _nxd_mqtt_thread_entry, + (ULONG)client_ptr, stack_ptr, stack_size, mqtt_thread_priority, mqtt_thread_priority, + NXD_MQTT_CLIENT_THREAD_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred. */ + if (status != TX_SUCCESS) + { + /* Delete the mutex. */ + tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); + + /* Return error code. */ + return(NXD_MQTT_INTERNAL_ERROR); + } + + status = tx_event_flags_create(&(client_ptr -> nxd_mqtt_events), client_name); + + if (status != TX_SUCCESS) + { + /* Delete the mutex. */ + tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); + + /* Delete the thread. */ + tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); + + /* Return error code. */ + return(NXD_MQTT_INTERNAL_ERROR); + } +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Record the client ID information. */ + client_ptr -> nxd_mqtt_client_id = client_id; + client_ptr -> nxd_mqtt_client_id_length = client_id_length; + client_ptr -> nxd_mqtt_client_ip_ptr = ip_ptr; + client_ptr -> nxd_mqtt_client_packet_pool_ptr = pool_ptr; + client_ptr -> nxd_mqtt_client_name = client_name; + + /* Create the socket. */ + status = nx_tcp_socket_create(client_ptr -> nxd_mqtt_client_ip_ptr, &(client_ptr -> nxd_mqtt_client_socket), client_ptr -> nxd_mqtt_client_name, + NX_IP_NORMAL, NX_DONT_FRAGMENT, 0x80, NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE, + NX_NULL, _mqtt_client_disconnect_callback); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { +#ifndef NXD_MQTT_CLOUD_ENABLE + /* Delete the mutex. */ + tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); + + /* Delete the event flags. */ + tx_event_flags_delete(&(client_ptr -> nxd_mqtt_events)); + + /* Delete the thread. */ + tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Record the client_ptr in the socket structure. */ + client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_reserved_ptr = (VOID *)client_ptr; + + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_INITIALIZE; + +#ifndef NXD_MQTT_CLOUD_ENABLE + /* Start MQTT thread. */ + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_START_EVENT, TX_OR); + tx_thread_resume(&(client_ptr -> nxd_mqtt_thread)); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + return(NXD_MQTT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_login_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets optional MQTT username and password. Note */ +/* if the broker requires username and password, this information */ +/* must be set prior to calling nxd_mqtt_client_connect or */ +/* nxd_mqtt_client_secure_connect. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* username User name, or NULL if user */ +/* name is not required */ +/* username_length Length of the user name, or */ +/* 0 if user name is NULL */ +/* password Password string, or NULL if */ +/* password is not required */ +/* password_length Length of the password, or */ +/* 0 if password is NULL */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, + CHAR *username, UINT username_length, CHAR *password, UINT password_length) +{ +UINT status; + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + client_ptr -> nxd_mqtt_client_username = username; + client_ptr -> nxd_mqtt_client_username_length = (USHORT)username_length; + client_ptr -> nxd_mqtt_client_password = password; + client_ptr -> nxd_mqtt_client_password_length = (USHORT)password_length; + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_will_message_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets optional MQTT will topic and will message. */ +/* Note that if will message is needed, application must set will */ +/* message prior to calling nxd_mqtt_client_connect or */ +/* nxd_mqtt_client_secure_connect. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* will_topic Will topic string. */ +/* will_topic_length Length of the will topic. */ +/* will_message Will message string. */ +/* will_message_length Length of the will message. */ +/* will_retain_flag Whether or not the will */ +/* message is to be retained */ +/* when it is published. */ +/* Valid values are NX_TRUE */ +/* NX_FALSE */ +/* will_QoS QoS level to be used when */ +/* publishing will message. */ +/* Valid values are 0, 1, 2 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, + const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, + UINT will_message_length, UINT will_retain_flag, UINT will_QoS) +{ +UINT status; + + if (will_QoS == 2) + { + return(NXD_MQTT_QOS2_NOT_SUPPORTED); + } + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + + client_ptr -> nxd_mqtt_client_will_topic = will_topic; + client_ptr -> nxd_mqtt_client_will_topic_length = will_topic_length; + client_ptr -> nxd_mqtt_client_will_message = will_message; + client_ptr -> nxd_mqtt_client_will_message_length = will_message_length; + + if (will_retain_flag == NX_TRUE) + { + client_ptr -> nxd_mqtt_client_will_qos_retain = 0x80; + } + client_ptr -> nxd_mqtt_client_will_qos_retain = (UCHAR)(client_ptr -> nxd_mqtt_client_will_qos_retain | will_QoS); + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_will_message_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the */ +/* nxd_mqtt_client_will_message_set call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* will_topic Will topic string. */ +/* will_topic_length Length of the will topic. */ +/* will_message Will message string. */ +/* will_message_length Length of the will message. */ +/* will_retain_flag Whether or not the will */ +/* message is to be retained */ +/* when it is published. */ +/* Valid values are NX_TRUE */ +/* NX_FALSE */ +/* will_QoS QoS level to be used when */ +/* publishing will message. */ +/* Valid values are 0, 1, 2 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_will_message_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, + const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, + UINT will_message_length, UINT will_retain_flag, UINT will_QoS) +{ + + if (client_ptr == NX_NULL) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + /* Valid will_topic string. The will topic string cannot be NULL. */ + if ((will_topic == NX_NULL) || (will_topic_length == 0)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + if ((will_retain_flag != NX_TRUE) && (will_retain_flag != NX_FALSE)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + if (will_QoS > 2) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + return(_nxd_mqtt_client_will_message_set(client_ptr, will_topic, will_topic_length, will_message, + will_message_length, will_retain_flag, will_QoS)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_login_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the nxd_mqtt_client_login call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* username User name, or NULL if user */ +/* name is not required */ +/* username_length Length of the user name, or */ +/* 0 if user name is NULL */ +/* password Password string, or NULL if */ +/* password is not required */ +/* password_length Length of the password, or */ +/* 0 if password is NULL */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_login_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, + CHAR *username, UINT username_length, CHAR *password, UINT password_length) +{ + if (client_ptr == NX_NULL) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + /* Username and username length don't match, + or password and password length don't match. */ + if (((username == NX_NULL) && (username_length != 0)) || + ((password == NX_NULL) && (password_length != 0))) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + return(_nxd_mqtt_client_login_set(client_ptr, username, username_length, password, password_length)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_retransmit_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retransmit QoS1 messages upon reconnection, if the */ +/* connection is not set CLEAN_SESSION. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* wait_option Timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* nx_secure_tls_session_send */ +/* nx_tcp_socket_send */ +/* nx_packet_release */ +/* tx_time_get */ +/* nx_packet_copy */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_client_retransmit_message(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) +{ +NX_PACKET *transmit_packet_ptr; +NX_PACKET *packet_ptr; +UINT status = NXD_MQTT_SUCCESS; +UINT mutex_status; +UCHAR fixed_header; + + transmit_packet_ptr = client_ptr -> message_transmit_queue_head; + + while (transmit_packet_ptr) + { + fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); + + if ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4)) + { + + /* Retransmit publish packet only. */ + /* Obtain a NetX Packet. */ + status = nx_packet_copy(transmit_packet_ptr, &packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + + if (status != NXD_MQTT_SUCCESS) + { + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Send the packet. */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + } +#else + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + +#endif /* NX_SECURE_ENABLE */ + + if (status) + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + + status = NXD_MQTT_COMMUNICATION_FAILURE; + } + /* Obtain the mutex. */ + mutex_status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, wait_option); + + if (mutex_status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + if (status) + { + return(status); + } + } + transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; + } + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function makes an initial connection to the MQTT server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* server_ip Server IP address structure */ +/* server_port Server port number, in host */ +/* byte order */ +/* keepalive Keepalive flag */ +/* clean_session Clean session flag */ +/* wait_option Timeout value */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* nx_tcp_socket_create Create TCP socket */ +/* nx_tcp_socket_receive_notify */ +/* nx_tcp_client_socket_bind */ +/* nxd_tcp_client_socket_connect */ +/* nx_tcp_client_socket_unbind */ +/* tx_mutex_put */ +/* nx_secure_tls_session_start */ +/* nx_secure_tls_session_send */ +/* nx_secure_tls_session_receive */ +/* _nxd_mqtt_packet_allocate */ +/* _nxd_mqtt_client_set_fixed_header */ +/* _nxd_mqtt_client_append_message */ +/* nx_tcp_socket_send */ +/* nx_packet_release */ +/* nx_tcp_socket_receive */ +/* tx_event_flag_set */ +/* _nxd_mqtt_release_transmit_packet */ +/* tx_timer_create */ +/* nx_secure_tls_session_receive */ +/* _nxd_mqtt_client_connection_end */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT keepalive, UINT clean_session, ULONG wait_option) +{ +NX_PACKET *packet_ptr; +UINT status; + + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif /* NX_SECURE_ENABLE */ + + return(NXD_MQTT_MUTEX_FAILURE); + } + + /* Do nothing if the client is already connected. */ + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) + { + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_ALREADY_CONNECTED); + } + +#if defined(NX_SECURE_ENABLE) && defined(NXD_MQTT_REQUIRE_TLS) + if (!client_ptr -> nxd_mqtt_client_use_tls) + { + + /* NXD_MQTT_REQUIRE_TLS is defined but the application does not use TLS. + This is security violation. Return with failure code. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_CONNECT_FAILURE); + } +#endif /* NX_SECURE_ENABLE && NXD_MQTT_REQUIRE_TLS*/ + + /* Record the keepalive value, converted to TX timer ticks. */ + client_ptr -> nxd_mqtt_keepalive = keepalive * NX_IP_PERIODIC_RATE; + if (keepalive) + { + client_ptr -> nxd_mqtt_timer_value = NXD_MQTT_KEEPALIVE_TIMER_RATE; + client_ptr -> nxd_mqtt_ping_timeout = NXD_MQTT_PING_TIMEOUT_DELAY; + + /* Create timer */ + status = tx_timer_create(&(client_ptr -> nxd_mqtt_timer), "MQTT Timer", _nxd_mqtt_periodic_timer_entry, (ULONG)client_ptr, + client_ptr -> nxd_mqtt_timer_value, client_ptr -> nxd_mqtt_timer_value, TX_AUTO_ACTIVATE); + if (status) + { +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif /* NX_SECURE_ENABLE */ + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_INTERNAL_ERROR); + } + } + else + { + client_ptr -> nxd_mqtt_timer_value = 0; + client_ptr -> nxd_mqtt_ping_timeout = 0; + } + + /* Record the clean session flag. */ + client_ptr -> nxd_mqtt_clean_session = clean_session; + + /* Set TCP connection establish notify for non-blocking mode. */ + if (wait_option == 0) + { + status = nx_tcp_socket_establish_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_tcp_establish_notify); + + /* Check status. */ + if (status != NX_SUCCESS) + { +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif /* NX_SECURE_ENABLE */ + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(status); + } + + /* Set the receive callback. */ + nx_tcp_socket_receive_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_receive_callback); + } + else + { + + /* Clean receive callback. */ + client_ptr -> nxd_mqtt_client_socket.nx_tcp_receive_callback = NX_NULL; + } + + /* Release mutex */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* First attempt to bind the client socket. */ + status = nx_tcp_client_socket_bind(&(client_ptr -> nxd_mqtt_client_socket), NX_ANY_PORT, wait_option); + + if (status != NX_SUCCESS) + { +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif /* NX_SECURE_ENABLE */ + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Obtain the mutex. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + /* Make state as NXD_MQTT_CLIENT_STATE_CONNECTING. */ + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTING; + + /* Release mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Connect to the MQTT server */ + status = nxd_tcp_client_socket_connect(&(client_ptr -> nxd_mqtt_client_socket), server_ip, server_port, wait_option); + if ((status != NX_SUCCESS) && (status != NX_IN_PROGRESS)) + { + + /* Obtain the mutex. */ + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + /* Make state as NXD_MQTT_CLIENT_STATE_IDLE. */ + client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; + + /* Release mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); + } +#endif /* NX_SECURE_ENABLE */ + nx_tcp_client_socket_unbind(&(client_ptr -> nxd_mqtt_client_socket)); + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + return(NXD_MQTT_CONNECT_FAILURE); + } + + /* Just return for non-blocking mode. */ + if (status == NX_IN_PROGRESS) + { + return(NX_IN_PROGRESS); + } + + /* If TLS is enabled, start TLS */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + + status = nx_secure_tls_session_start(&(client_ptr -> nxd_mqtt_tls_session), &(client_ptr -> nxd_mqtt_client_socket), wait_option); + + if (status != NX_SUCCESS) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + return(NXD_MQTT_CONNECT_FAILURE); + } + } +#endif /* NX_SECURE_ENABLE */ + + /* Start to send connect packet. */ + status = _nxd_mqtt_client_connect_packet_send(client_ptr, wait_option); + + if (status != NX_SUCCESS) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + + return(NXD_MQTT_CONNECT_FAILURE); + } + +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_receive(&(client_ptr -> nxd_mqtt_tls_session), &packet_ptr, wait_option); + } + else + { + status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, wait_option); + } +#else + status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, wait_option); +#endif /* NX_SECURE_ENABLE */ + + /* Check status. */ + if (status) + { + + /* End connection. */ + _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); + return(NXD_MQTT_COMMUNICATION_FAILURE); + } + + /* Process CONNACK message. */ + status = _nxd_mqtt_process_connack(client_ptr, packet_ptr, wait_option); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Check status. */ + if (status == NX_SUCCESS) + { + + /* Set the receive callback. */ + nx_tcp_socket_receive_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_receive_callback); + } + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_connect_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends CONNECT packet to MQTT server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* keepalive Keepalive flag */ +/* clean_session Clean session flag */ +/* wait_option Timeout value */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release */ +/* nx_tcp_socket_send */ +/* nx_secure_tls_session_send */ +/* _nxd_mqtt_packet_allocate */ +/* _nxd_mqtt_release_transmit_packet */ +/* _nxd_mqtt_client_connection_end */ +/* _nxd_mqtt_client_set_fixed_header */ +/* _nxd_mqtt_client_append_message */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_connect */ +/* _nxd_mqtt_tcp_establish_process */ +/* _nxd_mqtt_tls_establish_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_connect_packet_send(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) +{ +NX_PACKET *packet_ptr; +UINT status; +UINT length = 0; +UCHAR connection_flags = 0; +UINT ret = NXD_MQTT_SUCCESS; +UCHAR temp_data[4]; +UINT keepalive = (client_ptr -> nxd_mqtt_keepalive/NX_IP_PERIODIC_RATE); + + + /* Construct connect flags by taking the connect flag user supplies, or'ing the username and + password bits, if they are supplied. */ + if (client_ptr -> nxd_mqtt_client_username) + { + connection_flags |= MQTT_CONNECT_FLAGS_USERNAME; + + /* Add the password flag only if username is supplied. */ + if (client_ptr -> nxd_mqtt_client_password) + { + connection_flags |= MQTT_CONNECT_FLAGS_PASSWORD; + } + } + + if (client_ptr -> nxd_mqtt_client_will_topic) + { + connection_flags = connection_flags | MQTT_CONNECT_FLAGS_WILL_FLAG; + + + if (client_ptr -> nxd_mqtt_client_will_qos_retain & 0x80) + { + connection_flags = connection_flags | MQTT_CONNECT_FLAGS_WILL_RETAIN; + } + + connection_flags = (UCHAR)(connection_flags | ((client_ptr -> nxd_mqtt_client_will_qos_retain & 0x3) << 3)); + } + + if (client_ptr -> nxd_mqtt_clean_session == NX_TRUE) + { + connection_flags = connection_flags | MQTT_CONNECT_FLAGS_CLEAN_SESSION; + + /* Clear any transmit blocks from the previous session. */ + while (client_ptr -> message_transmit_queue_head) + { + _nxd_mqtt_release_transmit_packet(client_ptr, client_ptr -> message_transmit_queue_head, NX_NULL); + } + } + + /* Set the length of the packet. */ + length = 10; + + /* Add the size of the client Identifier. */ + length += (client_ptr -> nxd_mqtt_client_id_length + 2); + + /* Add the will topic, if present. */ + if (connection_flags & MQTT_CONNECT_FLAGS_WILL_FLAG) + { + length += (client_ptr -> nxd_mqtt_client_will_topic_length + 2); + length += (client_ptr -> nxd_mqtt_client_will_message_length + 2); + } + if (connection_flags & MQTT_CONNECT_FLAGS_USERNAME) + { + length += (UINT)(client_ptr -> nxd_mqtt_client_username_length + 2); + } + if (connection_flags & MQTT_CONNECT_FLAGS_PASSWORD) + { + length += (UINT)(client_ptr -> nxd_mqtt_client_password_length + 2); + } + + /* Check for invalid length. */ + if (length > (127 * 127 * 127 * 127)) + { + return(NXD_MQTT_INTERNAL_ERROR); + } + + status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); + if (status) + { + + return(status); + } + + /* Construct MQTT CONNECT message. */ + temp_data[0] = ((MQTT_CONTROL_PACKET_TYPE_CONNECT << 4) & 0xF0); + + /* Fill in fixed header. */ + ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, temp_data[0], length, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, "MQTT", 4, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Fill in protocol level, */ + temp_data[0] = MQTT_PROTOCOL_LEVEL; + + /* Fill in byte 8: connect flags */ + temp_data[1] = connection_flags; + + /* Fill in byte 9 and 10: keep alive */ + temp_data[2] = (keepalive >> 8) & 0xFF; + temp_data[3] = (keepalive & 0xFF); + + ret = nx_packet_data_append(packet_ptr, temp_data, 4, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Fill in payload area, in the order of: client identifier, will topic, will message, + user name, and password. */ + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_id, + client_ptr -> nxd_mqtt_client_id_length, wait_option); + + /* Next fill will topic and will message if the will flag is set. */ + if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_WILL_FLAG)) + { + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, (CHAR *)client_ptr -> nxd_mqtt_client_will_topic, + client_ptr -> nxd_mqtt_client_will_topic_length, wait_option); + + if (!ret) + { + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, (CHAR *)client_ptr -> nxd_mqtt_client_will_message, + client_ptr -> nxd_mqtt_client_will_message_length, wait_option); + } + } + + /* Fill username if username flag is set */ + if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_USERNAME)) + { + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_username, + client_ptr -> nxd_mqtt_client_username_length, wait_option); + } + + /* Fill password if password flag is set */ + if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_PASSWORD)) + { + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_password, + client_ptr -> nxd_mqtt_client_password_length, wait_option); + } + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Ready to send the connect message to the server. */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + } +#else + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + +#endif /* NX_SECURE_ENABLE */ + + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_secure_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function makes an initial secure (TLS) connection to */ +/* the MQTT server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* server_ip Server IP address structure */ +/* server_port Server port number, in host */ +/* byte order */ +/* tls_setup User-supplied callback */ +/* function to set up TLS */ +/* parameters. */ +/* username User name, or NULL if user */ +/* name is not required */ +/* username_length Length of the user name, or */ +/* 0 if user name is NULL */ +/* password Password string, or NULL if */ +/* password is not required */ +/* password_length Length of the password, or */ +/* 0 if password is NULL */ +/* connection_flag Flag passed to the server */ +/* timeout Timeout value */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_connect Actual MQTT Client connect */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifdef NX_SECURE_ENABLE +UINT _nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, + NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), + UINT keepalive, UINT clean_session, ULONG wait_option) +{ +UINT ret; + + /* Set up TLS session information. */ + ret = (*tls_setup)(client_ptr, &client_ptr -> nxd_mqtt_tls_session, + &client_ptr -> nxd_mqtt_tls_certificate, + &client_ptr -> nxd_mqtt_tls_trusted_certificate); + + if (ret) + { + return(ret); + } + + /* Mark the connection as secure. */ + client_ptr -> nxd_mqtt_client_use_tls = 1; + + ret = _nxd_mqtt_client_connect(client_ptr, server_ip, server_port, keepalive, clean_session, wait_option); + + return(ret); +} + +#endif /* NX_SECURE_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created MQTT client instance. */ +/* If the NXD_MQTT_SOCKET_TIMEOUT is set to NX_WAIT_FOREVER, this may */ +/* suspend infinitely. This is because the MQTT Client must */ +/* disconnect with the server, and if the network link is disabled or */ +/* the server is not responding, this will blocks this function from */ +/* completing. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr) +{ + + + /* Set the event flag for DELETE. Next time when the MQTT client thread + wakes up, it will perform the deletion process. */ +#ifndef NXD_MQTT_CLOUD_ENABLE + tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_DELETE_EVENT, TX_OR); +#else + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_DELETE_EVENT); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + /* Check if the MQTT client thread has completed. */ + while((client_ptr -> nxd_mqtt_client_socket).nx_tcp_socket_id != 0) + { + tx_thread_sleep(NX_IP_PERIODIC_RATE); + } + +#ifndef NXD_MQTT_CLOUD_ENABLE + /* Now we can delete the Client instance. */ + tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); +#else + /* Deregister mqtt module from cloud helper. */ + nx_cloud_module_deregister(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module)); + + /* Delete own created cloud. */ + if (client_ptr -> nxd_mqtt_client_cloud.nx_cloud_id == NX_CLOUD_ID) + nx_cloud_delete(&(client_ptr -> nxd_mqtt_client_cloud)); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + + return(NXD_MQTT_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_publish_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a publish packet to the connected broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* packet_ptr Pointer to publish packet */ +/* packet_id Current packet ID */ +/* QoS Quality of service */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* nx_tcp_socket_send */ +/* nx_secure_tls_session_send */ +/* nx_packet_release */ +/* _nxd_mqtt_copy_transmit_packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_publish */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, + USHORT packet_id, UINT QoS, ULONG wait_option) +{ + +UINT status; +UINT ret = NXD_MQTT_SUCCESS; + + if (QoS != 0) + { + /* This packet needs to be stored locally for possible retransmission. */ + NX_PACKET *transmit_packet_ptr; + + /* Copy packet for retransmission. */ + if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, + packet_id, NX_TRUE, wait_option)) + { + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + nx_packet_release(transmit_packet_ptr); + return(NXD_MQTT_MUTEX_FAILURE); + } + + if (client_ptr -> message_transmit_queue_head == NX_NULL) + { + client_ptr -> message_transmit_queue_head = transmit_packet_ptr; + } + else + { + client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; + } + client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; + } + else + { + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + } + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + /* Ready to send the connect message to the server. */ +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + } +#else + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); + +#endif /* NX_SECURE_ENABLE */ + + if (status) + { + ret = NXD_MQTT_COMMUNICATION_FAILURE; + } + + return(ret); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_publish PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function publishes a message to the connected broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Name of the topic */ +/* topic_name_length Length of the topic name */ +/* message Message string */ +/* message_length Length of the message, */ +/* in bytes */ +/* retain The retain flag, whether */ +/* or not the broker should */ +/* store this message */ +/* QoS Expected QoS level */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* _nxd_mqtt_packet_allocate */ +/* _nxd_mqtt_client_set_fixed_header */ +/* _nxd_mqtt_client_append_message */ +/* tx_mutex_put */ +/* nx_packet_release */ +/* _nxd_mqtt_client_publish_packet_send */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, + CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG wait_option) +{ + +NX_PACKET *packet_ptr; +UINT status; +UINT length = 0; +UCHAR flags; +USHORT packet_id = 0; +UINT ret = NXD_MQTT_SUCCESS; + + if (QoS == 2) + { + return(NXD_MQTT_QOS2_NOT_SUPPORTED); + } + + + /* Do nothing if the client is already connected. */ + if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED) + { + return(NXD_MQTT_NOT_CONNECTED); + } + + status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); + + if (status != NXD_MQTT_SUCCESS) + { + return(NXD_MQTT_PACKET_POOL_FAILURE); + } + + flags = (UCHAR)((MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4) | (QoS << 1)); + + if (retain) + { + flags = flags | MQTT_PUBLISH_RETAIN; + } + + + /* Compute the remaining length. */ + + /* Topic Name. */ + /* Compute Topic Name length. */ + length = topic_name_length + 2; + + /* Count packet ID for QoS 1 or QoS 2 message. */ + if ((QoS == 1) || (QoS == 2)) + { + length += 2; + } + + /* Count message. */ + if ((message != NX_NULL) && (message_length != 0)) + { + length += message_length; + } + + /* Write out the control header and remaining length field. */ + ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, flags, length, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_INTERNAL_ERROR); + } + + + /* Write out topic */ + ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, topic_name, topic_name_length, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Append Packet Identifier for QoS level 1 or 2 MQTT 3.3.2.2 */ + if ((QoS == 1) || (QoS == 2)) + { + UCHAR identifier[2]; + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + if (status != TX_SUCCESS) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + + packet_id = (USHORT)client_ptr -> nxd_mqtt_client_packet_identifier; + identifier[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8); + identifier[1] = (client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF); + + /* Update packet id. */ + client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF; + + /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ + if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) + client_ptr -> nxd_mqtt_client_packet_identifier = 1; + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + ret = nx_packet_data_append(packet_ptr, identifier, 2, + client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_INTERNAL_ERROR); + } + } + + /* Append message. */ + if ((message != NX_NULL) && (message_length) != 0) + { + + /* Use nx_packet_data_append to move user-supplied message data into the packet. + nx_packet_data_append uses chained packet if the additional storage space is + needed. */ + ret = nx_packet_data_append(packet_ptr, message, message_length, + client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); + if(ret) + { + /* Unable to obtain a new packet to store the message. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return(NXD_MQTT_INTERNAL_ERROR); + } + } + + /* Send publish packet. */ + ret = _nxd_mqtt_client_publish_packet_send(client_ptr, packet_ptr, packet_id, QoS, wait_option); + + if (ret) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + return(ret); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_subscribe PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a subscribe message to the broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Pointer to the topic string */ +/* to subscribe to */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* QoS Expected QoS level */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_sub_unsub The actual routine that */ +/* performs the sub/unsub */ +/* action. */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS) +{ + + if (QoS == 2) + { + return(NXD_MQTT_QOS2_NOT_SUPPORTED); + } + + return(_nxd_mqtt_client_sub_unsub(client_ptr, (MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02, + topic_name, topic_name_length, QoS)); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_unsubscribe PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unsubscribes a topic from the broker. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Pointer to the topic string */ +/* to subscribe to */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_sub_unsub */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length) +{ + return(_nxd_mqtt_client_sub_unsub(client_ptr, (MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE << 4) | 0x02, + topic_name, topic_name_length, 0)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_send_simple_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function handles the transmission of PINGREQ or */ +/* DISCONNECT message. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* header_value Value to be programmed into */ +/* MQTT header. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* _nxd_mqtt_packet_allocate */ +/* tx_mutex_put */ +/* nx_tcp_socket_send */ +/* nx_secure_tls_session_send */ +/* nx_packet_release */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_mqtt_client_ping */ +/* _nxd_mqtt_client_disconnect */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nxd_mqtt_send_simple_message(NXD_MQTT_CLIENT *client_ptr, UCHAR header_value) +{ + +NX_PACKET *packet_ptr; +UINT status; +UINT status_mutex; +UCHAR *byte; + + status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); + if (status) + { + return(NXD_MQTT_INTERNAL_ERROR); + } + + if (2u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) + { + nx_packet_release(packet_ptr); + + /* Packet buffer is too small to hold the message. */ + return(NX_SIZE_ERROR); + } + + byte = packet_ptr -> nx_packet_prepend_ptr; + + *byte = (UCHAR)(header_value << 4); + *(byte + 1) = 0; + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = 2; + + + /* Release MQTT protection before making NetX/TLS calls. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); +#ifdef NX_SECURE_ENABLE + if (client_ptr -> nxd_mqtt_client_use_tls) + { + status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); + } + else + { + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); + } +#else + + status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); + +#endif /* NX_SECURE_ENABLE */ + + status_mutex = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + status = NXD_MQTT_COMMUNICATION_FAILURE; + } + if (status_mutex) + { + return(NXD_MQTT_MUTEX_FAILURE); + } + + if (header_value == MQTT_CONTROL_PACKET_TYPE_PINGREQ) + { + /* Do not update the ping sent time if the outstanding ping has not been responded yet */ + if (client_ptr -> nxd_mqtt_ping_not_responded != 1) + { + /* Record the time we send out the PINGREG */ + client_ptr -> nxd_mqtt_ping_sent_time = tx_time_get(); + client_ptr -> nxd_mqtt_ping_not_responded = 1; + } + } + + /* Update the timeout value. */ + client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disconnects the MQTT client from a server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_send_simple_message */ +/* _nxd_mqtt_process_disconnect */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr) +{ +UINT status; + + /* Obtain the mutex. */ + status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); + if (status != TX_SUCCESS) + { + /* Disable timer if timer has been started. */ + if (client_ptr -> nxd_mqtt_keepalive) + { + tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); + } + + return(NXD_MQTT_MUTEX_FAILURE); + } + + /* Let the server know we are ending the MQTT session. */ + _nxd_mqtt_send_simple_message(client_ptr, MQTT_CONTROL_PACKET_TYPE_DISCONNECT); + + /* Call the disconnect routine to disconnect the socket, + release transmit packets, release received packets, + and delete the client timer. */ + _nxd_mqtt_process_disconnect(client_ptr); + + /* Release the mutex. */ + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_receive_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function installs the MQTT client publish notify callback */ +/* function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* mqtt_client_receive_notify User-supplied callback */ +/* function, which is invoked */ +/* upon receiving a publish */ +/* message. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, + VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)) +{ + + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + + client_ptr -> nxd_mqtt_client_receive_notify = receive_notify; + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + + return(NXD_MQTT_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_message_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves a published MQTT message. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_buffer Pointer to the topic buffer */ +/* where topic is copied to */ +/* topic_buffer_size Size of the topic buffer. */ +/* actual_topic_length Number of bytes copied into */ +/* topic_buffer */ +/* message_buffer Pointer to the buffer where */ +/* message is copied to */ +/* message_buffer_size Size of the message_buffer */ +/* actual_message_length Number of bytes copied into */ +/* the message buffer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_disconnect Actual MQTT Client disconnect */ +/* call */ +/* _nxd_mqtt_read_remaining_length Skip the remaining length */ +/* field */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, + UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG topic_offset; +USHORT topic_length; +ULONG message_offset; +ULONG message_length; + + tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); + while (client_ptr -> message_receive_queue_depth) + { + packet_ptr = client_ptr -> message_receive_queue_head; + status = _nxd_mqtt_process_publish_packet(packet_ptr, &topic_offset, &topic_length, &message_offset, &message_length); + if (status == NXD_MQTT_SUCCESS) + { + if ((topic_buffer_size < topic_length) || + (message_buffer_size < message_length)) + { + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_INSUFFICIENT_BUFFER_SPACE); + } + } + + client_ptr -> message_receive_queue_head = packet_ptr -> nx_packet_queue_next; + if (client_ptr -> message_receive_queue_tail == packet_ptr) + { + client_ptr -> message_receive_queue_tail = NX_NULL; + } + client_ptr -> message_receive_queue_depth--; + + if (status == NXD_MQTT_SUCCESS) + { + nx_packet_data_extract_offset(packet_ptr, topic_offset, topic_buffer, + topic_length, (ULONG *)actual_topic_length); + nx_packet_data_extract_offset(packet_ptr, message_offset, message_buffer, + message_length, (ULONG *)actual_message_length); + nx_packet_release(packet_ptr); + + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_SUCCESS); + } + nx_packet_release(packet_ptr); + } + tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); + return(NXD_MQTT_NO_MESSAGE); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in nxd_mqt_client_create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* client_name Name string used in by the */ +/* client */ +/* client_id Client ID used by the client */ +/* client_id_length Length of Client ID, in bytes */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* stack_ptr Client thread's stack pointer */ +/* stack_size Client thread's stack size */ +/* mqtt_thread_priority Priority for MQTT thread */ +/* memory_ptr Deprecated and not used */ +/* memory_size Deprecated and not used */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, + VOID *memory_ptr, ULONG memory_size) +{ + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (stack_ptr == NX_NULL) || (stack_size == 0) || (pool_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + return(_nxd_mqtt_client_create(client_ptr, client_name, client_id, client_id_length, ip_ptr, + pool_ptr, stack_ptr, stack_size, mqtt_thread_priority, + memory_ptr, memory_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* server_ip Server IP address structure */ +/* server_port Server port number, in host */ +/* byte order */ +/* keepalive The MQTT keepalive timer */ +/* clean_session Clean session flag */ +/* wait_option Suspension option */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_connect Actual MQTT Client connect */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT keepalive, UINT clean_session, ULONG wait_option) +{ + +UINT status; + + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (server_ip == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Test for IP version flag. */ + if ((server_ip -> nxd_ip_version != 4) && (server_ip -> nxd_ip_version != 6)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + if (server_port == 0) + { + return(NX_INVALID_PORT); + } + + + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_INITIALIZE) + { + return(NXD_MQTT_CLIENT_NOT_RUNNING); + } + + status = _nxd_mqtt_client_connect(client_ptr, server_ip, server_port, keepalive, clean_session, wait_option); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_secure_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client TLS secure connect. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* server_ip Server IP address structure */ +/* server_port Server port number, in host */ +/* byte order */ +/* tls_setup User-supplied callback */ +/* function to set up TLS */ +/* parameters. */ +/* keepalive The MQTT keepalive timer */ +/* wait_option Suspension option */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_connect Actual MQTT Client connect */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifdef NX_SECURE_ENABLE + +UINT _nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, + NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), + UINT keepalive, UINT clean_session, ULONG wait_option) +{ + +UINT status; + + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (server_ip == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (server_port == 0) + { + return(NX_INVALID_PORT); + } + + if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_INITIALIZE) + { + return(NXD_MQTT_CLIENT_NOT_RUNNING); + } + + status = _nxd_mqtt_client_secure_connect(client_ptr, server_ip, server_port, tls_setup, + keepalive, clean_session, wait_option); + + return(status); +} +#endif /* NX_SECURE_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_delete Actual MQTT Client delete */ +/* call. */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr) +{ + +UINT status; + + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + status = _nxd_mqtt_client_delete(client_ptr); + + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_publish PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking to the publish service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Name of the topic */ +/* topic_name_length Length of the topic name */ +/* message Message string */ +/* message_length Length of the message, */ +/* in bytes */ +/* retain The retain flag, whether */ +/* or not the broker should */ +/* store this message */ +/* QoS Expected QoS level */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, + CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG wait_option) +{ + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Validate topic_name */ + if ((topic_name == NX_NULL) || (topic_name_length == 0)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + /* Validate message length. */ + if (message && (message_length == 0)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + /* Validate QoS value. */ + if (QoS > 3) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + return(_nxd_mqtt_client_publish(client_ptr, topic_name, topic_name_length, message, message_length, retain, QoS, wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_subscribe PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking to the subscribe service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Pointer to the topic string */ +/* to subscribe to */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* */ +/* OUTPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Pointer to the topic string */ +/* to subscribe to */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* QoS Expected QoS level */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_subscribe */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS) +{ + + + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Validate topic_name */ + if ((topic_name == NX_NULL) || (topic_name_length == 0)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + /* Validate QoS value. */ + if (QoS > 2) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + return(_nxd_mqtt_client_subscribe(client_ptr, topic_name, topic_name_length, QoS)); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_unsubscribe PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking to the unsubscribe service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_name Pointer to the topic string */ +/* to unsubscribe */ +/* topic_name_length Length of the topic string */ +/* in bytes */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length) +{ + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Validate topic_name */ + if ((topic_name == NX_NULL) || (topic_name_length == 0)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + return(_nxd_mqtt_client_unsubscribe(client_ptr, topic_name, topic_name_length)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client disconnect call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_disconnect Actual MQTT Client disconnect */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr) +{ + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + return(_nxd_mqtt_client_disconnect(client_ptr)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_message_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client message get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* topic_buffer Pointer to the topic buffer */ +/* where topic is copied to */ +/* topic_buffer_size Size of the topic buffer. */ +/* actual_topic_length Number of bytes copied into */ +/* topic_buffer */ +/* message_buffer Pointer to the buffer where */ +/* message is copied to */ +/* message_buffer_size Size of the message_buffer */ +/* actual_message_length Number of bytes copied into */ +/* the message buffer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_message_get */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, + UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length) +{ + + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Topic and topic_length can be NULL if caller does not care the topic string. */ + + /* Validate message. Message_length can be NULL if caller does not care message length. */ + if ((message_buffer == NX_NULL) || (topic_buffer == NX_NULL)) + { + return(NXD_MQTT_INVALID_PARAMETER); + } + + + return(_nxd_mqtt_client_message_get(client_ptr, topic_buffer, topic_buffer_size, actual_topic_length, + message_buffer, message_buffer_size, actual_message_length)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_receive_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in MQTT client publish notify call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* receive_notify User-supplied callback */ +/* function, which is invoked */ +/* upon receiving a publish */ +/* message. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_receive_notify_set */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, + VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)) +{ + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (receive_notify == NX_NULL) + { + return(NX_PTR_ERROR); + } + + return(_nxd_mqtt_client_receive_notify_set(client_ptr, receive_notify)); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_disconnect_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the notify function for the disconnect event. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* disconnect_notify The notify function to be */ +/* used when the client is */ +/* disconnected from the */ +/* server. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)) +{ + + client_ptr -> nxd_mqtt_disconnect_notify = disconnect_notify; + + return(NXD_MQTT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_mqtt_client_disconnect_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in setting MQTT client disconnect */ +/* callback function. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* disconnect_callback The callback function to be */ +/* used when an on-going */ +/* connection is disconnected. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_disconnect_notify_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)) +{ + + /* Validate client_ptr */ + if (client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + return(_nxd_mqtt_client_disconnect_notify_set(client_ptr, disconnect_notify)); +} + + +#ifdef NXD_MQTT_CLOUD_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_mqtt_client_cloud_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates mqtt client running on cloud helper thread. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to MQTT Client */ +/* client_name Name string used in by the */ +/* client */ +/* client_id Client ID used by the client */ +/* client_id_length Length of Client ID, in bytes */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* cloud_ptr Pointer to Cloud instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_mqtt_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_mqtt_client_cloud_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_CLOUD *cloud_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (pool_ptr == NX_NULL) || (cloud_ptr == NX_NULL) || (cloud_ptr -> nx_cloud_id != NX_CLOUD_ID)) + { + return(NX_PTR_ERROR); + } + + /* Create MQTT client. */ + status = _nxd_mqtt_client_create_internal(client_ptr, client_name, client_id, client_id_length, ip_ptr, + pool_ptr, NX_NULL, 0, 0); + + /* Check status. */ + if (status) + { + return(status); + } + + /* Save the cloud pointer. */ + client_ptr -> nxd_mqtt_client_cloud_ptr = cloud_ptr; + + /* Save the mutex pointer. */ + client_ptr -> nxd_mqtt_client_mutex_ptr = &(cloud_ptr -> nx_cloud_mutex); + + /* Register MQTT on cloud helper. */ + status = nx_cloud_module_register(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module), client_name, NX_CLOUD_MODULE_MQTT_EVENT, + _nxd_mqtt_client_event_process, client_ptr); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ + + /* Delete socket. */ + nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); + + return(NXD_MQTT_INTERNAL_ERROR); + } + + /* Set start event to start MQTT. */ + nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_START_EVENT); + + return(NXD_MQTT_SUCCESS); +} +#endif /* NXD_MQTT_CLOUD_ENABLE */ diff --git a/addons/mqtt/nxd_mqtt_client.h b/addons/mqtt/nxd_mqtt_client.h new file mode 100644 index 00000000..f9be3d0b --- /dev/null +++ b/addons/mqtt/nxd_mqtt_client.h @@ -0,0 +1,510 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** MQTT (MQTT) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_mqtt_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX MQTT Client component, including all */ +/* data types and external references. It is assumed that nx_api.h */ +/* and nx_port.h have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef _NXD_MQTT_CLIENT_H_ +#define _NXD_MQTT_CLIENT_H_ + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#ifdef NX_SECURE_ENABLE +#include "nx_secure_tls_api.h" +#endif /* NX_SECURE_ENABLE */ + +#ifdef NXD_MQTT_CLOUD_ENABLE +#include "nx_cloud.h" +#endif /* NXD_MQTT_CLOUD_ENABLE */ + +#ifdef NXD_MQTT_REQUIRE_TLS +#ifndef NX_SECURE_ENABLE +#error "The feature NXD_MQTT_REQUIRE_TLS requires NX_SECURE_ENABLE." +#endif /* NX_SECURE_ENABLE */ +#endif /* NXD_MQTT_REQUIRE_TLS */ + +/* Define memcpy, memset and memcmp functions used internal. */ +#ifndef NXD_MQTT_SECURE_MEMCPY +#define NXD_MQTT_SECURE_MEMCPY memcpy +#endif /* NXD_MQTT_SECURE_MEMCPY */ + +#ifndef NXD_MQTT_SECURE_MEMCMP +#define NXD_MQTT_SECURE_MEMCMP memcmp +#endif /* NXD_MQTT_SECURE_MEMCMP */ + +#ifndef NXD_MQTT_SECURE_MEMSET +#define NXD_MQTT_SECURE_MEMSET memset +#endif /* NXD_SECURE_MEMSET */ + +#ifndef NXD_MQTT_SECURE_MEMMOVE +#define NXD_MQTT_SECURE_MEMMOVE memmove +#endif /* NXD_MQTT_SECURE_MEMMOVE */ + +/* Define the default MQTT Non-TLS (Non-secure) port number */ +#define NXD_MQTT_PORT 1883 + + +/* Define the default TCP socket window size. */ +#ifndef NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE +#define NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE 8192 +#endif /* NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE */ + +/* Define the default MQTT Thread time slice. */ +#ifndef NXD_MQTT_CLIENT_THREAD_TIME_SLICE +#define NXD_MQTT_CLIENT_THREAD_TIME_SLICE 2 +#endif + +/* Set the default timer rate for the keepalive timer, in ThreadX timer ticks. + THe default is one second. */ +#ifndef NXD_MQTT_KEEPALIVE_TIMER_RATE +#define NXD_MQTT_KEEPALIVE_TIMER_RATE (NX_IP_PERIODIC_RATE) +#endif + +/* Set the default timeout for PING response. */ +/* After sending out the MQTT Ping Request, if the client does not receive Ping Response within this + time, the client shall disconnect from the server. The default is one second. */ +#ifndef NXD_MQTT_PING_TIMEOUT_DELAY +#define NXD_MQTT_PING_TIMEOUT_DELAY (NX_IP_PERIODIC_RATE) +#endif + + +/* Deprecated. This symbol is defined for compatibility. */ +#ifndef NXD_MQTT_MAX_TOPIC_NAME_LENGTH +#define NXD_MQTT_MAX_TOPIC_NAME_LENGTH 12 +#endif + +/* Deprecated. This symbol is defined for compatibility. */ +#ifndef NXD_MQTT_MAX_MESSAGE_LENGTH +#define NXD_MQTT_MAX_MESSAGE_LENGTH 32 +#endif + +#ifndef NXD_MQTT_INITIAL_PACKET_ID_VALUE +#define NXD_MQTT_INITIAL_PACKET_ID_VALUE 1 +#endif + +/* Set a timeout for socket operations (send, receive, disconnect). */ +#ifndef NXD_MQTT_SOCKET_TIMEOUT +#define NXD_MQTT_SOCKET_TIMEOUT NX_WAIT_FOREVER +#endif + +/* Define the default MQTT TLS (secure) port number */ +#define NXD_MQTT_TLS_PORT 8883 + + +#define MQTT_PROTOCOL_LEVEL 4 + +/* Define bit fields and constant values used in the CONNECT packet. */ +#define MQTT_CONNECT_FLAGS_USERNAME (1 << 7) +#define MQTT_CONNECT_FLAGS_PASSWORD (1 << 6) +#define MQTT_CONNECT_FLAGS_WILL_RETAIN (1 << 5) +#define MQTT_CONNECT_FLAGS_WILL_QOS_0 0 +#define MQTT_CONNECT_FLAGS_WILL_QOS_1 (1 << 3) +#define MQTT_CONNECT_FLAGS_WILL_QOS_2 (2 << 3) +#define MQTT_CONNECT_FLAGS_WILL_FLAG (1 << 2) +#define MQTT_CONNECT_FLAGS_CLEAN_SESSION (1 << 1) +#define MQTT_CONNECT_FLAGS_WILL_QOS_FIELD (3 << 3) + +/* Define bit fields and constant values used in the CONNACK packet. */ +#define MQTT_CONNACK_CONNECT_FLAGS_SP (1) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_ACCEPTED (0) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_UNACCEPTABLE_PROTOCOL_VERSION (1) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_IDENTIFIER_REJECTED (2) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_SERVER_UNAVAILABLE (3) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_BAD_USERNAME_PASSWORD (4) +#define MQTT_CONNACK_CONNECT_RETURN_CODE_NOT_AUTHORIZED (5) + +/* Define bit fields and constant values used in the PUBLISH packet. */ +#define MQTT_PUBLISH_DUP_FLAG (1 << 3) +#define MQTT_PUBLISH_QOS_LEVEL_0 (0) +#define MQTT_PUBLISH_QOS_LEVEL_1 (1 << 1) +#define MQTT_PUBLISH_QOS_LEVEL_2 (2 << 1) +#define MQTT_PUBLISH_QOS_LEVEL_FIELD (3 << 1) +#define MQTT_PUBLISH_RETAIN (1) + +#define MQTT_CONTROL_PACKET_TYPE_FIELD 0xF0 + +#define MQTT_FIXED_HEADER_SIZE 2 + + +#define MQTT_CONTROL_PACKET_TYPE_CONNECT (1) +#define MQTT_CONTROL_PACKET_TYPE_CONNACK (2) +#define MQTT_CONTROL_PACKET_TYPE_PUBLISH (3) +#define MQTT_CONTROL_PACKET_TYPE_PUBACK (4) +#define MQTT_CONTROL_PACKET_TYPE_PUBREC (5) +#define MQTT_CONTROL_PACKET_TYPE_PUBREL (6) +#define MQTT_CONTROL_PACKET_TYPE_PUBCOMP (7) +#define MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE (8) +#define MQTT_CONTROL_PACKET_TYPE_SUBACK (9) +#define MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE (10) +#define MQTT_CONTROL_PACKET_TYPE_UNSUBACK (11) +#define MQTT_CONTROL_PACKET_TYPE_PINGREQ (12) +#define MQTT_CONTROL_PACKET_TYPE_PINGRESP (13) +#define MQTT_CONTROL_PACKET_TYPE_DISCONNECT (14) +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ + + +typedef struct MQTT_PACKET_CONNACK_STRUCT +{ + + UCHAR mqtt_connack_packet_header; + UCHAR mqtt_connack_packet_remaining_length; + UCHAR mqtt_connack_packet_ack_flags; + UCHAR mqtt_connack_packet_return_code; +} MQTT_PACKET_CONNACK; + +typedef struct MQTT_PACKET_PUBLISH_STRUCT +{ + UCHAR mqtt_publish_packet_header; + UCHAR mqtt_publish_packet_remaining_length; +} MQTT_PACKET_PUBLISH; + +typedef struct MQTT_PACKET_PUBLISH_RESPONSE_STRUCT +{ + UCHAR mqtt_publish_response_packet_header; + UCHAR mqtt_publish_response_packet_remaining_length; + UCHAR mqtt_publish_response_packet_packet_identifier_msb; + UCHAR mqtt_publish_response_packet_packet_identifier_lsb; +} MQTT_PACKET_PUBLISH_RESPONSE; + + +typedef struct MQTT_PACKET_SUBSCRIBE_STRUCT +{ + UCHAR mqtt_subscribe_packet_header; + UCHAR mqtt_subscribe_packet_remaining_length; + UCHAR mqtt_subscribe_packet_packet_identifier_msb; + UCHAR mqtt_subscribe_packet_packet_identifier_lsb; +} MQTT_PACKET_SUBSCRIBE; + +typedef struct MQTT_PACKET_PING_STRUCT +{ + UCHAR mqtt_ping_packet_header; + UCHAR mqtt_ping_packet_remaining_length; +} MQTT_PACKET_PING; + +typedef struct MQTT_PACKET_DISCONNECT_STRUCT +{ + UCHAR mqtt_disconnect_packet_header; + UCHAR mqtt_disconnect_packet_remaining_length; +} MQTT_PACKET_DISCONNECT; + + +/* Define the NetX MQTT CLIENT ID. */ +#define NXD_MQTT_CLIENT_ID 0x4D515454 + +/* Define the default MQTT Non-TLS (Non-secure) port number */ +#define NXD_MQTT_CLIENT_NONTLS_PORT 1883 + +/* Define the default MQTT TLS (secure) port number */ +#define NXD_MQTT_CLIENT_TLS_PORT 8883 + + +#define NXD_MQTT_CLIENT_STATE_INITIALIZE 0 +#define NXD_MQTT_CLIENT_STATE_IDLE 1 +#define NXD_MQTT_CLIENT_STATE_CONNECTING 2 +#define NXD_MQTT_CLIENT_STATE_CONNECTED 3 + + +#define NXD_MQTT_SUCCESS 0x0 +#define NXD_MQTT_ALREADY_CONNECTED 0x10001 +#define NXD_MQTT_NOT_CONNECTED 0x10002 +#define NXD_MQTT_MUTEX_FAILURE 0x10003 +#define NXD_MQTT_INTERNAL_ERROR 0x10004 +#define NXD_MQTT_CONNECT_FAILURE 0x10005 +#define NXD_MQTT_PACKET_POOL_FAILURE 0x10006 +#define NXD_MQTT_COMMUNICATION_FAILURE 0x10007 +#define NXD_MQTT_SERVER_MESSAGE_FAILURE 0x10008 +#define NXD_MQTT_INVALID_PARAMETER 0x10009 +#define NXD_MQTT_NO_MESSAGE 0x1000A +#define NXD_MQTT_PACKET_POOL_EMPTY 0x1000B +#define NXD_MQTT_QOS2_NOT_SUPPORTED 0x1000C +#define NXD_MQTT_INSUFFICIENT_BUFFER_SPACE 0x1000D +#define NXD_MQTT_CLIENT_NOT_RUNNING 0x1000E +#define NXD_MQTT_INVALID_PACKET 0x1000F +#define NXD_MQTT_PARTIAL_PACKET 0x10010 + +/* The following error codes match the Connect Return code in CONNACK message. */ +#define NXD_MQTT_ERROR_CONNECT_RETURN_CODE 0x10080 +#define NXD_MQTT_ERROR_UNACCEPTABLE_PROTOCOL 0x10081 +#define NXD_MQTT_ERROR_IDENTIFYIER_REJECTED 0x10082 +#define NXD_MQTT_ERROR_SERVER_UNAVAILABLE 0x10083 +#define NXD_MQTT_ERROR_BAD_USERNAME_PASSWORD 0x10084 +#define NXD_MQTT_ERROR_NOT_AUTHORIZED 0x10085 + + +/* Define the basic MQTT Client control block. */ +typedef struct NXD_MQTT_CLIENT_STRUCT +{ + CHAR *nxd_mqtt_client_name; + CHAR *nxd_mqtt_client_id; + UINT nxd_mqtt_client_id_length; + CHAR *nxd_mqtt_client_username; + USHORT nxd_mqtt_client_username_length; + CHAR *nxd_mqtt_client_password; + USHORT nxd_mqtt_client_password_length; + UCHAR nxd_mqtt_client_will_qos_retain; + const UCHAR *nxd_mqtt_client_will_topic; + UINT nxd_mqtt_client_will_topic_length; + const UCHAR *nxd_mqtt_client_will_message; + UINT nxd_mqtt_client_will_message_length; + NX_IP *nxd_mqtt_client_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nxd_mqtt_client_packet_pool_ptr; /* Pointer to client packet pool */ + TX_MUTEX *nxd_mqtt_client_mutex_ptr; /* Pointer to client mutex */ + TX_TIMER nxd_mqtt_timer; +#ifndef NXD_MQTT_CLOUD_ENABLE + TX_MUTEX nxd_mqtt_protection; + TX_THREAD nxd_mqtt_thread; + TX_EVENT_FLAGS_GROUP nxd_mqtt_events; +#else + NX_CLOUD *nxd_mqtt_client_cloud_ptr; /* Pointer to associated CLOUD structure. */ + NX_CLOUD nxd_mqtt_client_cloud; /* MQTT cloud. */ + NX_CLOUD_MODULE nxd_mqtt_client_cloud_module; /* Define mqtt module that running on cloud helper thread. */ +#endif /* NXD_MQTT_CLOUD_ENABLE */ + UINT nxd_mqtt_ping_timeout; + UINT nxd_mqtt_ping_not_responded; /* Flag indicating the ping has been responded or not. */ + UINT nxd_mqtt_ping_sent_time; /* TX Timer tick when the ping message was sent. */ + UINT nxd_mqtt_timeout; /* TX Timer tick when the next timeout happens. */ + UINT nxd_mqtt_timer_value; /* MQTT Client periodic timer tick value. */ + UINT nxd_mqtt_keepalive; /* Keepalive value, converted to TX ticks. */ + UINT nxd_mqtt_clean_session; /* Clean session flag. */ + UINT nxd_mqtt_client_state; /* Record client state */ + NX_TCP_SOCKET nxd_mqtt_client_socket; + struct NXD_MQTT_CLIENT_STRUCT *nxd_mqtt_client_next; + UINT nxd_mqtt_client_packet_identifier; + NX_PACKET *nxd_mqtt_client_processing_packet; + NX_PACKET *message_transmit_queue_head; + NX_PACKET *message_transmit_queue_tail; + NX_PACKET *message_receive_queue_head; + NX_PACKET *message_receive_queue_tail; + UINT message_receive_queue_depth; + VOID (*nxd_mqtt_client_receive_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, UINT number_of_messages); + VOID (*nxd_mqtt_connect_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, UINT status, VOID *context); + VOID *nxd_mqtt_connect_context; + VOID (*nxd_mqtt_disconnect_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr); + UINT (*nxd_mqtt_packet_receive_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, NX_PACKET *packet_ptr, VOID *context); + VOID *nxd_mqtt_packet_receive_context; +#ifdef NX_SECURE_ENABLE + UINT nxd_mqtt_client_use_tls; + UINT (*nxd_mqtt_tls_setup)(struct NXD_MQTT_CLIENT_STRUCT *, NX_SECURE_TLS_SESSION *, + NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *); + NX_SECURE_X509_CERT nxd_mqtt_tls_certificate; + NX_SECURE_X509_CERT nxd_mqtt_tls_trusted_certificate; + NX_SECURE_TLS_SESSION nxd_mqtt_tls_session; + UINT nxd_mqtt_tls_in_progress; +#endif +} NXD_MQTT_CLIENT; + + + +#ifndef NXD_MQTT_CLIENT_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +#define nxd_mqtt_client_create _nxd_mqtt_client_create +#define nxd_mqtt_client_login_set _nxd_mqtt_client_login_set +#define nxd_mqtt_client_will_message_set _nxd_mqtt_client_will_message_set +#define nxd_mqtt_client_delete _nxd_mqtt_client_delete +#define nxd_mqtt_client_connect _nxd_mqtt_client_connect +#define nxd_mqtt_client_secure_connect _nxd_mqtt_client_secure_connect +#define nxd_mqtt_client_publish _nxd_mqtt_client_publish +#define nxd_mqtt_client_subscribe _nxd_mqtt_client_subscribe +#define nxd_mqtt_client_unsubscribe _nxd_mqtt_client_unsubscribe +#define nxd_mqtt_client_disconnect _nxd_mqtt_client_disconnect +#define nxd_mqtt_client_receive_notify_set _nxd_mqtt_client_receive_notify_set +#define nxd_mqtt_client_message_get _nxd_mqtt_client_message_get +#define nxd_mqtt_client_disconnect_notify_set _nxd_mqtt_client_disconnect_notify_set +#else /* if !NXD_MQTT_CLIENT_SOURCE_CODE */ + +#define nxd_mqtt_client_create _nxde_mqtt_client_create +#define nxd_mqtt_client_login_set _nxde_mqtt_client_login_set +#define nxd_mqtt_client_will_message_set _nxde_mqtt_client_will_message_set +#define nxd_mqtt_client_delete _nxde_mqtt_client_delete +#define nxd_mqtt_client_connect _nxde_mqtt_client_connect +#define nxd_mqtt_client_secure_connect _nxde_mqtt_client_secure_connect +#define nxd_mqtt_client_publish _nxde_mqtt_client_publish +#define nxd_mqtt_client_subscribe _nxde_mqtt_client_subscribe +#define nxd_mqtt_client_unsubscribe _nxde_mqtt_client_unsubscribe +#define nxd_mqtt_client_disconnect _nxde_mqtt_client_disconnect +#define nxd_mqtt_client_receive_notify_set _nxde_mqtt_client_receive_notify_set +#define nxd_mqtt_client_message_get _nxde_mqtt_client_message_get +#define nxd_mqtt_client_disconnect_notify_set _nxde_mqtt_client_disconnect_notify_set +#endif /* NX_DISABLE_ERROR_CHECKING */ + + +UINT nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, + VOID *memory_ptr, ULONG memory_size); + +UINT nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT keepalive, UINT clean_session, ULONG timeout); + +UINT nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, + CHAR *username, UINT username_length, CHAR *password, UINT password_length); + +UINT nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, + const UCHAR *will_topic, UINT will_topic_length, UCHAR *will_message, UINT will_message_length, + UINT will_retain_flag, UINT will_QoS); +#ifdef NX_SECURE_ENABLE +UINT nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), + UINT keepalive, UINT clean_session, ULONG timeout); +#endif /* NX_SECURE_ENABLE */ +UINT nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, CHAR *message, UINT message_length, + UINT retain, UINT QoS, ULONG timeout); +UINT nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *mqtt_client_pr, CHAR *topic_name, UINT topic_name_length, UINT QoS); +UINT nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *mqtt_client_pr, CHAR *topic_name, UINT topic_name_length); +UINT nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, + VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT number_of_messages)); +UINT nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, + UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); +UINT nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); + +UINT nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); +UINT nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); + +#else /* ifdef NXD_MQTT_CLIENT_SOURCE_CODE */ + +UINT _nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT keepalive, UINT clean_session, ULONG wait_option); +UINT _nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, + CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, + VOID *memory_ptr, ULONG memory_size); +UINT _nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); +UINT _nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); +UINT _nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); +UINT _nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, + CHAR *username, UINT username_length, CHAR *password, UINT password_length); +UINT _nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, + UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); +UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, + USHORT packet_id, UINT QoS, ULONG wait_option); +UINT _nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, + CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG timeout); +UINT _nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, + VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)); +UINT _nxd_mqtt_client_release_callback_set(NXD_MQTT_CLIENT *client_ptr, VOID (*memory_release_function)(CHAR *, UINT)); +UINT _nxd_mqtt_client_sub_unsub(NXD_MQTT_CLIENT *client_ptr, UINT op, + CHAR *topic_name, UINT topic_name_length, UINT QoS); +UINT _nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS); +UINT _nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length); +UINT _nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, + const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, + UINT will_message_length, UINT will_retain_flag, UINT will_QoS); +UINT _nxd_mqtt_read_remaining_length(NX_PACKET *packet_ptr, UINT *remaining_length, ULONG *offset_ptr); +UINT _nxd_mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, UCHAR control_header, UINT length, UINT wait_option); +UINT _nxd_mqtt_client_append_message(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, CHAR *message, UINT length, ULONG wait_option); +VOID _nxd_mqtt_client_connection_end(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); +UINT _nxd_mqtt_process_publish_packet(NX_PACKET *packet_ptr, ULONG *topic_offset_ptr, USHORT *topic_length_ptr, + ULONG *message_offset_ptr, ULONG *message_length_ptr); + +UINT _nxde_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT keepalive, UINT clean_session, ULONG timeout); +UINT _nxde_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, + VOID *memory_ptr, ULONG memory_size); +UINT _nxde_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); +UINT _nxde_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); +UINT _nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); +UINT _nxde_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, + CHAR *username, UINT username_length, CHAR *password, UINT password_length); +UINT _nxde_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, + UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); +UINT _nxde_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, + CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG timeout); +UINT _nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, + VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)); +UINT _nxde_mqtt_client_release_callback_set(NXD_MQTT_CLIENT *client_ptr, VOID (*release_callback)(CHAR *, UINT)); +UINT _nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS); +UINT _nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length); +UINT _nxde_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, + const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, + UINT will_message_length, UINT will_retain_flag, UINT will_QoS); + +#ifdef NX_SECURE_ENABLE +UINT _nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, + NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), + UINT keepalive, UINT clean_session, ULONG wait_option); +UINT _nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, + NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), + UINT keepalive, UINT clean_session, ULONG timeout); +#endif /* NX_SECURE_ENABLE */ + +#endif /* ifndef NXD_MQTT_CLIENT_SOURCE_CODE */ + +#ifdef NXD_MQTT_CLOUD_ENABLE +/* MQTT create function based on cloud helper. */ +UINT _nxd_mqtt_client_cloud_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, + CHAR *client_id, UINT client_id_length, + NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_CLOUD *cloud_ptr); +#endif /* NXD_MQTT_CLOUD_ENABLE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus +} +#endif + + +#endif /* NXD_MQTT_CLIENT_H */ + diff --git a/addons/nat/nx_nat.c b/addons/nat/nx_nat.c new file mode 100644 index 00000000..0013d157 --- /dev/null +++ b/addons/nat/nx_nat.c @@ -0,0 +1,4542 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** Network Address Translation Protocol (NAT) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +#define NX_NAT_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + + +#include "tx_api.h" +#include "tx_thread.h" +#include "nx_api.h" +#include "nx_nat.h" +#include "nx_udp.h" +#include "nx_tcp.h" +#include "nx_icmp.h" +#include "nx_packet.h" +#include "nx_system.h" + +#ifdef NX_NAT_ENABLE +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/* Define */ +NX_NAT_DEVICE *nat_server_ptr; + + +/* Define internal NAT services. */ + +static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process); +static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr); +static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr); +static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address); +static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address); +static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address); +static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, ULONG local_ip_address, ULONG peer_ip_address, + USHORT local_port, USHORT external_port, USHORT peer_port, ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr); +static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); +static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr, UCHAR direction, UINT skip_static_entries); +static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr); +static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg); +static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port); +static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port); +static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port); +static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port); +static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *destination_port); +static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create NAT service. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* ip_ptr Pointer to NAT IP instance */ +/* global_interface_index Index of global interface */ +/* dynamic_cache_memory Pointer to dynamic entry cache */ +/* dynamic_cache_size The size of dynamic entry cache */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_NAT_PARAM_ERROR Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_create Creates the NAT instance service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size) +{ + +UINT status; + + + /* Check for valid input pointers. */ + if ((!nat_ptr) || (!ip_ptr)) + { + + /* Return pointer error. */ + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + + /* Return pointer error. */ + return(NX_NAT_PARAM_ERROR); + } + + /* Check the interface index. */ + if (global_interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + /* Return pointer error. */ + return(NX_NAT_PARAM_ERROR); + } + + /* Make sure entry cache is 4-byte aligned. */ + if ((((UINT)dynamic_cache_memory & 0x3) != 0) || + ((dynamic_cache_size & 0x3) != 0)) + { + + /* Return error status. */ + return(NX_NAT_CACHE_ERROR); + } + + /* Check the cache size. */ + if (dynamic_cache_size < (NX_NAT_MIN_ENTRY_COUNT * sizeof (NX_NAT_TRANSLATION_ENTRY))) + { + + /* Return error status. */ + return(NX_NAT_CACHE_ERROR); + } + + /* Call the actual NAT create service. */ + status = _nx_nat_create(nat_ptr, ip_ptr, global_interface_index, dynamic_cache_memory, dynamic_cache_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the NetX NAT instance and various NAT */ +/* configuration options, it also creates the NAT mutex. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* ip_ptr Pointer to NAT IP instance */ +/* global_interface_index Index of global interface */ +/* dynamic_cache_memory Pointer to dynamic entry cache */ +/* dynamic_cache_size The size of dynamic entry cache */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion */ +/* NX_NAT_OVERLAPPING_SUBNET_ERROR Invalid NAT network interfaces */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_create Create NAT flag group mutex */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size) +{ + +UINT i; +UINT dynamic_entries; +NX_NAT_TRANSLATION_ENTRY *entry_ptr; + + + /* First clear memory for setting up the NAT server instance. */ + memset(nat_ptr, 0, sizeof(NX_NAT_DEVICE)); + + /* Bind the IP instance and related parameters. */ + nat_ptr -> nx_nat_ip_ptr = ip_ptr; + nat_ptr -> nx_nat_global_interface_index = (UCHAR)global_interface_index; + + /* Clear the entry cache. */ + memset((void *) dynamic_cache_memory, 0, dynamic_cache_size); + + /* Pickup starting address of the available entry list. */ + entry_ptr = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory; + + /* Determine how many NAT daynamic entries will fit in this cache area. */ + dynamic_entries = dynamic_cache_size / sizeof(NX_NAT_TRANSLATION_ENTRY); + + /* Initialize the pointers of available NAT entries. */ + for (i = 0; i < (dynamic_entries - 1); i++) + { + /* Setup each entry to point to the next entry. */ + entry_ptr -> next_entry_ptr = entry_ptr + 1; + entry_ptr ++; + } + + /* Setup the head pointers of the available and dynamic (active) lists in the NAT Device. */ + nat_ptr -> nx_nat_dynamic_available_entry_head = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory; + nat_ptr -> nx_nat_dynamic_active_entry_head = NX_NULL; + nat_ptr -> nx_nat_dynamic_available_entries = dynamic_entries; + nat_ptr -> nx_nat_dynamic_active_entries = 0; + nat_ptr -> nx_nat_static_active_entries = 0; + + /* Load the NAT ID field in the NAT control block. */ + nat_ptr -> nx_nat_id = NX_NAT_ID; + + /* Define a global NAT pointer. NetX forwards all packets to _nx_nat_process_packet if _nx_ip_packet_forward() is defined as such. + The latter service can only send the current NX_IP and NX_PACKET pointer, so _nx_nat_process_packet() + requries this global pointer. */ + /* Set the pointer of global variable NAT. */ + nat_server_ptr = nat_ptr; + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the delete NAT service. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_delete Deletes a NAT instance */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_delete(NX_NAT_DEVICE *nat_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual NAT delete service. */ + status = _nx_nat_delete(nat_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the specified NetX NAT instance. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server to delete */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_delete Delete NAT mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_delete(NX_NAT_DEVICE *nat_ptr) +{ + + /* Clear the NAT ID to make it invalid. */ + nat_ptr -> nx_nat_id = 0; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the resume NAT thread */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_enable Actual enable NAT server */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_enable(NX_NAT_DEVICE *nat_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) + return(NX_PTR_ERROR); + + /* Call the actual service. */ + status = _nx_nat_enable(nat_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the NAT server. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server to resume */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get IP mutex */ +/* tx_mutex_put Put IP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_enable(NX_NAT_DEVICE *nat_ptr) +{ + + + /* Get the IP mutex. */ + tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup the IP nat processing routine pointer for NAT services. */ + nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = _nx_nat_process_packet; + + /* Setup the IP nat free port check for NAT services. */ + nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_port_verify = _nx_nat_entry_port_verify; + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the disable NAT service. */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_enable Actual enable NAT server */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_disable(NX_NAT_DEVICE *nat_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) + return(NX_PTR_ERROR); + + /* Call the actual service. */ + status = _nx_nat_disable(nat_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the NAT server. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server to resume */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get IP mutex */ +/* tx_mutex_put Put IP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_disable(NX_NAT_DEVICE *nat_ptr) +{ + + /* Get the IP mutex. */ + tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Clear the IP nat processing routine pointer. */ + nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = NX_NULL; + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the NAT cache full notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_cache_notify_set Actual cache notify set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (!nat_ptr) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (nat_ptr -> nx_nat_id != NX_NAT_ID) + { + return(NX_NAT_PARAM_ERROR); + } + + /* Call actual NAT cache notify set function. */ + status = _nx_nat_cache_notify_set(nat_ptr, cache_full_notify_cb); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_cache_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the cache full notify function. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to nat instance */ +/* cache_full_notify Cache full notify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get IP mutex */ +/* tx_mutex_put Put IP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)) +{ + + + /* Get the IP mutex. */ + tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the cache notify. */ + nat_ptr -> nx_nat_cache_full_notify = cache_full_notify_cb; + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_inbound_entry_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create NAT translation */ +/* inbound entry service. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* entry_ptr Pointer to entry to add to table */ +/* local_ip_address Entry local IP address */ +/* external_port Entry external port */ +/* local_port Entry local port */ +/* protocol Entry network protocol */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_NAT_PARAM_ERROR Invalid non pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_inbound_entry_create Calls actual create entry service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, + ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (!entry_ptr)) + { + return (NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if ((!local_ip_address) || (!protocol)) + { + + /* Return ptr error. */ + return (NX_NAT_PARAM_ERROR); + } + + /* Call the actual service. */ + status = _nx_nat_inbound_entry_create(nat_ptr, entry_ptr, local_ip_address, external_port, local_port, protocol); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_inbound_entry_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a inbound NAT translation entry and adds it to */ +/* the NAT entry list. This is allows an external host to initiate */ +/* a session with a private host (typically a server). */ +/* */ +/* This entry can never expire. To remove the entry, use the */ +/* nx_nat_inbound_entry_delete() service. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* entry_ptr Pointer to entry to add to table */ +/* local_ip_address Entry local IP address */ +/* external_port Entry external port */ +/* local_port Entry local port */ +/* protocol Table entry network protocol */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get IP mutex */ +/* tx_mutex_put Put IP mutex */ +/* _nx_nat_entry_add Add entry to table linked list */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, + ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol) +{ + +UINT bound; + + /* Get the IP mutex. */ + tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check whether this port has been used by NAT entry. */ + bound = _nx_nat_entry_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port); + + /* Check the status. */ + if (bound == NX_TRUE) + { + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return error status. */ + return(NX_NAT_PORT_UNAVAILABLE); + } + + /* Check whether this port has been used by NetXDuo socket. */ + bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port); + + /* Check the status. */ + if (bound == NX_TRUE) + { + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return error status. */ + return(NX_NAT_PORT_UNAVAILABLE); + } + + /* Initialize the entry to NULL. */ + memset(entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); + + /* Assign the entry attributes. */ + entry_ptr -> local_ip_address = local_ip_address; + entry_ptr -> external_port = external_port; + entry_ptr -> local_port = local_port; + entry_ptr -> protocol = protocol; + + /* Set the transaction type. */ + entry_ptr -> translation_type = NX_NAT_STATIC_ENTRY; + + /* Add the entry to the table. */ + _nx_nat_entry_add(nat_ptr, entry_ptr); + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_nat_inbound_entry_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the delete NAT translation */ +/* inbound entry service. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* remove_entry_ptr Pointer to NAT translation entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_inbound_entry_delete Actual table entry delete service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_nat_inbound_entry_delete( NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (delete_entry_ptr == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Check the entry tranlation type. */ + if (delete_entry_ptr ->translation_type != NX_NAT_STATIC_ENTRY) + { + return(NX_NAT_ENTRY_TYPE_ERROR); + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual NAT entry delete service. */ + status = _nx_nat_inbound_entry_delete(nat_ptr, delete_entry_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_inbound_entry_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the specified static entry from the NAT */ +/* translation list. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* remove_entry_ptr Pointer to NAT translation entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr) +{ + +NX_NAT_TRANSLATION_ENTRY *entry_ptr; +NX_NAT_TRANSLATION_ENTRY *previous_ptr; +NX_NAT_TRANSLATION_ENTRY *next_entry_ptr; + + + /* Get the IP mutex. */ + tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Get a pointer to the start of the entries in the translation table. */ + entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + + /* Initialize the previous pointer. */ + previous_ptr = NX_NULL; + + /* We need to loop through the translation table again so we + can remove the entry to delete and connect the previous and + next entries around it. */ + while (entry_ptr) + { + + /* Set a pointer to the next entry in the table. */ + next_entry_ptr = entry_ptr -> next_entry_ptr; + + /* Is this the entry we want to delete? */ + if (entry_ptr == delete_entry_ptr) + { + + /* Yes; check if this is the first entry in the list). */ + if (previous_ptr) + { + + /* It is not, so link the previous entry around the entry we are deleting. */ + previous_ptr -> next_entry_ptr = next_entry_ptr; + } + else + { + + /* It is the first entry, so set the next pointer as the starting translation table entry. */ + nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr; + } + + /* Update the static active entry count. */ + nat_ptr -> nx_nat_static_active_entries --; + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* We're done here. */ + return NX_SUCCESS; + } + + /* We didn't delete the current entry, so now it is the previous entry. */ + previous_ptr = entry_ptr; + + /* Get the next entry in the table. */ + entry_ptr = next_entry_ptr; + } + + /* Release the IP mutex. */ + tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); + + /* Return error status. */ + return (NX_NAT_ENTRY_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives packets to forward from both public and */ +/* private networks on either side of NAT if IP forwarding is enabled */ +/* and this function is specified as the packet handler. It determines */ +/* packet direction (e.g. out to the public internet or inbound to a */ +/* host on the private network) and forwards it to the appropriate */ +/* handler. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* packet_ptr Pointer to packet to forward */ +/* packet_process The flag for packet processing */ +/* NX_TRUE or NX_FALSE */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Packet is consumed by NAT */ +/* NX_FALSE Packet is not consumed by NAT */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release the packet */ +/* _nx_ip_route_find Find the outgoing interface */ +/* _nx_nat_process_outbound_packet Forward packet to public Internet */ +/* _nx_nat_process_inbound_packet Forward packet to private host */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ipv4_packet_receive Netx forwards packet to NAT first */ +/* if forwarding is enabled. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process) +{ + +UINT status; +UINT protocol; +ULONG header_size = sizeof(NX_IPV4_HEADER); +UINT global_interface_index; +ULONG next_hop_address; +NX_IPV4_HEADER *ip_header_ptr; +NX_INTERFACE *interface_ptr; + + + /* Check the NAT's IP instance. */ + if (nat_server_ptr -> nx_nat_ip_ptr != ip_ptr) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Pickup the packet header. */ + ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; + + /* Determine what protocol the current IP datagram is. */ + protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; + + /* Check the protocol. */ + if ((protocol != NX_PROTOCOL_ICMP) && (protocol != NX_PROTOCOL_UDP) && (protocol != NX_PROTOCOL_TCP)) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + /* Check the next protocol. */ + if (protocol == NX_PROTOCOL_ICMP) + { + header_size += sizeof(NX_ICMP_HEADER); + } + else if (protocol == NX_PROTOCOL_UDP) + { + header_size += sizeof(NX_UDP_HEADER); + } + else + { + header_size += sizeof(NX_TCP_HEADER); + } + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < header_size) + { + +#ifndef NX_DISABLE_IP_INFO + /* Increment the IP invalid packet error. */ + ip_ptr -> nx_ip_invalid_packets++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* Return NX_TRUE to indicate this packet has been processed. */ + return (NX_TRUE); + } +#endif /* NX_DISABLE_RX_SIZE_CHECKING */ + + /* Set the packet interface pointer and NAT's global interface index. */ + interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; + global_interface_index = nat_server_ptr -> nx_nat_global_interface_index; + + /* Check if the direction of the translation is inbound. */ + if (interface_ptr == &(ip_ptr -> nx_ip_interface[global_interface_index])) + { + + /* Yes, this packet is received on NAT's external interface (an inbound packet). */ + + /* Check the destination ip address against NAT's external IP address. */ + if (ip_header_ptr -> nx_ip_header_destination_ip != interface_ptr -> nx_interface_ip_address) + { + + /* NAT cannot process this packet. Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Check if the caller wants NAT to process this packet. */ + if (packet_process == NX_TRUE) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Yes, so update the count. */ + nat_server_ptr -> forwarded_packets_received ++; +#endif + + /* Try to deliver the packet to the local host. */ + status = _nx_nat_process_inbound_packet(nat_server_ptr, packet_ptr); + + /* Check the status. */ + if (status == NX_NAT_PACKET_CONSUMED_FAILED) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + } + } + else + { + + /* Check the destination ip address. */ + if ( + + /* Check for zero address. */ + (ip_header_ptr -> nx_ip_header_destination_ip == 0) || + + /* Check for limited broadcast. */ + (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) || + + /* Check for multicast address*/ + ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) || + + /* Check for loopback address. */ + ((ip_header_ptr -> nx_ip_header_destination_ip >= NX_IP_LOOPBACK_FIRST) && + (ip_header_ptr -> nx_ip_header_destination_ip <= NX_IP_LOOPBACK_LAST))) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Clear the packet interface. */ + interface_ptr = NX_NULL; + + /* Find the suitable interface and next hop address according to the destination ip. */ + if(_nx_ip_route_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &interface_ptr, &next_hop_address) != NX_SUCCESS) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Check the NAT forward interface. */ + if (interface_ptr != &(ip_ptr -> nx_ip_interface[global_interface_index])) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Check for IP broadcast. */ + if(((ip_header_ptr -> nx_ip_header_destination_ip & interface_ptr -> nx_interface_ip_network_mask) == + interface_ptr -> nx_interface_ip_network) && + ((ip_header_ptr -> nx_ip_header_destination_ip & ~(interface_ptr -> nx_interface_ip_network_mask)) == + ~(interface_ptr -> nx_interface_ip_network_mask))) + { + + /* Let IP packet receive process this packet. */ + return (NX_FALSE); + } + + /* Check if NAT need to process this packet. */ + if (packet_process == NX_TRUE) + { + + /* Set the packet interface as global interface. */ + packet_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr; + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_server_ptr -> forwarded_packets_received ++; +#endif + + /* Deliver the packet to the outbound packet handler. */ + _nx_nat_process_outbound_packet(nat_server_ptr, packet_ptr); + } + } + + /* Return NX_TRUE to indicate packet has been processed by NAT. */ + return (NX_TRUE); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_inbound_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a packet from the external network for */ +/* forwarding to the private network. It sends each packet to a */ +/* protocol handler for protocol specific processing. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_INVALID_PROTOCOL Unknown packet protocol */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_process_inbound_TCP_packet */ +/* Process external host's TCP packet */ +/* _nx_nat_process_inbound_UDCP_packet */ +/* Process external host's UDP packet */ +/* _nx_nat_process_inbound_ICMP_packet */ +/* Process external host's ICMP packet */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_packet Process packet from external host */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr) +{ + + +UINT status = NX_SUCCESS; +UCHAR protocol; +NX_IPV4_HEADER *ip_header_ptr; +NX_NAT_TRANSLATION_ENTRY translation_entry; + + + /* Pick a pointer to the IP header. */ + ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; + + /* Determine what protocol the current IP datagram is. */ + protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; + + /* Set up the search criteria in the NAT translation table. */ + memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); + translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_source_ip; + translation_entry.protocol = protocol; + + /* Choose which packet handler by protocol. */ + switch (protocol) + { + + case NX_PROTOCOL_TCP: + status = _nx_nat_process_inbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + + case NX_PROTOCOL_UDP: + status = _nx_nat_process_inbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + + case NX_PROTOCOL_ICMP: + status = _nx_nat_process_inbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + } + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_inbound_TCP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the local IP address:port for an incoming packet */ +/* in the NAT translation table and replaces the global packet */ +/* destination IP address and port with the local IP address and port. */ +/* If none is found, it rejects the packet. Otherwise it updates the TCP*/ +/* checksum with the changed IP address and port. The packet is then */ +/* sent to private host. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* (packet is not necessarily */ +/* forwarded) */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_packet Process inbound packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + +UINT status; +UINT entry_found; +USHORT old_port; +USHORT new_port; +ULONG old_address; +ULONG new_address; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_TCP_HEADER *tcp_header_ptr; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Initialize local variables. */ + compute_checksum = 1; + record_entry = NX_NULL; + entry_found = NX_TRUE; + + /* Pickup the pointer to the head of the TCP packet. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* For little endian processors, adjust byte order for big endianness. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Find the inbound entry, set the packet private interface and next hop address. */ + status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Check the status. */ + if (status == NX_NAT_ENTRY_NOT_FOUND) + { + + /* Set the entry found flag. */ + entry_found = NX_FALSE; + } + else + { + + /* Release the packet */ + nx_packet_release(packet_ptr); + + /* Return completion status. */ + return NX_SUCCESS; + } + } + else + { + + /* Check the inbound packet destination port, and update the TCP header. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Replace the destination port with the local (source) port of the preceding outbound packet. */ + + tcp_header_ptr -> nx_tcp_header_word_0 = ((ULONG)(tcp_header_ptr -> nx_tcp_header_word_0 & ~NX_LOWER_16_MASK)) | + ((ULONG) record_entry -> local_port); + } + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + if(compute_checksum) + { + + /* Get the old checksum. */ + checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16); + + /* Check whether the port is updated. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Set the old port and new port. */ + old_port = record_entry -> external_port; + new_port = record_entry -> local_port; + + /* Adjust the checksum for port. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + } + + /* Set the old address and new address. */ + old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + new_address = record_entry -> local_ip_address; + + /* Adjust the checksum for address. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); + + /* OK to clear the TCP checksum field to zero before the checksum update. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16); + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* OK to clear the TCP checksum field to zero before the checksum update. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + } + + /* Swap endianness back before sending. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Check the entry found flag. */ + if (entry_found == NX_FALSE) + { + + /* Stop processing, recover packet length to Let NetXDuo process this packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); + + /* Let NetXDuo process this pcaket. */ + return(NX_NAT_PACKET_CONSUMED_FAILED); + } + + /* Send the TCP packet onto the private host. */ + _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_inbound_UDP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the local IP address:port for an incoming packet */ +/* in the NAT translation table and replaces the global packet */ +/* destination IP address and port with the local IP address andport. */ +/* If none is found, it rejects the packet. Otherwise it updates the UDP*/ +/* checksum with the changed IP address and port. The packet is then */ +/* sent to private host. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_INVALID_IP_HEADER Invalid IP header */ +/* NX_NAT_BAD_UDP_CHECKSUM UDP checksum is invalid */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_packet Process inbound packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + +UINT status; +UINT entry_found; +USHORT old_port; +USHORT new_port; +ULONG old_address; +ULONG new_address; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_UDP_HEADER *udp_header_ptr; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Initialize local variables. */ + compute_checksum = 1; + record_entry = NX_NULL; + entry_found = NX_TRUE; + + /* Pickup the pointer to the head of the UDP packet. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* For little endian processors, adjust byte order for big endianness. */ + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + + /* Find the inbound entry, set the packet private interface and next hop address. */ + status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Check the status. */ + if (status == NX_NAT_ENTRY_NOT_FOUND) + { + + /* Set the entry found flag. */ + entry_found = NX_FALSE; + } + else + { + + /* Release the packet */ + nx_packet_release(packet_ptr); + + /* Return completion status. */ + return NX_SUCCESS; + } + } + else + { + + /* Update the destination port if the NAT device mapped it to another port. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Translate the destination UDP port to the private host port. If translation + does not involve port number this will essentially be the original port number. */ + udp_header_ptr -> nx_udp_header_word_0 = ((ULONG) (udp_header_ptr -> nx_udp_header_word_0 & ~NX_LOWER_16_MASK)) | + ((ULONG) record_entry -> local_port); + } + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Get the checksum. */ + checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK; + + /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */ + if (checksum == 0) + compute_checksum = 0; + + /* Check the checksum. */ + if(compute_checksum) + { + + /* Check whether the port is updated. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Set the old port and new port. */ + old_port = record_entry -> external_port; + new_port = record_entry -> local_port; + + /* Adjust the checksum for port. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + } + + /* Set the old address and new address. */ + old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + new_address = record_entry -> local_ip_address; + + /* Adjust the checksum for address. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); + + /* OK to clear the UDP checksum field to zero before the checksum update. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* OK to clear the UDP checksum field to zero before the checksum update. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + } + + /* Swap UDP header byte order back to big endian before sending. For big endian processors, + this will have no effect. */ + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + + /* Check the packet consumed flag. */ + if (entry_found == NX_FALSE) + { + + /* Stop processing, recover packet length to Let NetXDuo process this packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); + + /* Let NetXDuo process this pcaket. */ + return(NX_NAT_PACKET_CONSUMED_FAILED); + } + + /* Send the UDP packet onto the private host. */ + _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_inbound_ICMP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the local IP address:port for an incoming packet */ +/* in the NAT translation table and replaces the global packet */ +/* IP address and queryID with the local IP address and queryID. */ +/* If none is found, rejects the packet. Otherwise it updates the ICMP */ +/* checksum with the changed IP address and port. The packet is then */ +/* sent to private host. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* (packet is not necessarily */ +/* forwarded) */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_packet Process inbound packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ +UINT status; +UINT entry_found; +ULONG sequence; +UINT type; +USHORT old_port; +USHORT new_port; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_ICMP_HEADER *icmp_header_ptr; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Initialize local variables. */ + compute_checksum = 1; + record_entry = NX_NULL; + entry_found = NX_TRUE; + + /* Get a pointer to the ICMP header. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Adjust ICMP header byte order for endianness. */ + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); + + /* Extract the ICMP type and code. */ + type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; + + /* Find the inbound entry, set the packet private interface and next hop address. */ + status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Check the status. */ + if (status == NX_NAT_ENTRY_NOT_FOUND) + { + + /* Set the entry found flag. */ + entry_found = NX_FALSE; + } + else + { + + /* Release the packet */ + nx_packet_release(packet_ptr); + + /* Return completion status. */ + return NX_SUCCESS; + } + } + else + { + + /* Check the type. */ + if ((type != NX_ICMP_ECHO_REPLY_TYPE) && + (type != NX_ICMP_ECHO_REQUEST_TYPE)) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Unknown ICMP packet. Drop the packet and bail! */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + nx_packet_release(packet_ptr); + + return NX_SUCCESS; + } + + /* Now we have to translate the packet destination for private host address and + update packet header checksum. */ + if ((type == NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port)) + { + + /* Restore the local host ICMP Query ID. */ + sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK; + + /* Restore the local host ICMP Query ID from the 'source port' field in the NAT table entry. */ + icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG)(record_entry -> local_port << NX_SHIFT_BY_16) | sequence; + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + if(compute_checksum) + { + + /* Set the old checksum. */ + checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK; + + /* Set the old port and new port. */ + old_port = entry_ptr -> external_port; + new_port = record_entry -> local_port; + + /* Adjust the checksum. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + + /* Ok to zero out the checksum because we'll replace it with an updated checksum. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* Set the checksum to zero. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + } + } + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match + that of the data area. */ + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); + + /* Check the packet consumed flag. */ + if (entry_found == NX_FALSE) + { + + /* Stop processing, recover packet length to Let NetXDuo process this packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); + + /* Let NetXDuo process this pcaket. */ + return(NX_NAT_PACKET_CONSUMED_FAILED); + } + + /* Send the ICMP packet onto the private host. */ + _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); + + /* Return packet send completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_outbound_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a packet from a local host bound for the */ +/* external network. If a matching entry for the private host is not */ +/* found in the NAT translation table, one is created. Packets are then*/ +/* directed to protocol specific handlers for detailed processing of the*/ +/* packet before sending out on the external network. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_INVALID_PROTOCOL Unknown/unsupported protocol status*/ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_process_outbound_TCP_packet */ +/* Handler for outbound TCP packets */ +/* _nx_nat_process_outbound_UDP_packet */ +/* Handler for outbound UDP packets */ +/* _nx_nat_process_outbound_ICMP_packet */ +/* Handler for outbound ICMP packets */ +/* nx_packet_release Release packet back to packet pool */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_packet_process Process packets forwarded to NAT by*/ +/* Netx */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR protocol; +NX_IPV4_HEADER *ip_header_ptr; +NX_NAT_TRANSLATION_ENTRY translation_entry; + + + /* Set up an actual IP header pointer. */ + ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Determine what protocol the current IP datagram is. */ + protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; + + /* Set up the search criteria in the NAT translation table. */ + memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); + translation_entry.local_ip_address = ip_header_ptr -> nx_ip_header_source_ip; + translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_destination_ip; + translation_entry.protocol = protocol; + + /* Direct the packet to a protocol specific handler. */ + switch (protocol) + { + + case NX_PROTOCOL_TCP: + /* Process the packet for TCP protocol. */ + _nx_nat_process_outbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + + case NX_PROTOCOL_UDP: + /* Process the packet for UDP protocol. */ + _nx_nat_process_outbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + + case NX_PROTOCOL_ICMP: + /* Process the packet for ICMP (including error message packets) protocol. */ + _nx_nat_process_outbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry); + break; + + default: + { + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + nx_packet_release(packet_ptr); + + return NX_NAT_INVALID_PROTOCOL; + } + } + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_outbound_TCP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a TCP packet from a local host on the private*/ +/* network destined for the external network with a global IP address */ +/* and port. The source IP address and port are replaced by NAT with a */ +/* global IP address:port. NAT then updates the TCP header checksum. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + +UINT status; +USHORT old_port; +USHORT new_port; +ULONG old_address; +ULONG new_address; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_TCP_HEADER *tcp_header_ptr; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Initialize local variables. */ + compute_checksum = 1; + + /* Pickup the pointer to the head of the UDP packet. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Adjust byte order for endianness. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Find the outbound entry, set the packet global interface and next hop address. */ + status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Increase the session count of dropped forwarded packets. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Release the packet back to the packet pool. */ + nx_packet_release(packet_ptr); + + /* Return the error status. */ + return status; + } + + /* Update the source port if the NAT device mapped it to another port. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Yes, write to the upper bits of the TCP word. */ + tcp_header_ptr -> nx_tcp_header_word_0 = (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK) | + (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16); + } + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + if(compute_checksum) + { + + /* Get the old checksum. */ + checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16); + + /* Check whether the port is updated. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Set the old port and new port. */ + old_port = record_entry -> local_port; + new_port = record_entry -> external_port; + + /* Adjust the checksum for port. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + } + + /* Set the old address and new address. */ + old_address = record_entry -> local_ip_address; + new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + + /* Adjust the checksum for address. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); + + /* OK to clear the TCP checksum field to zero before the checksum update. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16); + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* OK to clear the TCP checksum field to zero before the checksum update. */ + tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Swap byte order back to big endian before sending if little endian is specified. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Send the TCP packet onto the global host. */ + _nx_nat_ip_packet_send(nat_ptr,packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_outbound_UDP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a UDP packet from a local host destined for */ +/* the external network; NAT replaces the private IP address:port with a*/ +/* global IP address:port. NAT updates the UDP header checksum field for*/ +/* all packets having a non zero UDP packet checksum. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_ZERO_UDP_CHECKSUM Illegal zero UDP header checksum */ +/* NX_NAT_BAD_UDP_CHECKSUM UDP header checksum is invalid */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + +UINT status; +USHORT old_port; +USHORT new_port; +ULONG old_address; +ULONG new_address; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_UDP_HEADER *udp_header_ptr; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + /* Initialize local variables. */ + compute_checksum = 1; + + /* Pickup the pointer to the head of the UDP packet. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* For little endian processors, swap byte order to little endian. */ + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + + /* Find the outbound entry, set the packet global interface and next hop address. */ + status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Increase the session count of dropped forwarded packets. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Release the packet back to the packet pool. */ + nx_packet_release(packet_ptr); + + /* Return the error status. */ + return status; + } + + /* OK to zero out the checksum field so we can update the header with a new checksum later. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; + + /* Did NAT assign a global UDP source port? */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Yes, so replace local host UDP port with NAT global inside UDP port in the header. */ + udp_header_ptr -> nx_udp_header_word_0 = (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK) | + (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16); + } + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Get the old checksum. */ + checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK; + + /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */ + if (checksum == 0) + compute_checksum = 0; + + /* Compute the checksum. */ + if(compute_checksum) + { + + /* Check whether the port is updated. */ + if (record_entry -> external_port != record_entry -> local_port) + { + + /* Set the old port and new port. */ + old_port = record_entry -> local_port; + new_port = record_entry -> external_port; + + /* Adjust the checksum for port. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + } + + /* Set the old address and new address. */ + old_address = record_entry -> local_ip_address; + new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + + /* Adjust the checksum for address. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); + + /* OK to clear the UDP checksum field to zero before the checksum update. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* OK to clear the UDP checksum field to zero before the checksum update. */ + udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match + that of the data area. */ + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + + /* Send the UDP packet onto the global host. */ + _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); + + /* Return packet send completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_process_outbound_ICMP_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a ICMP packet from a local network host for */ +/* sending out onto the external network. NAT replaces the private */ +/* source IP address and local query ID with a global source IP address */ +/* and query ID. NAT then recomputes the ICMP header checksum. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to the NAT server */ +/* packet_ptr Pointer to the packet to process */ +/* entry_ptr Pointer to the entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_BAD_ICMP_CHECKSUM Packet failed ICMP checksum check */ +/* NX_NAT_INVALID_IP_HEADER Packet has an invalid IP header */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* _nx_nat_ip_packet_send Send packet to private interface */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + +UINT status; +ULONG sequence; +UINT is_icmp_error_msg; +NX_ICMP_HEADER *icmp_header_ptr; +UINT type; +USHORT old_port; +USHORT new_port; +USHORT checksum; +ULONG compute_checksum; +ULONG next_hop_address; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Initialize local variables. */ + compute_checksum = 1; + + /* Pickup the pointer to the head of the ICMP packet. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); + icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Swap ENDian-ness for our ICMP header. We've only swapped the IP header data so far. */ + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); + + /* Extract the ICMP type and code. */ + type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; + + /* Determine if this outbound packet an ICMP error message packet. */ + _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); + + /* Is the this an error message packet? */ + if (is_icmp_error_msg) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Drop the packet and bail! */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return completion status. */ + return NX_SUCCESS; + } + + /* Find the outbound entry, set the packet global interface and next hop address. */ + status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Increase the session count of dropped forwarded packets. */ + nat_ptr -> forwarded_packets_dropped++; +#endif + + /* Release the packet back to the packet pool. */ + nx_packet_release(packet_ptr); + + /* Return the error status. */ + return status; + } + + /* Update the ICMP Query ID ("port") if the NAT device mapped it to another Query ID + but not if this is a local host responding to a REQUEST ICMP packet, in which case + it must keep the same Query ID. */ + if ((type != NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port)) + { + + /* Pick up the ICMP sequence number. */ + sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK; + + /* Set the ICMP Query ID in the ICMP header. */ + icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG) (record_entry -> external_port << NX_SHIFT_BY_16) | sequence; + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + if(compute_checksum) + { + + /* Set the old checksum. */ + checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK; + + /* Set the old port and new port. */ + old_port = record_entry -> local_port; + new_port = record_entry -> external_port; + + /* Adjust the checksum. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); + + /* Ok to zero out the checksum because we'll replace it with an updated checksum. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; + + /* Place the checksum into the first header word. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* Set the checksum to zero. */ + icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + } + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match + that of the data area. */ + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); + + /* Send the ICMP packet onto the global host. */ + _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_ip_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the NAT equivalent of nx_ip_packet_send. It handles */ +/* all packets inbound or outbound of any protocol and forwards them */ +/* directly to the driver. */ +/* */ +/* This function also handles fragmented datagrams. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server */ +/* packet_ptr Pointer to packet */ +/* entry_ptr Pointer to NAT entry */ +/* packet_type Packet type(inbound/outbound) */ +/* next_hop_address Next hop address to target */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status. */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_FRAGMENT_QUEUE_NOT_FOUND Fragment queue for datagram */ +/* not found */ +/* CALLS */ +/* */ +/* nx_packet_release Release the packet */ +/* _nx_packet_data_append Append the overflow data */ +/* _nx_nat_checksum_adjust Adjust checksum for NAT changes */ +/* to IP header */ +/* _nx_ip_driver_packet_send Forward packet to driver to send*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */ +/* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */ +/* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */ +/* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */ +/* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */ +/* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address) +{ + +ULONG fragment_bits; +ULONG old_address; +ULONG new_address; +ULONG old_fragment; +ULONG new_fragment; +USHORT checksum; +ULONG compute_checksum = 1; +ULONG destination_ip; +UINT status; +NX_IPV4_HEADER *ip_header_ptr; + + + /* Pickup the pointer to the head of the ICMP packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); + packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); + ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Check the packet type. */ + if (packet_type == NX_NAT_OUTBOUND_PACKET) + { + + /* Update the source ip address. */ + ip_header_ptr -> nx_ip_header_source_ip = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + + /* Set the local address and external address. */ + old_address = entry_ptr -> local_ip_address; + new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + } + else + { + /* Update the destination ip address. */ + ip_header_ptr -> nx_ip_header_destination_ip = entry_ptr -> local_ip_address; + + /* Set the old address and new address. */ + old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; + new_address = entry_ptr -> local_ip_address; + } + + /* Record the destination IP address. */ + destination_ip = ip_header_ptr -> nx_ip_header_destination_ip; + + /* Record the fragment bit. */ + fragment_bits = (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_DONT_FRAGMENT); + old_fragment = ip_header_ptr -> nx_ip_header_word_1 & NX_LOWER_16_MASK; + new_fragment = old_fragment; + + /* Check if the packet is fragmented and if the fragment field is not zero. */ + if ((fragment_bits != NX_IP_DONT_FRAGMENT) && (old_fragment != 0)) + { + + /* Clear the fragment field. */ + ip_header_ptr -> nx_ip_header_word_1 = ip_header_ptr -> nx_ip_header_word_1 & ~NX_LOWER_16_MASK; + new_fragment = 0; + } + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM) + compute_checksum = 0; + else + compute_checksum = 1; +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Compute the checksum. */ + if(compute_checksum) + { + + /* Get the checksum. */ + checksum = ip_header_ptr -> nx_ip_header_word_2 & NX_LOWER_16_MASK; + + /* Adjust the checksum for address. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); + + /* Check if the fragment field is updated. */ + if (old_fragment != new_fragment) + { + + /* Adjust the checksum for fragment field. */ + _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_fragment, sizeof(LONG), (UCHAR *)&new_fragment, sizeof(LONG)); + } + + /* Clear the checksum value. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK; + + /* Place the checksum into the header word. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | checksum; + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + + /* Clear the checksum value. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK; + + /* Set the flag. */ + packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the IP header. */ + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip); + NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip); + + /* Check if the packet can fill physical header. */ + status = _nx_packet_data_adjust(packet_ptr, NX_PHYSICAL_HEADER); + + /* Check status. */ + if (status) + { + +#ifndef NX_DISABLE_NAT_INFO + /* Update the count. */ + nat_ptr -> forwarded_packets_dropped ++; +#endif + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + return; + } + +#ifndef NX_DISABLE_NAT_INFO + /* Update the packet sent count. */ + nat_ptr -> forwarded_packets_sent++; +#endif + + /* Call the function to directly forward the packet. */ + _nx_ip_driver_packet_send(nat_ptr -> nx_nat_ip_ptr, packet_ptr, destination_ip, fragment_bits, next_hop_address); + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_inbound_entry_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the inbound entry in NAT translation entry list, */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server */ +/* packet_ptr Pointer to packet */ +/* entry_ptr Pointer to NAT entry */ +/* entry_ptr Pointer to the matched entry */ +/* next_hop_address The next hop address for route */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_utility_get_source_port Extract source port from packet */ +/* _nx_nat_utility_get_destination_port */ +/* Extract destination port from */ +/* packet */ +/* _nx_nat_entry_create Create entry for packet in NAT */ +/* translation table */ +/* _nx_nat_entry_find Find the entry */ +/* _nx_ip_route_find Find the suitable interface */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */ +/* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */ +/* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, + NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address) +{ + +UINT status; +ULONG timeout; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Check the protocol. */ + if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP)) + { + + /* Get sender's source port. */ + _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> peer_port); + } + + /* Get the destination port from header data. */ + _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> external_port); + + /* Check the timeout for all dynamic entries. */ + _nx_nat_entry_timeout_check(nat_ptr); + + /* Now search the table for a matching NAT translation entry. */ + _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_TRUE); + + /* Was a matching entry found in our translation table? */ + if (!record_entry) + { + + /* Next see if the destination is a local host server. */ + + /* Find a 'server' for packet destination IP address and port */ + _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_FALSE); + + /* Check the record entry. */ + if (record_entry) + { + + /* We found a matching server entry in the table. Now create an + entry specifically for this packet. */ + + /* Get the private IP address from the entry we just found, and apply to the new entry we're creating. */ + entry_ptr -> local_ip_address = record_entry -> local_ip_address; + + /* Check the private inside port. */ + if (record_entry -> local_port == 0) + { + + /* Set the private inside port same as global inside port. */ + entry_ptr -> local_port = entry_ptr -> external_port; + } + else + { + + /* Set private inside port. */ + entry_ptr -> local_port = record_entry -> local_port; + } + + /* Set the entry expiration timeout. */ + if (entry_ptr -> protocol == NX_PROTOCOL_TCP) + { + + /* TCP session. */ + timeout = NX_NAT_TCP_SESSION_TIMEOUT; + } + else + { + + /* Non-TCP session. */ + timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT; + } + + /* Now create the entry. */ + status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol, + entry_ptr -> local_ip_address, + entry_ptr -> peer_ip_address, + entry_ptr -> local_port, + entry_ptr -> external_port, + entry_ptr -> peer_port, + timeout, + &record_entry); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return status.*/ + return status; + } + } + else + { + + /* Return status.*/ + return (NX_NAT_ENTRY_NOT_FOUND); + } + } + + /* Clear the packet interface as private interface. */ + packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL; + + /* Set the inbound interface and next hop address. */ + if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> local_ip_address, + &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS) + { + + /* No suitable private interface configured. */ + + /* Return the error status. */ + return (NX_NAT_ROUTE_FIND_ERROR); + } + + /* Set the matched entry pointer. */ + *matched_entry_ptr = record_entry; + + /* Return success. */ + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_outbound_entry_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the outbound entry in NAT translation entry list.*/ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server */ +/* packet_ptr Pointer to packet */ +/* entry_ptr Pointer to NAT entry */ +/* entry_ptr Pointer to the matched entry */ +/* next_hop_address The next hop address for route */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_utility_get_source_port Extract source port from packet */ +/* _nx_nat_utility_get_destination_port */ +/* Extract destination port from */ +/* packet */ +/* _nx_nat_entry_create Create entry for packet in NAT */ +/* translation table */ +/* _nx_nat_entry_find Find the entry */ +/* _nx_ip_route_find Find the suitable interface */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */ +/* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */ +/* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, + NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address) +{ + +UINT status; +ULONG timeout; +NX_NAT_TRANSLATION_ENTRY *record_entry; + + + /* Get source ports from the header. */ + _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> local_port)); + + /* Check the protocol. */ + if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP)) + { + + /* Get destination port from the header. */ + _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> peer_port)); + } + + /* Check the timeout for all dynamic entries. */ + _nx_nat_entry_timeout_check(nat_ptr); + + /* Search the table for a match. */ + _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_OUTBOUND_PACKET, NX_TRUE); + + /* Was a matching table entry found? */ + if (!record_entry) + { + + /* Find the available port. */ + status = _nx_nat_find_available_port(nat_ptr, entry_ptr -> protocol, &entry_ptr -> external_port); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set the entry expiration timeout. */ + if (entry_ptr -> protocol == NX_PROTOCOL_TCP) + { + + /* TCP session. */ + timeout = NX_NAT_TCP_SESSION_TIMEOUT; + } + else + { + + /* Non-TCP session. */ + timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT; + } + + /* Create an entry with NAT translation for IP address/port. */ + status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol, + entry_ptr -> local_ip_address, + entry_ptr -> peer_ip_address, + entry_ptr -> local_port, + entry_ptr -> external_port, + entry_ptr -> peer_port, + timeout, + &record_entry); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + } + + /* Set the packet interface as global interface. */ + packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &(nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index]); + + /* Set the next hop address. */ + if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> peer_ip_address, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS) + { + + /* No suitable private interface configured. */ + + /* Return the error status. */ + return (NX_NAT_ROUTE_FIND_ERROR); + } + + /* Set the matched entry pointer. */ + *matched_entry_ptr = record_entry; + + /* Return success. */ + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_entry_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function dynamically creates a NAT translation table entry */ +/* and appends the entry to the translation list. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* protocol Protocol of packets matching entry*/ +/* local_ip_address Entry's private IP address */ +/* peer_ip_address Entry's external host IP */ +/* local_port Entry's private port */ +/* external_port Entry's global port */ +/* peer_port Entry's external port (optional) */ +/* response_timeout Entry expiration timeout */ +/* match_entry_ptr Pointer to entry created */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_TRANSLATION_TABLE_FULL Table is full (max capacity) */ +/* NX_NAT_INVALID_TABLE_ENTRY Invalid criteria for table entry */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_entry_add Add entry to linked list of entries*/ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, + ULONG local_ip_address, ULONG peer_ip_address, + USHORT local_port, USHORT external_port, USHORT peer_port, + ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr) +{ + +NX_NAT_TRANSLATION_ENTRY *insert_entry_ptr = NX_NULL; + +#ifdef NX_NAT_ENABLE_REPLACEMENT +NX_NAT_TRANSLATION_ENTRY *insert_previous_ptr = NX_NULL; +NX_NAT_TRANSLATION_ENTRY *entry_ptr = NX_NULL; +NX_NAT_TRANSLATION_ENTRY *previous_ptr = NX_NULL; +#endif /* NX_NAT_ENABLE_REPLACEMENT */ + + + /* Initialize result to not found. */ + *match_entry_ptr = NX_NULL; + + /* Perform some simple sanity checks on this entry. */ + + /* Was an invalid IP address submitted? */ + if ((peer_ip_address == 0x0) || + (local_ip_address == 0x0)) + { + + return (NX_NAT_INVALID_ENTRY); + } + + /* Check available entries. */ + if (nat_ptr -> nx_nat_dynamic_available_entries) + { + + /* Get one available entry. */ + insert_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head; + + /* Update the entry head. */ + nat_ptr -> nx_nat_dynamic_available_entry_head = insert_entry_ptr -> next_entry_ptr; + } + else + { +#ifdef NX_NAT_ENABLE_REPLACEMENT + + /* Get a pointer to the start of the entries in the translation table. */ + entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + + /* Search the whole entry list to find the oldest non-TCP entry. */ + while (entry_ptr) + { + + /* Check the entry type and protocol. */ + if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) || (entry_ptr -> protocol == NX_PROTOCOL_TCP)) + { + + /* Ingore this entry, Get the next entry in the table. */ + previous_ptr = entry_ptr; + entry_ptr = entry_ptr -> next_entry_ptr; + continue; + } + else + { + + /* Check if set the insert_entry_ptr(oldest entry). */ + if (insert_entry_ptr == NX_NULL) + { + + /* Assume the first entry is the oldest entry. */ + insert_entry_ptr = entry_ptr; + insert_previous_ptr = previous_ptr; + } + else + { + + /* Compare the timestamp. */ + if (((INT)insert_entry_ptr -> response_timestamp - (INT)entry_ptr -> response_timestamp) > 0) + { + + /* entry_ptr is an older entry, so update the insert_entry_ptr. */ + insert_entry_ptr = entry_ptr; + insert_previous_ptr = previous_ptr; + } + } + + /* Get the next entry in the table. */ + previous_ptr = entry_ptr; + entry_ptr = entry_ptr -> next_entry_ptr; + } + } + + /* Check if found the oldest non-TCP entry. */ + if (insert_entry_ptr) + { + + /* Yes, found it. Check if this is the first entry in the list. */ + if (insert_previous_ptr) + { + + /* It is not, so link the previous entry around the entry we are deleting. */ + insert_previous_ptr -> next_entry_ptr = insert_entry_ptr -> next_entry_ptr; + } + else + { + + /* It is the first entry, so set the next pointer as the starting translation table entry. */ + nat_ptr -> nx_nat_dynamic_active_entry_head = insert_entry_ptr -> next_entry_ptr; + } + + /* Update the entry count. */ + nat_ptr -> nx_nat_dynamic_active_entries --; + nat_ptr -> nx_nat_dynamic_available_entries ++; + } + else + { +#endif /* NX_NAT_ENABLE_REPLACEMENT */ + + /* This service cache does not have room for the entry. */ + /* Invoke user-installed cache full notify function .*/ + if(nat_ptr -> nx_nat_cache_full_notify) + { + + /* Call the callback function. */ + (nat_ptr -> nx_nat_cache_full_notify)(nat_ptr); + } + + /* Return error status. */ + return (NX_NAT_CACHE_FULL); + +#ifdef NX_NAT_ENABLE_REPLACEMENT + } +#endif /* NX_NAT_ENABLE_REPLACEMENT */ + } + + /* Initialize the allocated memory to NULL. */ + memset(insert_entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); + + /* Assign the entry attributes. */ + insert_entry_ptr -> protocol = protocol; + insert_entry_ptr -> local_ip_address = local_ip_address; + insert_entry_ptr -> peer_ip_address = peer_ip_address; + insert_entry_ptr -> local_port = local_port; + insert_entry_ptr -> external_port = external_port; + insert_entry_ptr -> peer_port = peer_port; + insert_entry_ptr -> response_timeout = response_timeout; + + /* Set the entry timestamp. */ + insert_entry_ptr -> response_timestamp = tx_time_get(); + + /* Set entry type to dynamically created. */ + insert_entry_ptr -> translation_type = NX_NAT_DYNAMIC_ENTRY; + + /* Append to the table. */ + _nx_nat_entry_add(nat_ptr, insert_entry_ptr); + + /* Set a pointer to the newly created entry. */ + *match_entry_ptr = insert_entry_ptr; + + /* Return successful completion status. */ + return (NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_entry_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a NAT translation entry to the NAT entry list */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* entry_ptr Pointer to NAT translation entry */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_create Create inbound entry to NAT table */ +/* before starting the NAT server */ +/* _nx_nat_entry_create Create and add entry to NAT table */ +/* after starting the NAT server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) +{ + + + /* Add this entry onto the table entry list. */ + entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr; + + /* Update the entry count. */ + if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY) + { + + /* Update the entry count. */ + nat_ptr -> nx_nat_dynamic_active_entries ++; + nat_ptr -> nx_nat_dynamic_available_entries --; + } + else + nat_ptr -> nx_nat_static_active_entries ++; + + /* Return success status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_entry_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to find an entry in the NAT translation list */ +/* that matches the entry submitted by the caller. If none is found it*/ +/* returns a null pointer. There is an option to skip entries */ +/* designated for local hosts accepting packets from external hosts */ +/* (e.g. servers). */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server */ +/* entry_to_match Pointer to entry to match in the list */ +/* match_entry_ptr Pointer to matching entry in the list */ +/* direction Forward direction(inbound/outbound) */ +/* skip_inbound_init_entries Skip entries for local hosts allowing */ +/* initial packet from external source */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_time_get Get the system time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr, + UCHAR direction, UINT skip_static_entries) +{ + +NX_NAT_TRANSLATION_ENTRY *entry_ptr; +NX_NAT_TRANSLATION_ENTRY *previous_ptr; + + + /* Initialize the search result to null (no match found). */ + *match_entry_ptr = 0x0; + + /* Check the inbound entry. */ + if ((direction == NX_NAT_INBOUND_PACKET) && + (!entry_to_match -> peer_ip_address)) + { + + /* Return. */ + return; + } + + /* Check the outbound entry. */ + if ((direction == NX_NAT_OUTBOUND_PACKET) && + ((!entry_to_match -> local_ip_address) || (!entry_to_match -> peer_ip_address))) + { + + /* Return. */ + return ; + } + + /* Initialize the previous pointer. */ + previous_ptr = NX_NULL; + + /* Get a pointer to the start of the entries in the translation table. */ + entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + + /* Search the whole table until a match is found. */ + while (entry_ptr) + { + + /* Check the entry type, (e.g. accepts packets from external hosts) ?*/ + if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) && (skip_static_entries == NX_TRUE)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* Ingore the static entry, get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + + /* Do sender and entry protocols match? */ + if (entry_ptr -> protocol != entry_to_match -> protocol) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* Get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + + /* Continue matching IP address and port criteria. */ + + /* Do external IP addresses, if specified, match? */ + if ((entry_ptr -> peer_ip_address) && + (entry_ptr -> peer_ip_address != entry_to_match -> peer_ip_address)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* No, get the next entry. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + + /* Do external ports, if specified match? */ + if ((entry_ptr -> peer_port) && + (entry_ptr -> peer_port != entry_to_match -> peer_port)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* No, get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + + /* Check the inbound entry. */ + if (direction == NX_NAT_INBOUND_PACKET) + { + + /* Does the inside host global port, if specified, match? */ + if ((entry_ptr -> external_port) && + (entry_ptr -> external_port != entry_to_match -> external_port)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* No, get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + } + else + { + + /* Do private inside IP addresses, if specified, match? */ + if ((entry_ptr -> local_ip_address) && + (entry_ptr -> local_ip_address != entry_to_match -> local_ip_address)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* No, get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + + /* Does the inside host private port, if specified, match? */ + if ((entry_ptr -> local_port) && + (entry_ptr -> local_port != entry_to_match -> local_port)) + { + + /* Set the previous entry pointer. */ + previous_ptr = entry_ptr; + + /* No, get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + + continue; + } + } + + /* If we got this far, all criteria matched up. Set a pointer to + this entry in the table. */ + *match_entry_ptr = entry_ptr; + + /* The entry is active, reset the timeout to the present. */ + entry_ptr -> response_timestamp = tx_time_get(); + + /* Yes; check if this is the first entry in the list. */ + if (previous_ptr) + { + + /* It is not. Put this entry at the head of the list to improve searching effectiveness. */ + previous_ptr -> next_entry_ptr = entry_ptr -> next_entry_ptr; + entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr; + } + break; + } + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_entry_timeout_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to check the entry's timeout, and remove the */ +/* expiration entries from dynamic active translation list. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_time_get Get the system time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr) +{ + +ULONG current_time; +ULONG elapsed_time; +NX_NAT_TRANSLATION_ENTRY *entry_ptr; +NX_NAT_TRANSLATION_ENTRY *previous_ptr; +NX_NAT_TRANSLATION_ENTRY *next_entry_ptr; + + + /* Get the current time. */ + current_time = tx_time_get(); + + /* Get a pointer to the start of the entries in the translation table. */ + entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + + /* Initialize the previous pointer. */ + previous_ptr = NX_NULL; + + /* Search thru the whole entry list. */ + while (entry_ptr) + { + + /* Set a pointer to the next entry in the table. */ + next_entry_ptr = entry_ptr -> next_entry_ptr; + + /* Check the entry type and update the time. */ + if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY) + { + + /* Calculate the elapsed time. */ + elapsed_time = current_time - entry_ptr -> response_timestamp; + + /* Update the time remaining. */ + if (elapsed_time >= entry_ptr -> response_timeout) + { + + /* Delete this entry from active entry list. */ + + /* Check if this is the first entry in the list). */ + if (previous_ptr) + { + + /* It is not, so link the previous entry around the entry we are deleting. */ + previous_ptr -> next_entry_ptr = next_entry_ptr; + } + else + { + + /* It is the first entry, so set the next pointer as the starting translation table entry. */ + nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr; + } + + /* Add the entry onto available entry list. */ + entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head; + nat_ptr -> nx_nat_dynamic_available_entry_head = entry_ptr; + + /* Update the entry count. */ + nat_ptr -> nx_nat_dynamic_active_entries --; + nat_ptr -> nx_nat_dynamic_available_entries ++; + } + else + { + + /* Set the previous entry. */ + previous_ptr = entry_ptr; + } + } + else + { + + /* Set the previous entry. */ + previous_ptr = entry_ptr; + } + + /* Get the next entry in the table. */ + entry_ptr = next_entry_ptr; + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_utility_get_destination_port PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the destination port from the packet's */ +/* protocol header. In the case of ICMP packets, it extracts the ICMP */ +/* header identifier (ID) instead. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet with destination port */ +/* protocol Packet protocol (TCP, UDP etc) */ +/* peer_port Pointer to external (destination) port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_packet_is_icmp_error_message */ +/* Indicate if ICMP packet is query or */ +/* error message packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *peer_port) +{ + +NX_TCP_HEADER *tcp_header_ptr; +NX_UDP_HEADER *udp_header_ptr; +NX_ICMP_HEADER *icmp_header_ptr; +UINT is_icmp_error_msg; + + + /* Is this a TCP packet? */ + if (protocol == NX_PROTOCOL_TCP) + { + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the destination TCP port. */ + *peer_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK); + } + /* Is this a UDP packet? */ + else if (protocol == NX_PROTOCOL_UDP) + { + + /* Pickup the pointer to the head of the UDP packet. */ + udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the destination UDP port. */ + *peer_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK); + } + /* Is this an ICMP packet? */ + else if (protocol == NX_PROTOCOL_ICMP) + { + + /* Determin type of ICMP message. */ + _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); + + /* Is this an ICMP error message? */ + if (is_icmp_error_msg ) + { + + /* Yes, these don't have query ID fields. */ + *peer_port = 0; + } + else + { + + /* Setup the pointer to the ICMP header located in the data area after the IP header. */ + icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the ICMP identifier which we will call the 'source port'. */ + *peer_port = (USHORT) (icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16); + } + } + else + { + + /* Unknown or unsupported packet protocol. */ + *peer_port = 0; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_utility_get_source_port PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the source port from the packet's protocol */ +/* header. In the case of ICMP packets, it extracts the query identifier*/ +/* (ID) instead. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to get source port */ +/* protocol Packet protocol (TCP, UDP etc) */ +/* source_port Pointer to packet source port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_nat_packet_is_icmp_error_message */ +/* Indicate if ICMP packet is query or */ +/* error message ICMP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port) +{ + +NX_TCP_HEADER *tcp_header_ptr; +NX_UDP_HEADER *udp_header_ptr; +NX_ICMP_HEADER *icmp_header_ptr; +UINT is_icmp_error_msg; + + if (protocol == NX_PROTOCOL_TCP) + { + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the source TCP port. */ + *source_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16); + } + else if (protocol == NX_PROTOCOL_UDP) + { + + /* Pickup the pointer to the head of the UDP packet. */ + udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the source UDP port. */ + *source_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16); + } + else if (protocol == NX_PROTOCOL_ICMP) + { + + /* Determine type of ICMP message. */ + _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); + + /* Is this an ICMP error message? */ + if (is_icmp_error_msg ) + { + + /* Yes, return a zero query ID (error messages have no Query ID). */ + *source_port = 0; + } + else + { + + /* Setup the pointer to the ICMP header located in the data area after the IP header. */ + icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Pickup the ICMP Query ID which is used in place of a source port. */ + *source_port = (USHORT)(icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16); + } + } + else + /* Unknown or unsupported protocol. */ + *source_port = 0; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_find_available_port PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds an available a ICMP query identifier (ID) or */ +/* or TCP/UDP port when NAT is configured to share a global IP address */ +/* among its local hosts and consequently must use the query ID/port */ +/* field to uniquely identify. */ +/* */ +/* INPUT */ +/* */ +/* nat_ptr Pointer to NAT instance */ +/* protocol Network protocol(TCP, UDP, ICMP) */ +/* port Pointer to an unused port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NAT_NO_FREE_PORT_AVAILABLE No free port found status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port) +{ + +UINT bound; +USHORT start_port; +USHORT end_port; +NX_NAT_TRANSLATION_ENTRY *entry_ptr; + + + /* Start at the lowest of number for translated query ID/port for NAT. */ + if (protocol == NX_PROTOCOL_TCP) + { + start_port = NX_NAT_START_TCP_PORT; + end_port = NX_NAT_END_TCP_PORT; + } + else if(protocol == NX_PROTOCOL_UDP) + { + start_port = NX_NAT_START_UDP_PORT; + end_port = NX_NAT_END_UDP_PORT; + } + else + { + start_port = NX_NAT_START_ICMP_QUERY_ID; + end_port = NX_NAT_END_ICMP_QUERY_ID; + } + + /* Set the start port. */ + *port = start_port; + + /* Search for a Query ID not found in the translation table. */ + while(*port < end_port) + { + + /* Initialize the bound flag. */ + bound = NX_FALSE; + + /* Serach dynamic entries. */ + entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; + + /* Loop through the whole translation table. */ + while(entry_ptr) + { + + /* Check the protocol. */ + if (entry_ptr -> protocol == protocol) + { + + /* Does this entry have a matching port ID. */ + if (entry_ptr -> external_port == *port) + { + + /* Set the flag so we can abort the current search. */ + bound = NX_TRUE; + break; + } + } + + /* Get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + } + + /* Check if we got through the entire table with no bound port. */ + if ((bound == NX_FALSE) && + ((protocol == NX_PROTOCOL_TCP) || (protocol == NX_PROTOCOL_UDP))) + { + + /* Yes, check the NetXDuo TCP/UDP socket. */ + bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, *port); + } + + /* Check if we found a socket with a matching port. */ + if (bound == NX_FALSE) + { + + /* We did not. OK to use this port. */ + return NX_SUCCESS; + } + + /* Found a match. This port is not available. */ + + /* Bump the port up one. */ + (*port)++; + } + + /* If we got here we could not find a free port. */ + return (NX_NAT_NO_FREE_PORT_AVAILABLE); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_entry_port_verify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function verifies whether the supplied port is bound. lookup */ +/* all NAT translation entries, If same ports are found, return */ +/* NX_TRUE, else return NX_FALSE. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* protocol Protocol */ +/* port Port */ +/* */ +/* OUTPUT */ +/* */ +/* bound Completion status */ +/* NX_TRUE: port is bound */ +/* NX_FALSE: port is not bound */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port) +{ + +UINT bound; +NX_NAT_TRANSLATION_ENTRY *entry_ptr; + + NX_PARAMETER_NOT_USED(ip_ptr); + + /* Initialize the return value. */ + bound = NX_FALSE; + + /* Serach dynamic entries. */ + entry_ptr = nat_server_ptr -> nx_nat_dynamic_active_entry_head; + + /* Loop through the whole translation table. */ + while(entry_ptr) + { + + /* Check the protocol. */ + if (entry_ptr -> protocol == protocol) + { + + /* Does this entry have a matching port ID. */ + if (entry_ptr -> external_port == port) + { + + /* Set the flag so we can abort the current search. */ + bound = NX_TRUE; + break; + } + } + + /* Get the next entry in the table. */ + entry_ptr = entry_ptr -> next_entry_ptr; + } + + /* Return status to the caller. */ + return(bound); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_socket_port_verify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function verifies whether the supplied port is bound. Search */ +/* all TCP/UDP sockets, and if the port is found, return NX_TRUE, */ +/* else return NX_TRUE. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* protocol Protocol */ +/* port Port */ +/* */ +/* OUTPUT */ +/* */ +/* bound Completion status */ +/* NX_TRUE: port is bound */ +/* NX_FALSE: port is not bound */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port) +{ + +UINT index; +UINT bound; +NX_TCP_SOCKET *tcp_search_ptr; +NX_TCP_SOCKET *tcp_end_ptr; +NX_UDP_SOCKET *udp_search_ptr; +NX_UDP_SOCKET *udp_end_ptr; + + + /* Initialize the return value. */ + bound = NX_FALSE; + + /* Check the protocol. */ + if (protocol == NX_PROTOCOL_TCP) + { + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT) ((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Pickup the head of the TCP ports bound list. */ + tcp_search_ptr = ip_ptr -> nx_ip_tcp_port_table[index]; + + /* Determine if we need to perform a list search. */ + if (tcp_search_ptr) + { + + /* Walk through the circular list of UDP sockets that are already bound. */ + tcp_end_ptr = tcp_search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (tcp_search_ptr -> nx_tcp_socket_port == port) + { + + /* Yes, the port has already been bound. */ + bound = NX_TRUE; + break; + } + + /* Move to the next entry in the list. */ + tcp_search_ptr = tcp_search_ptr -> nx_tcp_socket_bound_next; + + } while (tcp_search_ptr != tcp_end_ptr); + } + } + else + { + + /* Calculate the hash index in the UDP port array of the associated IP instance. */ + index = (UINT) ((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK); + + /* Pickup the head of the UDP ports bound list. */ + udp_search_ptr = ip_ptr -> nx_ip_udp_port_table[index]; + + /* Determine if we need to perform a list search. */ + if (udp_search_ptr) + { + + /* Walk through the circular list of UDP sockets that are already bound. */ + udp_end_ptr = udp_search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (udp_search_ptr -> nx_udp_socket_port == port) + { + + /* Yes, the port has already been bound. */ + bound = NX_TRUE; + break; + } + + /* Move to the next entry in the list. */ + udp_search_ptr = udp_search_ptr -> nx_udp_socket_bound_next; + + } while (udp_search_ptr != udp_end_ptr); + } + } + + /* Return success to the caller. */ + return(bound); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_packet_is_icmp_error_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if an ICMP packet is a query message or an */ +/* error message. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to ICMP packet to parse */ +/* is_icmp_error_msg Indicates if packet is an error */ +/* message packet */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_ICMP_packet Forward inbound ICMP packets */ +/* _nx_nat_process_outbound_ICMP_packet Forward outbound ICMP packets */ +/* _nx_nat_utility_get_source_port Extract source port from header*/ +/* _nx_nat_utility_get_destination_port Extract destination port from */ +/* header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg) +{ + +UINT type; +UINT protocol; +NX_IPV4_HEADER *ip_header_ptr; +NX_ICMP_HEADER *icmp_header_ptr; + + + /* Initialize the result to non error message type. */ + *is_icmp_error_msg = NX_FALSE; + + /* Set up an IP header pointer to the packet. */ + ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER)); + + /* Set up an ICMP header pointer to the packet. */ + icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); + + /* Determine what protocol the current IP datagram is. */ + protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; + + /* Is this an ICMP packet? */ + if (protocol == NX_PROTOCOL_ICMP) + { + + /* Extract the ICMP type and code. */ + type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; + + /* Determine if this is an error message. */ + if (type != NX_ICMP_ECHO_REPLY_TYPE && + type != NX_ICMP_ECHO_REQUEST_TYPE && + type < NX_ICMP_TIMESTAMP_REQ_TYPE) + { + + /* It is. Set the flag to true. */ + *is_icmp_error_msg = NX_TRUE; + } + } + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_nat_checksum_adjust PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is an optimization for recomputing a checksum by just */ +/* computing the difference where a small amount of data has changed. */ +/* NAT uses this optimization when, for example, it is only changing an */ +/* IP address or port. */ +/* */ +/* INPUT */ +/* old_checksum Pointer to the old checksum */ +/* old_data Pointer to the data being changed*/ +/* new_data Pointer to new data replacing the*/ +/* old data */ +/* data_adjustment_length Size of data being changed */ +/* adjusted_checksum Pointer to the updated checksum */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_nat_process_inbound_TCP_packet Send TCP packet to local host */ +/* _nx_nat_process_inbound_UDP_packet Send UDP packet to local host */ +/* _nx_nat_process_inbound_ICMP_packet Send ICMP packet to local host */ +/* _nx_nat_process_outbound_TCP_packet Send TCP packet to external host */ +/* _nx_nat_process_outbound_UDP_packet Send UDP packet to external host */ +/* _nx_nat_process_outbound_ICMP_packet Send ICMP packet to external host*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length) +{ + +LONG x, old_value, new_value; +INT i,j; + +#ifdef NX_LITTLE_ENDIAN + i = 1; + j = 0; +#else + i = 0; + j = 1; +#endif + + /* Checksum Adjustment, RFC 3022, Section 4.2, Page 9. */ + + /* Get the old checksum. */ + x = checksum[i] * 256 + checksum[j]; + x = ~x & 0xFFFF; + + /* Update the checksum for old data. */ + while (old_data_length) + { + + /* Get the old data. */ + old_value = old_data[i] * 256 + old_data[j]; + + /* Update the old data pointer. */ + old_data += 2; + + /* Update the checksum. */ + x -= old_value & 0xFFFF; + + /* Check the value. */ + if (x <= 0) + { + + /* Update the value. */ + x --; + x &= 0xFFFF; + } + + /* Update the old data length. */ + old_data_length -= 2; + } + + /* Update the checksum for new data. */ + while (new_data_length) + { + + /* Get the new data. */ + new_value = new_data[i] * 256 + new_data[j]; + + /* Update the new data pointer. */ + new_data += 2; + + /* Update the checksum. */ + x += new_value & 0xFFFF; + + /* Check the value. */ + if (x & 0x10000) + { + + /* Update the value. */ + x ++; + x &= 0xFFFF; + } + + /* Update the new data length. */ + new_data_length -= 2; + } + + /* Update the value. */ + x = ~x & 0xFFFF; + + /* Update the checksum. */ + checksum[i] = (UCHAR)(x /256); + checksum[j] = (UCHAR)(x & 0xFF); + + /* Return. */ + return; +} +#endif diff --git a/addons/nat/nx_nat.h b/addons/nat/nx_nat.h new file mode 100644 index 00000000..260a4a50 --- /dev/null +++ b/addons/nat/nx_nat.h @@ -0,0 +1,302 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX NAT Component */ +/** */ +/** Network Address Translation Protocol (NAT) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_nat.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Network Address Translation Protocol */ +/* (NAT) component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_NAT_H +#define NX_NAT_H + + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_system.h" + +#ifdef NX_NAT_ENABLE + +/* Thread ID for identifying as an NAT device. */ + +#define NX_NAT_ID 0x4E4154UL + + +/* Internal error processing codes. */ + +#define NX_NAT_ERROR_CONSTANT 0xD00 + +#define NX_NAT_PARAM_ERROR (NX_NAT_ERROR_CONSTANT | 0x01) /* Invalid parameter for NAT service */ +#define NX_NAT_CACHE_ERROR (NX_NAT_ERROR_CONSTANT | 0x02) /* NAT translation cache currently is full. */ +#define NX_NAT_NOT_ENABLED (NX_NAT_ERROR_CONSTANT | 0x03) /* NAT is not enabled. */ +#define NX_NAT_ENTRY_NOT_FOUND (NX_NAT_ERROR_CONSTANT | 0x04) /* Did not find the entry in NAT entry list. */ +#define NX_NAT_INVALID_PROTOCOL (NX_NAT_ERROR_CONSTANT | 0x05) /* Invalid network protocol specified for translation entry. */ +#define NX_NAT_ROUTE_FIND_ERROR (NX_NAT_ERROR_CONSTANT | 0x06) /* Nat can not find the suitable interface to send the packet. */ +#define NX_NAT_INVALID_ENTRY (NX_NAT_ERROR_CONSTANT | 0x07) /* Invalid entry submitted for translation entry list. (e.g. invalid address). */ +#define NX_NAT_CACHE_FULL (NX_NAT_ERROR_CONSTANT | 0x08) /* NAT translation cache currently is full. */ +#define NX_NAT_NO_FREE_PORT_AVAILABLE (NX_NAT_ERROR_CONSTANT | 0x09) /* NAT unable to provide a unique public source port for outbound packet. */ +#define NX_NAT_ZERO_UDP_CHECKSUM (NX_NAT_ERROR_CONSTANT | 0x0A) /* UDP header checksum is zero but NAT not is configured to accept packets with zero UDP checksum. */ +#define NX_NAT_PACKET_CONSUMED_FAILED (NX_NAT_ERROR_CONSTANT | 0x0B) /* NAT sonsumed the packets failed. */ +#define NX_NAT_ENTRY_TYPE_ERROR (NX_NAT_ERROR_CONSTANT | 0x0C) /* The entry translation type error. */ +#define NX_NAT_PORT_UNAVAILABLE (NX_NAT_ERROR_CONSTANT | 0x0D) /* The port is unavailable. */ + + +/* Define the NAT entry attribute, */ +#define NX_NAT_STATIC_ENTRY 1 +#define NX_NAT_DYNAMIC_ENTRY 2 + +/* NetX NAT translation entry's transaction status levels. */ + +/* Define packet type based on direction (inbound, outbound, local). */ + +#define NX_NAT_INBOUND_PACKET 1 /* Inbound packet with local host destination on private network */ +#define NX_NAT_OUTBOUND_PACKET 2 /* Outbound packet with external host destination on external network */ + + +/* Define the minimum count of NAT entries. */ + +#ifndef NX_NAT_MIN_ENTRY_COUNT +#define NX_NAT_MIN_ENTRY_COUNT 3 +#endif + + +/* Set the default expiration timeout (sec) for translation entries, + 24 hours for TCP sessions, 4 minutes for non-TCP sessions. + RFC 2663, Section2.6, Page5. */ + +#ifndef NX_NAT_TCP_SESSION_TIMEOUT +#define NX_NAT_TCP_SESSION_TIMEOUT (86400 * NX_IP_PERIODIC_RATE) +#endif + +/* For backward compatibility, map the symbol NX_NAT_ENTRY_RESPONSE_TIMEOUT to NX_NAT_NON_TCP_SESSION_TIMEOUT. */ +#ifdef NX_NAT_ENTRY_RESPONSE_TIMEOUT +#define NX_NAT_NON_TCP_SESSION_TIMEOUT NX_NAT_ENTRY_RESPONSE_TIMEOUT +#endif /* NX_NAT_ENTRY_RESPONSE_TIMEOUT */ + +#ifndef NX_NAT_NON_TCP_SESSION_TIMEOUT +#define NX_NAT_NON_TCP_SESSION_TIMEOUT (240 * NX_IP_PERIODIC_RATE) +#endif /* NX_NAT_NON_TCP_SESSION_TIMEOUT */ + +/* Defined, this option enables automatic replacement when NAT cache is full. + Notice: only replace the oldest non-TCP session. */ +/* +#define NX_NAT_ENABLE_REPLACEMENT +*/ + + +/* Set the ICMP query identifier/port for assigning to outbound ICMP/UDP/TCP packets + on NAT devices configured for port overloading (sharing a single global IP + address). Note this number must be high enough not to exceed with the local host + ICMP, UDP, TCP packet query IDs/port. */ + +/* Set the minimum TCP port for assigning to outbound TCP packets. */ +#ifndef NX_NAT_START_TCP_PORT +#define NX_NAT_START_TCP_PORT 20000 +#endif + +/* Set the maximum TCP port for assigning to outbound TCP packets. */ + +#ifndef NX_NAT_END_TCP_PORT +#define NX_NAT_END_TCP_PORT (NX_NAT_START_TCP_PORT + 10000) +#endif + +/* Set the minimum UDP port for assigning to outbound UDP packets. */ +#ifndef NX_NAT_START_UDP_PORT +#define NX_NAT_START_UDP_PORT 20000 +#endif + +/* Set the maximum UDP port for assigning to outbound UDP packets. */ + +#ifndef NX_NAT_END_UDP_PORT +#define NX_NAT_END_UDP_PORT (NX_NAT_START_UDP_PORT + 10000) +#endif + +/* Set the minimum ICMP query identifier for assigning to outbound ICMP packets. */ +#ifndef NX_NAT_START_ICMP_QUERY_ID +#define NX_NAT_START_ICMP_QUERY_ID 20000 +#endif + +/* Set the maximum ICMP query identifier for assigning to outbound ICMP packets. */ + +#ifndef NX_NAT_END_ICMP_QUERY_ID +#define NX_NAT_END_ICMP_QUERY_ID (NX_NAT_START_ICMP_QUERY_ID + 10000) +#endif + + +/* Configure NAT to disable record the packet forward counter. */ +/* +#define NX_DISABLE_NAT_INFO +*/ + +/* Define the NAT translation table entry structure. */ +typedef struct NX_NAT_TRANSLATION_ENTRY_STRUCT +{ + + /* + Local Network External Network + |----------------| + | | external port> peer port> + | | + | | + |----------------| + */ + struct NX_NAT_TRANSLATION_ENTRY_STRUCT *next_entry_ptr; /* Pointer to the next translation entry in table */ + ULONG peer_ip_address; /* IP address of an external host sending/receiving packets through NAT. */ + ULONG local_ip_address; /* IP address of the local (private) host. */ + USHORT peer_port; /* Source port of an external host sending/receiving packets through NAT. */ + USHORT external_port; /* The external port of local (private) host. */ + USHORT local_port; /* Port of the local (private) host. */ + UCHAR translation_type; /* Translation type (static or dynamic). */ + UCHAR protocol; /* Packet's network sub protocol (TCP, UDP etc). */ + ULONG response_timeout; /* Expiration timeout for the entry. */ + ULONG response_timestamp; /* The last timestamp for entry used. */ +} NX_NAT_TRANSLATION_ENTRY; + + +/* Define the NAT device structure. */ +typedef struct NX_NAT_DEVICE_STRUCT +{ + + ULONG nx_nat_id; /* NAT Server thread ID */ + NX_IP *nx_nat_ip_ptr; /* IP instance for NAT's network. */ + UCHAR nx_nat_global_interface_index; /* NAT's global network. */ + UCHAR reserved[3]; /* Reserved. */ +#ifndef NX_DISABLE_NAT_INFO + ULONG forwarded_packets_received; /* Total number of packets received by NAT. */ + ULONG forwarded_packets_dropped; /* Total number of packets which cannot be forwarded. */ + ULONG forwarded_packets_sent; /* Total number of packets sent by NAT. */ +#endif + NX_NAT_TRANSLATION_ENTRY *nx_nat_dynamic_available_entry_head;/* Define the head pointer of available dynamic entries list. */ + NX_NAT_TRANSLATION_ENTRY *nx_nat_dynamic_active_entry_head; /* Define the head pointer of active dynamic entries list. */ + UINT nx_nat_dynamic_available_entries; /* Define the number of available dynamic entries. */ + UINT nx_nat_dynamic_active_entries; /* Define the number of active dynamic entries. */ + UINT nx_nat_static_active_entries; /* Define the number of active static entries. */ + VOID (*nx_nat_cache_full_notify)(struct NX_NAT_DEVICE_STRUCT *); +} NX_NAT_DEVICE; + + +#ifndef NX_NAT_SOURCE_CODE + + +/* Define the system API mappings based on the error checking + selected by the user. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + + +#ifdef NX_NAT_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_nat_create _nx_nat_create +#define nx_nat_delete _nx_nat_delete +#define nx_nat_enable _nx_nat_enable +#define nx_nat_disable _nx_nat_disable +#define nx_nat_cache_notify_set _nx_nat_cache_notify_set +#define nx_nat_inbound_entry_create _nx_nat_inbound_entry_create +#define nx_nat_inbound_entry_delete _nx_nat_inbound_entry_delete + +#else + +/* Services with error checking. */ + +#define nx_nat_create _nxe_nat_create +#define nx_nat_delete _nxe_nat_delete +#define nx_nat_enable _nxe_nat_enable +#define nx_nat_disable _nxe_nat_disable +#define nx_nat_cache_notify_set _nxe_nat_cache_notify_set +#define nx_nat_inbound_entry_create _nxe_nat_inbound_entry_create +#define nx_nat_inbound_entry_delete _nxe_nat_inbound_entry_delete + +#endif /* NX_NAT_DISABLE_ERROR_CHECKING */ + +/* Define API services available for NAT applications. */ + +UINT nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); +UINT nx_nat_delete(NX_NAT_DEVICE *nat_ptr); +UINT nx_nat_enable(NX_NAT_DEVICE *nat_ptr); +UINT nx_nat_disable(NX_NAT_DEVICE *nat_ptr); +UINT nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); +UINT nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, UINT external_port, USHORT local_port, UCHAR protocol); +UINT nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); + +#else /* NX_NAT_SOURCE_CODE */ + +/* NAT source code is being compiled, do not perform any API mapping. */ + +UINT _nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); +UINT _nxe_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); +UINT _nx_nat_delete(NX_NAT_DEVICE *nat_ptr); +UINT _nxe_nat_delete(NX_NAT_DEVICE *nat_ptr); +UINT _nx_nat_enable(NX_NAT_DEVICE *nat_ptr); +UINT _nxe_nat_enable(NX_NAT_DEVICE *nat_pt); +UINT _nx_nat_disable(NX_NAT_DEVICE *nat_ptr); +UINT _nxe_nat_disable(NX_NAT_DEVICE *nat_ptr); +UINT _nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); +UINT _nxe_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); +UINT _nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol); +UINT _nxe_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol); +UINT _nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); +UINT _nxe_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); +#endif + +#endif /* NX_NAT_ENABLE */ + +/* If a C++ compiler is being used....*/ +#ifdef __cplusplus + } +#endif + +#endif /* NX_NAT_H */ + diff --git a/addons/pop3/nxd_pop3_client.c b/addons/pop3/nxd_pop3_client.c new file mode 100644 index 00000000..0b704148 --- /dev/null +++ b/addons/pop3/nxd_pop3_client.c @@ -0,0 +1,3227 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX POP3 Client Component */ +/** */ +/** Post Office Protocol Version 3 (POP3) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_pop3_client.c PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Post Office Protocol (POP3) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#define NX_POP3_CLIENT_SOURCE_CODE + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + + +#include "nx_api.h" +#include "nx_md5.h" +#include "nx_ip.h" +#include "nxd_pop3_client.h" +#include "nx_ipv6.h" +#include + +/* The following array of state handlers is indexed by the state. */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create POP3 client */ +/* service (IPv4 only). */ +/* */ +/* Note: The string lengths of client_name and client_password are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* APOP_authentication 1=enable APOP; 0=disable APOP */ +/* ip_ptr Pointer to client IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* server_ip_address POP3 server IP address */ +/* server_port POP3 server port */ +/* client_name Client POP3 user name */ +/* client_password Client POP3 password */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_create Creates the POP3 client */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, + NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, + CHAR *client_password) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for valid input pointers. */ + if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL) || (client_name == NX_NULL) || + (client_password == NX_NULL)) + { + + /* Return pointer error. */ + return(NX_PTR_ERROR); + } + + if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (server_ip_address == 0) || (server_port == 0)) + { + + return NX_POP3_PARAM_ERROR; + } + + /* Call the actual client create service. */ + status = _nx_pop3_client_create(client_ptr, + APOP_authentication, + ip_ptr, packet_pool_ptr, + server_ip_address, server_port, client_name, + client_password); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(APOP_authentication); + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + NX_PARAMETER_NOT_USED(server_ip_address); + NX_PARAMETER_NOT_USED(server_port); + NX_PARAMETER_NOT_USED(client_name); + NX_PARAMETER_NOT_USED(client_password); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a POP3 Client on the specified IP instance. */ +/* */ +/* Note: The string lengths of client_name and client_password are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* APOP_authentication 1=enable APOP; 0=disable APOP */ +/* ip_ptr Pointer to client IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* server_ip_address POP3 server IP address */ +/* server_port POP3 server port */ +/* client_name Client POP3 user name */ +/* client_password Client POP3 password */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* _nxd_pop3_client_create Duo Client POP3 create service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, + NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, + CHAR *client_password) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_address; + + server_address.nxd_ip_address.v4 = server_ip_address; + server_address.nxd_ip_version = NX_IP_VERSION_V4; + + status = _nxd_pop3_client_create(client_ptr, + APOP_authentication, + ip_ptr, packet_pool_ptr, + &server_address, server_port, client_name, + client_password); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(APOP_authentication); + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(packet_pool_ptr); + NX_PARAMETER_NOT_USED(server_ip_address); + NX_PARAMETER_NOT_USED(server_port); + NX_PARAMETER_NOT_USED(client_name); + NX_PARAMETER_NOT_USED(client_password); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_pop3_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the create POP3 client */ +/* service (supports IPv6 and IPv4). */ +/* */ +/* Note: The string lengths of client_name and client_password are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* APOP_authentication 1=enable APOP; 0=disable APOP */ +/* ip_ptr Pointer to client IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* server_duo_address POP3 server IPv6/IPv4 address */ +/* server_port POP3 server port */ +/* client_name Client POP3 user name */ +/* client_password Client POP3 password */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_pop3_client_create Creates the POP3 client */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, + NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port, CHAR *client_name, + CHAR *client_password) +{ + +UINT status; + + + /* Check for valid input pointers. */ + if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL) || (server_ip_address == NX_NULL) || + (client_name == NX_NULL) || (client_password == NX_NULL)) + { + + /* Return pointer error. */ + return(NX_PTR_ERROR); + } + + if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (server_port == 0)) + { + + return NX_POP3_PARAM_ERROR; + } + + /* Call the actual client create service. */ + status = _nxd_pop3_client_create(client_ptr, + APOP_authentication, + ip_ptr, packet_pool_ptr, + server_ip_address, server_port, client_name, + client_password); + + /* Return completion status. */ + return(status); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_pop3_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a POP3 Client on the specified IP instance. */ +/* This supports both IPv6 and IPv4 POP3 server connections. */ +/* */ +/* Note: The string lengths of client_name and client_password are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* APOP_authentication 1=enable APOP; 0=disable APOP */ +/* ip_ptr Pointer to client IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* server_ip_address POP3 server IP address */ +/* server_port POP3 server port */ +/* client_name Client POP3 user name */ +/* client_password Client POP3 password */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create NetX TCP socket create service */ +/* _nxd_pop3_client_connect Connect POP3 Client to Server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, + NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port, CHAR *client_name, + CHAR *client_password) + +{ + +UINT status; +UINT client_name_length; +UINT client_password_length; + + + client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; + + if (_nx_utility_string_length_check(client_name, &client_name_length, NX_POP3_MAX_USERNAME) || + _nx_utility_string_length_check(client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) + { + + return NX_POP3_PARAM_ERROR; + } + + /* Null the members of NX_POP3_CLIENT. */ + memset(client_ptr, 0, sizeof(NX_POP3_CLIENT)); + + /* Configure Client identification. */ + memset(client_ptr -> nx_pop3_client_name, 0, NX_POP3_MAX_USERNAME); + memcpy(client_ptr -> nx_pop3_client_name, client_name, client_name_length); + memset(client_ptr -> nx_pop3_client_password, 0, NX_POP3_MAX_PASSWORD); + memcpy(client_ptr -> nx_pop3_client_password, client_password, client_password_length); + + /* Configure Client POP3 authentication options. */ + client_ptr -> nx_pop3_client_enable_APOP_authentication = APOP_authentication; + + /* Create a tcp socket to send/receive POP3 data. */ + status = nx_tcp_socket_create(ip_ptr, &client_ptr -> nx_pop3_client_tcp_socket, "POP3 Client socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, + NX_POP3_CLIENT_TCP_WINDOW_SIZE, + NX_NULL, NX_NULL); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Configure Client NetX and TCP/IP options. */ + client_ptr -> nx_pop3_client_packet_pool_ptr = packet_pool_ptr; + + status = _nxd_pop3_client_connect(client_ptr, server_ip_address, server_port); + + /* Return successful completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the POP3 Client delete */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_delete Actual Client delete service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_delete(NX_POP3_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for valid input parameter. */ + if (client_ptr == NX_NULL) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + /* Call client create function. */ + status = _nx_pop3_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the specified POP3 Client. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_disconnect Closes the TCP connection */ +/* nx_tcp_client_socket_unbind Releases (unbinds) the TCP port */ +/* nx_tcp_socket_delete Deletes unbound TCP socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr) +{ + + if (client_ptr -> nx_pop3_client_message_ptr) + { + nx_packet_release(client_ptr -> nx_pop3_client_message_ptr); + } + + /* Yes, so disconnect client socket from server. */ + nx_tcp_socket_disconnect(&client_ptr -> nx_pop3_client_tcp_socket, NX_POP3_CLIENT_DISCONNECT_TIMEOUT); + + /* Unbind the port from client socket. */ + nx_tcp_client_socket_unbind(&client_ptr -> nx_pop3_client_tcp_socket); + + /* Release client socket. */ + nx_tcp_socket_delete(&client_ptr -> nx_pop3_client_tcp_socket); + + /* Clear the members of NX_POP3_CLIENT. */ + memset(client_ptr, 0, sizeof(NX_POP3_CLIENT)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_mail_items_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get mail items in */ +/* client mailbox service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* number_mail_items Pointer to items in mailbox */ +/* maildrop_total_size Pointer to total mailbox size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_pop3_client_mail_items_get Actual get mail items service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size) +{ + +UINT status; + + + /* Check for invalid pointer inpu. */ + if ((client_ptr == NX_NULL) || (number_mail_items == NX_NULL) || (maildrop_total_size == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + status = _nx_pop3_client_mail_items_get(client_ptr, number_mail_items, maildrop_total_size); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_mail_items_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the number of items and total size in bytes */ +/* of mail data in the Client's mailbox. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* number_mail_items Pointer to items in mailbox */ +/* maildrop_total_size Pointer to total mailbox size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size) +{ + +UINT status; +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer; +CHAR argument[10]; +UINT packet_type; + + /* Determine type of packet to allocate. */ + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + /* Check for sufficient packet buffer size for command. */ + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_STAT) - 1) + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Send the STAT command. */ + buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); + + memcpy(buffer, NX_POP3_COMMAND_STAT, (sizeof(NX_POP3_COMMAND_STAT) - 1)); + packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_STAT) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_STAT) - 1); + buffer += (sizeof(NX_POP3_COMMAND_STAT) - 1); + + memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Clear existing Client maildrop data. */ + client_ptr -> nx_pop3_client_total_message_size = 0; + client_ptr -> nx_pop3_client_maildrop_items = 0; + + /* Receive server reply. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to server error received. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* Yes. Clear memory for parsing the mail item count. */ + memset(argument, 0, 5); + + /* Get the number of messages. */ + _nx_pop3_parse_response(buffer, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Check if argument parsed successfully. */ + if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) + { + + /* It was; update session maildrop items. */ + client_ptr -> nx_pop3_client_maildrop_items = strtoul(argument, NULL, 10); + + /* Get total mail message data next. */ + memset(argument, 0, 5); + + /* Get the size in bytes of message data. */ + _nx_pop3_parse_response(buffer, 3, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Check if argument parsed successfully. */ + if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) + { + + /* It was; update total message data. */ + client_ptr -> nx_pop3_client_total_message_size = strtoul(argument, NULL, 10); + + status = NX_SUCCESS; + } + } + } + + *maildrop_total_size = client_ptr -> nx_pop3_client_total_message_size; + *number_mail_items = client_ptr -> nx_pop3_client_maildrop_items; + + nx_packet_release(recv_packet_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_get_mail_item PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get mail item size */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_item Index into POP3 mailbox */ +/* item_size Pointer to mail size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_get_mail_size Actual get mail size service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((client_ptr == NX_NULL) || (size == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + /* Check for an invalid index. */ + if (mail_item == 0) + { + return NX_POP3_CLIENT_INVALID_INDEX; + } + + status = _nx_pop3_client_mail_item_size_get(client_ptr, mail_item, size); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_mail_item_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a LIST command for the specified mail item and */ +/* processes the server response for size of the requested item. Note */ +/* that there is considerable discrepancy between reported size and */ +/* actual size, with the reported size usually 15% or more larger than */ +/* actual. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_item Index into POP3 mailbox */ +/* size Pointer to mail item size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* _nx_pop3_server_number_convert Convert integer to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size) +{ + +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer_ptr; +UINT num_size; +UINT status; +CHAR argument[10]; +UINT packet_type; + + + /* Initialize mail box to having zero items. */ + *size = 0; + + /* Verify mail_item is valid index (less than total number items in mailbox. */ + if (mail_item > client_ptr -> nx_pop3_client_maildrop_items) + { + return NX_POP3_INVALID_MAIL_ITEM; + } + + /* Determine which packet type to allocate. */ + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + num_size = _nx_pop3_server_number_convert(mail_item, &argument[0]); + + /* Determine if the packet payload is large enough for LIST command. */ + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_LIST) - 1) + 1 + + num_size + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Send LIST mail_item query to server */ + memcpy(buffer_ptr, NX_POP3_COMMAND_LIST, (sizeof(NX_POP3_COMMAND_LIST) - 1)); + packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_LIST) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_LIST) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_LIST) - 1); + + memcpy(buffer_ptr, " ", 1); + packet_ptr -> nx_packet_length++; + packet_ptr -> nx_packet_append_ptr++; + buffer_ptr++; + + memcpy(buffer_ptr, &argument[0], num_size); + packet_ptr -> nx_packet_length += num_size; + packet_ptr -> nx_packet_append_ptr += num_size; + buffer_ptr += num_size; + + memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Initialize status to bad reply error condition. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* Clear memory for parsing the mail item count. */ + memset(argument, 0, 5); + + /* Extact the message size. */ + _nx_pop3_parse_response(buffer_ptr, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Check if argument parsed successfully. */ + if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) + { + + /* It was; verify it matches the input mail index. */ + UINT server_maildrop_items = strtoul(argument, NULL, 10); + + if (mail_item == server_maildrop_items) + { + + /* It does. Parse the message size. */ + _nx_pop3_parse_response(buffer_ptr, 3, recv_packet_ptr -> nx_packet_length, + (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) + { + + *size = strtoul(argument, NULL, 10); + + status = NX_SUCCESS; + } + } + } + } + + /* Done with the server response, delete the packet. */ + nx_packet_release(recv_packet_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_mail_item_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get mail item */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_item Index into POP3 mailbox */ +/* item_size Pointer to mail size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_mail_item_get Actual get mail service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if ((client_ptr == NX_NULL) || (item_size == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + /* Check for an invalid index. */ + if (mail_item == 0) + { + return NX_POP3_CLIENT_INVALID_INDEX; + } + + status = _nx_pop3_client_mail_item_get(client_ptr, mail_item, item_size); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_mail_item_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the RETR command to the server for the specified*/ +/* mail item, and returns the server response. If accepted, it will */ +/* parse the mail item size as well. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_item Index into POP3 mailbox */ +/* item_size Pointer to mail size */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* _nx_pop3_server_number_convert Convert integer to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size) +{ + +UINT status; +UINT size; +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer; +CHAR argument[10]; +UINT packet_type; + + + client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; + + /* Verify mail_item is valid index (less than total number items in mailbox. */ + if (mail_item > client_ptr -> nx_pop3_client_maildrop_items) + { + return NX_POP3_INVALID_MAIL_ITEM; + } + + /* Allocate a packet. */ + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + /* Check packet payload can hold the Client message. . */ + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_RETR) - 1) + 1) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); + + /* Send a RETR command to the server. */ + memcpy(packet_ptr -> nx_packet_prepend_ptr, NX_POP3_COMMAND_RETR, (sizeof(NX_POP3_COMMAND_RETR) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_RETR) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_RETR) - 1); + buffer += (sizeof(NX_POP3_COMMAND_RETR) - 1); + + memcpy(buffer, " ", 1); + packet_ptr -> nx_packet_length++; + packet_ptr -> nx_packet_append_ptr++; + buffer++; + + /* Convert the mail item index to ascii. */ + size = _nx_pop3_server_number_convert(mail_item, &argument[0]); + if ((buffer + size + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= (CHAR *)packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + memcpy(buffer, &argument[0], size); + packet_ptr -> nx_packet_length += size; + packet_ptr -> nx_packet_append_ptr += size; + buffer += size; + + memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply over Client socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, + sizeof(argument), NX_FALSE, NX_FALSE); + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + client_ptr -> nx_pop3_client_ready_to_download = NX_TRUE; + *item_size = 0; + + /* Yes. Clear memory for parsing the mail item size. */ + memset(argument, 0, sizeof(argument)); + + /* Get the number of szie of the message. . */ + _nx_pop3_parse_response(buffer, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, + sizeof(argument) - 1, NX_FALSE, NX_FALSE); + + /* Check if argument parsed successfully. */ + if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) + { + + /* It was; set the size of th e mail item. */ + *item_size = strtoul(argument, NULL, 10); + } + + while (((ULONG)buffer < ((ULONG)recv_packet_ptr -> nx_packet_append_ptr - 1)) && + ((*buffer != 0x0D) || (*(buffer + 1) != 0x0A))) + { + buffer++; + } + + buffer += 2; + + if ((UCHAR *)buffer == recv_packet_ptr -> nx_packet_append_ptr) + { + nx_packet_release(recv_packet_ptr); + } + else + { + client_ptr -> nx_pop3_client_message_ptr = recv_packet_ptr; + recv_packet_ptr -> nx_packet_length -= + (ULONG)buffer - (ULONG)recv_packet_ptr -> nx_packet_prepend_ptr; + recv_packet_ptr -> nx_packet_prepend_ptr = (UCHAR *)buffer; + } + + return NX_SUCCESS; + } + else + { + nx_packet_release(recv_packet_ptr); + return NX_POP3_SERVER_ERROR_STATUS; + } + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_mail_item_message_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get message data */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* recv_packet_ptr Pointer to received PP3 packet */ +/* bytes_retrieved Size of message data in packet */ +/* final_packet Indicates if last packet */ +/* NX_FALSE = not the last packet */ +/* NX_TRUE = is the last packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_mail_item_message_data_get */ +/* Actual get message data service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet) +{ + +UINT status; + + + if ((client_ptr == NX_NULL) || (recv_packet_ptr == NX_NULL) || (bytes_retrieved == NX_NULL) || (final_packet == NX_NULL)) + { + + return NX_PTR_ERROR; + } + + status = _nx_pop3_client_mail_item_message_get(client_ptr, recv_packet_ptr, bytes_retrieved, final_packet); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_mail_item_message_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves message packets from the POP3 Client TCP */ +/* socket and returns them to the caller without further processing. */ +/* It is up to the caller to strip off the trailing end of message tag */ +/* \r\n.\r\n if one is appended to the message. Note the end of */ +/* message is included in the packet length. */ +/* */ +/* When packets are received with only the end of message tag (EOM), */ +/* this function returns zero bytes retrieved and sets final_packet to */ +/* true. */ +/* */ +/* If the status return is NX_SUCCESS, the caller MUST release the */ +/* packet, even if there bytes_retrieved is set to zero. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* recv_packet_ptr Pointer to received packet */ +/* bytes_retrieved Received packet length */ +/* final_packet If last packet of message */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet) +{ +UINT status; +UINT index; +CHAR *buffer_ptr; + + /* Initialize results to no data retrieved, or if the received packet is the last in the message. */ + *final_packet = NX_FALSE; + *bytes_retrieved = 0; + + /* Verify client is ready to download mail messages. */ + if (client_ptr -> nx_pop3_client_ready_to_download == NX_FALSE) + { + + return NX_POP3_CLIENT_INVALID_STATE; + } + + if (client_ptr -> nx_pop3_client_message_ptr) + { + status = NX_SUCCESS; + *recv_packet_ptr = client_ptr -> nx_pop3_client_message_ptr; + client_ptr -> nx_pop3_client_message_ptr = NX_NULL; + } + else + { + + /* Retrieve the next data packet. */ + status = nx_tcp_socket_receive(&client_ptr -> nx_pop3_client_tcp_socket, recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + } + + if (status == NX_SUCCESS) + { + + /* Update the bytes_retrieved with amount of data in the packet. */ + *bytes_retrieved = (*recv_packet_ptr) -> nx_packet_length; + + /* Check for end of message tag in this packet. */ + if (*bytes_retrieved > (sizeof(NX_POP3_END_OF_MESSAGE) - 1)) + { + buffer_ptr = (CHAR *)(*recv_packet_ptr) -> nx_packet_prepend_ptr; + + index = *bytes_retrieved - (sizeof(NX_POP3_END_OF_MESSAGE) - 1); + + /* Determine if the end of the data contains the terminating \r\n.\r\n marker. */ + if (memcmp((buffer_ptr + index), NX_POP3_END_OF_MESSAGE, (sizeof(NX_POP3_END_OF_MESSAGE) - 1)) == 0) + { + + /* It does; indicate this is the end of the mail download. */ + *final_packet = NX_TRUE; + + /* Client cannot download any data for this particular mail item. */ + client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; + } + } + else + { + + if ( + (memcmp((*recv_packet_ptr) -> nx_packet_prepend_ptr, NX_POP3_END_OF_MESSAGE, (sizeof(NX_POP3_END_OF_MESSAGE) - 1))== 0) || + (memcmp((*recv_packet_ptr) -> nx_packet_prepend_ptr, NX_POP3_END_OF_MESSAGE_TAG, (sizeof(NX_POP3_END_OF_MESSAGE_TAG) - 1))== 0) + ) + { + + /* Yes, but this is not considered part of the message. Indicate this with the bytes retrieved. */ + *bytes_retrieved = 0; + + /* It does; indicate this is the end of the mail download. */ + *final_packet = NX_TRUE; + + /* Client cannot download any data for this particular mail item. */ + client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; + } + } + } + + return status; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_mail_item_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the delete mail item */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_index Index of mail item to delete */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_mail_item_delete Actual delete mail service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Check for invalid mail item input. */ + if (mail_index == 0) + { + + return NX_POP3_CLIENT_INVALID_INDEX; + } + + status = _nx_pop3_client_mail_item_delete(client_ptr, mail_index); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_mail_item_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the DELE command for the specified mail item */ +/* and verifies the server will delete the item. Note that for some */ +/* servers, items marked for deletion are not deleted immediately, in */ +/* some cases only if they receive the QUIT command. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* mail_item Index into POP3 mailbox */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* _nx_pop3_server_number_convert Convert integer to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index) +{ + +UINT status; +UINT size; +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer_ptr; +CHAR argument[10]; +UINT packet_type; + + + /* Allocate a packet. */ + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Convert the ascii word to a number. */ + size = _nx_pop3_server_number_convert(mail_index, &argument[0]); + + /* Check packet payload is large enough for DEL request. */ + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_DELE) - 1) + 1 + size + + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + /* Send the DELE command. */ + memcpy(buffer_ptr, NX_POP3_COMMAND_DELE, (sizeof(NX_POP3_COMMAND_DELE) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_DELE) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_DELE) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_DELE) - 1); + + + memcpy(buffer_ptr, " ", 1); + packet_ptr -> nx_packet_length++; + packet_ptr -> nx_packet_append_ptr++; + buffer_ptr++; + + memcpy(buffer_ptr, &argument[0], size); + packet_ptr -> nx_packet_length += size; + packet_ptr -> nx_packet_append_ptr += size; + buffer_ptr += size; + + memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the DELE command out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply to DELE command. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to server error status received. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* Yes, set status to successful completion. */ + status = NX_SUCCESS; + } + + nx_packet_release(recv_packet_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pop3_client_quit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* The service performs error checking for the send QUIT service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to POP3 Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application thread */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_quit Actual send QUIT command service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pop3_client_quit(NX_POP3_CLIENT *client_ptr) +{ + +UINT status; + + if (client_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + status = _nx_pop3_client_quit(client_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_quit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* The service sends a QUIT command to the Client POP3 server. The */ +/* QUIT command takes no arguments and can be called at any time during*/ +/* the Client session. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to POP3 Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application thread */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer_ptr; +CHAR argument[10]; +UINT packet_type; + + + /* Allocate a packet. */ + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Check packet payload will hold the QUIT request. */ + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_QUIT) - 1) + 1 + + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + memcpy(buffer_ptr, NX_POP3_COMMAND_QUIT, (sizeof(NX_POP3_COMMAND_QUIT) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_QUIT) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_QUIT) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_QUIT) - 1); + + memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to bad reply error condition. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* Yes, set status to successful completion. */ + status = NX_SUCCESS; + } + + nx_packet_release(recv_packet_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_digest_authenticate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an MD5 digest based on input string which per */ +/* POP3 protocol is the process ID and secret (e.g. Client password). */ +/* This digest is used in APOP commands for the Client to authenticate */ +/* itself without clear texting it's password. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr POP3 Client pointer */ +/* process_ID_ptr Pointer to process_ID string */ +/* process_ID_length Process ID string length */ +/* result Pointer to MD5 digest */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_md5_initialize Initialize MD5 algorithm */ +/* _nx_md5_update Update MD5 digest */ +/* _nx_md5_digest_calculate Complete the MD5 algorithm */ +/* _nx_pop3_hex_ascii_convert Convert digest to ascii */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pop3_client_apop Send APOP cmd to Server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_digest_authenticate(NX_POP3_CLIENT *client_ptr, CHAR *process_ID_ptr, UINT process_ID_length, CHAR *result) +{ + +CHAR md5_binary[NX_POP3_MAX_BINARY_MD5]; + + /* Initialize the Client session MD5 data. */ + _nx_md5_initialize(&client_ptr -> nx_pop3_client_md5data); + + + _nx_md5_update(&client_ptr -> nx_pop3_client_md5data, (unsigned char *)process_ID_ptr, process_ID_length); + + /* Finish calculation of the MD5 digest. */ + _nx_md5_digest_calculate(&client_ptr -> nx_pop3_client_md5data, (unsigned char *)&md5_binary[0]); + + /* Convert digest to ASCII Hex representation. */ + _nx_pop3_hex_ascii_convert(&md5_binary[0], NX_POP3_MAX_BINARY_MD5, result); + + /* Return successful completion */ + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_parse_process_id PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the process ID in the greeting from server. */ +/* If found the Server is indicating we may use APOP to secure (open) */ +/* the mailbox. The process ID is saved to the POP3 Client instance. If*/ +/* no process ID is found, this field is set to NULL. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* buffer Pointer to server reply buffer */ +/* buffer_length Size of server reply buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_pop3_client_connect Connect and authenticate with server*/ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pop3_parse_process_id(NX_POP3_CLIENT *client_ptr, CHAR *buffer, UINT buffer_length) +{ + +CHAR c; +UINT index; +UINT pid_index; + + + /* Set a pointer to the start of the buffer to search. */ + index = 0; + + /* Clear memory for parsing the server process ID. */ + memset(&client_ptr -> nx_pop3_server_process_id[0], 0, NX_POP3_SERVER_PROCESS_ID_SIZE); + + while(index < buffer_length) + { + c = *buffer; + if (c == '<') + { + + /* Found the start of the process ID. Now save it to the session instance including the angle brackets. */ + pid_index = 0; + + /* Check that we don't go over the size of the process ID buffer or off the end of the packet data. */ + while ((pid_index < NX_POP3_SERVER_PROCESS_ID_SIZE) && (index < buffer_length)) + { + + /* Copy the next character and advance the counters and buffer pointer. */ + client_ptr -> nx_pop3_server_process_id[pid_index] = *buffer; + + /* Check if this is the end of the time stamp which is included in the process id string. . */ + if (*buffer == '>') + { + + /* This is the enclosing bracket. We're done. */ + return; + } + + index++; + pid_index++; + buffer++; + } + + } + index++; + buffer++; + } + + /* If we got here, we did not find any process IDs. */ + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_parse_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service parses the specified argument from the input buffer */ +/* and returns a pointer to the argument if found, else the a NULL */ +/* pointer. Dashes are handled as word separators. */ +/* */ +/* crlf_are_word_breaks indicates if CR LF's should be handled as word */ +/* separators. convert_to_uppercase indicates if the argument should be*/ +/* converted to uppercase. */ +/* */ +/* This service removes CR LF's at the end of the message. It does not*/ +/* allocate or clear argument memory, but does. */ +/* */ +/* INPUT */ +/* */ +/* buffer Pointer to buffer to parse */ +/* argument_index Index of argument to parse */ +/* buffer_length Buffer size */ +/* argument Pointer to argument parsed */ +/* argument_length Argument buffer size */ +/* convert_to_uppercase Convert argument to uppercase */ +/* crlf_are_word_breaks Handle CR LF's as word breaks */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_pop3_parse_response(CHAR *buffer, UINT argument_index, UINT buffer_length, CHAR *argument, UINT argument_length, + UINT convert_to_uppercase, UINT crlf_are_word_breaks) +{ + +UINT i = 0; +UINT j = 0; +UINT argument_char_count; + + + /* Check for invalid input. */ + if ((buffer == NX_NULL)|| (buffer[0] == 0x0) || (argument == NX_NULL) || (buffer_length == 0) || + (argument_length == 0) || (argument_index == 0)) + { + + /* Return with argument not found status. */ + return; + } + + /* Initialize the argument to not found with NULL character. */ + *argument = (CHAR)0x0; + argument_char_count = 0; + + /* Is this the first argument? */ + if (argument_index == 1) + { + + /* Yes, search each character up to the end of the buffer for the first separator. */ + while (i < buffer_length) + { + + /* Did we find it? */ + if (*buffer == ' ') + { + + /* Yes, we're done with this loop! */ + break; + } + + /* Treat a hyphen as word breaks if it is between words, not if it is the first char. */ + if (*buffer == '-' && i > 0) + { + + /* Yes, we're done with this loop! */ + break; + } + + /* Did we go past the argument size limit? */ + if (argument_char_count >= argument_length) + { + + /* Yes, no argument found. */ + break; + } + + /* Copy the next character into the argument, converting + to uppercase if the caller requested this. */ + *argument++ = convert_to_uppercase ? (CHAR)toupper((INT)(*buffer)) : *buffer; + + argument_char_count++; + + /* Move to the next character. */ + i++; + buffer++; + } + + /* Are we at the end of the buffer? */ + if (i == buffer_length) + { + + /* Yes, is there a line terminator? */ + if (*(argument - 2) == 0x0D && *(argument - 1) == 0x0A) + { + + /* Yes, remove it with a null character */ + *(argument - 2) = (CHAR) 0x0; + } + } + } + else + { + /* No, we're not parsing the first argument. */ + + /* Mark the start of the argument at the separator after the end of the previous argument. */ + while (j < argument_index && i < buffer_length) + { + + /* Keep track of the number of separators in the buffer */ + + /* Did we hit a line terminator? */ + if ((*buffer == 0x0D) && (*(buffer + 1) == 0x0A)) + { + + /* Yes, Update the count of separators. */ + j++; + + /* Are line terminators as word breaks? */ + if (!crlf_are_word_breaks) + { + + /* No, treat as the end of the search string buffer. */ + break; + } + + buffer++; + } + + /* Did we hit a space or a dash in the first argument? */ + else if (*buffer == ' ' || + (*buffer == '-' && j == 0)) + { + + /* These are counted as separators (note that + dashes found in arguments after the first arg + are NOT considered separators */ + j++; + } + else + { + + if (j == argument_index - 1) + { + + /* Have we exceeded the limit on the argument size? */ + if (argument_char_count < argument_length) + { + + /* No, copy the next character into the argument. */ + argument_char_count++; + + /* Convert to uppercase if the caller requests. */ + *argument++ = convert_to_uppercase ? (CHAR)toupper((INT)*buffer) : *buffer; + } + } + } + + /* Get the next character */ + i++; + buffer++; + } + } + + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_hex_ascii_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts hexadecimal characters into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* source Source hex string */ +/* source_length Length of source string */ +/* destination Pointer to destination string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pop3_utility_digest_authenticate Create digest for */ +/* authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pop3_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) +{ + +UINT i,j; +CHAR digit; + + + /* Setup destination index. */ + j = 0; + + /* Loop to process the entire source string. */ + for (i = 0; i < source_length; i++) + { + + /* Pickup the first nibble. */ + digit = (source[i] >> 4) & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + + /* Pickup the second nibble. */ + digit = source[i] & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + } + + /* Place a NULL in the destination string. */ + destination[j] = (CHAR) NX_NULL; + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_server_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number into an ASCII string and returns the*/ +/* size of the string holding the number. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* string_to_convert Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* _nx_pop3_client_mail_item_get Get mail item size */ +/* _nx_pop3_client_mail_item_delete Delete mail item */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_server_number_convert(UINT number, CHAR *string_to_convert) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < 9) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string_to_convert[j] = string_to_convert[j - 1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + string_to_convert[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Make the string NULL terminated. */ + string_to_convert[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string_to_convert[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_pop3_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function binds the Client socket to the POP3 port and connects */ +/* to the POP3 server. If the connection is made, this function */ +/* processes the server greeting, and initiates the APOP/USER */ +/* authentication with the sever. */ +/* */ +/* This supports both IPv6 and IPv4 POP3 server connections. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* server_ip_address Pointer to POP3 server IP address */ +/* server_port POP3 server port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_POP3_PARAM_ERROR Invalid Client user or password */ +/* NX_POP3_CANNOT_PARSE_REPLY Unable to parse server reply */ +/* status TCP service completion status */ +/* */ +/* CALLED BY */ +/* */ +/* _nxd_pop3_client_create Create POP3 Client and socket */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_bind NetX TCP socket bind service */ +/* nxd_tcp_client_socket_connect NetX TCP socket connect service */ +/* nx_tcp_socket_receive NetX TCP socket receive service */ +/* _nx_pop3_parse_response Parse Server reply code */ +/* _nx_pop3_parse_process_id Parse server ID for APOP digest */ +/* _nx_pop3_client_apop Send Authenticated user/pass */ +/* _nx_pop3_client_user_pass Send User Pass in clear text */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_pop3_client_connect(NX_POP3_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port) +{ + +UINT status; +NX_PACKET *recv_packet_ptr; +CHAR *buffer_ptr; +CHAR argument[10]; + + + /* Check for client name/password/shared secret too long for allotted buffer. */ + if ((_nx_utility_string_length_check(&client_ptr -> nx_pop3_client_name[0], NX_NULL, NX_POP3_MAX_USERNAME)) || + (_nx_utility_string_length_check(&client_ptr -> nx_pop3_client_password[0], NX_NULL, NX_POP3_MAX_PASSWORD))) + { + + return NX_POP3_PARAM_ERROR; + } + + status = nx_tcp_client_socket_bind(&client_ptr -> nx_pop3_client_tcp_socket, 4228, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + return status; + } + + status = nxd_tcp_client_socket_connect(&client_ptr -> nx_pop3_client_tcp_socket, + server_ip_address, + server_port, + NX_POP3_CLIENT_CONNECTION_TIMEOUT); + + if (status != NX_SUCCESS) + { + return status; + } + + /* Receive server reply over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to bad reply error condition. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + if (client_ptr -> nx_pop3_client_enable_APOP_authentication) + { + + /* Attempt to extract the server process ID in the greeting. */ + _nx_pop3_parse_process_id(client_ptr, buffer_ptr, recv_packet_ptr -> nx_packet_length); + + /* Did we find a process ID? */ + if (client_ptr -> nx_pop3_server_process_id[0] != 0) + { + + /* Do APOP authentication. */ + status = _nx_pop3_client_apop(client_ptr); + + if (status == NX_SUCCESS) + { + return status; + } + else if (status != NX_POP3_SERVER_ERROR_STATUS) + { + + /* Another error encountered (packet pool depletion, broken connection, etc*/ + return status; + } + } + else + { + /* Possibly the server doesn't like APOP. Try User Pass */ + client_ptr -> nx_pop3_client_enable_APOP_authentication = NX_FALSE; + } + } + + /* Try USER PASS authentication. */ + status = _nx_pop3_client_user_pass(client_ptr); + } + + nx_packet_release(recv_packet_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_apop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to authenticate the POP3 client with the POP3*/ +/* server. If successful returns NX_SUCCESS. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Authentication accepted by server */ +/* NX_POP3_APOP_FAILED_MD5_DIGEST Error creating digest */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* _nx_pop3_digest_authenticate Create authentication string */ +/* */ +/* CALLED BY */ +/* */ +/* nxd_pop3_client_connect Connect with POP3 server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_apop(NX_POP3_CLIENT *client_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr, *recv_packet_ptr; +CHAR *buffer; +CHAR argument[10]; +CHAR md5_digest_buffer[NX_POP3_MAX_ASCII_MD5 + 1]; +UINT packet_type; +UINT index; +CHAR userid_buffer[100]; +UINT server_process_id_length; +UINT client_password_length; +UINT client_name_length; +UINT md5_digest_buffer_length; + + + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + /* Create the APOP digest. */ + memset(&userid_buffer[0],0,sizeof(userid_buffer)); + + /* Validate copy size. */ + if (_nx_utility_string_length_check(client_ptr -> nx_pop3_server_process_id, &server_process_id_length, NX_POP3_SERVER_PROCESS_ID_SIZE) || + _nx_utility_string_length_check(client_ptr -> nx_pop3_client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) + { + nx_packet_release(packet_ptr); + return(NX_POP3_INSUFFICIENT_PACKET_PAYLOAD); + } + if((server_process_id_length + client_password_length) > sizeof(userid_buffer)) + { + nx_packet_release(packet_ptr); + return(NX_POP3_INSUFFICIENT_PACKET_PAYLOAD); + } + + memcpy(&userid_buffer[0], &client_ptr -> nx_pop3_server_process_id[0], server_process_id_length); + index = server_process_id_length; + memcpy(&userid_buffer[index], &client_ptr -> nx_pop3_client_password[0], client_password_length); + status = _nx_pop3_digest_authenticate(client_ptr, &userid_buffer[0], (server_process_id_length + client_password_length), &md5_digest_buffer[0]); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Return failed APOP attempt error condition. */ + return NX_POP3_APOP_FAILED_MD5_DIGEST; + } + + /* Verify the packet payload will hold the APOP command. */ + if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_name, &client_name_length, NX_POP3_MAX_USERNAME) || + _nx_utility_string_length_check(md5_digest_buffer, &md5_digest_buffer_length, NX_POP3_MAX_ASCII_MD5)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_APOP) - 1) + + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1) + 2 + + client_name_length + + md5_digest_buffer_length) >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + buffer = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Create the APOP command. */ + memcpy(buffer, NX_POP3_COMMAND_APOP, (sizeof(NX_POP3_COMMAND_APOP) - 1)); + buffer += (sizeof(NX_POP3_COMMAND_APOP) - 1); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_APOP) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_APOP) - 1); + + memcpy(buffer, " ", 1); + buffer++; + packet_ptr -> nx_packet_append_ptr++; + packet_ptr -> nx_packet_length++; + + memcpy(buffer, client_ptr -> nx_pop3_client_name, client_name_length); + buffer += client_name_length; + packet_ptr -> nx_packet_length += client_name_length; + packet_ptr -> nx_packet_append_ptr += client_name_length; + + memcpy(buffer, " ", 1); + buffer++; + packet_ptr -> nx_packet_append_ptr++; + packet_ptr -> nx_packet_length++; + + memcpy(buffer, &md5_digest_buffer[0], md5_digest_buffer_length); + buffer += md5_digest_buffer_length; + packet_ptr -> nx_packet_length += md5_digest_buffer_length; + packet_ptr -> nx_packet_append_ptr += md5_digest_buffer_length; + + memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to bad reply error condition. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* APOP command accepted. */ + status = NX_SUCCESS; + } + + nx_packet_release(recv_packet_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pop3_client_user_pass PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to login using client sername and password */ +/* with the POP3 server. If successful returns NX_SUCCESS. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Login accepted by server */ +/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ +/* Packet too small for command */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_tcp_socket_send Send packet out TCP socket */ +/* nx_tcp_socket_receive Retrieve packet from TCP socket */ +/* _nx_pop3_parse_response Extract word from server response */ +/* _nx_pop3_digest_authenticate Create authentication string */ +/* */ +/* CALLED BY */ +/* */ +/* nxd_pop3_client_connect Connect with POP3 server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pop3_client_user_pass(NX_POP3_CLIENT *client_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr, *recv_packet_ptr, *next_recv_packet_ptr; +CHAR *buffer; +CHAR argument[10]; +UINT packet_type; +UINT client_name_length; +UINT client_password_length; + + + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + /* Verify the packet payload will hold the user command message. */ + if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_name, &client_name_length, NX_POP3_MAX_USERNAME)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_USER) - 1) + + 1 + client_name_length + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) + >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); + + + memcpy(buffer, NX_POP3_COMMAND_USER, (sizeof(NX_POP3_COMMAND_USER) - 1)); + packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_USER) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_USER) - 1); + buffer += (sizeof(NX_POP3_COMMAND_USER) - 1); + + memcpy(buffer, " ", 1); + packet_ptr -> nx_packet_length++; + packet_ptr -> nx_packet_append_ptr++; + buffer++; + + memcpy(buffer, client_ptr -> nx_pop3_client_name, client_name_length); + packet_ptr -> nx_packet_length += client_name_length; + packet_ptr -> nx_packet_append_ptr += client_name_length; + buffer += client_name_length; + + memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply to Client username over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Initialize status to bad reply error condition. */ + status = NX_POP3_SERVER_ERROR_STATUS; + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + /* We are done with this packet. */ + nx_packet_release(recv_packet_ptr); + + if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate another packet. */ + status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return(status); + } + + /* Verify the packet payload will hold the password request. */ + if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_PASS) - 1) + + 1 + client_password_length + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) + >= packet_ptr -> nx_packet_data_end) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; + } + + buffer = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + memcpy(buffer, NX_POP3_COMMAND_PASS, (sizeof(NX_POP3_COMMAND_PASS) - 1)); + buffer += (sizeof(NX_POP3_COMMAND_PASS) - 1); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_PASS) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_PASS) - 1); + + memcpy(buffer, " ", 1); + buffer++; + packet_ptr -> nx_packet_length++; + packet_ptr -> nx_packet_append_ptr++; + + memcpy(buffer, client_ptr -> nx_pop3_client_password, client_password_length); + buffer += client_password_length; + packet_ptr -> nx_packet_length += client_password_length; + packet_ptr -> nx_packet_append_ptr += client_password_length; + + memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); + buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); + + /* Send the next Client message out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return the error condition. */ + return(status); + } + + /* Receive server reply to Client password over session socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &next_recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (next_recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(next_recv_packet_ptr); + return(NX_INVALID_PACKET); + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set a pointer to the packet data. */ + buffer = (CHAR *)(next_recv_packet_ptr -> nx_packet_prepend_ptr); + + /* Parse the first argument of the server reply. */ + _nx_pop3_parse_response(buffer, 1, next_recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); + + /* Did the server accept the Client command? */ + if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) + { + + status = NX_SUCCESS; + } + + /* We are done with this packet. */ + nx_packet_release(next_recv_packet_ptr); + } + else + { + + /* Server rejected the Client message. */ + nx_packet_release(recv_packet_ptr); + } + + return status; +} + diff --git a/addons/pop3/nxd_pop3_client.h b/addons/pop3/nxd_pop3_client.h new file mode 100644 index 00000000..776d7424 --- /dev/null +++ b/addons/pop3/nxd_pop3_client.h @@ -0,0 +1,277 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX POP3 Client Component */ +/** */ +/** Post Office Protocol Version 3 (POP3) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_pop3_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Post Office Protocol Version 3 (POP3) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, nx_port.h, */ +/* fx_api.h and fx_port.h have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_POP3_CLIENT_H +#define NX_POP3_CLIENT_H + + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +#include "nx_md5.h" +#include "nx_api.h" + +#define NX_POP3_CLIENT_ERROR_CONSTANT 0xB0 + +#define NX_POP3_PARAM_ERROR (NX_POP3_CLIENT_ERROR_CONSTANT | 0x1) /* Invalid non pointer parameter passed */ +#define NX_POP3_INVALID_MAIL_ITEM (NX_POP3_CLIENT_ERROR_CONSTANT | 0x2) /* Client block pool not large enough to store packet payload. */ +#define NX_POP3_APOP_FAILED_MD5_DIGEST (NX_POP3_CLIENT_ERROR_CONSTANT | 0x3) /* Client authentication failed; MD5 digest of server ID and password failed. */ +#define NX_POP3_SERVER_ERROR_STATUS (NX_POP3_CLIENT_ERROR_CONSTANT | 0x4) /* Server reply appears to missing expected argument(s). */ +#define NX_POP3_MAIL_BUFFER_OVERFLOW (NX_POP3_CLIENT_ERROR_CONSTANT | 0x5) /* Mail data extraction has filled up mail buffer before extraction complete. */ +#define NX_POP3_INSUFFICIENT_PACKET_PAYLOAD (NX_POP3_CLIENT_ERROR_CONSTANT | 0x6) /* Client mail spool callback is not successful. */ +#define NX_POP3_CLIENT_INVALID_STATE (NX_POP3_CLIENT_ERROR_CONSTANT | 0x7)/* Client not in proper state for specific POP3 action or command. */ +#define NX_POP3_CLIENT_INVALID_INDEX (NX_POP3_CLIENT_ERROR_CONSTANT | 0x8) /* Client command refers to an out of bounds mail index. */ + + + +#define NX_POP3_MAX_BINARY_MD5 16 +#define NX_POP3_MAX_ASCII_MD5 32 + +#define NX_POP3_SERVER_PROCESS_ID_SIZE 75 + +/* POP3 Server replies */ +#define NX_POP3_POSITIVE_STATUS "+OK" +#define NX_POP3_NEGATIVE_STATUS "-ERR" + + +/* Set the maximum size for Client command and Server reply text. */ + +#define NX_POP3_MAX_SERVER_REPLY 512 +#define NX_POP3_MAX_CLIENT_COMMAND 150 + +/* Create symbols for common POP3 sequences. */ +#define NX_POP3_COMMAND_TERMINATION "\r\n" +#define NX_POP3_END_OF_MESSAGE_TAG ".\r\n" +#define NX_POP3_DOT "." +#define NX_POP3_END_OF_MESSAGE "\r\n.\r\n" + +/* Enumerate the server POP3 replies. */ +#define NX_POP3_CODE_INVALID 0 +#define NX_POP3_CODE_OK 1 +#define NX_POP3_CODE_ERR 2 + + +/* Define POP3 Client commands strings. */ + +#define NX_POP3_COMMAND_GREETING "GREETING" +#define NX_POP3_COMMAND_USER "USER" +#define NX_POP3_COMMAND_APOP "APOP" +#define NX_POP3_COMMAND_PASS "PASS" +#define NX_POP3_COMMAND_STAT "STAT" +#define NX_POP3_COMMAND_RETR "RETR" +#define NX_POP3_COMMAND_DELE "DELE" +#define NX_POP3_COMMAND_QUIT "QUIT" +#define NX_POP3_COMMAND_LIST "LIST" +#define NX_POP3_COMMAND_RSET "RSET" +#define NX_POP3_COMMAND_NOOP "NOOP" + +/* Determine the maximum size buffer to store messages in. This need not be + limited to a single packet payload of message data, since the POP3 Client + will receive one or more packets till it sees an end of message symbol, + and appends each packet message data to this buffer. */ + +#ifndef NX_POP3_CLIENT_MAIL_BUFFER_SIZE +#define NX_POP3_CLIENT_MAIL_BUFFER_SIZE 2000 +#endif + + + +#ifndef NX_POP3_CLIENT_PACKET_TIMEOUT +#define NX_POP3_CLIENT_PACKET_TIMEOUT (1 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_POP3_TCP_SOCKET_SEND_WAIT +#define NX_POP3_TCP_SOCKET_SEND_WAIT (10 * NX_IP_PERIODIC_RATE) +#endif + + + +#ifndef NX_POP3_CLIENT_CONNECTION_TIMEOUT +#define NX_POP3_CLIENT_CONNECTION_TIMEOUT (30 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_POP3_CLIENT_DISCONNECT_TIMEOUT +#define NX_POP3_CLIENT_DISCONNECT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_POP3_SERVER_REPLY_TIMEOUT +#define NX_POP3_SERVER_REPLY_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_POP3_MAX_USERNAME +#define NX_POP3_MAX_USERNAME 40 +#endif + +#ifndef NX_POP3_MAX_PASSWORD +#define NX_POP3_MAX_PASSWORD 20 +#endif + +/* Set the size of the POP3 Client window size. This should leave room + for the IP and TCP headers within the IP instance MTU. */ +#ifndef NX_POP3_CLIENT_TCP_WINDOW_SIZE +#define NX_POP3_CLIENT_TCP_WINDOW_SIZE 1460 +#endif + + +/* Define the POP3 Client structure */ + +typedef struct NX_POP3_CLIENT_STRUCT +{ + CHAR nx_pop3_client_name[NX_POP3_MAX_USERNAME + 1]; /* Client name (also used in authentication) */ + CHAR nx_pop3_client_password[NX_POP3_MAX_PASSWORD + 1]; /* Client password for authentication */ + NX_TCP_SOCKET nx_pop3_client_tcp_socket; /* NetX TCP client socket. */ + NX_PACKET_POOL *nx_pop3_client_packet_pool_ptr; /* Packet pool for allocating packets for transmitting POP3 messages */ + UINT nx_pop3_client_enable_APOP_authentication; /* Enable client for APOP authentication */ + UINT nx_pop3_client_mail_status; /* Indication if the mail item was retrieved successfully */ + UINT nx_pop3_client_maildrop_items; /* Number of mail messages waiting in client (user) maildrop. */ + UINT nx_pop3_client_maildrop_index; /* Index of current mail item. */ + ULONG nx_pop3_client_total_message_size; /* Size of message data in bytes sitting in client (user) maildrop. */ + UINT nx_pop3_client_ready_to_download; /* Indicate POP3 Client can download mail data (e.g. RETR accepted by server). */ + CHAR nx_pop3_server_process_id[NX_POP3_SERVER_PROCESS_ID_SIZE + 1]; + NX_MD5 nx_pop3_client_md5data; + NX_PACKET *nx_pop3_client_message_ptr; +} NX_POP3_CLIENT; + + +#ifndef NX_POP3_CLIENT_SOURCE_CODE + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + + +#define nx_pop3_client_create _nx_pop3_client_create +#define nxd_pop3_client_create _nxd_pop3_client_create +#define nx_pop3_client_mail_items_get _nx_pop3_client_mail_items_get +#define nx_pop3_client_mail_item_size_get _nx_pop3_client_mail_item_size_get +#define nx_pop3_client_mail_item_message_get _nx_pop3_client_mail_item_message_get +#define nx_pop3_client_mail_item_get _nx_pop3_client_mail_item_get +#define nx_pop3_client_mail_item_delete _nx_pop3_client_mail_item_delete +#define nx_pop3_client_quit _nx_pop3_client_quit +#define nx_pop3_client_delete _nx_pop3_client_delete + +#else + +/* Services with error checking. */ + +#define nx_pop3_client_create _nxe_pop3_client_create +#define nxd_pop3_client_create _nxde_pop3_client_create +#define nx_pop3_client_mail_items_get _nxe_pop3_client_mail_items_get +#define nx_pop3_client_mail_item_size_get _nxe_pop3_client_mail_item_size_get +#define nx_pop3_client_mail_item_message_get _nxe_pop3_client_mail_item_message_get +#define nx_pop3_client_mail_item_get _nxe_pop3_client_mail_item_get +#define nx_pop3_client_mail_item_delete _nxe_pop3_client_mail_item_delete +#define nx_pop3_client_quit _nxe_pop3_client_quit +#define nx_pop3_client_delete _nxe_pop3_client_delete + +#endif /* if NX_DISABLE_ERROR_CHECKING */ + + + +UINT nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); +UINT nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); +UINT nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); +UINT nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); +UINT nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); +UINT nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr); +UINT nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr); + + +#else /* if NX_POP3_CLIENT_SOURCE_CODE */ + + +/* Client and session specific functions. */ + +UINT _nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT _nxe_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT _nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT _nxde_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); +UINT _nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); +UINT _nxe_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); +UINT _nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); +UINT _nxe_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); +UINT _nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); +UINT _nxe_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); +UINT _nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); +UINT _nxe_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); +UINT _nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); +UINT _nxe_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); +UINT _nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr); +UINT _nxe_pop3_client_delete(NX_POP3_CLIENT *client_ptr); +UINT _nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr); +UINT _nxe_pop3_client_quit(NX_POP3_CLIENT *client_ptr); + +#endif + +/* NetX POP3 Client internal functions */ + +UINT _nx_pop3_digest_authenticate(NX_POP3_CLIENT *client_ptr, CHAR *process_ID_ptr, UINT process_ID_length, CHAR *result); +VOID _nx_pop3_parse_process_id(NX_POP3_CLIENT *client_ptr, CHAR *buffer, UINT buffer_length); +VOID _nx_pop3_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); +UINT _nxd_pop3_client_connect(NX_POP3_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port); +UINT _nx_pop3_server_number_convert(UINT number, CHAR *string_to_convert); +VOID _nx_pop3_parse_response(CHAR *buffer, UINT argument_index, UINT buffer_length, CHAR *argument, UINT argument_length, UINT convert_to_uppercase, UINT include_crlf); +UINT _nx_pop3_client_user_pass(NX_POP3_CLIENT *client_ptr); +UINT _nx_pop3_client_apop(NX_POP3_CLIENT *client_ptr); + + +/* If a C++ compiler is being used....*/ +#ifdef __cplusplus + } +#endif + + +#endif /* NX_POP3_CLIENT_H */ diff --git a/addons/ppp/nx_ppp.c b/addons/ppp/nx_ppp.c new file mode 100644 index 00000000..7c1eda85 --- /dev/null +++ b/addons/ppp/nx_ppp.c @@ -0,0 +1,12044 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Point-to-Point Protocol (PPP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_PPP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_ppp.h" +#ifndef NX_PPP_DISABLE_CHAP +#include "nx_md5.h" +#endif + +/* Define global PPP variables and data structures. */ + +/* Define the PPP created list head pointer and count. */ + +NX_PPP *_nx_ppp_created_ptr = NX_NULL; +ULONG _nx_ppp_created_count = 0; + + +/* Define the CRC lookup table. This is used to improve the + CRC calculation performance. */ + +const USHORT _nx_ppp_crc_table[256] = +{ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all PPP processing, including assembly of */ +/* PPP requests and dispatching them. */ +/* */ +/* INPUT */ +/* */ +/* ppp_addr Address of PPP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Get PPP event flags */ +/* nx_packet_release Release packet */ +/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ +/* _nx_ppp_lcp_state_machine_update Update LCP state machine */ +/* _nx_ppp_process_deferred_ip_packet_send */ +/* Process deferred IP packet */ +/* send */ +/* _nx_ppp_process_deferred_raw_string_send */ +/* Process deferred raw string */ +/* send */ +/* _nx_ppp_receive_packet_get Get PPP receive packet */ +/* _nx_ppp_receive_packet_process Process received PPP packet */ +/* _nx_ppp_timeout Process PPP timeout */ +/* [_nx_ppp_debug_log_capture] Optional PPP debug log */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_thread_entry(ULONG ppp_addr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PPP *ppp_ptr; +ULONG ppp_events; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; +ULONG count; + + + /* Setup the PPP pointer. */ + ppp_ptr = (NX_PPP *) ppp_addr; + + /* Loop to continue processing incoming bytes. */ + while(NX_FOREVER) + { + + +#ifdef NX_PPP_DEBUG_LOG_PRINT_PROTOCOL + /* Display debug output of PPP protocol status. */ + _nx_ppp_debug_log_capture_protocol(ppp_ptr); +#endif + + /* Wait for PPP event(s). The timeout on the wait will drive PPP timeout processing + as well. */ + tx_event_flags_get(&(ppp_ptr -> nx_ppp_event), (ULONG) 0xFFFFFFFF, TX_OR_CLEAR, &ppp_events, NX_WAIT_FOREVER); + + /* Check for PPP stop event. */ + if (ppp_events & NX_PPP_EVENT_STOP) + { + + /* Is PPP already stopped? */ + if (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) + { + + /* No, stop this PPP instance an prepare for the next start operation. */ + + /* Set state to stopped. */ + ppp_ptr -> nx_ppp_state = NX_PPP_STOPPED; + + /* Clean up resources and prepare for next PPP start. */ + + /* Release any packets queued up for the PPP instance. */ + + /* Release any partial receive packets. */ + if (ppp_ptr -> nx_ppp_receive_partial_packet) + nx_packet_release(ppp_ptr -> nx_ppp_receive_partial_packet); + + /* Clear the saved receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Setup the receive buffer processing. */ + ppp_ptr -> nx_ppp_serial_buffer_write_index = 0; + ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; + ppp_ptr -> nx_ppp_serial_buffer_byte_count = 0; + +#ifdef NX_PPP_PPPOE_ENABLE + + /* Loop to release all packets in the deferred processing queue.. */ + while (ppp_ptr -> nx_ppp_deferred_received_packet_head) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Pickup the packet. */ + packet_ptr = ppp_ptr -> nx_ppp_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (ppp_ptr -> nx_ppp_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + ppp_ptr -> nx_ppp_deferred_received_packet_tail = NX_NULL; + } + + /* Release all packets in the raw packet queue. */ + TX_DISABLE + + /* Release packet. */ + nx_packet_release(packet_ptr); + } +#endif /* NX_PPP_PPPOE_ENABLE */ + + /* Release all packets in the IP packet queue. */ + TX_DISABLE + + /* Pickup the head pointer and count. */ + packet_ptr = ppp_ptr -> nx_ppp_ip_packet_queue_head; + + /* Set the list head and tail pointers to NULL. */ + ppp_ptr -> nx_ppp_ip_packet_queue_head = NX_NULL; + ppp_ptr -> nx_ppp_ip_packet_queue_tail = NX_NULL; + + /* Pickup the count. */ + count = ppp_ptr -> nx_ppp_ip_packet_queue_count; + + /* Clear the count. */ + ppp_ptr -> nx_ppp_ip_packet_queue_count = 0; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to release all packets. */ + while (count) + { + /* Pickup next packet. */ + next_packet_ptr = packet_ptr -> nx_packet_queue_next; + + /* Release packet. */ + nx_packet_release(packet_ptr); + + /* Move to next packet. */ + packet_ptr = next_packet_ptr; + + /* Decrement the count. */ + count--; + } + + /* Release all packets in the raw packet queue. */ + TX_DISABLE + + /* Pickup the head pointer and count. */ + packet_ptr = ppp_ptr -> nx_ppp_raw_packet_queue_head; + + /* Set the list head and tail pointers to NULL. */ + ppp_ptr -> nx_ppp_raw_packet_queue_head = NX_NULL; + ppp_ptr -> nx_ppp_raw_packet_queue_tail = NX_NULL; + + /* Pickup the count. */ + count = ppp_ptr -> nx_ppp_raw_packet_queue_count; + + /* Clear the count. */ + ppp_ptr -> nx_ppp_raw_packet_queue_count = 0; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to release all packets. */ + while (count) + { + /* Pickup next packet. */ + next_packet_ptr = packet_ptr -> nx_packet_queue_next; + + /* Release packet. */ + nx_packet_release(packet_ptr); + + /* Move to next packet. */ + packet_ptr = next_packet_ptr; + + /* Decrement the count. */ + count--; + } + + /* Reset all state machines. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_INITIAL_STATE; + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_INITIAL_STATE; + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_INITIAL_STATE; + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_INITIAL_STATE; + + /* Determine how to setup the initial authenticated field. */ + if ((ppp_ptr -> nx_ppp_pap_verify_login) || + (ppp_ptr -> nx_ppp_pap_generate_login) || + (ppp_ptr -> nx_ppp_chap_get_verification_values)) + { + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + } + else + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Clear the IP address. */ + nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, 0, 0); + + /* Clear the local information for PPP client. */ + if (ppp_ptr -> nx_ppp_server == NX_FALSE) + { + + /* Clear the IP addresses. */ + ppp_ptr -> nx_ppp_ipcp_local_ip[0] = 0; + ppp_ptr -> nx_ppp_ipcp_local_ip[1] = 0; + ppp_ptr -> nx_ppp_ipcp_local_ip[2] = 0; + ppp_ptr -> nx_ppp_ipcp_local_ip[3] = 0; + ppp_ptr -> nx_ppp_ipcp_peer_ip[0] = 0; + ppp_ptr -> nx_ppp_ipcp_peer_ip[1] = 0; + ppp_ptr -> nx_ppp_ipcp_peer_ip[2] = 0; + ppp_ptr -> nx_ppp_ipcp_peer_ip[3] = 0; + + /* Clear the DNS addresses. */ + ppp_ptr -> nx_ppp_primary_dns_address = 0; + ppp_ptr -> nx_ppp_secondary_dns_address = 0; + } + } + } + + /* Check for PPP start event. */ + if (ppp_events & NX_PPP_EVENT_START) + { + + /* Is PPP in a stopped state? */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) + { + + /* Update the PPP state. */ + ppp_ptr -> nx_ppp_state = NX_PPP_STARTED; + + /* Yes, move to the initial LCP state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_START_STATE; + + /* Initiate the PPP protocol. */ + _nx_ppp_lcp_state_machine_update(ppp_ptr, NX_NULL); + } + } + + /* Check for PPP raw packet send request. */ + if (ppp_events & NX_PPP_EVENT_RAW_STRING_SEND) + { + + /* Process deferred raw string send requests. */ + _nx_ppp_process_deferred_raw_string_send(ppp_ptr); + } + + /* Check for deferred IP transmit requests. */ + if (ppp_events & NX_PPP_EVENT_IP_PACKET_SEND) + { + + /* Process deferred IP transmit packets. */ + _nx_ppp_process_deferred_ip_packet_send(ppp_ptr); + } + +#ifndef NX_PPP_DISABLE_CHAP + + /* Check for CHAP challenge event. */ + if (ppp_events & NX_PPP_EVENT_CHAP_CHALLENGE) + { + + /* Determine if CHAP is in a completed state. */ + if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_COMPLETED_STATE) + { + + /* Move the state to the new challenge state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_NEW_STATE; + + /* Now update the CHAP state machine in order to force the + new CHAP challenge out. */ + _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); + } + } +#endif + + /* Now check for timeout processing. */ + if (ppp_events & NX_PPP_EVENT_TIMEOUT) + { + + /* Timeout occurred. Is there are PPP timeout active? */ + if (ppp_ptr -> nx_ppp_timeout) + { + + /* Decrement the timeout count. */ + ppp_ptr -> nx_ppp_timeout--; + + /* Has the timeout expired? */ + if (ppp_ptr -> nx_ppp_timeout == 0) + { + + /* Process timeout request. */ + _nx_ppp_timeout(ppp_ptr); + } + } + + /* Increment the receive timeout processing. */ + ppp_ptr -> nx_ppp_receive_timeouts++; + } + + /* Check for PPP Packet receive event. */ + if (ppp_events & NX_PPP_EVENT_PACKET_RECEIVE) + { + + /* Pickup the next PPP packet from serial port to process. This is called whether an event was set or not + simply to handle the case when a non-PPP frame is received. */ + _nx_ppp_receive_packet_get(ppp_ptr, &packet_ptr); + + /* Now determine if there is a packet to process. */ + if (packet_ptr) + { + +#ifdef NX_PPP_DEBUG_LOG_ENABLE + + /* Insert an entry into the PPP frame debug log. */ + _nx_ppp_debug_log_capture(ppp_ptr, 'R', packet_ptr); +#endif + + /* Yes, call the PPP packet processing routine. */ + _nx_ppp_receive_packet_process(ppp_ptr, packet_ptr); + } + } + +#ifdef NX_PPP_PPPOE_ENABLE + + /* Check for PPP Packet receive event. */ + if (ppp_events & NX_PPP_EVENT_PPPOE_PACKET_RECEIVE) + { + + /* Loop to process all deferred packet requests. */ + while (ppp_ptr -> nx_ppp_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = ppp_ptr -> nx_ppp_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (ppp_ptr -> nx_ppp_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + ppp_ptr -> nx_ppp_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + +#ifdef NX_PPP_DEBUG_LOG_ENABLE + + /* Insert an entry into the PPP frame debug log. */ + _nx_ppp_debug_log_capture(ppp_ptr, 'R', packet_ptr); +#endif + + /* Yes, call the PPP packet processing routine. */ + _nx_ppp_receive_packet_process(ppp_ptr, packet_ptr); + } + } +#endif /* NX_PPP_PPPOE_ENABLE */ + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_driver PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides the basic interface to the NetX TCP/IP */ +/* network stack. */ +/* */ +/* INPUT */ +/* */ +/* driver_req_ptr NetX driver request structure */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_transmit_release Release transmit packet */ +/* tx_event_flags_set Set PPP events */ +/* tx_thread_resume Resume PPP thread */ +/* tx_timer_activate Activate PPP timer */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_INTERFACE *interface_ptr; +NX_PPP *ppp_ptr; +NX_PACKET *packet_ptr; +UINT i; + + + /* Setup the IP pointer from the driver request. */ + ip_ptr = driver_req_ptr -> nx_ip_driver_ptr; + + /* Pickup the interface pointer. */ + interface_ptr = driver_req_ptr -> nx_ip_driver_interface; + + /* Default to successful return. */ + driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS; + + /* Process according to the driver request type in the driver control + block. */ + switch (driver_req_ptr -> nx_ip_driver_command) + { + + case NX_LINK_INTERFACE_ATTACH: + { + + /* First, we need to find the PPP instance that is mapped to + this IP instance and that doesn't have its interface attach + complete yet. This requires that PPP is created prior to + IP creation. */ + ppp_ptr = _nx_ppp_created_ptr; + i = 0; + while (i < _nx_ppp_created_count) + { + + /* Does this PPP instance point to the current IP instance? */ + if ((ppp_ptr -> nx_ppp_ip_ptr == ip_ptr) && (ppp_ptr -> nx_ppp_interface_ptr == NX_NULL)) + { + + /* Yes, we found an un-attached PPP instance for this IP interface instance. Get out of + the search loop. */ + break; + } + + /* Move the next PPP instance. */ + ppp_ptr = ppp_ptr -> nx_ppp_created_next; + + /* Increment counter. */ + i++; + } + + /* Determine if a PPP instance was found. */ + if (i >= _nx_ppp_created_count) + { + + /* Return an error to NetX. */ + driver_req_ptr -> nx_ip_driver_status = NX_IP_INTERNAL_ERROR; + return; + } + + /* Now find interface index. */ + i = 0; + while (i < NX_MAX_PHYSICAL_INTERFACES) + { + + /* Is this the interface index? */ + if (&(ip_ptr -> nx_ip_interface[i]) == interface_ptr) + { + + /* Found the index, get out of the loop. */ + break; + } + + /* Move to next interface. */ + i++; + } + + /* Determine if the interface index was found. */ + if (i >= NX_MAX_PHYSICAL_INTERFACES) + { + + /* Return an error to NetX. */ + driver_req_ptr -> nx_ip_driver_status = NX_IP_INTERNAL_ERROR; + return; + } + + /* Otherwise, we have everything we need to perform the attachment. */ + + /* Remember the PPP instance pointer in the IP interface pointer. */ + interface_ptr -> nx_interface_additional_link_info = (void *) ppp_ptr; + + /* Remember the interface pointer and index in the PPP structure. */ + ppp_ptr -> nx_ppp_interface_ptr = interface_ptr; + ppp_ptr -> nx_ppp_interface_index = i; + break; + } + + case NX_LINK_INITIALIZE: + { + + /* Process driver initialization. */ + + + /* Otherwise, we have found the PPP instance, continue initialization. */ + + /* Pickup the associated PPP instance address. */ + ppp_ptr = (NX_PPP *) interface_ptr-> nx_interface_additional_link_info; + + /* Setup the link maximum transfer unit. */ + interface_ptr -> nx_interface_ip_mtu_size = NX_PPP_MRU; + + /* Clear the hardware physical address, since there is no + such thing in PPP. */ + interface_ptr -> nx_interface_physical_address_msw = 0; + interface_ptr -> nx_interface_physical_address_lsw = 0; + + /* Indicate to the IP software that IP to physical mapping + is not required in PPP. */ + interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; + + /* Set the link up to false. */ + interface_ptr -> nx_interface_link_up = NX_FALSE; + + /* Resume the PPP thread. */ + tx_thread_resume(&(ppp_ptr -> nx_ppp_thread)); + + /* Activate the PPP timer. */ + tx_timer_activate(&(ppp_ptr -> nx_ppp_timer)); + break; + } + + + case NX_LINK_ENABLE: + { + + /* Pickup the associated PPP instance address. */ + ppp_ptr = (NX_PPP *) interface_ptr-> nx_interface_additional_link_info; + + /* Now set event flag to start PPP. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); + break; + } + + case NX_LINK_DISABLE: + { + + /* Process driver link disable. */ + + /* Pickup the associated PPP instance address. */ + ppp_ptr = (NX_PPP*) interface_ptr-> nx_interface_additional_link_info; + + /* Now set event flag to start PPP. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + break; + } + + case NX_LINK_PACKET_SEND: + { + + /* Pickup the associated PPP instance address. */ + ppp_ptr = (NX_PPP*) interface_ptr -> nx_interface_additional_link_info; + + /* Pickup packet pointer. */ + packet_ptr = driver_req_ptr -> nx_ip_driver_packet; + + /* Determine if the interface link is still up. */ + if (interface_ptr -> nx_interface_link_up == NX_FALSE) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the transmit frames dropped counter. */ + ppp_ptr -> nx_ppp_transmit_frames_dropped++; +#endif + /* No, release the packet. */ + nx_packet_transmit_release(packet_ptr); + break; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the transmit queue is empty. */ + if (ppp_ptr -> nx_ppp_ip_packet_queue_count++) + { + + /* Not empty, simply link the new packet to the tail and update the tail. */ + (ppp_ptr -> nx_ppp_ip_packet_queue_tail) -> nx_packet_queue_next = packet_ptr; + ppp_ptr -> nx_ppp_ip_packet_queue_tail = packet_ptr; + } + else + { + + /* List is empty, set the head and tail to this packet. */ + ppp_ptr -> nx_ppp_ip_packet_queue_head = packet_ptr; + ppp_ptr -> nx_ppp_ip_packet_queue_tail = packet_ptr; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Set event flag to wake up PPP thread for processing. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_IP_PACKET_SEND, TX_OR); + break; + } + + case NX_LINK_GET_STATUS: + { + + /* Return the link status in the supplied return pointer. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = interface_ptr -> nx_interface_link_up; + break; + } + + case NX_LINK_UNINITIALIZE: + { + + break; + } + + default: + { + + /* Invalid driver request. */ + + /* Return the unhandled command status. */ + driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_receive_packet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function assembles the PPP frame, which involves moving bytes */ +/* from the serial buffer, converting the escape sequences, and */ +/* returning the formed PPP packet to the caller. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* return_packet_ptr Return packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_check_crc Check HDLC frame CRC */ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_receive_packet_get(NX_PPP *ppp_ptr, NX_PACKET **return_packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +NX_PACKET *packet_head_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN +NX_PACKET *next_packet_ptr; +#endif +UCHAR byte; +UCHAR *buffer_ptr; +ULONG buffer_size; +ULONG timeouts; +NX_PACKET *packet_ptr; +UINT status; + + + /* Default the return packet pointer NULL. */ + *return_packet_ptr = NX_NULL; + + /* Pickup the current working packet. */ + packet_ptr = ppp_ptr -> nx_ppp_receive_partial_packet; + + /* Determine if there is a working receive packet. */ + if (packet_ptr == NX_NULL) + { + + /* No, setup new working receive packet. */ + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Save the working receive packet pointer. */ + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup the packet head pointer. */ + packet_head_ptr = packet_ptr; + ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; + + /* Setup packet payload pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Setup packet size. */ + buffer_size = 0; + + /* Initialize the timeout counter. */ + timeouts = 0; + } + else + { + + /* Pickup saved buffer ptr, size and timeout counter. */ + buffer_ptr = ppp_ptr -> nx_ppp_receive_buffer_ptr; + buffer_size = ppp_ptr -> nx_ppp_receive_buffer_size; + + /* Pickup saved timeout count. */ + timeouts = ppp_ptr -> nx_ppp_receive_timeouts; + /* Setup the packet head pointer. */ + packet_head_ptr = ppp_ptr -> nx_ppp_head_packet; + } + + /* Loop to drain the serial buffer. */ + do + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if there are any characters in the serial receive buffer. */ + if (ppp_ptr -> nx_ppp_serial_buffer_byte_count) + { + + /* Yes, there are one or more characters. */ + + /* Pickup the character. */ + byte = ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_read_index]; + + /* Now determine if there is an escape sequence character and we don't have the following + character. */ + if ((byte == 0x7d) && (ppp_ptr -> nx_ppp_serial_buffer_byte_count == 1)) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* We need to wait for another character. */ + break; + } + } + else + { + + /* Nothing is left in the buffer. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if the timeout count has been exceeded. */ + if (timeouts > NX_PPP_RECEIVE_TIMEOUTS) + { + + /* Timeout count has been exceeded. */ + + /* Determine if the packet is non-PPP. If so, we should dispatch it to + the non-PPP packet handler. */ + if ((buffer_size) && (packet_head_ptr -> nx_packet_prepend_ptr[0] != 0x7e)) + { + + /* Determine if there is a user handler for non-PPP packets. */ + if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) + { + + /* Adjust the packet parameters. */ + packet_head_ptr -> nx_packet_length = buffer_size; + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + + /* Dispatch packet to user's handler for non-PPP packets. */ + (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); + } + else + { + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + } + } + else + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the frame timeout counter. */ + ppp_ptr -> nx_ppp_frame_timeouts++; +#endif + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + } + + /* Clear the saved receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Save the new receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup the packet head pointer. */ + packet_head_ptr = packet_ptr; + ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; + + /* Setup packet payload pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Setup packet size. */ + buffer_size = 0; + + /* Initialize the timeout counter. */ + timeouts = 0; + } + + /* We need to wait for another character. */ + break; + } + + /* At this point, we have a character. Adjust the serial buffer information. */ + ppp_ptr -> nx_ppp_serial_buffer_read_index++; + + /* Check for serial buffer wrap-around condition. */ + if (ppp_ptr -> nx_ppp_serial_buffer_read_index >= NX_PPP_SERIAL_BUFFER_SIZE) + { + + /* Reset the buffer read index. */ + ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; + } + + /* Adjust the serial buffer count. */ + ppp_ptr -> nx_ppp_serial_buffer_byte_count--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Clear the timeouts counter. */ + timeouts = 0; + + /* Determine if we are at the beginning of the packet. */ + if (buffer_size == 0) + { + + /* Determine if we should add a PPP frame header. */ + if (byte == 0xFF) + { + + /* Yes, a packet is present without a leading 0x7e. Simply place it in the buffer. */ + *buffer_ptr++ = 0x7e; + + /* Increment the buffer size. */ + buffer_size++; + } + } + + /* Determine if we are at the end of the PPP frame. */ + else if (byte == 0x7e) + { + + /* Yes, we are at the end of the PPP frame. */ + + /* Determine if a non-PPP frame preceded this end of frame marker. */ + if (packet_head_ptr -> nx_packet_prepend_ptr[0] != 0x7e) + { + + /* Determine if there is a handler for non-PPP packets. */ + if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) + { + + /* Adjust the packet parameters. */ + packet_head_ptr -> nx_packet_length = buffer_size; + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + + /* Dispatch packet to user's handler for non-PPP packets. */ + (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); + } + else + { + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + } + + /* Clear the saved receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Save the current receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup the packet head pointer. */ + packet_head_ptr = packet_ptr; + ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; + + /* Setup packet payload pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Setup packet size. */ + buffer_size = 0; + + /* Initialize the timeout counter. */ + timeouts = 0; + + /* Continue to get the next byte. */ + continue; + } + + /* A PPP frame is present. Put the 0x7e into the frame. */ + + /* Yes, place the final 0x7e in the buffer. */ + *buffer_ptr++ = 0x7e; + + /* Increment the buffer size. */ + buffer_size++; + + /* Adjust the packet parameters. */ + packet_head_ptr -> nx_packet_length = buffer_size; + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + + /* Check the CRC of the packet. */ + status = _nx_ppp_check_crc(packet_head_ptr); + + /* Determine if there was an error. */ + if (status != NX_SUCCESS) + { + + /* CRC error is present, just give up on the current frame. */ + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the frame CRC error counter. */ + ppp_ptr -> nx_ppp_frame_crc_errors++; +#endif + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + + /* Clear the saved receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_WAIT_FOREVER); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Save the current receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup the packet head pointer. */ + packet_head_ptr = packet_ptr; + ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; + + /* Setup packet payload pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Setup packet size. */ + buffer_size = 0; + + /* Initialize the timeout counter. */ + timeouts = 0; + + break; + } + + /* Remove the FCS (2 bytes) and Flag (1 byte). */ + packet_head_ptr -> nx_packet_length = packet_head_ptr -> nx_packet_length - 3; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - 3; + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Check for the condition where there is essentially no data in the last packet. */ + if (packet_ptr -> nx_packet_append_ptr <= packet_ptr -> nx_packet_prepend_ptr) + { + ULONG diff = (ULONG)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_append_ptr); + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; + + if (packet_head_ptr != packet_ptr) + { + + + NX_PACKET *tmp_packet_ptr = packet_head_ptr; + NX_PACKET *prev_packet_ptr = tmp_packet_ptr; + while (tmp_packet_ptr -> nx_packet_next != 0x0) + { + prev_packet_ptr = tmp_packet_ptr; + tmp_packet_ptr = tmp_packet_ptr -> nx_packet_next; + } + + nx_packet_release(tmp_packet_ptr); + prev_packet_ptr -> nx_packet_next = NX_NULL; + prev_packet_ptr -> nx_packet_append_ptr -= diff; + } + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Remove the HDLC header. */ + packet_head_ptr -> nx_packet_prepend_ptr += 3; + packet_head_ptr -> nx_packet_length -= 3; + + /* Return the pointer. */ + *return_packet_ptr = packet_head_ptr; + + /* Set the receive packet to NULL to indicate there is no partial packet being + processed. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Return to caller. */ + return; + } + + /* Determine if an escape byte is present. */ + if (byte == 0x7d) + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the character - we know there is one because of earlier logic. */ + byte = ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_read_index++]; + + /* Check for serial buffer wrap-around condition. */ + if (ppp_ptr -> nx_ppp_serial_buffer_read_index >= NX_PPP_SERIAL_BUFFER_SIZE) + { + + /* Reset the buffer read index. */ + ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; + } + + /* Adjust the serial buffer count. */ + ppp_ptr -> nx_ppp_serial_buffer_byte_count--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Convert the escape sequence character. */ + byte = byte ^ 0x20; + } + + /* Determine if there is room in the payload. */ + if (buffer_ptr < (packet_ptr -> nx_packet_data_end - 4)) + { + + /* Put the character in the packet payload. */ + *buffer_ptr++ = byte; + + /* Increment the buffer size. */ + buffer_size++; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* We need to perform packet chaining at this point, but only for IP data frames. Non PPP data and + the other PPP protocol packets must fit within the payload of one packet. */ + else if ((packet_head_ptr -> nx_packet_prepend_ptr[0] == 0x7e) && + (packet_head_ptr -> nx_packet_prepend_ptr[1] == 0xff) && + (packet_head_ptr -> nx_packet_prepend_ptr[2] == 0x03) && + (packet_head_ptr -> nx_packet_prepend_ptr[3] == 0x00) && + (packet_head_ptr -> nx_packet_prepend_ptr[4] == 0x21)) /* 0x0021 is NX_PPP_DATA */ + { + + /* We need to move to the next packet and chain them. */ + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + + /* Allocate a new packet to for packet chaining. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &next_packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* Clear the partial receive packet pointer. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Adjust the next packet pointer. */ + packet_ptr -> nx_packet_next = next_packet_ptr; + + /* Setup the last pointer. */ + packet_head_ptr -> nx_packet_last = next_packet_ptr; + + /* Use the packet pointer. */ + packet_ptr = next_packet_ptr; + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup buffer pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Put the character in the packet payload. */ + *buffer_ptr++ = byte; + + /* Increment the buffer size. */ + buffer_size++; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + else + { + + /* At this point we know we have a buffer full of non-PPP characters, in + most cases this is simply noise. */ + + /* Determine if there is a non-PPP handler. */ + if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) + { + + /* Adjust the packet parameters. */ + packet_head_ptr -> nx_packet_length = buffer_size; + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + + /* Dispatch packet to user's handler for non-PPP packets. */ + (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); + } + else + { + + /* Release the current packet. */ + nx_packet_release(packet_head_ptr); + } + + /* Clear the partial receive packet pointer. */ + ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Save the current receive packet. */ + ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; + + /* Setup the packet head pointer. */ + packet_head_ptr = packet_ptr; + ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; + + /* Setup packet payload pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Setup packet size. */ + buffer_size = 0; + + /* Initialize the timeout counter. */ + timeouts = 0; + } + } while(ppp_ptr -> nx_ppp_serial_buffer_byte_count); + + /* Save the buffer size, buffer pointer, and timeout count. */ + ppp_ptr -> nx_ppp_receive_buffer_size = buffer_size; + ppp_ptr -> nx_ppp_receive_buffer_ptr = buffer_ptr; + ppp_ptr -> nx_ppp_receive_timeouts = timeouts; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_receive_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a received PPP request and dispatches it */ +/* to the appropriate protocol or to NetX. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to PPP packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* _nx_ppp_lcp_state_machine_update Process LCP message */ +/* _nx_ppp_pap_state_machine_update Process PAP message */ +/* _nx_ppp_chap_state_machine_update Process CHAP message */ +/* _nx_ppp_ipcp_state_machine_update Process IPCP message */ +/* _nx_ppp_netx_packet_transfer Transfer packet to NetX */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_thread_entry PPP thread entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_receive_packet_process(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UINT protocol; +UINT ppp_ipcp_state; +UINT code; + + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IP frames sent. */ + ppp_ptr -> nx_ppp_total_frames_received++; +#endif + + /* Check for valid packet length for Protocol (2 bytes). */ + if (packet_ptr -> nx_packet_length < 2) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } + + /* Pickup the protocol type. */ + protocol = (((UINT) packet_ptr -> nx_packet_prepend_ptr[0]) << 8) | ((UINT) packet_ptr -> nx_packet_prepend_ptr[1]); + + /* Check protocol. */ + if (protocol != NX_PPP_DATA) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Discard the chained packets. */ + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } +#endif + + /* Other Protocols must also have Code:1 byte, Identifier:1 bytes, Length: 2 bytes. */ + if (packet_ptr -> nx_packet_length < 6) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } + } + + /* Determine if the packet is LCP. */ + if (protocol == NX_PPP_LCP_PROTOCOL) + { + + /* Pickup the type of received LCP code. */ + code = packet_ptr -> nx_packet_prepend_ptr[2]; + + /* Process the LCP message, updating the LCP state machine. */ + _nx_ppp_lcp_state_machine_update(ppp_ptr, packet_ptr); + + /* Determine if the LCP is now complete. */ + if (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_COMPLETED_STATE) + { + +#ifndef NX_PPP_DISABLE_PAP + + /* Determine if the PAP state machine should be started. */ + if ((ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_PAP_PROTOCOL) || + (ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_PAP_PROTOCOL)) + { + + /* Check if PAP already start. */ + if (ppp_ptr -> nx_ppp_pap_state == NX_PPP_PAP_INITIAL_STATE) + { + + /* Yes, change state to PAP start state and update the PAP state machine. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_START_STATE; + + /* Process the PAP message. */ + _nx_ppp_pap_state_machine_update(ppp_ptr, NX_NULL); + } + } +#endif + +#ifndef NX_PPP_DISABLE_CHAP + + /* Determine if the CHAP state machine should be started. */ + if ((ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) || + (ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_CHAP_PROTOCOL)) + { + + /* Check if CHAP already start. */ + if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_INITIAL_STATE) + { + + /* Yes, change state to CHAP start state and update the CHAP state machine. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_START_STATE; + + /* Process the CHAP message. */ + _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); + } + } +#endif + + /* Do not set the IPCP state to INIT on receipt of an LCP echo request or reply! */ + if ((code != NX_PPP_LCP_ECHO_REQUEST) && (code != NX_PPP_LCP_ECHO_REPLY)) + { + + /* Check for authentication. */ + if (ppp_ptr -> nx_ppp_authenticated) + { + + /* Check if IPCP already start. */ + if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) + { + + /* Yes, change state to IPCP start state and update the PAP state machine. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; + + /* Process the IPCP message. */ + _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); + } + } + } + + /* Check if the packet is Echo Request. */ + if (code == NX_PPP_LCP_ECHO_REQUEST) + { + + /* Clear the pointer since it was sent out as Echo Reply. */ + packet_ptr = NX_NULL; + } + } + } + + +#ifndef NX_PPP_DISABLE_PAP + + /* Determine if the packet is PAP. */ + else if (protocol == NX_PPP_PAP_PROTOCOL) + { + + /* Process the PAP message. */ + _nx_ppp_pap_state_machine_update(ppp_ptr, packet_ptr); + + /* Check for authentication. */ + if (ppp_ptr -> nx_ppp_authenticated) + { + + /* Check if IPCP already start. */ + if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) + { + + /* Yes, change state to IPCP start state and update the IPCP state machine. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; + + /* Process the IPCP message. */ + _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); + } + } + } +#endif + +#ifndef NX_PPP_DISABLE_CHAP + + /* Determine if the packet is CHAP. */ + else if (protocol == NX_PPP_CHAP_PROTOCOL) + { + + /* Process the CHAP message. */ + _nx_ppp_chap_state_machine_update(ppp_ptr, packet_ptr); + + /* Check for authentication. */ + if (ppp_ptr -> nx_ppp_authenticated) + { + + /* Check if IPCP already start. */ + if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) + { + + /* Yes, change state to IPCP start state and update the IPCP state machine. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; + + /* Process the IPCP message. */ + _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); + } + } + } +#endif + + /* Determine if packet is IPCP. */ + else if (protocol == NX_PPP_IPCP_PROTOCOL) + { + + /* Process the IPCP message. */ + ppp_ipcp_state = ppp_ptr -> nx_ppp_ipcp_state; + + _nx_ppp_ipcp_state_machine_update(ppp_ptr, packet_ptr); + + /* Check for IPCP completion... when this happens, the link is up! */ + if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_COMPLETED_STATE) + { + + /* Set the PPP state machine to indicate it is complete. */ + ppp_ptr -> nx_ppp_state = NX_PPP_ESTABLISHED; + + /* Mark the IP interface instance as link up. */ + (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_link_up = NX_TRUE; + + /* Determine if the application has registered a link up notification + callback. */ + if ((ppp_ptr -> nx_ppp_link_up_callback) && (ppp_ipcp_state!=NX_PPP_IPCP_COMPLETED_STATE)) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_up_callback)(ppp_ptr); + } + } + } + + /* Check for normal data packet. */ + else if (protocol == NX_PPP_DATA) + { + + /* Transfer the packet to NetX. */ + _nx_ppp_netx_packet_transfer(ppp_ptr, packet_ptr); + + /* Clear the pointer since it was passed to NetX. */ + packet_ptr = NX_NULL; + } +#ifndef NX_PPP_DISABLE_INFO + + else + /* Increment the number of frames dropped. */ + ppp_ptr -> nx_ppp_receive_frames_dropped++; +#endif + + /* Determine if the packet needs to be released. */ + if (packet_ptr) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes PPP time-out events, which includes */ +/* updating the responsible state machine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_lcp_state_machine_update PPP state machine update */ +/* _nx_ppp_pap_state_machine_update PPP PAP state machine update */ +/* _nx_ppp_chap_state_machine_update PPP CHAP state machine update */ +/* _nx_ppp_ipcp_state_machine_update PPP IPCP state machine update */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_timeout(NX_PPP *ppp_ptr) +{ + + /* Determine if the LCP state machine needs updating. */ + if ((ppp_ptr -> nx_ppp_lcp_state >= NX_PPP_LCP_START_STATE) && + (ppp_ptr -> nx_ppp_lcp_state < NX_PPP_LCP_COMPLETED_STATE)) + { + + /* Update the PPP state machine. */ + _nx_ppp_lcp_state_machine_update(ppp_ptr, NX_NULL); + } + +#ifndef NX_PPP_DISABLE_PAP + + /* Determine if the PAP state machine needs updating. */ + if ((ppp_ptr -> nx_ppp_pap_state >= NX_PPP_PAP_START_STATE) && + (ppp_ptr -> nx_ppp_pap_state < NX_PPP_PAP_COMPLETED_STATE)) + { + + /* Update the PAP state machine. */ + _nx_ppp_pap_state_machine_update(ppp_ptr, NX_NULL); + } +#endif + +#ifndef NX_PPP_DISABLE_CHAP + + /* Determine if the CHAP state machine needs updating. */ + if ((ppp_ptr -> nx_ppp_chap_state >= NX_PPP_CHAP_START_STATE) && + (ppp_ptr -> nx_ppp_chap_state < NX_PPP_CHAP_COMPLETED_STATE)) + { + + /* Update the CHAP state machine. */ + _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); + } +#endif + + /* Determine if the IPCP state machine needs updating. */ + if ((ppp_ptr -> nx_ppp_ipcp_state >= NX_PPP_IPCP_START_STATE) && + (ppp_ptr -> nx_ppp_ipcp_state < NX_PPP_IPCP_COMPLETED_STATE)) + { + + /* Update the IPCP state machine. */ + _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes PPP time-outs, which sets a time-out event */ +/* that wakes up the PPP processing thread. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set timeout event flag */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_timer_entry(ULONG id) +{ + +NX_PPP *ppp_ptr; + + + /* Pickup the PPP pointer. */ + ppp_ptr = (NX_PPP *) id; + + /* Make sure the PPP pointer is good. */ + if ((ppp_ptr != NX_NULL) && (ppp_ptr -> nx_ppp_id == NX_PPP_ID)) + { + + /* Set the timeout event for the PPP thread. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_TIMEOUT, TX_OR); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_netx_packet_transfer PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the PPP header and passes the packet to */ +/* NetX. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_deferred_receive Deferred IP packet receive */ +/* _nx_ip_packet_receive IP packet receive */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_process Receive packet processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_netx_packet_transfer(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +ULONG offset; + +#ifndef NX_PPP_DISABLE_INFO + /* Increment the number of IP frames received. */ + ppp_ptr -> nx_ppp_ip_frames_received++; +#endif + + /* Add the incoming interface pointer. */ + packet_ptr -> nx_packet_ip_interface = ppp_ptr -> nx_ppp_interface_ptr; + + /* Remove the PPP header [00,21] in the front of the IP packet. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Calculate the offset for four byte alignment. */ + offset = (((ULONG)packet_ptr -> nx_packet_prepend_ptr) & 3); + + /* Move the data to keep four byte alignment for first packet. */ + if (offset) + { + memmove(packet_ptr -> nx_packet_prepend_ptr - offset, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr)); + packet_ptr -> nx_packet_prepend_ptr -= offset; + packet_ptr -> nx_packet_append_ptr -= offset; + } + + /* Transfer the receive packet to NetX. */ +#ifdef NX_DIRECT_ISR_CALL + _nx_ip_packet_receive(ppp_ptr -> nx_ppp_ip_ptr, packet_ptr); +#else + _nx_ip_packet_deferred_receive(ppp_ptr -> nx_ppp_ip_ptr, packet_ptr); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_process_deferred_raw_string_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function takes all the raw string packets from the deferred raw*/ +/* string packet queue and then sends them out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* (nx_ppp_byte_send) User's byte output routine */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_thread_entry PPP processing thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_process_deferred_raw_string_send(NX_PPP *ppp_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *packet_ptr; +ULONG i; +#ifdef NX_PPP_PPPOE_ENABLE +UINT release_packet; +#endif /* NX_PPP_PPPOE_ENABLE */ + + + /* Loop to process all queued packets. */ + do + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the number of queued packets. */ + if (ppp_ptr -> nx_ppp_raw_packet_queue_count) + { + + /* Pickup the oldest packet. */ + packet_ptr = ppp_ptr -> nx_ppp_raw_packet_queue_head; + + /* Update the head pointer to the next packet. */ + ppp_ptr -> nx_ppp_raw_packet_queue_head = packet_ptr -> nx_packet_queue_next; + + /* Decrement the number of queued packets. */ + ppp_ptr -> nx_ppp_raw_packet_queue_count--; + } + else + { + + /* No packet just set the packet pointer to NULL. */ + packet_ptr = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Is there a packet to process? */ + if (packet_ptr == NX_NULL) + { + + /* No, just get out of the loop! */ + break; + } + +#ifdef NX_PPP_PPPOE_ENABLE + release_packet = NX_TRUE; +#endif /* NX_PPP_PPPOE_ENABLE */ + + if (ppp_ptr -> nx_ppp_byte_send) + { + + /* Loop to send all the bytes of the packet out. */ + for (i = 0; i < packet_ptr -> nx_packet_length; i++) + { + + /* Send each byte out. */ + (ppp_ptr -> nx_ppp_byte_send)(packet_ptr -> nx_packet_prepend_ptr[i]); + } + } + +#ifdef NX_PPP_PPPOE_ENABLE + + /* Check the PPPoE packet send function. */ + if (ppp_ptr -> nx_ppp_packet_send) + { + + /* Send the packet out. */ + (ppp_ptr -> nx_ppp_packet_send)(packet_ptr); + + /* Update the flag since this packet should been released in PPPoE. */ + release_packet = NX_FALSE; + } + + /* Check if need to release the packet. */ + if (release_packet == NX_TRUE) +#endif /* NX_PPP_PPPOE_ENABLE */ + + nx_packet_release(packet_ptr); + + } while (1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_process_deferred_ip_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function takes all the packets from the deferred IP packet */ +/* queue, packages them in an PPP frame, and then sends them out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_packet_transmit Send AHDLC packet */ +/* nx_packet_transmit_release Release NetX packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_thread_entry PPP processing thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_process_deferred_ip_packet_send(NX_PPP *ppp_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *packet_ptr; + + + /* Loop to process all queued packets. */ + do + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the number of queued packets. */ + if (ppp_ptr -> nx_ppp_ip_packet_queue_count) + { + + /* Pickup the oldest packet. */ + packet_ptr = ppp_ptr -> nx_ppp_ip_packet_queue_head; + + /* Update the head pointer to the next packet. */ + ppp_ptr -> nx_ppp_ip_packet_queue_head = packet_ptr -> nx_packet_queue_next; + + /* Decrement the number of queued packets. */ + ppp_ptr -> nx_ppp_ip_packet_queue_count--; + } + else + { + + /* No packet just set the packet pointer to NULL. */ + packet_ptr = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Is there a packet to process? */ + if (packet_ptr == NX_NULL) + { + + /* No, just get out of the loop! */ + break; + } + + /* Determine if there is room in the front of the packet for the PPP header. */ + if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < 2) + { + + /* Error, there is no room at the front of the packet to prepend the PPP header. */ + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* Release the NetX packet. */ + nx_packet_transmit_release(packet_ptr); + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Otherwise, backup the prepend pointer. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 2; + + /* Place the PPP header in the packet. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_DATA & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_DATA & 0xFF; + + /* Adjust the length of the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 2; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IP frames sent. */ + ppp_ptr -> nx_ppp_ip_frames_sent++; +#endif + + /* Send the packet! */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); + } while (1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_state_machine_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes LCP messages and updates the LCP state */ +/* machine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to LCP packet. If the */ +/* packet is NULL, a timeout is*/ +/* present */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_lcp_code_reject Reject received code */ +/* _nx_ppp_lcp_configuration_retrieve Retrieve configuration info */ +/* _nx_ppp_lcp_configure_reply_send Send configure reply */ +/* _nx_ppp_lcp_configure_request_send Send configure request */ +/* _nx_ppp_lcp_nak_configure_list Get options naked */ +/* _nx_ppp_lcp_terminate_ack_send Send terminate ack */ +/* _nx_ppp_lcp_terminate_request_send Send terminate request */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_process Receive packet processing */ +/* _nx_ppp_timeout PPP timeout */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UINT configure_status; +UCHAR *lcp_message_ptr; +UCHAR code; + + /* Determine if a packet is present. If so, derive the event from the packet. */ + if (packet_ptr) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames received. */ + ppp_ptr -> nx_ppp_lcp_frames_received++; +#endif + + /* Setup a pointer to the LCP pointer. */ + lcp_message_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the type of received LCP code. */ + code = packet_ptr -> nx_packet_prepend_ptr[2]; + +#ifndef NX_PPP_DISABLE_INFO + + /* Count the number of specific LCP requests. */ + switch (code) + { + + case NX_PPP_LCP_CONFIGURE_REQUEST: + + /* Increment the number of LCP configure requests received. */ + ppp_ptr -> nx_ppp_lcp_configure_requests_received++; + break; + + case NX_PPP_LCP_CONFIGURE_ACK: + + /* Increment the number of LCP configure ACKs received. */ + ppp_ptr -> nx_ppp_lcp_configure_acks_received++; + break; + + case NX_PPP_LCP_CONFIGURE_NAK: + + /* Increment the number of LCP configure NAKs received. */ + ppp_ptr -> nx_ppp_lcp_configure_naks_received++; + break; + + case NX_PPP_LCP_CONFIGURE_REJECT: + + /* Increment the number of LCP configure rejects received. */ + ppp_ptr -> nx_ppp_lcp_configure_rejects_received++; + break; + + case NX_PPP_LCP_TERMINATE_REQUEST: + + /* Increment the number of LCP terminate requests received. */ + ppp_ptr -> nx_ppp_lcp_terminate_requests_received++; + break; + + case NX_PPP_LCP_TERMINATE_ACK: + + /* Increment the number of LCP terminate ACKs received. */ + ppp_ptr -> nx_ppp_lcp_terminate_acks_received++; + break; + + case NX_PPP_LCP_CODE_REJECT: + + /* Increment the number of LCP code rejects received. */ + ppp_ptr -> nx_ppp_lcp_code_rejects_received++; + break; + + case NX_PPP_LCP_PROTOCOL_REJECT: + + /* Increment the number of LCP protocol rejects received. */ + ppp_ptr -> nx_ppp_lcp_protocol_rejects_received++; + break; + + case NX_PPP_LCP_ECHO_REQUEST: + + /* Increment the number of LCP echo requests received. */ + ppp_ptr -> nx_ppp_lcp_echo_requests_received++; + + break; + + case NX_PPP_LCP_ECHO_REPLY: + + /* Increment the number of LCP echo replies received. */ + break; + + case NX_PPP_LCP_DISCARD_REQUEST: + + /* Increment the number of LCP discard requests received. */ + ppp_ptr -> nx_ppp_lcp_discard_requests_received++; + break; + + default: + + /* Increment the number of LCP unknown (unhandled) requests received. */ + ppp_ptr -> nx_ppp_lcp_unknown_requests_received++; + } +#endif + + /* Remember receive id. */ + ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Is the code supported by PPP? */ + if ((code < NX_PPP_LCP_CONFIGURE_REQUEST) || + (code > NX_PPP_LCP_DISCARD_REQUEST)) + { + + /* No, this code is not supported. Reject the code. */ + _nx_ppp_lcp_code_reject(ppp_ptr, lcp_message_ptr); + + /* Return. */ + return; + } + } + else + { + + /* Set the LCP pointer to NULL. */ + lcp_message_ptr = NX_NULL; + + /* Set the code to timeout to indicate a timeout has occurred. */ + code = NX_PPP_LCP_TIMEOUT; + +#ifndef NX_PPP_DISABLE_INFO + + /* Determine if we are in the initial state. If so, this really isn't a timeout. */ + if (ppp_ptr -> nx_ppp_lcp_state != NX_PPP_LCP_START_STATE) + { + + /* Increment the LCP timeout counter. */ + ppp_ptr -> nx_ppp_lcp_state_machine_timeouts++; + } +#endif + } + + /* Process relative to the current state. */ + switch (ppp_ptr -> nx_ppp_lcp_state) + { + + case NX_PPP_LCP_START_STATE: + { + + /* Initial LCP state. */ + + /* Initialize the NAK and rejected lists. */ +#ifndef NX_PPP_DNS_OPTION_DISABLE + + ppp_ptr -> nx_ppp_naked_list[0] = 0; +#else + ppp_ptr -> nx_ppp_naked_list[0] = 1; +#endif + ppp_ptr -> nx_ppp_peer_naked_list[0] = 0; + ppp_ptr -> nx_ppp_rejected_list[0] = 0; + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send configuration request to peer. */ + _nx_ppp_lcp_configure_request_send(ppp_ptr); + + /* Move to the next state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE; + break; + } + + case NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE: + { + + /* In this state, we have sent a configuration request but had not received an ACK + or a configuration request from the peer. */ + + /* Process relative to the incoming code. */ + if (code == NX_PPP_LCP_CONFIGURE_ACK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* The peer has ACKed our configuration request. Move to the + configure request ACKed state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE; + + /* Turn off the timeout for the configuration request. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + else if (code == NX_PPP_LCP_CONFIGURE_NAK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Figure out what options were naked. */ + _nx_ppp_lcp_nak_configure_list(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + + /* Send new configure request. */ + _nx_ppp_lcp_configure_request_send(ppp_ptr); + } + + else if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + + /* The peer has sent a configuration request. */ + + /* Retrieve configuration. */ + configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + + /* Determine if the configuration request is fine or needs to be negotiated further. */ + if (configure_status == 0) + { + + /* The peer's request is acceptable, move into peer configuration request ACKed state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE; + } + + /* Send configuration reply. */ + _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + } + else if (code == NX_PPP_LCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the LCP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Timeout, send configuration request again. */ + _nx_ppp_lcp_configure_request_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter LCP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE: + { + + /* In this state, we have received the ACK for our configuration request, but have not yet + received a configuration request from the peer. */ + + /* Process relative to the incoming code. */ + if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + + /* The peer has sent a configuration request. */ + + /* Retrieve configuration. */ + configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + + /* Determine if the configuration request is fine or needs to be negotiated further. */ + if (configure_status == 0) + { + + /* The peer's request is acceptable, move into the LCP done state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; + + /* Determine if we need to update the IP's MTU. */ + if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) + { + + /* Yes, the peer can accept larger messages than the default. */ + (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; + } + + /* Disable the LCP timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + /* Send configuration reply. */ + _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE: + { + + /* In this state, we have sent our configuration request, but haven't received an ACK. We have also received + a peer configuration request and have ACKed that request. */ + + /* Process relative to the incoming code. */ + if (code == NX_PPP_LCP_CONFIGURE_ACK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* The peer has ACKed our configuration request. Move to the + LCP completed state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; + + /* Determine if we need to update the IP's MTU. */ + if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) + { + + /* Yes, the peer can accept larger messages than the default. */ + (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; + } + + /* Turn off the timeout for the configuration request. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + else if (code == NX_PPP_LCP_CONFIGURE_NAK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Figure out what options were naked. */ + _nx_ppp_lcp_nak_configure_list(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + + /* Send new configure request. */ + _nx_ppp_lcp_configure_request_send(ppp_ptr); + } + + else if (code == NX_PPP_LCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the LCP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Timeout, send configuration request again. */ + _nx_ppp_lcp_configure_request_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter LCP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_LCP_COMPLETED_STATE: + { + + /* PPP is up and operational at this point. */ + + /* Process relative to incoming code. */ + if (code == NX_PPP_LCP_TERMINATE_REQUEST) + { + + /* ACK the terminate request. */ + _nx_ppp_lcp_terminate_ack_send(ppp_ptr); + + /* Move to stopped state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPED_STATE; + + /* Set the event to stop the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + else if ((code == NX_PPP_LCP_ECHO_REQUEST) && (packet_ptr)) + { + + /* Respond to the echo request. */ + _nx_ppp_lcp_ping_reply(ppp_ptr, packet_ptr); + } + + else if ((code == NX_PPP_LCP_ECHO_REPLY) && (packet_ptr)) + { + + /* Check if the PPP instance is waiting on an echo reply. */ + if (ppp_ptr -> nx_ppp_lcp_echo_reply_id) + { + + /* It is. Check if this is a valid reply. */ + _nx_ppp_lcp_ping_process_echo_reply(ppp_ptr, packet_ptr); + } + + break; + } + + /* In this state, we have received the ACK for our configuration request/completed LCP, but are expecting + a configuration request from the peer. */ + + /* Process relative to the incoming code. */ + else if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + + /* The peer has sent a configuration request. */ + + /* Retrieve configuration. */ + configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + + /* Determine if the configuration request is fine or needs to be negotiated further. */ + if (configure_status == 0) + { + + + /* The peer's request is acceptable, move into the LCP done state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; + + /* Determine if we need to update the IP's MTU. */ + if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) + { + + /* Yes, the peer can accept larger messages than the default. */ + (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; + } + + /* Disable the LCP timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + /* Send configuration reply. */ + _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_LCP_STOPPING_STATE: + { + + /* We received a terminate request from the other side and just need to get the ACK. */ + + /* Process relative to incoming code. */ + if (code == NX_PPP_LCP_TERMINATE_ACK) + { + + /* Move to stopped state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPED_STATE; + + /* Set the event to stop the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + else if (code == NX_PPP_LCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the LCP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send terminate request. */ + _nx_ppp_lcp_terminate_request_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter LCP failed state. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; + + /* Set the event to stop the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + +#ifndef NX_PPP_DISABLE_INFO + if (code == NX_PPP_LCP_ECHO_REQUEST) + { + + + ppp_ptr -> nx_ppp_lcp_echo_requests_dropped++; + } +#endif + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + default: + { + +#ifndef NX_PPP_DISABLE_INFO + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; + } +#endif + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_code_reject PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a code reject message and sends it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* lcp_ptr Pointer to LCP message */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send PPP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_code_reject(NX_PPP *ppp_ptr, UCHAR *lcp_ptr) +{ + +UINT i; +UINT status; +UINT length; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return. */ + return; + } + + /* Build the configuration request. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CODE_REJECT; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = lcp_ptr[4]; + packet_ptr -> nx_packet_prepend_ptr[5] = lcp_ptr[5]; + + length = (((UINT) lcp_ptr[4]) << 8) | ((UINT) lcp_ptr[5]); + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (length + 2)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Send the options that were received with RCR. */ + for(i = 0; i < (length - 4); i++) + { + + /* Copy option byte into new packet. */ + packet_ptr -> nx_packet_prepend_ptr[6+i] = lcp_ptr[6+i]; + } + + /* Setup the packet length and append pointer. */ + packet_ptr -> nx_packet_length = length + 2; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; + + /* Increment code rejects sent counter. */ + ppp_ptr -> nx_ppp_lcp_code_rejects_sent++; +#endif + + /* Send code reject message. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_configure_reply_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a configuration reply. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* configure_status Status from configure request */ +/* lcp_ptr Pointer to LCP message */ +/* naked_list List of NAKed options */ +/* rejected_list List of rejected options */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send PPP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_configure_reply_send(NX_PPP *ppp_ptr, UINT configure_status, UCHAR *lcp_ptr, UCHAR *naked_list, UCHAR *rejected_list) +{ + +UINT i; +UINT status; +UINT length; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build the configuration reply. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + + /* Process relative to the supplied status. */ + if (configure_status == 0) + { + /* Send ACK. */ + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_ACK; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP ACKs sent. */ + ppp_ptr -> nx_ppp_lcp_configure_acks_sent++; +#endif + } + else if (configure_status & 2) + { + /* Send reject. */ + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_REJECT; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP rejects sent. */ + ppp_ptr -> nx_ppp_lcp_configure_rejects_sent++; +#endif + } + else + { + /* Send NAK. */ + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_NAK; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP NAKs sent. */ + ppp_ptr -> nx_ppp_lcp_configure_naks_sent++; +#endif + } + + /* Insert the id. */ + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + + /* Process again according to the status. */ + if (configure_status == 0) + { + + /* Setup the options list. */ + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = lcp_ptr[4]; + packet_ptr -> nx_packet_prepend_ptr[5] = lcp_ptr[5]; + + length = (((UINT) lcp_ptr[4]) << 8) | ((UINT) lcp_ptr[5]); + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (length + 2)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Send the options that were received with the request. */ + for(i = 0; i < (length - 4); i++) + { + + /* Copy option byte into new packet. */ + packet_ptr -> nx_packet_prepend_ptr[6+i] = lcp_ptr[6+i]; + } + + /* Setup the packet length and append pointer. */ + packet_ptr -> nx_packet_length = length + 2; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + } + else if (configure_status & 2) + { + + /* Rejected options. */ + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(rejected_list[0] + 4); + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(rejected_list[0] + 6)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Load entire rejected list. */ + for(i = 1; i < (UCHAR)(rejected_list[0] + 1); i++) + { + /* Copy option byte into new packet. */ + packet_ptr -> nx_packet_prepend_ptr[6+i-1] = rejected_list[i]; + } + + /* Setup the packet length and append pointer. */ + packet_ptr -> nx_packet_length = (ULONG)(rejected_list[0] + 6); + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + } + else + { + + /* NAKed options. */ + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(naked_list[0] + 4); + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(naked_list[0] + 6)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Load entire naked list. */ + for(i = 1; i < (UCHAR)(naked_list[0] + 1); i++) + { + /* Copy option byte into new packet. */ + packet_ptr -> nx_packet_prepend_ptr[6+i-1] = naked_list[i]; + } + + /* Setup the packet length and append pointer. */ + packet_ptr -> nx_packet_length = (ULONG)(naked_list[0] + 6); + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; +#endif + + /* Send the reply out. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_configure_request_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a LCP configuration request. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate PPP packet */ +/* _nx_ppp_packet_transmit Send LCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_configure_request_send(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Increment the transmit ID. */ + ppp_ptr -> nx_ppp_transmit_id++; + + /* Build the configuration request. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + + /* Load the MRU. */ + packet_ptr -> nx_packet_prepend_ptr[6] = 1; + packet_ptr -> nx_packet_prepend_ptr[7] = 4; + packet_ptr -> nx_packet_prepend_ptr[8] = (UCHAR) ((NX_PPP_MRU) >> 8); + packet_ptr -> nx_packet_prepend_ptr[9] = (UCHAR) ((NX_PPP_MRU) & 0xff); + + /* Load the authentication protocol type. */ + if ((ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_PAP_PROTOCOL) && (ppp_ptr -> nx_ppp_pap_verify_login)) + { + + /* Set the length for PAP authentication protocol. */ + packet_ptr -> nx_packet_prepend_ptr[5] = 12; + + packet_ptr -> nx_packet_prepend_ptr[10] = 3; + packet_ptr -> nx_packet_prepend_ptr[11] = 4; + packet_ptr -> nx_packet_prepend_ptr[12] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[13] = NX_PPP_PAP_PROTOCOL & 0xFF; + } + else if ((ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_CHAP_PROTOCOL) && + (ppp_ptr -> nx_ppp_chap_get_challenge_values) && (ppp_ptr -> nx_ppp_chap_get_verification_values)) + { + + /* Set the length for CHAP authentication protocol. */ + packet_ptr -> nx_packet_prepend_ptr[5] = 13; + + packet_ptr -> nx_packet_prepend_ptr[10] = 3; + packet_ptr -> nx_packet_prepend_ptr[11] = 5; + packet_ptr -> nx_packet_prepend_ptr[12] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[13] = NX_PPP_CHAP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[14] = 0x05; + } + else + { + + /* Set the length for no authentication protocol. */ + packet_ptr -> nx_packet_prepend_ptr[5] = 8; + } + + /* Setup the append pointer and the packet length (LCP length + PPP header). */ + packet_ptr -> nx_packet_length = (ULONG)(packet_ptr -> nx_packet_prepend_ptr[5] + 2); + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; + + /* Increment the number of LCP configure requests sent. */ + ppp_ptr -> nx_ppp_lcp_configure_requests_sent++; +#endif + + /* Send the configure request packet. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_configuration_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function pickup the configuration options. Unhandled options */ +/* are placed in NAKed or Rejected lists. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* naked_list List of NAKed options */ +/* rejected_list List of rejected options */ +/* */ +/* OUTPUT */ +/* */ +/* 0 -> Success */ +/* 1 -> NAKed one or more options */ +/* 2 -> Rejected on or more options */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_lcp_configuration_retrieve(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list) +{ + +UINT option_index, nak_list_index, rejected_list_index; +UINT len, status = 0; +UINT type; +UINT counter; +ULONG authentication_protocol; +UCHAR *option_data; + + + /* Clear both the NAKed and rejected list length. */ + naked_list[0] = 0; + rejected_list[0] = 0; + + /* Start indexes at 1, since byte 0 contains length. */ + nak_list_index = 1; + rejected_list_index = 1; + + /* Process the options in the LCP message. */ + for (option_index = 6; (option_index + 2) <= packet_ptr -> nx_packet_length; ) + { + + /* Pickup the option type - section 6 of RFC1661. */ + type = packet_ptr -> nx_packet_prepend_ptr[option_index++]; + + /* Get the length of the option. The length also includes the type and length fields. */ + len = packet_ptr -> nx_packet_prepend_ptr[option_index++]; + + /* Check if the length is valid. */ + if ((len < 2) || (len > (packet_ptr -> nx_packet_length - (option_index - 2)))) + return(2); + + /* Set a pointer to option data. */ + option_data = &packet_ptr -> nx_packet_prepend_ptr[option_index]; + + /* Advance the index to next option. */ + option_index += len - 2; + + /* Process relative to the option type. */ + switch (type) + { + + case 1: + + /* Maximum Receive Unit (MRU) option. */ + ppp_ptr -> nx_ppp_mru = (ULONG)((((USHORT) option_data[0]) << 8) | ((USHORT) option_data[1])); + + /* Determine if the MRU is too small. */ + if (ppp_ptr -> nx_ppp_mru < NX_PPP_MINIMUM_MRU) + { + status |= 1; + + /* Default the MRU. */ + ppp_ptr -> nx_ppp_mru = NX_PPP_MRU; + + /* Check if out of boundary. */ + if ((nak_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* Yes, enter it in the NAK list. */ + naked_list[nak_list_index++] = (UCHAR)type; + naked_list[nak_list_index++] = (UCHAR)len; + for (counter = 0; counter < (len-2); counter++) + naked_list[nak_list_index++] = option_data[counter]; + naked_list[0] = (UCHAR)(nak_list_index - 1); + } + break; + + case 3: + + /* Authentication protocol selection. */ + + /* Pickup the authentication protocol. */ + authentication_protocol = (((UINT) option_data[0]) << 8) | ((UINT) option_data[1]); + + /* Determine if the authentication protocol specified by the peer is PAP and we have a generate + routine defined. */ + if ((authentication_protocol == NX_PPP_PAP_PROTOCOL) && (ppp_ptr -> nx_ppp_pap_generate_login)) + { + + /* Yes, enable the PAP protocol. */ + ppp_ptr -> nx_ppp_generate_authentication_protocol = NX_PPP_PAP_PROTOCOL; + } + + /* Determine if the authentication protocol specified by the peer is CHAP and we have a generate + response routine defined. */ + if ((authentication_protocol == NX_PPP_CHAP_PROTOCOL) && (ppp_ptr -> nx_ppp_chap_get_responder_values)) + { + + /* Yes, enable the CHAP protocol. */ + ppp_ptr -> nx_ppp_generate_authentication_protocol = NX_PPP_CHAP_PROTOCOL; + } + + /* Determine if the required authentication at the peer is the same as what this peer can generate + login information for. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol != authentication_protocol) + { + + /* We do not support the requested authentication by the peer. */ + + /* Check to see if we don't have any authentication protocols enabled. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol == 0) + { + status |= 2; + + /* Check if out of boundary. */ + if ((rejected_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* No authentication is supported, simply include requested authentication + option in the rejected list. */ + rejected_list[rejected_list_index++] = (UCHAR)type; + rejected_list[rejected_list_index++] = (UCHAR)len; + for (counter = 0; counter < (len-2); counter++) + rejected_list[rejected_list_index++] = option_data[counter]; + rejected_list[0] = (UCHAR)(rejected_list_index - 1); + } + + /* Determine if this peer has PAP enabled. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_PAP_PROTOCOL) + { + status |= 1; + + /* Check if out of boundary. */ + if ((nak_list_index + 4) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* PAP enabled but something different is requested by the peer, build NAK entry with PAP hint. */ + naked_list[nak_list_index++] = 3; + naked_list[nak_list_index++] = NX_PPP_PAP_AUTHENTICATE_NAK; + naked_list[nak_list_index++] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; + naked_list[nak_list_index++] = NX_PPP_PAP_PROTOCOL & 0xFF; + naked_list[0] = (UCHAR)(nak_list_index - 1); + + /* Clear authentication protocol. */ + ppp_ptr -> nx_ppp_verify_authentication_protocol = 0; + } + + /* Determine if this peer has CHAP enabled. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) + { + status |= 1; + + /* Check if out of boundary. */ + if ((nak_list_index + 5) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* CHAP enabled but something different is requested by the peer, build NAK entry with CHAP hint. */ + naked_list[nak_list_index++] = 3; + naked_list[nak_list_index++] = 5; + naked_list[nak_list_index++] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + naked_list[nak_list_index++] = NX_PPP_CHAP_PROTOCOL & 0xFF; + naked_list[nak_list_index++] = 0x05; + naked_list[0] = (UCHAR)(nak_list_index - 1); + } + } + else + { + + /* Matching authentication protocol. */ + + /* Check to see if we have the CHAP authentication protocol enabled. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) + { + + /* Now determine if something other than CHAP MD5 was requested. */ + if (option_data[2] != 0x05) + { + status |= 1; + + /* Check if out of boundary. */ + if ((nak_list_index + 5) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* CHAP enabled but something different is requested by the peer, build NAK entry with CHAP hint. */ + naked_list[nak_list_index++] = 3; + naked_list[nak_list_index++] = 5; + naked_list[nak_list_index++] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + naked_list[nak_list_index++] = NX_PPP_CHAP_PROTOCOL & 0xFF; + naked_list[nak_list_index++] = 0x05; + naked_list[0] = (UCHAR)(nak_list_index - 1); + } + else + { + + /* Clear the authenticated flag since peer requires CHAP authentication. */ + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + } + } + else + { + + /* Clear the authenticated flag since peer requires PAP authentication. */ + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + } + } + break; + + case 2: /* ACCM, Not implemented. */ + case 5: /* Magic number - just acknowledge, we do not send out magic number. */ + case 7: /* The sender can receive protocol compression. */ + case 8: /* The sender can receive address compression. */ + + /* Skip these options, since we don't care to object. */ + break; + + default: + + status |= 2; + + /* Check if out of boundary. */ + if ((rejected_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* All other options we must reject since we do not negotiate. */ + rejected_list[rejected_list_index++] = (UCHAR)type; + rejected_list[rejected_list_index++] = (UCHAR)len; + for (counter = 0; counter < (len-2); counter++) + rejected_list[rejected_list_index++] = option_data[counter]; + rejected_list[0] = (UCHAR)(rejected_list_index - 1); + break; + } + } + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_nak_configure_list PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the NAKed option list. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* naked_list List of NAKed options */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_nak_configure_list(NX_PPP *ppp_ptr, UCHAR *naked_list) +{ + +UINT i; + + NX_PARAMETER_NOT_USED(ppp_ptr); + + /* Currently, nothing needs to be done in this routine since the options + we are asking for are basic and must be supported. If additional options + are added, we will need to process the NAK list. */ + + /* Just clear the naked list for now. */ + for(i = 0; i < NX_PPP_OPTION_MESSAGE_LENGTH; i++) + naked_list[i] = 0; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_terminate_ack_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a terminate ACK LCP message and sends it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send AHDLC packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_terminate_ack_send(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build terminate ACK LCP message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_TERMINATE_ACK; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = 4; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 6; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; + + /* Increment the number of LCP terminate ACKs sent. */ + ppp_ptr -> nx_ppp_lcp_terminate_acks_sent++; +#endif + + /* Send the packet out. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_terminate_request_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a LCP terminate message and sends it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send PPP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_terminate_request_send(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build terminate request message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_TERMINATE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = 4; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 6; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; + + /* Increment the number of LCP terminate requests sent. */ + ppp_ptr -> nx_ppp_lcp_terminate_requests_sent++; +#endif + + /* Send terminate request. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +#ifndef NX_PPP_DISABLE_PAP +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_state_machine_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes events and state changes in the PPP PAP */ +/* state machine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to PAP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_pap_login_valid Check for valid peer login */ +/* _nx_ppp_pap_authentication_request Send authentication request */ +/* _nx_ppp_pap_authentication_ack Send authentication ACK */ +/* _nx_ppp_pap_authentication_nak Send authentication NAK */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_process Receive PPP packet processing */ +/* _nx_ppp_timeout PPP timeout */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_pap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR code; +UINT valid; + + + /* Determine if a packet is present. If so, drive the event from the packet. */ + if (packet_ptr) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of PAP frames received. */ + ppp_ptr -> nx_ppp_pap_frames_received++; +#endif + + /* Pickup the type of received PAP code. */ + code = packet_ptr -> nx_packet_prepend_ptr[2]; + + /* Remember receive id. */ + ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Check the incoming code. */ + if ((code < NX_PPP_PAP_AUTHENTICATE_REQUEST) || (code > NX_PPP_PAP_AUTHENTICATE_NAK)) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; + + /* Increment the PAP unknown requests counter. */ + ppp_ptr -> nx_ppp_pap_unknown_requests_received++; +#endif + return; + } + } + else + { + + /* Set the code to timeout. */ + code = NX_PPP_PAP_AUTHENTICATE_TIMEOUT; + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the appropriate counter. */ + switch (code) + { + + case NX_PPP_PAP_AUTHENTICATE_REQUEST: + + /* Increment the authenticate requests counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_requests_received++; + break; + + case NX_PPP_PAP_AUTHENTICATE_ACK: + + /* Increment the authenticate acks counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_acks_received++; + break; + + case NX_PPP_PAP_AUTHENTICATE_NAK: + + /* Increment the authenticate naks counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_naks_received++; + break; + + case NX_PPP_PAP_AUTHENTICATE_TIMEOUT: + + /* Determine if we are in the initial state. If so, this really isn't a timeout. */ + if (ppp_ptr -> nx_ppp_pap_state != NX_PPP_PAP_START_STATE) + { + + /* Increment the authenticate timeout counter. */ + ppp_ptr -> nx_ppp_pap_state_machine_timeouts++; + } + break; + } +#endif + + /* Process relative to the current state. */ + switch (ppp_ptr -> nx_ppp_pap_state) + { + + /* Starting state. */ + case NX_PPP_PAP_START_STATE: + { + + /* Determine if we need to generate a login for the peer to verify. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol) + { + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Generate PAP login request and send to the peer. */ + _nx_ppp_pap_authentication_request(ppp_ptr); + + /* Move to the authenticate request sent state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE; + } + else + { + + /* Move to the authenticate wait state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE; + } + break; + } + + case NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE: + { + + /* In this state, this peer has sent an authentication request and is waiting for + an ACK or NAK from the peer. */ + if ((code == NX_PPP_PAP_AUTHENTICATE_REQUEST) && (packet_ptr)) + { + + /* Determine if the login information is valid. */ + valid = _nx_ppp_pap_login_valid(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_TRUE) + { + + /* Send an ACK message. */ + _nx_ppp_pap_authentication_ack(ppp_ptr); + + /* Now determine if we need to authenticate ourselves. */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol != NX_PPP_PAP_PROTOCOL) + { + + /* We do not need to authenticate ourselves, so we can move into PAP completed state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + } + else + { + + /* Send NAK to tell peer the authentication failed. */ + _nx_ppp_pap_authentication_nak(ppp_ptr); + + /* No state change, just stay here! */ + } + } + + /* Was a NAK received? */ + else if (code == NX_PPP_PAP_AUTHENTICATE_NAK) + { + + /* Determine if there is an application NAK callback. */ + if (ppp_ptr -> nx_ppp_nak_authentication_notify) + { + + /* Yes, call the application's authentication NAK notify callback function. */ + (ppp_ptr -> nx_ppp_nak_authentication_notify)(); + } + + /* Generate a new PAP login request and send to the peer. */ + _nx_ppp_pap_authentication_request(ppp_ptr); + } + + /* Was an ACK received? */ + else if (code == NX_PPP_PAP_AUTHENTICATE_ACK) + { + + /* Determine if this peer requires authentication. */ + if (ppp_ptr -> nx_ppp_pap_verify_login) + { + + /* Yes, we require PAP verification so move to the request wait state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE; + } + else + { + + /* Otherwise, we have completed the PAP authentication. Move to the completed + state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + } + + /* Was a timeout received? */ + else if (code == NX_PPP_PAP_AUTHENTICATE_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the PAP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_PAP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Generate a new PAP login request and send to the peer. */ + _nx_ppp_pap_authentication_request(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter PAP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; + } +#endif + + break; + } + + case NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE: + { + + /* In this state, this peer must send an authenticate request. There is no + authentication required by the peer. */ + if ((code == NX_PPP_PAP_AUTHENTICATE_REQUEST) && (packet_ptr)) + { + + /* Determine if the login information is valid. */ + valid = _nx_ppp_pap_login_valid(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_TRUE) + { + + /* Send an ACK message. */ + _nx_ppp_pap_authentication_ack(ppp_ptr); + + /* No authentication is required by peer, so we can move into PAP completed state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + else + { + + /* Send NAK to tell peer the authentication failed. */ + _nx_ppp_pap_authentication_nak(ppp_ptr); + + /* No state change, just stay here! */ + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; + } +#endif + break; + } + + default: +#ifndef NX_PPP_DISABLE_INFO + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; + } +#endif + break; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_authentication_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an authentication request message */ +/* the peer. The peer will then either ACK or NAK the request. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* (nx_ppp_pap_generate_login) Pickup name and password */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_pap_state_machine_update PPP state machine update */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_pap_authentication_request(NX_PPP *ppp_ptr) +{ + +UINT length, password_length, i, j; +UCHAR name[NX_PPP_NAME_SIZE + 1]; +UCHAR password[NX_PPP_PASSWORD_SIZE + 1]; +UINT status; +NX_PACKET *packet_ptr; + + + /* Initialize name and password. */ + name[0] = 0; + password[0] = 0; + + /* Determine if there is a login name/password generation routine. */ + if (ppp_ptr -> nx_ppp_pap_generate_login) + { + + /* Get the name and password */ + ppp_ptr -> nx_ppp_pap_generate_login((CHAR *) name, (CHAR *) password); + } + + /* Allocate a packet for the PPP PAP response packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Calculate the size of the name and password. */ + if (_nx_utility_string_length_check((CHAR *)name, &length, NX_PPP_NAME_SIZE) || + _nx_utility_string_length_check((CHAR *)password, &password_length, NX_PPP_PASSWORD_SIZE)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 1 + password_length + 1 + 6)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Set PAP authentication request, ID, and length. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; /* ID */ + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) (((length) + 1 + (password_length) + 1 + 4) >> 8); + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) (((length) + 1 + (password_length) + 1 + 4) & 0xFF); + + /* Store the PAP name. */ + packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR)(length & 0xFF); + for (i = 0; i < length; i++) + { + + /* Store byte of name. */ + packet_ptr -> nx_packet_prepend_ptr[i+7] = name[i]; + } + + /* Store PAP password. */ + packet_ptr -> nx_packet_prepend_ptr[i+7] = (password_length & 0xFF); + for (j = 0; j < password_length; j++) + { + + /* Store byte of name. */ + packet_ptr -> nx_packet_prepend_ptr[j+i+8] = password[j]; + } + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = (length) + 1 + (password_length) + 1 + 4 + 2; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of PAP frames sent. */ + ppp_ptr -> nx_ppp_pap_frames_sent++; + + /* Increment the authentication requests sent counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_requests_sent++; +#endif + + /* Send the PAP request. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_login_valid PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function validates the login information supplied by the */ +/* peer. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to PAP packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Valid login */ +/* NX_FALSE Invalid login */ +/* */ +/* CALLS */ +/* */ +/* (nx_ppp_pap_verify_login) Verify name and password */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_pap_state_machine_update PAP state machine update */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_pap_login_valid(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR length, password_length, i, j; +UCHAR name[NX_PPP_NAME_SIZE + 1]; +UCHAR password[NX_PPP_PASSWORD_SIZE + 1]; +UINT status; + + + /* Get the name length. */ + length = packet_ptr -> nx_packet_prepend_ptr[6]; + + /* Check for valid packet length. */ + if ((ULONG)(length + 7) > packet_ptr -> nx_packet_length) + { + return(NX_FALSE); + } + + /* Determine if the length is greater than the name size. */ + if (length > NX_PPP_NAME_SIZE) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + return(NX_FALSE); + } + + /* Get the name. */ + for(i = 0; i < length; i++) + { + + /* Get a character of the name. */ + name[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; + } + + /* Null terminate the name. */ + name[i] = 0; + + /* Get length of password. */ + password_length = packet_ptr -> nx_packet_prepend_ptr[i+7]; + + /* Check for valid packet length. */ + if ((ULONG)(password_length + i + 8) > packet_ptr -> nx_packet_length) + { + return(NX_FALSE); + } + + /* Determine if the length is greater than the password size. */ + if (password_length > NX_PPP_PASSWORD_SIZE) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + return(NX_FALSE); + } + + /* Get the password. */ + for(j = 0; j < password_length; j++) + { + + /* Get a character of the password. */ + password[j] = packet_ptr -> nx_packet_prepend_ptr[j+i+8]; + } + + /* Null terminate the password. */ + password[j] = 0; + + /* Determine if there is an authentication routine. */ + if (ppp_ptr -> nx_ppp_pap_verify_login) + { + + /* Call the user supplied PAP authentication routine. */ + status = ppp_ptr -> nx_ppp_pap_verify_login((CHAR *) name, (CHAR *) password); + + /* Check to see if it is valid. */ + if (status) + { + + /* Return NX_FALSE, which indicates the password is invalid. */ + return (NX_FALSE); + } + } + + /* Return NX_TRUE. */ + return(NX_TRUE); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_authentication_ack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an authentication ACK message to */ +/* the peer in response to the peer's authentication request. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_pap_state_machine_update PPP state machine update */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_pap_authentication_ack(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP PAP response packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build the PAP ACK response message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_ACK; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = 5; + packet_ptr -> nx_packet_prepend_ptr[6] = 0; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 7; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + /* Set the authenticated flag to true. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of PAP frames sent. */ + ppp_ptr -> nx_ppp_pap_frames_sent++; + + /* Increment the number of authentication ACKs sent counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_acks_sent++; +#endif + + /* Send the ACK message out. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_authentication_nak PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an authentication NAK message to */ +/* the peer in response to the peer's authentication request. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_pap_state_machine_update PPP state machine update */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_pap_authentication_nak(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the PPP PAP response packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build the PAP ACK response message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_NAK; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0; + packet_ptr -> nx_packet_prepend_ptr[5] = 5; + packet_ptr -> nx_packet_prepend_ptr[6] = 0; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 7; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of PAP frames sent. */ + ppp_ptr -> nx_ppp_pap_frames_sent++; + + /* Increment the authentication NAKs sent counter. */ + ppp_ptr -> nx_ppp_pap_authenticate_naks_sent++; +#endif + + /* Send the authentication NAK message out. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + +#endif + + +#ifndef NX_PPP_DISABLE_CHAP +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_state_machine_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes events and state changes in the PPP CHAP */ +/* state machine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr CHAP packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_chap_challenge_send Send CHAP challenge to peer */ +/* _nx_ppp_chap_challenge_respond Respond to challenge from peer*/ +/* _nx_ppp_chap_challenge_validate Validate challenge response */ +/* from peer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_process Receive PPP packet processing */ +/* _nx_ppp_timeout PPP timeout */ +/* _nx_ppp_thread_entry PPP processing thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_chap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR code; +UINT valid; + + + /* Determine if a packet is present. If so, derive the event from the packet. */ + if (packet_ptr) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of CHAP frames received. */ + ppp_ptr -> nx_ppp_chap_frames_received++; +#endif + + /* Pickup the type of received CHAP code. */ + code = packet_ptr -> nx_packet_prepend_ptr[2]; + + /* Remember receive id. */ + ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Check the incoming code. */ + if ((code < NX_PPP_CHAP_CHALLENGE_REQUEST) || (code > NX_PPP_CHAP_CHALLENGE_FAILURE)) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; + + /* Increment the number of unknown CHAP requests received. */ + ppp_ptr -> nx_ppp_chap_unknown_requests_received++; +#endif + return; + } + } + else + { + + /* Set the code to timeout. */ + code = NX_PPP_CHAP_CHALLENGE_TIMEOUT; + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Update receive counters. */ + switch (code) + { + + case NX_PPP_CHAP_CHALLENGE_REQUEST: + + /* Increment the number of CHAP challenge requests received. */ + ppp_ptr -> nx_ppp_chap_challenge_requests_received++; + break; + + case NX_PPP_CHAP_CHALLENGE_RESPONSE: + + /* Increment the number of CHAP challenge responses received. */ + ppp_ptr -> nx_ppp_chap_challenge_responses_received++; + break; + + case NX_PPP_CHAP_CHALLENGE_SUCCESS: + + /* Increment the number of CHAP challenge successful notifications received. */ + ppp_ptr -> nx_ppp_chap_challenge_successes_received++; + break; + + case NX_PPP_CHAP_CHALLENGE_FAILURE: + + /* Increment the number of CHAP challenge failures received. */ + ppp_ptr -> nx_ppp_chap_challenge_failures_received++; + break; + + case NX_PPP_CHAP_CHALLENGE_TIMEOUT: + + + /* Determine if we are in the initial state. If so, this really isn't a timeout. */ + if (ppp_ptr -> nx_ppp_chap_state != NX_PPP_CHAP_START_STATE) + { + + /* Increment the number of CHAP timeouts received. */ + ppp_ptr -> nx_ppp_chap_state_machine_timeouts++; + } + break; + } +#endif + + /* Process relative to the current state. */ + switch (ppp_ptr -> nx_ppp_chap_state) + { + /* Starting state. */ + case NX_PPP_CHAP_START_STATE: + { + + /* Determine if we need to challenge the peer. */ + if (ppp_ptr -> nx_ppp_verify_authentication_protocol) + { + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send(ppp_ptr); + + /* Move to the challenge request sent state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE; + } + else if (ppp_ptr -> nx_ppp_generate_authentication_protocol) + { + + /* Move to the challenge wait state, since the peer must challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE; + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE: + { + + /* In this state, this peer has sent a challenge request and is waiting for + response from the peer. */ + if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) + { + + /* Generate a challenge response and send it to the peer. */ + _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); + + /* Move to the sent both challenge and response sent state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE; + } + + else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) + { + + /* Determine if the challenge response is valid. Note this function all sends the Success or + Failure to the peer. */ + valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_TRUE) + { + + /* Does the peer need to perform an initial challenge? */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol) + { + + /* Move to the challenge wait state, since the peer must challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE; + } + else + { + + /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + } + else + { + + /* Determine if there is an application NAK callback. */ + if (ppp_ptr -> nx_ppp_nak_authentication_notify) + { + + /* Yes, call the application's authentication NAK notify callback function. */ + (ppp_ptr -> nx_ppp_nak_authentication_notify)(); + } + + /* Enter into a failed state since challenge failed. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } + + /* Was a timeout received? */ + else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the CHAP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter CHAP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE: + { + + /* In this state, this peer has sent a challenge request and a challenge response and is waiting for + response from the peer. */ + if (code == NX_PPP_CHAP_CHALLENGE_SUCCESS) + { + + /* Move to the challenge sent received response state, since the original challenge is still pending. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE; + } + + else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) + { + + /* Move to the failed state since our response failed to satisfy the peer's challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + + else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) + { + + /* Determine if the challenge response is valid. Note this function all sends the Success or + Failure to the peer. */ + valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_TRUE) + { + + /* Does the peer need to perform an initial challenge? */ + if (ppp_ptr -> nx_ppp_generate_authentication_protocol) + { + + /* Move to the challenge wait state, since the peer must challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE; + } + else + { + + /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + } + else + { + + /* Enter into a failed state since challenge failed. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } + + /* Was a timeout received? */ + else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the CHAP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter CHAP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE: + { + + /* In this state, we have already successfully responded to a challenge from the peer + but are still waiting for the initial reply from the peer to our challenge request. */ + if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) + { + + /* Determine if the challenge response is valid. Note this function all sends the Success or + Failure to the peer. */ + valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_TRUE) + { + + /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + else + { + + /* Enter into a failed state since challenge failed. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } + + /* Was a timeout received? */ + else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the CHAP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter CHAP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE: + { + + /* In this state we only need the challenge from peer, either this peer doesn't challenge or + the initial challenge has already successfully completed. */ + if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) + { + + /* Generate a challenge response and send it to the peer. */ + _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); + + /* Move to the wait for challenge response state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE; + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE: + { + + /* In this state, this peer has sent a challenge response and is waiting for + response from the peer. */ + if (code == NX_PPP_CHAP_CHALLENGE_SUCCESS) + { + + /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; + + /* Mark the PPP instance as authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) + { + + /* Move to the failed state since our response failed to satisfy the peer's challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_COMPLETED_STATE: + { + + /* In this state the initial challenge(s) have been processed... This state is used to field + additional challenges during the life of the link. */ + if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) + { + + /* Generate a challenge response and send it to the peer. */ + _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); + + /* Stay in this state. */ + } + else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) + { + + /* Move to the failed state since our response failed to satisfy the peer's challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_CHAP_COMPLETED_NEW_STATE: + { + + /* In this state the new challenge(s) is issued... */ + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send (ppp_ptr); + + /* Move to the new challenge request sent state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE; + break; + } + + case NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE: + { + + /* In this state the initial challenge(s) have been processed... This state is used to field + additional challenges during the life of the link. */ + if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) + { + + /* Generate a challenge response and send it to the peer. */ + _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); + + /* Stay in this state. */ + } + + else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) + { + + /* Determine if there is an application NAK callback. */ + if (ppp_ptr -> nx_ppp_nak_authentication_notify) + { + + /* Yes, call the application's authentication NAK notify callback function. */ + (ppp_ptr -> nx_ppp_nak_authentication_notify)(); + } + + /* Move to the failed state since our response failed to satisfy the peer's challenge. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Mark the PPP instance as not authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + + else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) + { + + /* Determine if the challenge response is valid. Note this function all sends the Success or + Failure to the peer. */ + valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); + + /* Is the login valid? */ + if (valid == NX_FALSE) + { + + /* No: Determine if there is an application NAK callback. */ + if (ppp_ptr -> nx_ppp_nak_authentication_notify) + { + + /* Yes, call the application's authentication NAK notify callback function. */ + (ppp_ptr -> nx_ppp_nak_authentication_notify)(); + } + + /* Enter into a failed state since challenge failed. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Mark the PPP instance as not authenticated. */ + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + else + { + + /* Simply move back to the completed state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + } + /* Was a timeout received? */ + else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the CHAP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send challenge request to peer. */ + _nx_ppp_chap_challenge_send (ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter CHAP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; + } +#endif + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_challenge_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a CHAP challenge to the peer. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* (nx_ppp_chap_get_challenge_values) Get values for challenge */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_chap_challenge_send(NX_PPP *ppp_ptr) +{ + +UCHAR id; +UINT length, length1, i, j; +NX_PACKET *packet_ptr; +UINT status; + + + /* Determine if there is a challenge generation routine. */ + if (ppp_ptr -> nx_ppp_chap_get_challenge_values) + { + + /* Yes, get the challenge values. */ + ppp_ptr -> nx_ppp_chap_get_challenge_values(ppp_ptr -> nx_ppp_chap_random_value, + (CHAR *) &id, ppp_ptr -> nx_ppp_chap_challenger_name); + } + else + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* An error was detected, simply return. */ + return; + } + + /* Allocate a packet for the PPP CHAP challenge packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Calculate the lengths of the challenger name and random value. */ + if (_nx_utility_string_length_check(ppp_ptr -> nx_ppp_chap_challenger_name, &length1, NX_PPP_NAME_SIZE) || + _nx_utility_string_length_check(ppp_ptr -> nx_ppp_chap_random_value, &length, NX_PPP_VALUE_SIZE)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 1 + length1 + 6)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Build CHAP challenge message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ + + /* Setup the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) ((((UINT) length) + 1 + ((UINT) length1) + 4) >> 8); + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) ((((UINT) length) + 1 + ((UINT) length1) + 4) & 0xFF); + + /* Store the CHAP random value. */ + packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR)length; + for (i = 0; i < length; i++) + { + + /* Store byte of name. */ + packet_ptr -> nx_packet_prepend_ptr[i+7] = (UCHAR)(ppp_ptr -> nx_ppp_chap_random_value[i]); + } + + /* Store CHAP challenge name. */ + for (j = 0; j < length1; j++) + { + + /* Store byte of name. */ + packet_ptr -> nx_packet_prepend_ptr[j+i+7] = (UCHAR)(ppp_ptr -> nx_ppp_chap_challenger_name[j]); + } + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = ((UINT) length) + 1 + ((UINT) length1) + 4 + 2; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of CHAP frames sent. */ + ppp_ptr -> nx_ppp_chap_frames_sent++; + + /* Increment the number of CHAP challenge requests. */ + ppp_ptr -> nx_ppp_chap_challenge_requests_sent++; +#endif + + /* Send challenge message. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_challenge_respond PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the CHAP challenge request from the peer. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to CHAP challenge */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* (nx_ppp_chap_get_responder_values) Get responder values for reply*/ +/* _nx_ppp_hash_generator Generate MD5 hash */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_chap_challenge_respond(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR name[NX_PPP_NAME_SIZE + 1], secret[NX_PPP_NAME_SIZE + 1]; +UCHAR value[NX_PPP_VALUE_SIZE + 1], hvalue[NX_PPP_HASHED_VALUE_SIZE + 1]; +UCHAR id; +UINT length, length1, i, j; +NX_PACKET *response_packet_ptr; +UINT status; +UINT name_length; + + + /* Pickup the id and length. */ + id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Pickup the length. */ + length = (UINT) packet_ptr -> nx_packet_prepend_ptr[4]; + length1 = (UINT) packet_ptr -> nx_packet_prepend_ptr[5]; + length1 = (length << 8) | (length1) ; + + /* Check for valid packet length. */ + if ((length1 + 2) > packet_ptr -> nx_packet_length) + { + return; + } + + /* Pickup the length of the random value. */ + length = (UINT) packet_ptr -> nx_packet_prepend_ptr[6]; + + /* Check for valid packet length. */ + if ((length == 0) || ((ULONG)(length + 7) > packet_ptr -> nx_packet_length)) + { + return; + } + + /* Determine if the length is greater than the destination. */ + name_length = length1 - length - 5; + if ((length > NX_PPP_VALUE_SIZE) || + (name_length > NX_PPP_NAME_SIZE)) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + return; + } + + /* Pickup the random value. */ + for(i = 0; i < length; i++) + { + + /* Pickup a byte of the random value. */ + value[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; + } + + /* Now pickup the challenge name. */ + for(j = 0; j < name_length; j++) + { + + /* Pickup a byte of the challenger name. */ + name[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+7]; + } + + /* Null terminate it. */ + name[j] = 0; + + /* Determine if there is a challenge get responder values routine. */ + if (ppp_ptr -> nx_ppp_chap_get_responder_values) + { + + /* Get name and password for this server */ + ppp_ptr -> nx_ppp_chap_get_responder_values((CHAR*) name, (CHAR *) name, (CHAR *) secret); + } + else + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Generate hash value. */ + _nx_ppp_hash_generator(hvalue, id, secret, value, length); + + /* Allocate a packet for the PPP CHAP response packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &response_packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Calculate length of the name */ + for(length = 0; name[length]; length++); + + /* Check if out of boundary. */ + if ((UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + NX_PPP_HASHED_VALUE_SIZE + 7)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Build CHAP challenge response message. */ + response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; + response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_RESPONSE; + response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ + + /* Setup the length. */ + response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) ((((UINT) length) + NX_PPP_HASHED_VALUE_SIZE + 5) >> 8); + response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) ((((UINT) length) + NX_PPP_HASHED_VALUE_SIZE + 5) & 0xFF); + + /* Set the length of the hashed response value. */ + response_packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR) NX_PPP_HASHED_VALUE_SIZE; + + /* Loop to insert the hashed value. */ + for(i = 0; i < NX_PPP_HASHED_VALUE_SIZE; i++) + { + + /* Copy one byte of the hashed value. */ + response_packet_ptr -> nx_packet_prepend_ptr[i+7] = hvalue[i]; + } + + /* Loop to insert the name. */ + for(j = 0; j < length; j++) + { + + /* Copy one byte of the name. */ + response_packet_ptr -> nx_packet_prepend_ptr[i+j+7] = name[j]; + } + + /* Setup the append pointer and the packet length. */ + response_packet_ptr -> nx_packet_length = length + NX_PPP_HASHED_VALUE_SIZE + 5 + 2; + response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of CHAP frames sent. */ + ppp_ptr -> nx_ppp_chap_frames_sent++; + + /* Increment the number of CHAP responses sent. */ + ppp_ptr -> nx_ppp_chap_challenge_responses_sent++; +#endif + + /* Transmit response message. */ + _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_challenge_validate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function validates the CHAP response from the peer. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to CHAP challenge */ +/* */ +/* OUTPUT */ +/* */ +/* status NX_TRUE - valid login */ +/* NX_FALSE - invalid login */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* (nx_ppp_chap_get_verification_values) Get verification values */ +/* _nx_ppp_hash_generator Generate MD5 hash */ +/* _nx_ppp_packet_transmit Send PAP response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_chap_challenge_validate(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR name[NX_PPP_NAME_SIZE + 1], secret[NX_PPP_NAME_SIZE + 1]; +UCHAR hvalue[NX_PPP_HASHED_VALUE_SIZE + 1]; +UCHAR hvalue1[NX_PPP_HASHED_VALUE_SIZE + 1]; +UCHAR id; +UINT length, length1, i, j; +NX_PACKET *response_packet_ptr; +UINT status; +UINT name_length; + + + /* Pickup the id and length. */ + id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Pickup the length. */ + length = (UINT) packet_ptr -> nx_packet_prepend_ptr[4]; + length1 = (UINT) packet_ptr -> nx_packet_prepend_ptr[5]; + length1 = (length << 8) | (length1) ; + + /* Check for valid packet length. */ + if ((length1 + 2) > packet_ptr -> nx_packet_length) + { + return(NX_FALSE); + } + + /* Pickup the length of the hashed value. */ + length = (UINT) packet_ptr -> nx_packet_prepend_ptr[6]; + + /* Check for valid packet length. */ + if ((length == 0) || ((ULONG)(length + 7) > packet_ptr -> nx_packet_length)) + { + return(NX_FALSE); + } + + /* Determine if the length is greater than the destination. */ + name_length = length1 - length - 5; + if ((length > NX_PPP_HASHED_VALUE_SIZE) || + (name_length > NX_PPP_NAME_SIZE)) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* Return false in case of internal error. */ + return(NX_FALSE); + } + + /* Pickup the hashed value. */ + for(i = 0; i < length; i++) + { + + /* Pickup one byte of the hashed value. */ + hvalue[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; + } + + /* Pickup the name. */ + for(j = 0; j < name_length; j++) + { + + /* Pickup one byte of the hashed value. */ + name[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+7]; + } + + /* Null terminate the name. */ + name[j] = 0; + + /* Determine if there is a challenge get verification values routine. */ + if (ppp_ptr -> nx_ppp_chap_get_verification_values) + { + + /* Get name and password for this server */ + ppp_ptr -> nx_ppp_chap_get_verification_values(ppp_ptr -> nx_ppp_chap_challenger_name, (CHAR *) name, (CHAR *) secret); + } + else + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* Return false in case of internal error. */ + return(NX_FALSE); + } + + /* Generate hash value. */ + _nx_ppp_hash_generator(hvalue1, id, secret, (UCHAR *) ppp_ptr -> nx_ppp_chap_random_value, 0); + + /* Compare the computed hash value with the hash value received. */ + for(i = 0; i < NX_PPP_HASHED_VALUE_SIZE; i++) + { + + /* Are the hash values equal? */ + if (hvalue[i] != hvalue1[i]) + { + /* No, get out of the loop. */ + break; + } + } + + + /* Allocate a packet for the PPP CHAP response packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &response_packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* Return false in case of internal error. */ + return(NX_FALSE); + } + + /* Determine if challenge was successful. */ + if (i == NX_PPP_HASHED_VALUE_SIZE) + { + + /* Build CHAP ACK message. */ + response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; + response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_SUCCESS; + response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ + + /* Setup the length. */ + response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) 0; + response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) 4; + + /* Setup the append pointer and the packet length. */ + response_packet_ptr -> nx_packet_length = 6; + response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of CHAP frames sent. */ + ppp_ptr -> nx_ppp_chap_frames_sent++; + + /* Increment the number of CHAP success notifications sent. */ + ppp_ptr -> nx_ppp_chap_challenge_successes_sent++; +#endif + + /* Transmit the message. */ + _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); + + /* Return true to indicate the response was valid. */ + return(NX_TRUE); + } + else + { + + /* Build CHAP NAK message. */ + response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; + response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; + response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_FAILURE; + response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ + + /* Setup the length. */ + response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) 0; + response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) 4; + + /* Setup the append pointer and the packet length. */ + response_packet_ptr -> nx_packet_length = 6; + response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of CHAP frames sent. */ + ppp_ptr -> nx_ppp_chap_frames_sent++; + + /* Increment the number of CHAP failure notifications sent. */ + ppp_ptr -> nx_ppp_chap_challenge_failures_sent++; +#endif + + /* Transmit the message. */ + _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); + + /* Return false to indicate the response was invalid. */ + return(NX_FALSE); + } +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_state_machine_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes events and state changes in the PPP IPCP */ +/* state machine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_ipcp_configure_check Check configuration info */ +/* _nx_ppp_ipcp_configure_request_send Send configuration request */ +/* _nx_ppp_ipcp_response_extract Extract info from response */ +/* _nx_ppp_ipcp_response_send Send response */ +/* _nx_ppp_ipcp_terminate_send Send terminate */ +/* _nx_ppp_ipcp_terminate_ack_send Send terminate ack */ +/* nx_ip_interface_address_set Set interface IP address */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_process Receive PPP packet processing */ +/* _nx_ppp_timeout PPP timeout */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UINT acceptable_configuration; +UCHAR good_data[NX_PPP_OPTION_MESSAGE_LENGTH]; +UCHAR code; + + + /* Determine if a packet is present. If so, derive the event from the packet. */ + if (packet_ptr) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IPCP frames received. */ + ppp_ptr -> nx_ppp_ipcp_frames_received++; +#endif + + /* Pickup the type of received IPCP code. */ + code = packet_ptr -> nx_packet_prepend_ptr[2]; + + /* Remember receive id. */ + ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; + + /* Is the code supported by PPP? */ + if ((code < NX_PPP_IPCP_CONFIGURE_REQUEST) || + (code > NX_PPP_IPCP_TERMINATE_ACK)) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of internal errors. */ + ppp_ptr -> nx_ppp_internal_errors++; + + /* Increment the number of unhandled requests. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; +#endif + return; + } + } + else + { + + /* Set the code to timeout to indicate a timeout has occurred. */ + code = NX_PPP_IPCP_TIMEOUT; + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the corresponding request counter. */ + switch (code) + { + + case NX_PPP_IPCP_CONFIGURE_REQUEST: + + /* Increment the number of IPCP configure requests received. */ + ppp_ptr -> nx_ppp_ipcp_configure_requests_received++; + break; + + case NX_PPP_IPCP_CONFIGURE_ACK: + + /* Increment the number of IPCP configure ACKs received. */ + ppp_ptr -> nx_ppp_ipcp_configure_acks_received++; + break; + + case NX_PPP_IPCP_CONFIGURE_NAK: + + /* Increment the number of IPCP configure NAKs received. */ + ppp_ptr -> nx_ppp_ipcp_configure_naks_received++; + break; + + case NX_PPP_IPCP_CONFIGURE_REJECT: + + /* Increment the number of IPCP configure rejects received. */ + ppp_ptr -> nx_ppp_ipcp_configure_rejects_received++; + break; + + case NX_PPP_IPCP_TERMINATE_REQUEST: + + /* Increment the number of IPCP terminate requests received. */ + ppp_ptr -> nx_ppp_ipcp_terminate_requests_received++; + break; + + case NX_PPP_IPCP_TERMINATE_ACK: + + /* Increment the number of IPCP terminate ACKs received. */ + ppp_ptr -> nx_ppp_ipcp_terminate_acks_received++; + break; + + case NX_PPP_IPCP_TIMEOUT: + + /* Determine if we are in the initial state. If so, this really isn't a timeout. */ + if (ppp_ptr -> nx_ppp_ipcp_state != NX_PPP_IPCP_START_STATE) + { + + /* Increment the number of IPCP state machine timeouts. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_timeouts++; + } + break; + } +#endif + + /* Process relative to the current state. */ + switch (ppp_ptr -> nx_ppp_ipcp_state) + { + + case NX_PPP_IPCP_START_STATE: + { + + /* Initial IPCP state. */ + + /* Initialize the NAK and rejected list. */ +#ifndef NX_PPP_DNS_OPTION_DISABLE + ppp_ptr -> nx_ppp_naked_list[0] = 0; + ppp_ptr -> nx_ppp_naked_list[1] = 0; +#else + ppp_ptr -> nx_ppp_naked_list[0] = 1; + ppp_ptr -> nx_ppp_naked_list[1] = 1; +#endif + + ppp_ptr -> nx_ppp_peer_naked_list[0] = 0; + ppp_ptr -> nx_ppp_rejected_list[0] = 0; + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + + /* Move into the request sent state. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE; + break; + } + + case NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE: + { + + /* In this state, we have sent a configuration request but had not received an ACK + or a configuration request from the peer. */ + + /* Process relative to the incoming code. */ + if (code == NX_PPP_IPCP_CONFIGURE_ACK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* The peer has ACKed our configuration request. Move to the + configure request ACKed state. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE; + + /* Turn off the timeout for the configuration request. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + else if (code == NX_PPP_IPCP_CONFIGURE_REJECT) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Set the NAK option list, just to indicate to the configure request that + the IPCP request without DNS option is what we want. */ + ppp_ptr -> nx_ppp_naked_list[0] = 1; + + /* Send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + + else if ((code == NX_PPP_IPCP_CONFIGURE_NAK) && (packet_ptr)) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Extract the information from response... looking for IP address and possibly DNS server IP address. */ + _nx_ppp_ipcp_response_extract(ppp_ptr, packet_ptr); + + /* Send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + + else if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + + /* The peer has sent a configuration request. */ + + /* Check configuration information. */ + acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, + ppp_ptr -> nx_ppp_rejected_list, + good_data); + + /* Check for acceptable configuration. */ + if (acceptable_configuration == NX_TRUE) + { + + /* Yes, send an ack. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); + + /* Move to the state where the peer's configuration has been ACKed. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE; + } + else + { + + /* Otherwise, configuration is unacceptable, send a nak. */ + + /* Check rejected list. */ + if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) + { + + /* Yes, there are rejected options so send a configure reject. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, + &ppp_ptr -> nx_ppp_rejected_list[1], + ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); + + } + else if (ppp_ptr -> nx_ppp_peer_naked_list[0] != 0) + { + + /* Yes, there are naked options so send a new request. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, + &ppp_ptr -> nx_ppp_peer_naked_list[1], + ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); + + } + } + } + else if (code == NX_PPP_IPCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the IPCP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_IPCP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Timeout, send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter IPCP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE: + { + + /* In this state, we have received the ACK for our configuration request, but have not yet + received a configuration request from the peer. */ + + /* Process relative to the incoming code. */ + if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + + /* The peer has sent a configuration request. */ + + /* Check configuration information. */ + acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list, good_data); + + /* Check for acceptable configuration. */ + if (acceptable_configuration == NX_TRUE) + { + + /* Yes, send an ack. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); + + /* Move to the state where the peer's configuration has been ACKed. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_COMPLETED_STATE; + + /* Set the IP address for the specific interface from the configuration. */ + nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, + IP_ADDRESS(ppp_ptr -> nx_ppp_ipcp_local_ip[0], + ppp_ptr -> nx_ppp_ipcp_local_ip[1], + ppp_ptr -> nx_ppp_ipcp_local_ip[2], + ppp_ptr -> nx_ppp_ipcp_local_ip[3]), + 0xffffffff); + + /* Set gateway address. */ + (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_address = (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_address; + (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_interface = ppp_ptr -> nx_ppp_interface_ptr; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + else + { + + /* Otherwise, configuration is unacceptable, send a NAK. */ + + /* Check rejected list. */ + if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) + { + + /* Yes, there are rejected options so send a new request. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, &ppp_ptr -> nx_ppp_rejected_list[1], ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); + } + else if (ppp_ptr -> nx_ppp_naked_list[0] != 0) + { + + /* Yes, there are naked options so send a new request. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, &ppp_ptr -> nx_ppp_peer_naked_list[1], ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE: + { + + /* In this state, we have sent our configuration request, but haven't received an ACK. We have also received + a peer configuration request and have ACKed that request. */ + + /* Process relative to the incoming code. */ + if (code == NX_PPP_IPCP_CONFIGURE_ACK) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* The peer has ACKed our configuration request. Move to the + IPCP completed state. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_COMPLETED_STATE; + + /* Turn off the timeout for the configuration request. */ + ppp_ptr -> nx_ppp_timeout = 0; + + /* Set the IP address for the specific interface from the configuration. */ + nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, + IP_ADDRESS(ppp_ptr -> nx_ppp_ipcp_local_ip[0], ppp_ptr -> nx_ppp_ipcp_local_ip[1], + ppp_ptr -> nx_ppp_ipcp_local_ip[2], ppp_ptr -> nx_ppp_ipcp_local_ip[3]), + 0xffffffff); + + /* Set gateway address. */ + (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_address = (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_address; + (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_interface = ppp_ptr -> nx_ppp_interface_ptr; + + /* Turn off the timeout. */ + ppp_ptr -> nx_ppp_timeout = 0; + } + + else if (code == NX_PPP_IPCP_CONFIGURE_REJECT) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Set the NAK option list, just to indicate to the configure request that + the IPCP request without DNS option is what we want. */ + ppp_ptr -> nx_ppp_naked_list[0] = 1; + + /* Send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + + else if ((code == NX_PPP_IPCP_CONFIGURE_NAK) && (packet_ptr)) + { + + /* Determine if the ID matches our last transmit ID. If not, just discard it. */ + if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the invalid frame ID counter. */ + ppp_ptr -> nx_ppp_invalid_frame_id++; +#endif + + /* Discard this request by simply returning! */ + return; + } + + /* Extract the information from response... looking for IP address and possibly DNS server IP address. */ + _nx_ppp_ipcp_response_extract(ppp_ptr, packet_ptr); + + /* Send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + + else if (code == NX_PPP_IPCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Timeout, send the configuration request. */ + _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); + } + +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_IPCP_COMPLETED_STATE: + { + + /* IPCP is up and operational at this point. */ + + /* Process relative to incoming code. */ + if (code == NX_PPP_IPCP_TERMINATE_REQUEST) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* ACK the terminate request. */ + _nx_ppp_ipcp_terminate_ack_send(ppp_ptr); + + /* Send terminate request. */ + _nx_ppp_ipcp_terminate_send(ppp_ptr); + + /* Move into the IPCP stopping state. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_STOPPING_STATE; + } + else if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) + { + /* The peer has sent a configuration request. */ + + /* Check configuration information. */ + acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list, good_data); + + /* Check for acceptable configuration. */ + if (acceptable_configuration == NX_TRUE) + { + + /* Yes, send an ack. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); + } + else + { + /* Otherwise, configuration is unacceptable, send a nak. */ + + /* Check rejected list. */ + if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) + { + + /* Yes, there are rejected options so send a new request. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, &ppp_ptr -> nx_ppp_rejected_list[1], ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); + } + else if (ppp_ptr -> nx_ppp_peer_naked_list[0] != 0) + { + + /* Yes, there are naked options so send a new request. */ + _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, &ppp_ptr -> nx_ppp_peer_naked_list[1], ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); + } + } + } + +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + case NX_PPP_LCP_STOPPING_STATE: + { + + /* We received a terminate request from the other side and just need to get the ACK. */ + + /* Process relative to incoming code. */ + if (code == NX_PPP_IPCP_TERMINATE_ACK) + { + + /* Move the the stopped state. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_STOPPED_STATE; + } + else if (code == NX_PPP_IPCP_TIMEOUT) + { + + /* Increment the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter++; + + /* Determine if the IPCP retry counter has been exceeded. */ + if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_IPCP_PROTOCOL_RETRIES) + { + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Send terminate request. */ + _nx_ppp_ipcp_terminate_send(ppp_ptr); + } + else + { + + /* Retry counter exceeded. */ + + /* Enter IPCP failed state. PPP must be stopped and started to try again. */ + ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_FAILED_STATE; + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } +#ifndef NX_PPP_DISABLE_INFO + else + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + + default: + { + +#ifndef NX_PPP_DISABLE_INFO + { + + /* Increment the number of unhandled state machine events. */ + ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; + } +#endif + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_configure_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the IPCP message options. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr IPCP packet pointer */ +/* naked_list NAKed option list */ +/* rejected_list Rejected option list */ +/* good_data Good options */ +/* */ +/* OUTPUT */ +/* */ +/* status */ +/* NX_TRUE 1 indicates no errors, address obtained */ +/* NX_FALSE 0 indicates an error or unknown option or address */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_ipcp_configure_check(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list, UCHAR *good_data) +{ + +UINT length, ip_stat, status; +UINT i, w, m; +UINT nak_length = 0; +UINT rej_length = 0; +UINT good_index = 0; +UINT nak_index = 0; +UINT rej_index = 0; +UCHAR option; + + + /* Extract the length. */ + length = ((UINT)(packet_ptr -> nx_packet_prepend_ptr[4] << 8) | (UINT)packet_ptr -> nx_packet_prepend_ptr[5]); + + /* Subtract 4 to remove the code, id, and length bytes from the length. */ + length = length - 4; + + /* Check for valid packet length. */ + if ((length + 6) > packet_ptr -> nx_packet_length) + { + return(NX_FALSE); + } + + /* Initialize the rejected and naked lists. */ + rejected_list[0] = naked_list[0] = good_data[0] = 0; + + /* Loop to process the IPCP configuration options. */ + for(w = 0, rej_index = 1, status = 1, nak_index = 1; (w + 2) <= length;) + { + + UINT opt_length; + + /* Pickup the IPCP option. */ + option = packet_ptr -> nx_packet_prepend_ptr[w + 6]; + + /* Pickup the IPCP option length. */ + opt_length = (UINT) packet_ptr -> nx_packet_prepend_ptr[w + 7]; + + /* Determine if the length is valid. */ + if ((opt_length < 2) || (opt_length > (length - w))) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal overflow counter. */ + ppp_ptr -> nx_ppp_packet_overflow++; +#endif + + /* Something is wrong, just get out of the loop! */ + return(status); + } + + /* Adjust the option length. */ + opt_length -= 2; + + /* Process relative to the option. */ + switch (option) + { + + case NX_PPP_IP_ADDRESS_OPTION: + { + + /* Check if out of boundary. */ + if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) + return(NX_FALSE); + + /* IP address option. */ + good_data[good_index++] = NX_PPP_IP_ADDRESS_OPTION; + good_data[good_index++] = 6; + + ip_stat = 0; + for(i = 0; i < 4; i++) + { + + /* Pick up each byte of the IP address. */ + good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; + + /* OR in the IP address bytes to make it easy to see if we got something. */ + ip_stat |= good_data[i + good_index]; + } + + /* Adjust the main index. */ + w += (opt_length + good_index); + + /* Check if we really have an IP address. */ + if (!ip_stat) + { + + /* Copy default IP address. */ + for(i = 0; i < 4; i++) + { + good_data[i + good_index] = ppp_ptr -> nx_ppp_ipcp_peer_ip[i]; + } + + /* Setup NAK list so we can get the IP address hint. */ + for(i = 0; i < 6; i++) + { + naked_list[nak_index++] = good_data[i]; + } + + nak_length = nak_index - 1; + + /* Clear status. */ + status = 0; + } + else + { + + /* We did get an IP address for the peer. Remember it! */ + for (i = 0; i < 4; i++) + { + + /* Remember each byte of peer's IP address. */ + ppp_ptr -> nx_ppp_ipcp_peer_ip[i] = good_data[i + good_index]; + } + } + + good_index += opt_length; + + break; + } + + case NX_PPP_IP_COMPRESSION_OPTION: + { + + /* IP Compression Option. Since this is the receiver telling us what they + support it is not important to us since we don't support compression. */ + + /* Simply adjust the main index into the option list. */ + w += (opt_length + 2); /* skip */ + break; + } + + case NX_PPP_DNS_SERVER_OPTION: + { + + /* Check if out of boundary. */ + if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* Only request a hint if we don't have already have a dns address . */ + good_data[good_index++] = NX_PPP_DNS_SERVER_OPTION; + good_data[good_index++] = 6; + ip_stat = 0; + for(i = 0; i < 4; i++) + { + + /* Pick up each byte of the primary DNS address. */ + good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; + + /* Or in the IP address bytes to make it easy to see if we got something. */ + ip_stat |= good_data[i + good_index]; + } + + /* Adjust the main index. */ + w += (opt_length + 2); + + /* Check if we really have an primary DNS address. */ + if (!ip_stat) + { + + + /* Update the number of retries on secondary address requests. */ + ppp_ptr -> nx_ppp_dns_address_retries++; + + /* Check if we have reached the limit on retries. */ + if (ppp_ptr -> nx_ppp_dns_address_retries >= NX_PPP_DNS_ADDRESS_MAX_RETRIES) + { + /* We have. Return successful result and let IPCP complete. */ + break; + } + + /* Copy default DNS IP address. */ + good_data[good_index] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address >> 24); + good_data[good_index + 1] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 16) & 0xff); + good_data[good_index + 2] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 8) & 0xff); + good_data[good_index + 3]= (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address & 0xff); + + /* Setup NAK list so we can get the DNS IP address hint. */ + for(i = 0; i < 6; i++) + { + naked_list[nak_index++] = good_data[good_index + i - 2]; + } + + /* Clear status. */ + status = 0; + + /* Update the size of the nak and reject data. */ + nak_length = nak_index - 1; + } + else + { + + /* Copy good IP address. */ + ppp_ptr -> nx_ppp_primary_dns_address = ((ULONG)good_data[good_index] << 24) & 0xFF000000; + ppp_ptr -> nx_ppp_primary_dns_address |= (good_data[good_index + 1] << 16) & 0x00FF0000; + ppp_ptr -> nx_ppp_primary_dns_address |= (good_data[good_index + 2] << 8) & 0x0000FF00; + ppp_ptr -> nx_ppp_primary_dns_address |= good_data[good_index + 3] & 0x000000FF; + } + + good_index += opt_length; + + break; + } + + case NX_PPP_DNS_SECONDARY_SERVER_OPTION: + { + + /* Check if out of boundary. */ + if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) + break; + + /* Only request a hint if we don't have already have a dns address . */ + good_data[good_index++] = NX_PPP_DNS_SECONDARY_SERVER_OPTION; + good_data[good_index++] = 6; + ip_stat = 0; + for(i = 0; i < 4; i++) + { + + /* Pick up each byte of the secondary DNS address. */ + good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; + + /* Or in the IP address bytes to make it easy to see if we got something. */ + ip_stat |= good_data[i + good_index]; + } + + /* Adjust the main index. */ + w += (opt_length + 2); + + /* Check if we really have an primary DNS address. */ + if (!ip_stat) + { + + /* Update the number of retries on primary address requests. */ + ppp_ptr -> nx_ppp_secondary_dns_address_retries++; + + /* Check if we have reached the limit on retries. */ + if (ppp_ptr -> nx_ppp_secondary_dns_address_retries >= NX_PPP_DNS_ADDRESS_MAX_RETRIES) + { + /* We have. Return successful result and let IPCP complete. */ + break; + } + + /* Copy the primary DNS IP address from the packet data. */ + good_data[good_index] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address >> 24); + good_data[good_index + 1] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 16) & 0xff); + good_data[good_index + 2] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 8) & 0xff); + good_data[good_index + 3]= (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address & 0xff); + + /* Setup NAK list so we can get the DNS IP address hint. */ + for(i = 0; i < 6; i++) + { + naked_list[nak_index++] = good_data[good_index + i - 2]; + } + + /* Clear status. */ + status = 0; + + /* Update the size of the nak and reject data. */ + nak_length = nak_index - 1; + } + + else + { + + /* Copy good IP address. */ + ppp_ptr -> nx_ppp_secondary_dns_address = ((ULONG)good_data[good_index] << 24) & 0xFF000000; + ppp_ptr -> nx_ppp_secondary_dns_address |= (good_data[good_index + 1] << 16) & 0x00FF0000; + ppp_ptr -> nx_ppp_secondary_dns_address |= (good_data[good_index + 2] << 8) & 0x0000FF00; + ppp_ptr -> nx_ppp_secondary_dns_address |= good_data[good_index + 3] & 0x000000FF; + } + + good_index += opt_length; + + break; + } + + default: + { + + /* All other options get NAKed. */ + status = 0; + + /* Determine if the option will fit. */ + if ((rej_index + opt_length + 2) >= NX_PPP_OPTION_MESSAGE_LENGTH) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal overflow counter. */ + ppp_ptr -> nx_ppp_packet_overflow++; +#endif + + /* Return status. */ + return(status); + } + + /* Place the option in the rejected list. */ + rejected_list[rej_index++] = option; + rejected_list[rej_index++] = (UCHAR)(opt_length + 2); + + /* Loop to copy the rest of the options into the rejected list. */ + for (m = 0; m < opt_length; m++) + { + + /* Copy option byte into the rejected option list. */ + rejected_list[rej_index] = packet_ptr -> nx_packet_prepend_ptr[w + m + 8]; + rej_index++; + } + + rej_length = rej_index - 1; + + /* Adjust the main index into the option list. */ + w += (opt_length + 2); /* skip */ + break; + } + } + } + + /* Setup the length in the naked and rejected lists. */ + naked_list[0] = (UCHAR)nak_length; + rejected_list[0] = (UCHAR)rej_length; + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_configure_request_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a configure request message and sends it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* negotiate_list List of options to negotiate */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send IPCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_configure_request_send(NX_PPP *ppp_ptr, UCHAR *negotiate_list) +{ + +UINT status, i; +NX_PACKET *packet_ptr; +UINT index; + + + /* Allocate a packet for the IPCP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Clear the packet memory.*/ + memset(packet_ptr -> nx_packet_prepend_ptr, 0, (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)); + + /* Adjust the transmit ID. */ + ppp_ptr -> nx_ppp_transmit_id++; + + /* Build IPCP request message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_CONFIGURE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; + packet_ptr -> nx_packet_prepend_ptr[5] = 0x0A; /* Size of the IPCP data */ + packet_ptr -> nx_packet_prepend_ptr[6] = 0x03; + packet_ptr -> nx_packet_prepend_ptr[7] = 0x06; + + /* Load up the default IP address. */ + for(i = 0; i < 4; i++) + { + + /* Copy byte of IP address. */ + packet_ptr -> nx_packet_prepend_ptr[i+8] = ppp_ptr -> nx_ppp_ipcp_local_ip[i]; + } + + index = i + 8; + + /* Determine if we want the DNS option ... */ + if (negotiate_list[0] == 0) + { + + /* Yes (because it is not obvious from the code style), let's try to get the DNS server. */ + + /* Update the IPCP length for DNS address. */ + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(packet_ptr -> nx_packet_prepend_ptr[5] + 6); + + /* Add the option for retrieving the DNS server as well. */ + packet_ptr -> nx_packet_prepend_ptr[index] = NX_PPP_DNS_SERVER_OPTION; + packet_ptr -> nx_packet_prepend_ptr[index+1] = 0x06; + packet_ptr -> nx_packet_prepend_ptr[index+2] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address >> 24); + packet_ptr -> nx_packet_prepend_ptr[index+3] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 16) & 0xff); + packet_ptr -> nx_packet_prepend_ptr[index+4] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 8) & 0xff); + packet_ptr -> nx_packet_prepend_ptr[index+5] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address & 0xff); + index += 6; + + /* Also check for a secondary DNS address request. */ + if (negotiate_list[1] == 0) + { + + /* Update the IPCP length for secondary DNS address. */ + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(packet_ptr -> nx_packet_prepend_ptr[5] + 6); + + /* Add the option for retrieving the DNS server as well. */ + packet_ptr -> nx_packet_prepend_ptr[index] = NX_PPP_DNS_SECONDARY_SERVER_OPTION; + packet_ptr -> nx_packet_prepend_ptr[index+1] = 0x06; + packet_ptr -> nx_packet_prepend_ptr[index+2] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address >> 24); + packet_ptr -> nx_packet_prepend_ptr[index+3] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 16) & 0xff); + packet_ptr -> nx_packet_prepend_ptr[index+4] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 8) & 0xff); + packet_ptr -> nx_packet_prepend_ptr[index+5] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address & 0xff); + index += 6; + } + } + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = index; + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IPCP frames sent. */ + ppp_ptr -> nx_ppp_ipcp_frames_sent++; + + /* Increment the number of IPCP configure requests sent. */ + ppp_ptr -> nx_ppp_ipcp_configure_requests_sent++; +#endif + + /* Send IPCP configure request packet. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_response_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts information from the IPCP response */ +/* message. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* packet_ptr Pointer to IPCP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_response_extract(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UINT i, j; +ULONG length; + + + + /* Search for IP address and DNS address in response. */ + + /* Setup the packet length. */ + length = (((ULONG) packet_ptr -> nx_packet_prepend_ptr[4]) << 8) | ((ULONG) packet_ptr -> nx_packet_prepend_ptr[5]); + + /* Subtract the request type, id, and length. */ + if (length >= 4) + length = length - 4; + else + length = 0; + + /* Check for valid packet length. */ + if ((length + 6) > packet_ptr -> nx_packet_length) + { + return; + } + + /* Loop to parse the options to look for primary DNS address. */ + i = 6; + while (length) + { + + /* Subtract the length. */ + if (length >= ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1])) + length = length - ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1]); + else + length = 0; + + /* Check for the IP address. */ + if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_IP_ADDRESS_OPTION) + { + + + /* Copy the IP address bytes into the PPP storage. */ + for(j = 0; j < 4; j++) + { + + /* Copy a byte of the IP address. */ + ppp_ptr -> nx_ppp_ipcp_local_ip[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+2]; + } + } + + /* Check for the primary DNS option. */ + else if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_DNS_SERVER_OPTION) + { + + /* Yes, we have a primary DNS address. */ + + /* Let's copy it into the PPP structure in case we need it later. */ + ppp_ptr -> nx_ppp_primary_dns_address = ((((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+2]) << 24) | + (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+3]) << 16) | + (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+4]) << 8) | + ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+5])); + + } + + /* Check for the primary DNS option. */ + else if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_DNS_SECONDARY_SERVER_OPTION) + { + + /* Yes, we have a secondary DNS address. */ + + /* Let's copy it into the PPP structure in case we need it later. */ + ppp_ptr -> nx_ppp_secondary_dns_address = ((((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+2]) << 24) | + (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+3]) << 16) | + (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+4]) << 8) | + ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+5])); + + + /* Break out of the loop. */ + break; + } + + /* Otherwise move to the next option. */ + if (length >= ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1])) + { + + /* Yes, there is another option. */ + + /* Position to the next option. */ + i = i + (((UINT) packet_ptr -> nx_packet_prepend_ptr[i+1])); + } + else + { + + /* Make sure the length is 0. */ + length = 0; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an IPCP response message. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* type ACK or NAK selection */ +/* data Previous IPCP message */ +/* length Length of previous IPCP msg */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send frame */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_response_send(NX_PPP *ppp_ptr, UCHAR type, UCHAR *data, UCHAR length, NX_PACKET *cfg_packet_ptr) +{ + +UINT status, i; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the IPCP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Determine if an ACK is requested. */ + if (type == NX_PPP_IPCP_CONFIGURE_ACK) + { + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(cfg_packet_ptr -> nx_packet_length)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Yes, an ACK is requested. Simply copy the config packet into the new packet and change + the type. */ + for (i = 0; i < cfg_packet_ptr -> nx_packet_length; i++) + { + + /* Determine if the copy exceeds the payload. */ + if (&packet_ptr -> nx_packet_prepend_ptr[i] >= packet_ptr -> nx_packet_data_end) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Simply return. */ + return; + } + + /* Copy one byte. */ + packet_ptr -> nx_packet_prepend_ptr[i] = cfg_packet_ptr -> nx_packet_prepend_ptr[i]; + } + + /* Adjust the type of the new packet to represent an ACK. */ + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_CONFIGURE_ACK; + + /* Adjust the length and append pointers of the packet. */ + packet_ptr -> nx_packet_length = cfg_packet_ptr -> nx_packet_length; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + } + else + { + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 6)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Build IPCP response message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = type; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(length + 4); + + /* Load up the default IP address. */ + for(i = 0; i < length; i++) + { + + /* Copy byte of IP address. */ + packet_ptr -> nx_packet_prepend_ptr[i+6] = data[i]; + } + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = (UCHAR)(length + 4 + 2); + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IPCP frames sent. */ + ppp_ptr -> nx_ppp_ipcp_frames_sent++; + + /* Increment counters based on type of response. */ + if (type == NX_PPP_IPCP_CONFIGURE_ACK) + { + + /* Increment the number of IPCP configure ACKs sent. */ + ppp_ptr -> nx_ppp_ipcp_configure_acks_sent++; + } + else if (type == NX_PPP_IPCP_CONFIGURE_NAK) + { + + /* Increment the number of IPCP configure NAKs sent. */ + ppp_ptr -> nx_ppp_ipcp_configure_naks_sent++; + } + else if (type == NX_PPP_IPCP_CONFIGURE_REJECT) + { + + /* Increment the number of IPCP configure rejects sent. */ + ppp_ptr -> nx_ppp_ipcp_configure_rejects_sent++; + } +#endif + + /* Send IPCP response. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_terminate_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a terminate request message and sends */ +/* it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send AHDLC packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_terminate_send(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the IPCP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build IPCP terminate message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_TERMINATE_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; + packet_ptr -> nx_packet_prepend_ptr[5] = 0x04; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 6; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IPCP frames sent. */ + ppp_ptr -> nx_ppp_ipcp_frames_sent++; + + /* Increment the number of IPCP terminate sent. */ + ppp_ptr -> nx_ppp_ipcp_terminate_requests_sent++; +#endif + + /* Send IPCP terminate packet. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ipcp_terminate_ack_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a terminate ACK request message and sends */ +/* it out. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send AHDLC packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_ipcp_terminate_ack_send(NX_PPP *ppp_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Allocate a packet for the IPCP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* An error was detected, simply return a NULL pointer. */ + return; + } + + /* Build IPCP terminate ACK message. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_TERMINATE_ACK; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; + packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; + packet_ptr -> nx_packet_prepend_ptr[5] = 0x04; + + /* Setup the append pointer and the packet length. */ + packet_ptr -> nx_packet_length = 6; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of IPCP frames sent. */ + ppp_ptr -> nx_ppp_ipcp_frames_sent++; + + /* Increment the number of IPCP terminate ACKs sent. */ + ppp_ptr -> nx_ppp_ipcp_terminate_acks_sent++; +#endif + + /* Send IPCP terminate ACK packet. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_packet_transmit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a CRC to the current transmit buffer and then */ +/* sends the buffer via the user supplied byte output routine. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* packet_ptr Pointer to PPP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_nx_ppp_debug_log_capture] Put send frame in debug log */ +/* _nx_ppp_crc_append Add PPP CRC */ +/* (nx_ppp_byte_send) User supplied byte send */ +/* nx_packet_transmit_release Release the transmit packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_process_deferred_ip_packet_send Process deferred IP packet */ +/* _nx_ppp_lcp_code_reject Send LCP code reject message */ +/* _nx_ppp_lcp_configure_reply_send Send LCP configure reply */ +/* _nx_ppp_lcp_configure_request_send Send LCP configure request */ +/* _nx_ppp_lcp_terminate_ack_send Send LCP terminate ACK */ +/* _nx_ppp_lcp_terminate_request_send Send LCP terminate request */ +/* _nx_ppp_pap_authentication_request PAP authentication request */ +/* _nx_ppp_pap_authentication_ack PAP authentication ACK */ +/* _nx_ppp_pap_authentication_nak PAP authentication NAK */ +/* _nx_ppp_chap_challenge_send CHAP challenge send */ +/* _nx_ppp_chap_challenge_respond CHAP challenge respond */ +/* _nx_ppp_chap_challenge_validate CHAP challenge validate */ +/* _nx_ppp_ipcp_configure_request_send Send IPCP configure request */ +/* _nx_ppp_ipcp_response_send Send IPCP response */ +/* _nx_ppp_ipcp_terminate_send Send IPCP terminate */ +/* _nx_ppp_ipcp_terminate_ack_send Send IPCP terminate ACK */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_packet_transmit(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +NX_PACKET *current_packet_ptr; +UINT i; +UCHAR byte; +UCHAR *buffer_ptr; +UCHAR hdlc[3] = {0x7e, 0xff, 0x03}; +UCHAR crc[2]; +#ifdef NX_PPP_PPPOE_ENABLE +UINT release_packet = NX_TRUE; +#endif /* NX_PPP_PPPOE_ENABLE */ + + +#ifdef NX_PPP_DEBUG_LOG_ENABLE + + /* Place the outgoing frame into the optional PPP debug log. */ + _nx_ppp_debug_log_capture(ppp_ptr, 'S', packet_ptr); +#endif + + /* Check for send function. */ + if (ppp_ptr -> nx_ppp_byte_send) + { + + /* Step1. Send the HDLC bytes. */ + for (i = 0; i < 3; i++) + { + + /* Pickup the byte. */ + byte = hdlc[i]; + + /* Determine if it needs an escape sequence. */ + if ((byte < ((UCHAR) 0x20)) || ((byte == ((UCHAR) 0x7e)) && (i != 0)) || (byte == ((UCHAR) 0x7d))) + { + + /* Yes, this byte needs an escape sequence. */ + + /* Change the byte. */ + byte = byte ^ 0x20; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Send the escape sequence byte via the user supplied output routine. */ + ppp_ptr -> nx_ppp_byte_send(0x7d); + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Call user supplied byte output routine. */ + ppp_ptr -> nx_ppp_byte_send(byte); + } + + /* Step2. Send the data. */ + /* Initialize the current packet pointer to the packet pointer. */ + current_packet_ptr = packet_ptr; + + /* Setup the initial buffer pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Loop through the buffer to send each byte out. */ + for(i = 0; i < packet_ptr -> nx_packet_length; i++) + { + + /* Determine if we need to move to any additional packets. */ + if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Yes, we need to move to the next packet. */ + current_packet_ptr = current_packet_ptr -> nx_packet_next; + + /* Determine if there is a next packet. */ + if (current_packet_ptr == NX_NULL) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the internal error counter. */ + ppp_ptr -> nx_ppp_internal_errors++; +#endif + + /* Get out of the loop. */ + break; + } + + /* Otherwise setup new buffer pointer. */ + buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; +#else + break; + +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } + + /* Pickup the next byte to be sent. */ + byte = *buffer_ptr++; + + /* Determine if this byte needs an escape sequence. */ + if ((byte < ((UCHAR) 0x20)) || (byte == 0x7e) || (byte == 0x7d)) + { + + /* Yes, this byte needs an escape sequence. */ + + /* Change the byte. */ + byte = byte ^ 0x20; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Send the escape sequence byte via the user supplied output routine. */ + ppp_ptr -> nx_ppp_byte_send(0x7d); + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Call user supplied byte output routine. */ + ppp_ptr -> nx_ppp_byte_send(byte); + } + + /* Step3. Send CRC. */ + /* Place a CRC at the end of the transmit buffer. */ + _nx_ppp_crc_append(packet_ptr, crc); + + /* Now send the CRC and end-of-frame bytes. */ + for (i = 0; i < 2; i++) + { + + /* Pickup the byte. */ + byte = crc[i]; + + /* Determine if it needs an escape sequence. */ + if ((byte < ((UCHAR) 0x20)) || (byte == ((UCHAR) 0x7e)) || (byte == ((UCHAR) 0x7d))) + { + + /* Yes, this byte needs an escape sequence. */ + + /* Change the byte. */ + byte = byte ^ 0x20; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Send the escape sequence byte via the user supplied output routine. */ + ppp_ptr -> nx_ppp_byte_send(0x7d); + } + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of bytes sent. */ + ppp_ptr -> nx_ppp_bytes_sent++; +#endif + + /* Call user supplied byte output routine. */ + ppp_ptr -> nx_ppp_byte_send(byte); + } + + /* Step4. Finally, send an end-of-frame character. */ + ppp_ptr -> nx_ppp_byte_send((UCHAR) 0x7e); + } + +#ifdef NX_PPP_PPPOE_ENABLE + + /* Check the PPPoE packet send function. */ + if (ppp_ptr -> nx_ppp_packet_send) + { + + /* Send the packet out. */ + (ppp_ptr -> nx_ppp_packet_send)(packet_ptr); + + /* Update the flag since this packet should been released in PPPoE. */ + release_packet = NX_FALSE; + + } + + /* Check if need to release the packet. */ + if (release_packet == NX_TRUE) + { +#endif /* NX_PPP_PPPOE_ENABLE */ + + /* Remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + +#ifdef NX_PPP_PPPOE_ENABLE + } +#endif /* NX_PPP_PPPOE_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_check_crc PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the CRC of the AHDLC packet in the packet */ +/* payload. If the CRC is correct, the CRC is removed from the receive */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Address of PPP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_receive_packet_get Receive PPP packet processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_check_crc(NX_PACKET *packet_ptr) +{ + +NX_PACKET *current_packet_ptr; +UCHAR byte; +UCHAR *buffer_ptr; +USHORT i; +USHORT crc_value; + + + /* Set initial CRC value. */ + crc_value = 0xffff; + + /* Setup buffer pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 1; + + /* Setup the current packet pointer. */ + current_packet_ptr = packet_ptr; + + /* Loop to process the CRC for the receive buffer. */ + for(i = 1; i < (packet_ptr -> nx_packet_length - 1); i++) + { + + /* Determine if the buffer pointer is inside the current packet. */ + if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* We have exhausted this packet and must move to the next. */ + current_packet_ptr = current_packet_ptr -> nx_packet_next; + + /* Determine if there is a next packet. */ + if (current_packet_ptr == NX_NULL) + break; + + /* Otherwise, we have a valid next packet. Setup the buffer pointer + to the first byte in the next packet. */ + buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; +#else + break; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } + + /* Pickup character from buffer. */ + byte = *buffer_ptr++; + + /* Update the CRC. */ + crc_value = (( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ byte ]); + } + + /* At this point, the CRC should be 0xf0b8. */ + if (crc_value != 0xf0b8) + { + + /* CRC failed, not a valid PPP packet. */ + return(NX_PPP_BAD_PACKET); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_crc_append PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates and appends the two byte CRC to the */ +/* frame. It also adds the end of frame marker after the CRC. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to PPP packet */ +/* crc Destination for CRC */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_packet_transmit PPP packet transmit routine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_crc_append(NX_PACKET *packet_ptr, UCHAR crc[2]) +{ + +NX_PACKET *current_packet_ptr; +UCHAR *buffer_ptr; +UINT i; +USHORT crc_value; +UCHAR byte; +UCHAR address = 0xff; +UCHAR control = 0x03; + + + /* The FCS field is calculated over all bits of the Address, Control, + Protocol, Information and Padding fields, not including any start + and stop bits (asynchronous) nor any bits (synchronous) or octets + (asynchronous or synchronous) inserted for transparency. This + also does not include the Flag Sequences nor the FCS field itself. + RFC1662, Section3.1, Page6. */ + + /* Initialize CRC value. */ + crc_value = 0xffff; + + /* Step1. Calculate address and control. */ + crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ address ]; + crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ control ]; + + /* Step2. Calculate protocol, information and padding fiedls. */ + + /* Initialize the current packet pointer to the packet pointer. */ + current_packet_ptr = packet_ptr; + + /* Setup the initial buffer pointer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Loop to calculate CRC. */ + for(i = 0; i < packet_ptr -> nx_packet_length; i++) + { + + /* Determine if we need to move to any additional packets. */ + if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Yes, we need to move to the next packet. */ + current_packet_ptr = current_packet_ptr -> nx_packet_next; + + /* Determine if there is a next packet. */ + if (current_packet_ptr == NX_NULL) + { + + /* Get out of the loop. */ + break; + } + + /* Otherwise setup new buffer pointer. */ + buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; +#else + break; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } + + /* Pickup the next byte to be sent. */ + byte = *buffer_ptr++; + + /* Update the CRC. */ + crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ byte ]; + } + + /* Now complement the CRC value. */ + crc_value = crc_value ^ 0xffff; + + /* Store first byte of the CRC. */ + crc[0] = (UCHAR) (crc_value & 0xff); + + /* Store second byte of the CRC. */ + crc[1] = (UCHAR) ((crc_value >> 8) & 0xff); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + + +#ifdef NX_PPP_DEBUG_LOG_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_debug_log_capture PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the current frame into the circular debug */ +/* log. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP structure */ +/* packet_type Either a send or receive */ +/* packet_ptr Pointer to PPP packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_time_get Get time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_packet_transmit Transmit packet processing */ +/* _nx_ppp_thread_entry Receive thread processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_debug_log_capture(NX_PPP *ppp_ptr, UCHAR packet_type, NX_PACKET *packet_ptr) +{ + +UINT i; +ULONG time; +NX_PPP_DEBUG_ENTRY *entry_ptr; + + /* Check for a NULL pointer. */ + if (packet_ptr == NX_NULL) + return; + + /* Pickup current time. */ + time = tx_time_get(); + +#ifdef NX_PPP_DEBUG_LOG_PRINT_ENABLE + /* Print out the current time stamp. */ + printf("Time: %lu, ", time); + + /* Print out the PPP name. */ + printf("PPP Name: %s, ", ppp_ptr -> nx_ppp_name); + + /* Print out the current PPP state. */ + printf("PPP State: %u, ", ppp_ptr -> nx_ppp_state); + + /* Print out the current PPP LCP state. */ + printf("PPP LCP State: %u, ", ppp_ptr -> nx_ppp_lcp_state); + + /* Print out the current PPP PAP state. */ + printf("PPP PAP State: %u, ", ppp_ptr -> nx_ppp_pap_state); + + /* Print out the current PPP CHAP state. */ + printf("PPP CHAP State: %u, ", ppp_ptr -> nx_ppp_chap_state); + + /* Print out the current IPCP state. */ + printf("PPP IPCP State: %u, ", ppp_ptr -> nx_ppp_ipcp_state); + + /* Print out the authentication flag. */ + if (ppp_ptr -> nx_ppp_authenticated) + printf("Authenticated, "); + else + printf("Not Authenticated, "); + + /* Determine if the packet is a receive packet or a send packet. */ + if (packet_type == 'R') + printf("Received Packet Length: %lu, Packet: ", packet_ptr -> nx_packet_length); + else + printf("Send Packet Length: %lu, Packet: ", packet_ptr -> nx_packet_length); + + /* Dump out at least part of the packet payload. */ + for (i = 0; i < packet_ptr -> nx_packet_length; i++) + { + + /* Check for packet spanning multiple packets. */ + if ((packet_ptr -> nx_packet_prepend_ptr+i) >= packet_ptr -> nx_packet_append_ptr) + break; + + /* Check for maximum dump size. */ + if (i >= NX_PPP_DEBUG_FRAME_SIZE) + break; + + /* Print one character. */ + printf("%02x ", packet_ptr -> nx_packet_prepend_ptr[i]); + } + + printf("\n"); +#endif /* NX_PPP_DEBUG_LOG_PRINT_ENABLE */ + + /* Now load the internal PPP log. */ + + /* Setup the debug log entry pointer. */ + entry_ptr = &(ppp_ptr -> nx_ppp_debug_log[ppp_ptr -> nx_ppp_debug_log_oldest_index++]); + + /* Check for wrap-around of the index. */ + if (ppp_ptr -> nx_ppp_debug_log_oldest_index >= NX_PPP_DEBUG_LOG_SIZE) + ppp_ptr -> nx_ppp_debug_log_oldest_index = 0; + + /* Setup the debug log entries. */ + entry_ptr -> nx_ppp_debug_entry_time_stamp = time; + entry_ptr -> nx_ppp_debug_ppp_state = (UCHAR) ppp_ptr -> nx_ppp_state; + entry_ptr -> nx_ppp_debug_lcp_state = (UCHAR) ppp_ptr -> nx_ppp_lcp_state; + entry_ptr -> nx_ppp_debug_pap_state = (UCHAR) ppp_ptr -> nx_ppp_pap_state; + entry_ptr -> nx_ppp_debug_chap_state = (UCHAR) ppp_ptr -> nx_ppp_chap_state; + entry_ptr -> nx_ppp_debug_ipcp_state = (UCHAR) ppp_ptr -> nx_ppp_ipcp_state; + entry_ptr -> nx_ppp_debug_authenticated = ppp_ptr -> nx_ppp_authenticated; + entry_ptr -> nx_ppp_debug_frame_type = packet_type; + entry_ptr -> nx_ppp_debug_packet_length = packet_ptr -> nx_packet_length; + + /* Store at least part of the packet payload. */ + for (i = 0; i < packet_ptr -> nx_packet_length; i++) + { + + /* Check for packet spanning multiple packets. */ + if ((packet_ptr -> nx_packet_prepend_ptr+i) >= packet_ptr -> nx_packet_append_ptr) + break; + + /* Check for maximum dump size. */ + if (i >= NX_PPP_DEBUG_FRAME_SIZE) + break; + + /* Store one character. */ + entry_ptr -> nx_ppp_debug_frame[i] = packet_ptr -> nx_packet_prepend_ptr[i]; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_debug_log_capture_protocol PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function outputs the status of various protocols and timeouts */ +/* of the specified PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP structure */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_thread_entry PPP event processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_debug_log_capture_protocol(NX_PPP *ppp_ptr) +{ + + + /* Print out the PPP name. */ + printf("%s: ", ppp_ptr -> nx_ppp_name); + + /* Print out the current PPP state. */ + printf("State: %u, ", ppp_ptr -> nx_ppp_state); + + /* Print out the current PPP LCP state. */ + printf("LCP State: %u, ", ppp_ptr -> nx_ppp_lcp_state); + + /* Print out the current IPCP state. */ + printf("IPCP State: %u, ", ppp_ptr -> nx_ppp_ipcp_state); + + if ((ppp_ptr -> nx_ppp_chap_enabled) || (ppp_ptr -> nx_ppp_pap_enabled)) + { + + /* Print out the authentication flag. */ + if (ppp_ptr -> nx_ppp_authenticated) + printf("Authenticated, "); + else + { + + printf("Not Authenticated, "); + + /* Print out the current PPP PAP state. */ + printf("PAP State: %u, ", ppp_ptr -> nx_ppp_pap_state); + + /* Print out the current PPP CHAP state. */ + printf("CHAP State: %u, ", ppp_ptr -> nx_ppp_chap_state); + } + } + + /* Print out the current PPP LCP state. */ + printf("Time remaining: %lu, ", ppp_ptr -> nx_ppp_timeout); + printf("Timeouts: %lu, ", ppp_ptr -> nx_ppp_receive_timeouts); + printf("Protocol retries: %lu, ", ppp_ptr -> nx_ppp_protocol_retry_counter); + + printf("\n"); +} +#endif /* NX_PPP_DEBUG_LOG_ENABLE */ + + +#ifndef NX_PPP_DISABLE_CHAP +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_hash_generator PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the MD5 hash value for CHAP authentication */ +/* processing. The input challenge "rand_value" is a stream of octets,*/ +/* including 0x0, so the length option ensures the rand_value length is*/ +/* set correctly. */ +/* */ +/* If the caller is certain there is no 0x0 within the rand_value it */ +/* can send a zero length arguement and this function will compute the */ +/* rand_value length. */ +/* */ +/* INPUT */ +/* */ +/* hvalue Hash value return string */ +/* id PPP message ID */ +/* secret Secret input string */ +/* rand_value Random value input string */ +/* length Length of random string, */ +/* if zero, assume null */ +/* terminated */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_chap_challenge_respond CHAP challenge response */ +/* _nx_ppp_chap_challenge_validate CHAP validate response */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_hash_generator(unsigned char *hvalue, unsigned char id, + unsigned char *secret, unsigned char *rand_value, UINT length) +{ + +UINT slen, rlen; +NX_MD5 context; + + + /* Compute the length of the secret. */ + for(slen = 0; secret[slen]; slen++); + + /* Compute the length of the rand_value if no length is specified. */ + if(length==0) + { + for(rlen = 0; rand_value[rlen]; rlen++); + } + else + { + rlen = length; + } + + /* Initialize the MD5 digest calculation. */ + _nx_md5_initialize(&context); + + /* Update the digest. */ + _nx_md5_update(&context, &id, 1); + _nx_md5_update(&context, secret, slen); + _nx_md5_update(&context, rand_value, rlen); + + /* Finally, calculate the digest. */ + _nx_md5_digest_calculate(&context, hvalue); +} +#endif /* NX_PPP_DISABLE_CHAP */ + + +/* Define externally available API functions. */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_byte_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP byte receive */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* byte Newly received byte */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_byte_receive Actual PPP byte receive */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Call actual byte receive function. */ + status = _nx_ppp_byte_receive(ppp_ptr, byte); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_byte_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a byte from the application (usually an */ +/* application ISR), buffers it, and notifies the PPP receive thread. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* byte Newly received byte */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Notify PPP receiving thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code (Including ISRs) */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Check for no longer active PPP instance. */ + if (ppp_ptr -> nx_ppp_id != NX_PPP_ID) + { + + /* PPP is no longer active. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return an error. */ + return(NX_PTR_ERROR); + } + + /* Check for a stopped PPP instance. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) + { + + /* Silently discard byte. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(NX_SUCCESS); + } + + /* Determine if there is enough room in the serial buffer. */ + if (ppp_ptr -> nx_ppp_serial_buffer_byte_count >= NX_PPP_SERIAL_BUFFER_SIZE) + { + +#ifndef NX_PPP_DISABLE_INFO + /* Increment the number of bytes dropped. */ + ppp_ptr -> nx_ppp_bytes_dropped++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* No, return an error. */ + return(NX_PPP_BUFFER_FULL); + } + + /* Otherwise, PPP is active and there is room in the buffer! */ + + /* Place the byte in the buffer. */ + ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_write_index++] = byte; + + /* Check for a wrap-around of the serial buffer. */ + if (ppp_ptr -> nx_ppp_serial_buffer_write_index >= NX_PPP_SERIAL_BUFFER_SIZE) + { + + /* Yes, buffer wrap-around is present. Reset the write pointer to the beginning of the + buffer. */ + ppp_ptr -> nx_ppp_serial_buffer_write_index = 0; + } + + /* Increment the byte count. */ + ppp_ptr -> nx_ppp_serial_buffer_byte_count++; + +#ifndef NX_PPP_DISABLE_INFO + /* Increment the number of bytes received. */ + ppp_ptr -> nx_ppp_bytes_received++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if the PPP receive thread needs to be alerted. */ + if ((ppp_ptr -> nx_ppp_serial_buffer_byte_count >= NX_PPP_SERIAL_BUFFER_ALERT_THRESHOLD) || + (byte == 0x7e)) + { + + /* Yes, alert the receiving thread that a byte is available for processing. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_PACKET_RECEIVE, TX_OR); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP create instance */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* name Pointer to instance name */ +/* ip_ptr Pointer to IP instance */ +/* stack_memory_ptr Pointer to thread stack */ +/* stack_size Pointer to thread stack size */ +/* thread_priority Priority of thread(s) created */ +/* for PPP */ +/* pool_ptr Default packet pool pointer */ +/* ppp_non_ppp_packet_handler Non PPP packet handler */ +/* provided by the application */ +/* ppp_byte_send Byte output function provided */ +/* by the application */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_create Actual PPP create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, + VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, + NX_PACKET_POOL *pool_ptr, + void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), + void (*ppp_byte_send)(UCHAR byte)) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id == NX_PPP_ID) || + (ip_ptr == NX_NULL) || (stack_memory_ptr == NX_NULL) || (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP create function. */ + status = _nx_ppp_create(ppp_ptr, name, ip_ptr, stack_memory_ptr, stack_size, thread_priority, + pool_ptr, ppp_non_ppp_packet_handler, ppp_byte_send); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a PPP instance for the specified IP. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* name Pointer to instance name */ +/* ip_ptr Pointer to IP instance */ +/* stack_memory_ptr Pointer to thread stack */ +/* stack_size Pointer to thread stack size */ +/* thread_priority Priority of thread(s) created */ +/* for PPP */ +/* pool_ptr Default packet pool pointer */ +/* ppp_non_ppp_packet_handler Non PPP packet handler */ +/* provided by the application */ +/* ppp_byte_send Byte output function provided */ +/* by the application */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create PPP event flags group */ +/* tx_thread_create Create PPP helper thread */ +/* tx_time_get Get time for IDs */ +/* tx_timer_create Create PPP timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, + VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, + NX_PACKET_POOL *pool_ptr, + void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), + void (*ppp_byte_send)(UCHAR byte)) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PPP *tail_ptr; + + + /* Check the supplied packet pool for minimum required payload length. */ + if (pool_ptr -> nx_packet_pool_payload_size < NX_PPP_MIN_PACKET_PAYLOAD) + { + return(NX_PPP_BAD_PACKET); + } + + /* Initialize the PPP control block to zero. */ + memset((void *) ppp_ptr, 0, sizeof(NX_PPP)); + + /* Save the PPP name. */ + ppp_ptr -> nx_ppp_name = name; + + /* Save the IP pointer. */ + ppp_ptr -> nx_ppp_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + ppp_ptr -> nx_ppp_packet_pool_ptr = pool_ptr; + + /* Save the byte output routine specified by the user. */ + ppp_ptr -> nx_ppp_byte_send = ppp_byte_send; + ppp_ptr -> nx_ppp_non_ppp_packet_handler = ppp_non_ppp_packet_handler; + + /* Setup the initial state. */ + ppp_ptr -> nx_ppp_state = NX_PPP_STOPPED; + + /* Setup the Maximum Receive Unit (MRU). */ + ppp_ptr -> nx_ppp_mru = NX_PPP_MRU; + + /* Setup receive and transmit IDs. */ + ppp_ptr -> nx_ppp_transmit_id = (UCHAR) tx_time_get(); + + /* Default the authenticated field to true. */ + ppp_ptr -> nx_ppp_authenticated = NX_TRUE; + + /* Create event flag group to control the PPP processing thread. */ + tx_event_flags_create(&(ppp_ptr -> nx_ppp_event), "PPP EVENTS") ; + + /* Create the PPP processing thread. Note that this thread does not run until the PPP driver is + initialized during the IP create. */ + tx_thread_create(&(ppp_ptr -> nx_ppp_thread), "PPP THREAD", _nx_ppp_thread_entry, (ULONG) ppp_ptr, + stack_memory_ptr, stack_size, thread_priority, thread_priority, NX_PPP_THREAD_TIME_SLICE, TX_DONT_START); + + /* Create the PPP timeout timer. */ + tx_timer_create(&(ppp_ptr -> nx_ppp_timer), "PPP TIMER", _nx_ppp_timer_entry, (ULONG) ppp_ptr, NX_PPP_BASE_TIMEOUT, NX_PPP_BASE_TIMEOUT, TX_NO_ACTIVATE); + + /* Otherwise, the PPP initialization was successful. Place the + PPP control block on the list of created PPP instances. */ + TX_DISABLE + + /* Load the PPP ID field in the PPP control block. */ + ppp_ptr -> nx_ppp_id = NX_PPP_ID; + + /* Place the new PPP control block on the list of created IPs. First, + check for an empty list. */ + if (_nx_ppp_created_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = _nx_ppp_created_ptr -> nx_ppp_created_previous; + + /* Place the new PPP control block in the list. */ + _nx_ppp_created_ptr -> nx_ppp_created_previous = ppp_ptr; + tail_ptr -> nx_ppp_created_next = ppp_ptr; + + /* Setup this PPP's created links. */ + ppp_ptr -> nx_ppp_created_previous = tail_ptr; + ppp_ptr -> nx_ppp_created_next = _nx_ppp_created_ptr; + } + else + { + + /* The created PPP list is empty. Add PPP control block to empty list. */ + _nx_ppp_created_ptr = ppp_ptr; + ppp_ptr -> nx_ppp_created_next = ppp_ptr; + ppp_ptr -> nx_ppp_created_previous = ppp_ptr; + } + + /* Increment the created PPP counter. */ + _nx_ppp_created_count++; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP delete instance */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_delete Actual PPP delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_delete(NX_PPP *ppp_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP delete function. */ + status = _nx_ppp_delete(ppp_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a PPP instance for the specified IP. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_delete Delete PPP event flags group */ +/* tx_event_flags_set Set PPP event flag to stop PPP*/ +/* tx_thread_delete Create PPP helper threads */ +/* tx_thread_identify Identify current thread */ +/* tx_thread_sleep Sleep for a small time */ +/* tx_timer_deactivate Timer deactivate */ +/* tx_timer_delete Delete timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_delete(NX_PPP *ppp_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Determine if the caller is the PPP thread itself. This is not allowed since + a thread cannot delete itself in ThreadX. */ + if (&ppp_ptr -> nx_ppp_thread == tx_thread_identify()) + { + + /* Invalid caller of this routine, return an error! */ + return(NX_CALLER_ERROR); + } + + /* Set the event to close the PPP thread. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Now wait until the PPP thread goes to a closed state before proceeding with the delete. + This will give PPP the opportunity to properly release all packets being worked on. */ + while (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) + { + + /* Sleep for a tick. */ + tx_thread_sleep(1); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Clear the PPP ID to show that it is no longer valid. */ + ppp_ptr -> nx_ppp_id = 0; + + /* Decrement the number of PPP instances created. */ + _nx_ppp_created_count--; + + /* See if the PPP instance is the only one on the list. */ + if (ppp_ptr == ppp_ptr -> nx_ppp_created_next) + { + + /* Only created PPP instance, just set the created list to NULL. */ + _nx_ppp_created_ptr = TX_NULL; + } + else + { + + /* Link-up the neighbors. */ + (ppp_ptr -> nx_ppp_created_next) -> nx_ppp_created_previous = + ppp_ptr -> nx_ppp_created_previous; + (ppp_ptr -> nx_ppp_created_previous) -> nx_ppp_created_next = + ppp_ptr -> nx_ppp_created_next; + + /* See if we have to update the created list head pointer. */ + if (_nx_ppp_created_ptr == ppp_ptr) + + /* Yes, move the head pointer to the next link. */ + _nx_ppp_created_ptr = ppp_ptr -> nx_ppp_created_next; + } + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Terminate the thread. */ + tx_thread_terminate(&(ppp_ptr -> nx_ppp_thread)); + + /* Delete the PPP thread. */ + tx_thread_delete(&(ppp_ptr -> nx_ppp_thread)); + + /* Deactivate the PPP timer. */ + tx_timer_deactivate(&(ppp_ptr -> nx_ppp_timer)); + + /* Delete the PPP timer. */ + tx_timer_delete(&(ppp_ptr -> nx_ppp_timer)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(ppp_ptr -> nx_ppp_event)); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_link_up_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP link up notify callback */ +/* notify set function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* ppp_link_up_callback Pointer to application */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_link_up_notify Actual PPP link up notify set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP link up notify set function. */ + status = _nx_ppp_link_up_notify(ppp_ptr, ppp_link_up_callback); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_link_up_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers an application callback for the link up */ +/* event. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* ppp_link_up_callback Pointer to application */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)) +{ + + /* Valid PPP pointer, now setup the notification callback. Note that supplying + a NULL for the callback will disable notification. */ + ppp_ptr -> nx_ppp_link_up_callback = ppp_link_up_callback; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_link_down_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP link down notify callback*/ +/* notify set function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* ppp_link_down_callback Pointer to application */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_link_down_notify Actual PPP link down notify */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP link down notify set function. */ + status = _nx_ppp_link_down_notify(ppp_ptr, ppp_link_down_callback); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_link_down_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers an application callback for the link down */ +/* event. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* ppp_link_down_callback Pointer to application */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)) +{ + + /* Valid PPP pointer, now setup the notification callback. Note that supplying + a NULL for the callback will disable notification. */ + ppp_ptr -> nx_ppp_link_down_callback = ppp_link_down_callback; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_pap_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP PAP enable */ +/* function call. */ +/* */ +/* Note: The first string lengths of name and password are limited by */ +/* internal buffer size. The second string of name and password are */ +/* NULL terminated. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* generate_login Pointer to login function */ +/* verify_login Pointer to verify function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_pap_enable Actual PPP PAP enable function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), + UINT (*verify_login)(CHAR *name, CHAR *password)) +{ + +UINT status; + + + /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) || + ((generate_login == NX_NULL) && (verify_login == NX_NULL))) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP PAP enable function. */ + status = _nx_ppp_pap_enable(ppp_ptr, generate_login, verify_login); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_pap_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables PAP for the specified PPP instance. */ +/* */ +/* Note: The first string lengths of name and password are limited by */ +/* internal buffer size. The second string of name and password are */ +/* NULL terminated. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* generate_login Pointer to application */ +/* function that generates */ +/* name and password for login */ +/* verify_login Pointer to application */ +/* function that verifies the */ +/* supplied name and password */ +/* are valid */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), + UINT (*verify_login)(CHAR *name, CHAR *password)) +{ + +#ifdef NX_PPP_DISABLE_PAP + + /* Return the non implemented error. */ + return(NX_NOT_IMPLEMENTED); + +#else + + /* Setup the PAP information. */ + if (generate_login) + { + + /* Setup login generation information. */ + ppp_ptr -> nx_ppp_pap_generate_login = generate_login; + + /* The authenticated flag is not cleared for the generate login, since the + peer may choose not to require PAP. */ + } + + /* Determine if the generate login is provided. */ + if (verify_login) + { + /* Setup login verification information. */ + ppp_ptr -> nx_ppp_pap_verify_login = verify_login; + ppp_ptr -> nx_ppp_verify_authentication_protocol = NX_PPP_PAP_PROTOCOL; + + /* Authentication is needed, clear the flag. */ + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + } + + /* Show that the PAP is enabled. */ + ppp_ptr -> nx_ppp_pap_enabled = NX_TRUE; + + /* Set the initial PAP state. */ + ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_INITIAL_STATE; + + /* Return success. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_chap_challenge PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP CHAP challenge */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_chap_challenge Actual PPP CHAP challenge */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_chap_challenge(NX_PPP *ppp_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP CHAP challenge function. */ + status = _nx_ppp_chap_challenge(ppp_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_challenge PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function generates a CHAP challenge for the specified PPP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Notify PPP receiving thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_chap_challenge(NX_PPP *ppp_ptr) +{ + +#ifdef NX_PPP_DISABLE_CHAP + + /* Return the non implemented error. */ + return(NX_NOT_IMPLEMENTED); + +#else + + /* Determine if the CHAP of the PPP instance is enabled and able to challenge. */ + if ((ppp_ptr -> nx_ppp_chap_enabled) && + (ppp_ptr -> nx_ppp_chap_get_challenge_values) && + (ppp_ptr -> nx_ppp_chap_get_verification_values)) + { + + /* Check for the appropriate CHAP state. If the initial CHAP has not yet + completed, simply discard this request. */ + if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_COMPLETED_STATE) + { + + /* Yes, the CHAP protocol is in an open state so another challenge is legal. */ + + /* Initiate CHAP challenge by setting the appropriate event flag to wakeup the PPP thread. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_CHAP_CHALLENGE, TX_OR); + } + + /* Return successful completion. */ + return(NX_SUCCESS); + } + else + { + + /* CHAP is either not enabled or is setup only for CHAP response - not a challenge. Return an error! */ + return(NX_PPP_FAILURE); + } +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_chap_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP CHAP enable */ +/* function call. */ +/* */ +/* Note: The string lengths of rand_value, name, system and secret are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* get_challenge_values Pointer to application */ +/* function that retrieves */ +/* values required to make */ +/* a challenge */ +/* get_responder_values Pointer to application */ +/* function that retrieves */ +/* values required to respond */ +/* to a challenge */ +/* get_verification_values Pointer to application */ +/* function that retrieves */ +/* values required to verify */ +/* a challenge */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_chap_enable Actual PPP CHAP enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_chap_enable(NX_PPP *ppp_ptr, + UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), + UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), + UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)) +{ + +UINT status; + + + /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) || + ((get_challenge_values == NX_NULL) && (get_responder_values == NX_NULL) && (get_verification_values == NX_NULL))) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP CHAP enable function. */ + status = _nx_ppp_chap_enable(ppp_ptr, get_challenge_values, get_responder_values, get_verification_values); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_chap_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables CHAP for the specified PPP instance. */ +/* */ +/* Note: The string lengths of rand_value, name, system and secret are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* get_challenge_values Pointer to application */ +/* function that retrieves */ +/* values required to make */ +/* a challenge */ +/* get_responder_values Pointer to application */ +/* function that retrieves */ +/* values required to respond */ +/* to a challenge */ +/* get_verification_values Pointer to application */ +/* function that retrieves */ +/* values required to verify */ +/* a challenge response */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_chap_enable(NX_PPP *ppp_ptr, + UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), + UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), + UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)) +{ + +#ifdef NX_PPP_DISABLE_CHAP + + /* Return the non implemented error. */ + return(NX_NOT_IMPLEMENTED); + +#else + + /* Setup CHAP information. */ + if (get_responder_values) + { + + /* Setup challenge response callback. */ + ppp_ptr -> nx_ppp_chap_get_responder_values = get_responder_values; + + /* The authenticated flag is not cleared for the generate login, since the + peer may choose not to require CHAP. */ + } + + /* Determine if we are going to challenge the peer. */ + if ((get_challenge_values) && (get_verification_values)) + { + + /* Setup the CHAP information. */ + ppp_ptr -> nx_ppp_chap_get_challenge_values = get_challenge_values; + ppp_ptr -> nx_ppp_chap_get_verification_values = get_verification_values; + + /* Yes, we must generate a challenge. */ + ppp_ptr -> nx_ppp_verify_authentication_protocol = NX_PPP_CHAP_PROTOCOL; + ppp_ptr -> nx_ppp_authenticated = NX_FALSE; + } + + /* Show that the CHAP is enabled. */ + ppp_ptr -> nx_ppp_chap_enabled = NX_TRUE; + + /* Set the initial CHAP state. */ + ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_INITIAL_STATE; + + /* Return success. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_dns_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS address of the PPP */ +/* instance get function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* dns_address_ptr Destination for DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_dns_address_get Actual PPP DNS address get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer... */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || + (dns_address_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP DNS address get function. */ + status = _nx_ppp_dns_address_get(ppp_ptr, dns_address_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_dns_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the DNS address of the PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* dns_address_ptr Destination for DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr) +{ + + /* Determine if the PPP instance is in an established state. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) + { + + if (ppp_ptr -> nx_ppp_primary_dns_address == 0x0) + { + return NX_PPP_ADDRESS_NOT_ESTABLISHED; + } + + /* Return the DNS address ptr. */ + *dns_address_ptr = ppp_ptr -> nx_ppp_primary_dns_address; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Set the DNS address to 0. */ + *dns_address_ptr = 0; + + /* The PPP connection has not yet been established. */ + return(NX_PPP_NOT_ESTABLISHED); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_dns_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the DNS address of the PPP */ +/* instance set function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* dns_address Primary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_dns_address_set Actual PPP DNS address set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address) +{ + +UINT status; + + /* Check for an invalid input pointer... */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for invalid address. */ + if (dns_address == 0x0) + return(NX_PPP_INVALID_PARAMETER); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP DNS address set function. */ + status = _nx_ppp_dns_address_set(ppp_ptr, dns_address); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_dns_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the primary DNS address for the PPP device to */ +/* supply if it receives a DNS option request (129) in the configure */ +/* request NAKed list. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* dns_address Primary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address) +{ + + /* Set the primary DNS address. */ + ppp_ptr -> nx_ppp_primary_dns_address = dns_address; + + /* Return success. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_secondary_dns_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secondary DNS address of the */ +/* PPP instance get function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* secondary_dns_address_ptr Secondary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_secondary_dns_address_get Actual PPP secondary DNS */ +/* address get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer... */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || + (secondary_dns_address_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP secondary DNS address get function. */ + status = _nx_ppp_secondary_dns_address_get(ppp_ptr, secondary_dns_address_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_secondary_dns_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the secondary DNS address of the PPP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* secondary_dns_address_ptr Secondary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr) +{ + + /* Determine if the PPP instance is in an established state. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) + { + + if (ppp_ptr -> nx_ppp_secondary_dns_address == 0x0) + { + return(NX_PPP_ADDRESS_NOT_ESTABLISHED); + } + + /* Return the DNS address ptr. */ + *secondary_dns_address_ptr = ppp_ptr -> nx_ppp_secondary_dns_address; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Set the DNS address to 0. */ + *secondary_dns_address_ptr = 0; + + /* The PPP connection has not yet been established. */ + return(NX_PPP_NOT_ESTABLISHED); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_secondary_dns_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secondary DNS address of the */ +/* PPP instance set function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* secondary_dns_address_ptr Secondary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_secondary_dns_address_set Actual PPP secondary DNS */ +/* address set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address) +{ + +UINT status; + + /* Check for an invalid input pointer... */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for invalid address. */ + if (secondary_dns_address == 0x0) + return(NX_PPP_INVALID_PARAMETER); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP secondary DNS address set function. */ + status = _nx_ppp_secondary_dns_address_set(ppp_ptr, secondary_dns_address); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_secondary_dns_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the secondary DNS address for the PPP device to */ +/* supply if it receives a DNS option request (131) in the configure */ +/* request NAKed list. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* secondary_dns_address_ptr Secondary DNS address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address) +{ + + /* Set the secondary DNS address. */ + ppp_ptr -> nx_ppp_secondary_dns_address = secondary_dns_address; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_interface_index_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP interface index get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* index_ptr Index of associated interface */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_ppp_interface_index_get Actual PPP interface index get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP interface idnex get function. */ + status = _nx_ppp_interface_index_get(ppp_ptr, index_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_interface_index_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the interface index with a particular PPP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* index_ptr Index of associated interface */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr) +{ + + /* Return the interface index. */ + *index_ptr = ppp_ptr -> nx_ppp_interface_index; + + /* Determine if the interface is actually setup. */ + if (ppp_ptr -> nx_ppp_interface_ptr) + { + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + /* Return an error. The IP thread has not executed yet which means the + interface has not be setup. */ + return(NX_IN_PROGRESS); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_ip_address_assign PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP IP address assign */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* local_ip_address Local IP address */ +/* peer_ip_address Peer IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_ip_address_assign Actual PPP IP address assign */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address) +{ + +UINT status; + + + /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP IP address assign function. */ + status = _nx_ppp_ip_address_assign(ppp_ptr, local_ip_address, peer_ip_address); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ip_address_assign PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function assigns a local and peer IP address for the */ +/* specified PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* local_ip_address Local IP address */ +/* peer_ip_address Peer IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address) +{ + +UINT i; + + + /* Check if set the local IP address. */ + if (local_ip_address != 0) + { + + /* If true, this PPP instance is a Server. Update the flag. */ + ppp_ptr -> nx_ppp_server = NX_TRUE; + } + + /* Load the IP addresses into the PPP IPCP arrays. */ + i = 4; + do + { + + /* Load the IP values into the array. */ + ppp_ptr -> nx_ppp_ipcp_local_ip[i-1] = (UCHAR) (local_ip_address & 0xFF); + ppp_ptr -> nx_ppp_ipcp_peer_ip[i-1] = (UCHAR) (peer_ip_address & 0xFF); + + /* Shift the IP address down. */ + local_ip_address = local_ip_address >> 8; + peer_ip_address = peer_ip_address >> 8; + + /* Decrement the index. */ + i--; + + } while (i); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_nak_authentication_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PP NAK authentication notify */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* nak_authentication_notify Authentication NAK callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_nak_authentication_notify Actual PPP NAK authentication */ +/* notify set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)) +{ + +UINT status; + + /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual PPP NAK authentication notify set function. */ + status = _nx_ppp_nak_authentication_notify(ppp_ptr, nak_authentication_notify); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_nak_authentication_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function assigns an application callback function to be */ +/* called if an authentication NAK is received from the peer. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* nak_authentication_notify Authentication NAK callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)) +{ + + /* Store the callback function pointer in the PPP structure. */ + ppp_ptr -> nx_ppp_nak_authentication_notify = nak_authentication_notify; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_raw_string_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP raw string send */ +/* function call. */ +/* */ +/* Note: The string length of string_ptr is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* string_ptr Pointer to ASCII string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_raw_string_send Actual PPP raw string send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (string_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP raw string send function. */ + status = _nx_ppp_raw_string_send(ppp_ptr, string_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_raw_string_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a raw ASCII string to through PPP without any */ +/* PPP framing. This is useful to respond to modem commands in some */ +/* applications. */ +/* */ +/* Note: The string length of string_ptr is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* string_ptr Pointer to ASCII string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet */ +/* tx_event_flags_set Alert PPP thread to process */ +/* raw packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT i, j; +UINT status; +NX_PACKET *packet_ptr; + + + /* Initialize the string index. */ + i = 0; + + /* Loop to process the raw string send request. */ + while (string_ptr[i]) + { + + /* Allocate a packet to defer the raw string send to the PPP thread. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); + + /* Determine if there was an error allocating a packet. */ + if (status != NX_SUCCESS) + { + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of packet allocation timeouts. */ + ppp_ptr -> nx_ppp_packet_allocate_timeouts++; +#endif + + /* Just return an error. */ + return(NX_NO_PACKET); + } + + /* Initialize the packet index. */ + j = 0; + + /* Loop through the string copying the characters into the packet. */ + do + { + + /* Copy character into the packet. */ + packet_ptr -> nx_packet_prepend_ptr[j++] = (UCHAR)(string_ptr[i++]); + + } while ((string_ptr[i]) && (&(packet_ptr -> nx_packet_prepend_ptr[j]) < packet_ptr -> nx_packet_data_end)); + + /* Update the append pointer. */ + packet_ptr -> nx_packet_append_ptr = &(packet_ptr -> nx_packet_prepend_ptr[j]); + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = j; + + /* Now place the packet on the raw packet queue. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the raw transmit queue is empty. */ + if (ppp_ptr -> nx_ppp_raw_packet_queue_count++) + { + + /* Not empty, simply link the new packet to the tail and update the tail. */ + (ppp_ptr -> nx_ppp_raw_packet_queue_tail) -> nx_packet_queue_next = packet_ptr; + ppp_ptr -> nx_ppp_raw_packet_queue_tail = packet_ptr; + } + else + { + + /* List is empty, set the head and tail to this packet. */ + ppp_ptr -> nx_ppp_raw_packet_queue_head = packet_ptr; + ppp_ptr -> nx_ppp_raw_packet_queue_tail = packet_ptr; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Set event flag to wake up PPP thread for processing. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_RAW_STRING_SEND, TX_OR); + } + + /* Return success. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP start function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_start Actual PPP start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_start(NX_PPP *ppp_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP start function. */ + status = _nx_ppp_start(ppp_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set PPP event flag to */ +/* start PPP */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_start(NX_PPP *ppp_ptr) +{ + + /* Determine the current state. */ + if (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) + { + + /* Already started. */ + return(NX_PPP_ALREADY_STARTED); + } + else + { + + /* Now restart the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); + } + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP stop function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_stop Actual PPP stop function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_stop(NX_PPP *ppp_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP stop function. */ + status = _nx_ppp_stop(ppp_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops the PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set PPP event flag to stop PPP*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_stop(NX_PPP *ppp_ptr) +{ + + + /* Determine the current state. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) + { + + /* Already stopped. */ + return(NX_PPP_ALREADY_STOPPED); + } + else + { + + /* Check if LCP connection is already established or in negotiation. */ + if ((ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_COMPLETED_STATE) || + (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE) || + (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE) || + (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE)) + { + + /* Setup the retry counter. */ + ppp_ptr -> nx_ppp_protocol_retry_counter = 0; + + /* Setup the timeout. */ + ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; + + /* Move into the stopping to wait for terminate ack. */ + ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPING_STATE; + + /* Send terminate request. */ + _nx_ppp_lcp_terminate_request_send(ppp_ptr); + } + else + { + + /* Set the event to stop the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Determine if the application has registered a link down notification + callback. */ + if (ppp_ptr -> nx_ppp_link_down_callback) + { + + /* Yes, call the application's callback function. */ + (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); + } + } + } + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_restart PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP restart function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_restart Actual PPP restart function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_restart(NX_PPP *ppp_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP restart function. */ + status = _nx_ppp_restart(ppp_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_restart PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restarts the PPP instance. This is typically done */ +/* after a link down situation. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set PPP event flag to stop PPP*/ +/* tx_thread_sleep Sleep for a small time */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_restart(NX_PPP *ppp_ptr) +{ + + /* Set the event to stop the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); + + /* Now restart the PPP instance. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_status_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP status get function call.*/ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* status_ptr Pointer to destination for */ +/* PPP status */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_status_get Actual PPP status get function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr) +{ + +UINT status; + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (status_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PPP status get function. */ + status = _nx_ppp_status_get(ppp_ptr, status_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_status_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the current status of the PPP instance. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* status_ptr Pointer to destination for */ +/* PPP status */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr) +{ + + /* Now determine the current state. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) + { + + /* PPP is up, return established state. */ + *status_ptr = NX_PPP_STATUS_ESTABLISHED; + + /* Return success! */ + return(NX_SUCCESS); + } + else if ((ppp_ptr -> nx_ppp_lcp_state > NX_PPP_LCP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_lcp_state < NX_PPP_LCP_COMPLETED_STATE)) + { + + /* Is LCP in a failed state? */ + if (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_FAILED_STATE) + { + + /* Return LCP failed state. */ + *status_ptr = NX_PPP_STATUS_LCP_FAILED; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Return LCP in-progress state. */ + *status_ptr = NX_PPP_STATUS_LCP_IN_PROGRESS; + + /* Return success. */ + return(NX_SUCCESS); + } + } + else if ((ppp_ptr -> nx_ppp_pap_state > NX_PPP_PAP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_pap_state < NX_PPP_PAP_COMPLETED_STATE)) + { + + /* Is PAP in a failed state? */ + if (ppp_ptr -> nx_ppp_pap_state == NX_PPP_PAP_FAILED_STATE) + { + + /* Return PAP failed state. */ + *status_ptr = NX_PPP_STATUS_PAP_FAILED; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Return PAP in-progress state. */ + *status_ptr = NX_PPP_STATUS_PAP_IN_PROGRESS; + + /* Return success. */ + return(NX_SUCCESS); + } + } + else if ((ppp_ptr -> nx_ppp_chap_state > NX_PPP_CHAP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_chap_state < NX_PPP_CHAP_COMPLETED_STATE)) + { + + /* Is CHAP in a failed state? */ + if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_CHALLENGE_FAILED_STATE) + { + + /* Return CHAP failed state. */ + *status_ptr = NX_PPP_STATUS_CHAP_FAILED; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Return CHAP in-progress state. */ + *status_ptr = NX_PPP_STATUS_CHAP_IN_PROGRESS; + + /* Return success. */ + return(NX_SUCCESS); + } + } + else + { + + /* Is IPCP in a failed state? */ + if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_FAILED_STATE) + { + + /* Return IPCP failed state. */ + *status_ptr = NX_PPP_STATUS_IPCP_FAILED; + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Return IPCP in-progress state. */ + *status_ptr = NX_PPP_STATUS_IPCP_IN_PROGRESS; + + /* Return success. */ + return(NX_SUCCESS); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_ping_reply PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the PPP instance detects an LCP echo */ +/* request is received, and retransmits a response. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* packet_ptr Pointer to echo request packet*/ +/* received */ +/* */ +/* OUTPUT */ +/* */ +/* None Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_packet_transmit Transmit the PPP data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update Processes events and updates */ +/* the PPP in the LCP state */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_ping_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + + + /* Change the coding to indicate an Echo reply. */ + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_ECHO_REPLY; + + /* Set the Magic number as zero. */ + packet_ptr -> nx_packet_prepend_ptr[6] = 0; + packet_ptr -> nx_packet_prepend_ptr[7] = 0; + packet_ptr -> nx_packet_prepend_ptr[8] = 0; + packet_ptr -> nx_packet_prepend_ptr[9] = 0; + +#ifndef NX_PPP_DISABLE_INFO + + ppp_ptr -> nx_ppp_lcp_echo_replies_sent++; + + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; +#endif + + /* Send the reply out. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_lcp_ping_process_echo_reply PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the PPP instance detects an LCP echo */ +/* reply is received. It checks if the reply has a matching ID with the */ +/* previous echo request sent out and if so clears the */ +/* nx_ppp_lcp_echo_reply_id to indicate the device received a valid */ +/* reply. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* packet_ptr Pointer to echo request packet*/ +/* received */ +/* */ +/* OUTPUT */ +/* */ +/* None Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ppp_lcp_state_machine_update Processes events and updates */ +/* the PPP in the LCP state */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ppp_lcp_ping_process_echo_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + + /* Verify the PPP ID matches. */ + if (packet_ptr -> nx_packet_prepend_ptr[3] == ppp_ptr -> nx_ppp_lcp_echo_reply_id) + { + + /* Successful ping received. */ +#ifndef NX_PPP_DISABLE_INFO + /* Increment the number of LCP echo replies received. */ + ppp_ptr -> nx_ppp_lcp_echo_replies_received++; +#endif + + /* Clear the echo ID to indicate we received an LCP echo reply + matching the one we just sent out. */ + ppp_ptr -> nx_ppp_lcp_echo_reply_id = 0; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_ping_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the nx_ppp_ping_request */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* data_ptr Pointer to data in LCP echo */ +/* data_size Size of data in LCP echo */ +/* wait_option Wait option to transmit echo */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_PPP_INVALID_PARAMETER Invalid non pointer input */ +/* NX_SUCCESS Successful echo request sent */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_ping_request Actual LCP echo service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option) +{ + +UINT status; + + if ((ppp_ptr == NX_NULL) || (data_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + if (data_size == 0) + { + return NX_PPP_INVALID_PARAMETER; + } + + status = _nx_ppp_ping_request(ppp_ptr, data_ptr, data_size, wait_option); + + return status; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_ping_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an LCP echo request, and sets the */ +/* echo ID to the PPP nx_ppp_transmit_id. The caller waits for the echo*/ +/* ID (nx_ppp_lcp_echo_reply_id) to be reset to zero to indicate a */ +/* matching echo reply was received. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr PPP instance pointer */ +/* data_ptr Pointer to data in LCP echo */ +/* data_size Size of data in LCP echo */ +/* wait_option Wait option to transmit echo */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Echo request successfully sent*/ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for sending */ +/* _nx_ppp_packet_transmit Send PPP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option) +{ + +UINT status; +UINT i; +CHAR *work_ptr; +NX_PACKET *packet_ptr; + + + /* Echo request may only be sent in the LCP completed state.. */ + if (ppp_ptr -> nx_ppp_lcp_state != NX_PPP_LCP_COMPLETED_STATE) + { + + return NX_PPP_NOT_ESTABLISHED; + } + + /* Allocate a packet for the PPP packet. */ + status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, wait_option); + + /* Determine if the packet was allocated successfully. */ + if (status != NX_SUCCESS) + { + + /* An error was detected, simply return a NULL pointer. */ + return status; + } + + /* Check if out of boundary. */ + if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(data_size + 10)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return(NX_PPP_BAD_PACKET); + } + + /* Increment the transmit ID. */ + ppp_ptr -> nx_ppp_transmit_id++; + + /* Build the configuration request. */ + packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; + packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; + packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_ECHO_REQUEST; + packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; + + /* Indicate the PPP instance is waiting on an ECHO reply with this id: */ + ppp_ptr -> nx_ppp_lcp_echo_reply_id = ppp_ptr -> nx_ppp_transmit_id; + + /* Set up the length. */ + packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR)(((UINT)(data_size + 8)) >> 8); + packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(((UINT)(data_size + 8)) & 0xFF); + + /* Magic number will be all zeroes. */ + packet_ptr -> nx_packet_prepend_ptr[6] = 0; + packet_ptr -> nx_packet_prepend_ptr[7] = 0; + packet_ptr -> nx_packet_prepend_ptr[8] = 0; + packet_ptr -> nx_packet_prepend_ptr[9] = 0; + + /* Load the data */ + work_ptr = data_ptr; + + /* Loop through the input buffer. */ + for(i = 1; i <= data_size; i++) + { + + /* Copy byte of IP address. */ + packet_ptr -> nx_packet_prepend_ptr[i+9] = (UCHAR)(*work_ptr); + work_ptr++ ; + } + + packet_ptr -> nx_packet_length = i + 9; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; + +#ifndef NX_PPP_DISABLE_INFO + + /* Increment the number of LCP echo requests sent. */ + ppp_ptr -> nx_ppp_lcp_echo_requests_sent++; + + /* Increment the number of LCP frames sent. */ + ppp_ptr -> nx_ppp_lcp_frames_sent++; +#endif + + /* Send the configure request packet. */ + _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); + + return NX_SUCCESS; +} + + + +#ifdef NX_PPP_PPPOE_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP packet receive */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ppp_packet_receive Actual PPP packet receive */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for packet pointer. */ + if (packet_ptr == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual packet receive function. */ + status = _nx_ppp_packet_receive(ppp_ptr, packet_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives packet from the application (usually an */ +/* application ISR), buffers it, and notifies the PPP receive thread. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Notify PPP receiving thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code (Including ISRs) */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Check for no longer active PPP instance. */ + if (ppp_ptr -> nx_ppp_id != NX_PPP_ID) + { + + /* PPP is no longer active. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return an error. */ + return(NX_PTR_ERROR); + } + + /* Check for a stopped PPP instance. */ + if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) + { + + /* Silently discard byte. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + return(NX_SUCCESS); + } + + /* Check to see if the deferred processing queue is empty. */ + if (ppp_ptr -> nx_ppp_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the queue. */ + (ppp_ptr -> nx_ppp_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + ppp_ptr -> nx_ppp_deferred_received_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Empty deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the PPP helper thread looks at the deferred processing + queue. */ + ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr; + ppp_ptr -> nx_ppp_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup PPP helper thread to process the PPP deferred receive. */ + tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_PPPOE_PACKET_RECEIVE, TX_OR); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ppp_packet_send_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPP set packet send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* nx_ppp_packet_send Routine to send PPP packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_ppp_packet_send_set Actual PPP packet send set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)) +{ + +UINT status; + + + /* Check for an invalid input pointer. */ + if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) + return(NX_PTR_ERROR); + + /* Check for packet pointer. */ + if (nx_ppp_packet_send == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual packet send set function. */ + status = _nx_ppp_packet_send_set(ppp_ptr, nx_ppp_packet_send); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ppp_packet_send_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function set the PPP packet send function. */ +/* */ +/* INPUT */ +/* */ +/* ppp_ptr Pointer to PPP instance */ +/* nx_ppp_packet_send Routine to send PPP packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* none */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)) +{ + + + /* Set the PPP packet send function. */ + ppp_ptr -> nx_ppp_packet_send = nx_ppp_packet_send; + + /* Return successful completion. */ + return(NX_SUCCESS); +} +#endif /* NX_PPP_PPPOE_ENABLE */ +#endif /* NX_DISABLE_IPV4 */ diff --git a/addons/ppp/nx_ppp.h b/addons/ppp/nx_ppp.h new file mode 100644 index 00000000..d757c9d8 --- /dev/null +++ b/addons/ppp/nx_ppp.h @@ -0,0 +1,824 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Point-to-Point Protocol (PPP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_ppp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Point-to-Point Protocol (PPP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PPP_H +#define NX_PPP_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the PPP ID. */ + +#define NX_PPP_ID 0x50505020UL + +#define NX_PPP_SERIAL_BUFFER_ALERT_THRESHOLD NX_PPP_SERIAL_BUFFER_SIZE/4 + +/* Defined, support for transmitting PPP over Ethernet. */ +/* +#define NX_PPP_PPPOE_ENABLE +*/ + +/* If defined, this removes logic for compiling PPP transmit and receive statistics. +#define NX_PPP_DISABLE_INFO +*/ + +/* If defined, this enables PPP event logging. +#define NX_PPP_DEBUG_LOG_ENABLE +*/ + +/* If defined, this enables data saved to the PPP log to be printed out (printf). +#define NX_PPP_DEBUG_LOG_PRINT_ENABLE +*/ + +/* If defined, this disables CHAP authentication. +#define NX_PPP_DISABLE_CHAP +*/ + +/* If defined, this disables PAP authentication. +#define NX_PPP_DISABLE_PAP +*/ + +/* If defined, the primary DNS address request option is not set in NAKed list. +#define NX_PPP_DNS_OPTION_DISABLE +*/ + +/* Define how many times the PPP should try to request DNS address from the Peer. This + will have no effect if NX_PPP_DNS_OPTION_DISABLE is defined. */ +#ifndef NX_PPP_DNS_ADDRESS_MAX_RETRIES +#define NX_PPP_DNS_ADDRESS_MAX_RETRIES 2 +#endif + +/* Define the thread time slice. */ +#ifndef NX_PPP_THREAD_TIME_SLICE +#define NX_PPP_THREAD_TIME_SLICE TX_NO_TIME_SLICE +#endif + +/* Set the link transfer size. */ +#ifndef NX_PPP_MRU +#ifdef NX_PPP_PPPOE_ENABLE +#define NX_PPP_MRU 1480 /* Minimum value! */ +#else /* !NX_PPP_PPPOE_ENABLE */ +#define NX_PPP_MRU 1500 /* Minimum value! */ +#endif /* NX_PPP_PPPOE_ENABLE */ +#endif /* NX_PPP_MRU */ + +/* Minimum MRU to accept in MRU parsed from received LCP configuration request. */ +#ifndef NX_PPP_MINIMUM_MRU +#ifdef NX_PPP_PPPOE_ENABLE +#define NX_PPP_MINIMUM_MRU 1480 +#else /* !NX_PPP_PPPOE_ENABLE */ +#define NX_PPP_MINIMUM_MRU 1500 +#endif /* NX_PPP_PPPOE_ENABLE */ +#endif /* NX_PPP_MINIMUM_MRU */ + +/* Size of the receive character buffer. */ +#ifndef NX_PPP_SERIAL_BUFFER_SIZE +#define NX_PPP_SERIAL_BUFFER_SIZE NX_PPP_MRU*2 +#endif + + +/* User name buffer size for PAP login. */ +#ifndef NX_PPP_NAME_SIZE +#define NX_PPP_NAME_SIZE 32 +#endif + +/* Password buffer size for PAP login. */ +#ifndef NX_PPP_PASSWORD_SIZE +#define NX_PPP_PASSWORD_SIZE 32 +#endif + +/* Buffer size of the random value to process the CHAP challenge name */ +#ifndef NX_PPP_VALUE_SIZE +#define NX_PPP_VALUE_SIZE 32 +#endif + +/* Buffer size of the hash value to process the CHAP challenge name */ +#ifndef NX_PPP_HASHED_VALUE_SIZE +#define NX_PPP_HASHED_VALUE_SIZE 16 +#endif + + +/* The time period in timer ticks at which the PPP timer function executes and wakes up the PPP processing thread + to check for PPP events. */ +#ifndef NX_PPP_BASE_TIMEOUT +#define NX_PPP_BASE_TIMEOUT (NX_IP_PERIODIC_RATE * 1) /* 1 second */ +#endif + +/* The time out in timer ticks on allocating packets for processing PPP data into IP packets either receiving or sending. */ +#ifndef NX_PPP_TIMEOUT +#define NX_PPP_TIMEOUT (NX_IP_PERIODIC_RATE * 4) /* 4 seconds */ +#endif + +/* Number of times the PPP task times out waiting for another byte in the serial buffer. On reaching + this value, the PPP instance releases the packet and allocates a fresh packet for a new message. */ +#ifndef NX_PPP_RECEIVE_TIMEOUTS +#define NX_PPP_RECEIVE_TIMEOUTS 4 +#endif + +/* Timeout in seconds on the PPP task to receive a response to PPP protocol request. */ +#ifndef NX_PPP_PROTOCOL_TIMEOUT +#define NX_PPP_PROTOCOL_TIMEOUT 4 /* 4 seconds. */ +#endif + +/* Size of debug entry, this is also the wrap around index for debug output to overwrite oldest data. */ +#ifndef NX_PPP_DEBUG_LOG_SIZE +#define NX_PPP_DEBUG_LOG_SIZE 50 +#endif + +/* Maximum amount of data to add to debug output from received packet. */ +#ifndef NX_PPP_DEBUG_FRAME_SIZE +#define NX_PPP_DEBUG_FRAME_SIZE 50 +#endif + +/* Size of the NAK list. Not in use. */ +#ifndef NX_PPP_OPTION_MESSAGE_LENGTH +#define NX_PPP_OPTION_MESSAGE_LENGTH 64 +#endif + +/* Number of instances the PPP instance resends another LCP configure request message without a response. + When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ +#ifndef NX_PPP_MAX_LCP_PROTOCOL_RETRIES +#define NX_PPP_MAX_LCP_PROTOCOL_RETRIES 20 +#endif + +/* Number of instances the PPP instance resends another PAP authentication request message without a response. + When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ +#ifndef NX_PPP_MAX_PAP_PROTOCOL_RETRIES +#define NX_PPP_MAX_PAP_PROTOCOL_RETRIES 20 +#endif + +/* Number of instances the PPP instance resends another CHAP challenge message without a response. + When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ +#ifndef NX_PPP_MAX_CHAP_PROTOCOL_RETRIES +#define NX_PPP_MAX_CHAP_PROTOCOL_RETRIES 20 +#endif + +/* Number of instances the PPP instance times out before the IPCP part of the PPP handshake. + When this number is reached, the PPP instance aborts and the link is down. */ +#ifndef NX_PPP_MAX_IPCP_PROTOCOL_RETRIES +#define NX_PPP_MAX_IPCP_PROTOCOL_RETRIES 20 +#endif + +/* Define the packet header. */ +#ifdef NX_PPP_PPPOE_ENABLE +#ifndef NX_PPP_PACKET +#define NX_PPP_PACKET 22 /* Ethernet Header(14) + (PPPoE Header(6) + 2), keep four-byte alignment for Ethernet. */ +#endif /* NX_PPP_PACKET */ +#else /* !NX_PPP_PPPOE_ENABLE */ +#define NX_PPP_PACKET 0 +#endif /* NX_PPP_PPPOE_ENABLE */ + +/* Define the minimum PPP packet payload, the PPP commands (LCP, PAP, CHAP, IPCP) should be in one packet. */ + +#ifndef NX_PPP_MIN_PACKET_PAYLOAD +#define NX_PPP_MIN_PACKET_PAYLOAD (NX_PPP_PACKET + 128) +#endif + +/* Define PPP protocol types. */ + +#define NX_PPP_LCP_PROTOCOL 0xC021 +#define NX_PPP_IPCP_PROTOCOL 0x8021 +#define NX_PPP_PAP_PROTOCOL 0xC023 +#define NX_PPP_CHAP_PROTOCOL 0xC223 +#define NX_PPP_DATA 0x0021 + + +/* Define PPP LCP codes and action. */ + +#define NX_PPP_LCP_CONFIGURE_REQUEST 1 +#define NX_PPP_LCP_CONFIGURE_ACK 2 +#define NX_PPP_LCP_CONFIGURE_NAK 3 +#define NX_PPP_LCP_CONFIGURE_REJECT 4 +#define NX_PPP_LCP_TERMINATE_REQUEST 5 +#define NX_PPP_LCP_TERMINATE_ACK 6 +#define NX_PPP_LCP_CODE_REJECT 7 +#define NX_PPP_LCP_PROTOCOL_REJECT 8 +#define NX_PPP_LCP_ECHO_REQUEST 9 +#define NX_PPP_LCP_ECHO_REPLY 10 +#define NX_PPP_LCP_DISCARD_REQUEST 11 +#define NX_PPP_LCP_TIMEOUT 99 + + +/* Define PPP PAP codes and action. */ + +#define NX_PPP_PAP_AUTHENTICATE_REQUEST 1 +#define NX_PPP_PAP_AUTHENTICATE_ACK 2 +#define NX_PPP_PAP_AUTHENTICATE_NAK 3 +#define NX_PPP_PAP_AUTHENTICATE_TIMEOUT 99 + + +/* Define PPP CHAP codes and action. */ + +#define NX_PPP_CHAP_CHALLENGE_REQUEST 1 +#define NX_PPP_CHAP_CHALLENGE_RESPONSE 2 +#define NX_PPP_CHAP_CHALLENGE_SUCCESS 3 +#define NX_PPP_CHAP_CHALLENGE_FAILURE 4 +#define NX_PPP_CHAP_CHALLENGE_TIMEOUT 99 + + +/* Define PPP IPCP codes and action. */ + +#define NX_PPP_IPCP_CONFIGURE_REQUEST 1 +#define NX_PPP_IPCP_CONFIGURE_ACK 2 +#define NX_PPP_IPCP_CONFIGURE_NAK 3 +#define NX_PPP_IPCP_CONFIGURE_REJECT 4 +#define NX_PPP_IPCP_TERMINATE_REQUEST 5 +#define NX_PPP_IPCP_TERMINATE_ACK 6 +#define NX_PPP_IPCP_TIMEOUT 99 + + +/* Define API return codes. */ + +#define NX_PPP_FAILURE 0xb0 +#define NX_PPP_BUFFER_FULL 0xb1 +#define NX_PPP_BAD_PACKET 0xb3 +#define NX_PPP_ERROR 0xb4 +#define NX_PPP_NOT_ESTABLISHED 0xb5 +#define NX_PPP_INVALID_PARAMETER 0xb6 +#define NX_PPP_ADDRESS_NOT_ESTABLISHED 0xb7 +#define NX_PPP_ALREADY_STOPPED 0xb8 +#define NX_PPP_ALREADY_STARTED 0xb9 + +/* Define PPP state machine states. */ + +#define NX_PPP_STOPPED 0 +#define NX_PPP_STARTED 1 +#define NX_PPP_ESTABLISHED 2 + + +/* Define LCP state machine states. */ + +#define NX_PPP_LCP_INITIAL_STATE 0 +#define NX_PPP_LCP_START_STATE 1 +#define NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE 2 +#define NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE 3 +#define NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE 4 +#define NX_PPP_LCP_STOPPING_STATE 5 +#define NX_PPP_LCP_STOPPED_STATE 6 +#define NX_PPP_LCP_FAILED_STATE 7 +#define NX_PPP_LCP_COMPLETED_STATE 8 + + +/* Define PAP state machine states. */ + +#define NX_PPP_PAP_INITIAL_STATE 0 +#define NX_PPP_PAP_START_STATE 1 +#define NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE 2 +#define NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE 3 +#define NX_PPP_PAP_FAILED_STATE 4 +#define NX_PPP_PAP_COMPLETED_STATE 5 + + +/* Define CHAP state machine states. */ + +#define NX_PPP_CHAP_INITIAL_STATE 0 +#define NX_PPP_CHAP_START_STATE 1 +#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE 2 +#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE 3 +#define NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE 4 +#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE 5 +#define NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE 6 +#define NX_PPP_CHAP_COMPLETED_NEW_STATE 8 +#define NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE 9 +#define NX_PPP_CHAP_CHALLENGE_FAILED_STATE 10 +#define NX_PPP_CHAP_COMPLETED_STATE 11 + + +/* Define IPCP state machine states. */ + +#define NX_PPP_IPCP_INITIAL_STATE 0 +#define NX_PPP_IPCP_START_STATE 1 +#define NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE 2 +#define NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE 3 +#define NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE 4 +#define NX_PPP_IPCP_STOPPING_STATE 5 +#define NX_PPP_IPCP_STOPPED_STATE 6 +#define NX_PPP_IPCP_FAILED_STATE 7 +#define NX_PPP_IPCP_COMPLETED_STATE 8 + + +/* Define event flags for PPP thread control. */ + +#define NX_PPP_EVENT_START 0x01 +#define NX_PPP_EVENT_STOP 0x02 +#define NX_PPP_EVENT_PACKET_RECEIVE 0x04 +#define NX_PPP_EVENT_RAW_STRING_SEND 0x08 +#define NX_PPP_EVENT_IP_PACKET_SEND 0x10 +#define NX_PPP_EVENT_CHAP_CHALLENGE 0x20 +#define NX_PPP_EVENT_TIMEOUT 0x40 +#define NX_PPP_EVENT_PPPOE_PACKET_RECEIVE 0x80 + + +/* Define PPP status return values. */ + +#define NX_PPP_STATUS_LCP_IN_PROGRESS 0 +#define NX_PPP_STATUS_LCP_FAILED 1 +#define NX_PPP_STATUS_PAP_IN_PROGRESS 2 +#define NX_PPP_STATUS_PAP_FAILED 3 +#define NX_PPP_STATUS_CHAP_IN_PROGRESS 4 +#define NX_PPP_STATUS_CHAP_FAILED 5 +#define NX_PPP_STATUS_IPCP_IN_PROGRESS 6 +#define NX_PPP_STATUS_IPCP_FAILED 7 +#define NX_PPP_STATUS_ESTABLISHED 8 + +/* Define NAKed list options */ +#define NX_PPP_IP_COMPRESSION_OPTION 0x02 +#define NX_PPP_IP_ADDRESS_OPTION 0x03 +#define NX_PPP_DNS_SERVER_OPTION 0x81 +#define NX_PPP_DNS_SECONDARY_SERVER_OPTION 0x83 + + + +/* Define optional debug log. This is used to capture the PPP traffic for debug + purposes. */ + +typedef struct NX_PPP_DEBUG_ENTRY_STRUCT +{ + + ULONG nx_ppp_debug_entry_time_stamp; + UCHAR nx_ppp_debug_ppp_state; + UCHAR nx_ppp_debug_lcp_state; + UCHAR nx_ppp_debug_pap_state; + UCHAR nx_ppp_debug_chap_state; + UCHAR nx_ppp_debug_ipcp_state; + UCHAR nx_ppp_debug_authenticated; + UCHAR nx_ppp_debug_frame_type; + ULONG nx_ppp_debug_packet_length; + UCHAR nx_ppp_debug_frame[NX_PPP_DEBUG_FRAME_SIZE]; +} NX_PPP_DEBUG_ENTRY; + + + +/* Define the main PPP data structure. */ + +typedef struct NX_PPP_STRUCT +{ + + ULONG nx_ppp_id; + CHAR *nx_ppp_name; + NX_IP *nx_ppp_ip_ptr; + NX_INTERFACE *nx_ppp_interface_ptr; + UINT nx_ppp_interface_index; + NX_PACKET_POOL *nx_ppp_packet_pool_ptr; + UCHAR nx_ppp_transmit_id; + UCHAR nx_ppp_receive_id; + UCHAR nx_ppp_lcp_echo_reply_id; + UCHAR nx_ppp_reserved; + ULONG nx_ppp_mru; + UINT nx_ppp_server; + UINT nx_ppp_state; + UINT nx_ppp_lcp_state; + UINT nx_ppp_pap_state; + UINT nx_ppp_chap_state; + UINT nx_ppp_ipcp_state; + UINT nx_ppp_authenticated; + UINT nx_ppp_generate_authentication_protocol; + UINT nx_ppp_verify_authentication_protocol; + USHORT nx_ppp_pap_enabled; + USHORT nx_ppp_chap_enabled; + CHAR nx_ppp_chap_challenger_name[NX_PPP_NAME_SIZE + 1]; + CHAR nx_ppp_chap_random_value[NX_PPP_VALUE_SIZE + 1]; + UCHAR nx_ppp_ipcp_local_ip[4]; + UCHAR nx_ppp_ipcp_peer_ip[4]; + ULONG nx_ppp_primary_dns_address; + ULONG nx_ppp_secondary_dns_address; + UINT nx_ppp_dns_address_retries; + UINT nx_ppp_secondary_dns_address_retries; + ULONG nx_ppp_timeout; + ULONG nx_ppp_receive_timeouts; + ULONG nx_ppp_protocol_retry_counter; +#ifndef NX_PPP_DISABLE_INFO + ULONG nx_ppp_packet_allocate_timeouts; + ULONG nx_ppp_frame_timeouts; + ULONG nx_ppp_internal_errors; + ULONG nx_ppp_frame_crc_errors; + ULONG nx_ppp_packet_overflow; + ULONG nx_ppp_bytes_received; + ULONG nx_ppp_bytes_sent; + ULONG nx_ppp_bytes_dropped; + ULONG nx_ppp_bytes_invalid; + ULONG nx_ppp_total_frames_received; + ULONG nx_ppp_lcp_frames_received; + ULONG nx_ppp_lcp_frames_sent; + ULONG nx_ppp_lcp_configure_requests_sent; + ULONG nx_ppp_lcp_configure_requests_received; + ULONG nx_ppp_lcp_configure_acks_sent; + ULONG nx_ppp_lcp_configure_acks_received; + ULONG nx_ppp_lcp_configure_naks_sent; + ULONG nx_ppp_lcp_configure_naks_received; + ULONG nx_ppp_lcp_configure_rejects_sent; + ULONG nx_ppp_lcp_configure_rejects_received; + ULONG nx_ppp_lcp_terminate_requests_sent; + ULONG nx_ppp_lcp_terminate_requests_received; + ULONG nx_ppp_lcp_terminate_acks_sent; + ULONG nx_ppp_lcp_terminate_acks_received; + ULONG nx_ppp_lcp_code_rejects_sent; + ULONG nx_ppp_lcp_code_rejects_received; + ULONG nx_ppp_lcp_protocol_rejects_sent; + ULONG nx_ppp_lcp_protocol_rejects_received; + ULONG nx_ppp_lcp_echo_requests_sent; + ULONG nx_ppp_lcp_echo_replies_received; + ULONG nx_ppp_lcp_echo_requests_received; + ULONG nx_ppp_lcp_echo_requests_dropped; + ULONG nx_ppp_lcp_echo_replies_sent; + ULONG nx_ppp_lcp_discard_requests_sent; + ULONG nx_ppp_lcp_discard_requests_received; + ULONG nx_ppp_lcp_unknown_requests_received; + ULONG nx_ppp_lcp_state_machine_unhandled_requests; + ULONG nx_ppp_lcp_state_machine_timeouts; +#ifndef NX_PPP_DISABLE_PAP + ULONG nx_ppp_pap_frames_received; + ULONG nx_ppp_pap_frames_sent; + ULONG nx_ppp_pap_authenticate_requests_sent; + ULONG nx_ppp_pap_authenticate_requests_received; + ULONG nx_ppp_pap_authenticate_acks_sent; + ULONG nx_ppp_pap_authenticate_acks_received; + ULONG nx_ppp_pap_authenticate_naks_sent; + ULONG nx_ppp_pap_authenticate_naks_received; + ULONG nx_ppp_pap_unknown_requests_received; + ULONG nx_ppp_pap_state_machine_unhandled_requests; + ULONG nx_ppp_pap_state_machine_timeouts; +#endif +#ifndef NX_PPP_DISABLE_CHAP + ULONG nx_ppp_chap_frames_received; + ULONG nx_ppp_chap_frames_sent; + ULONG nx_ppp_chap_challenge_requests_sent; + ULONG nx_ppp_chap_challenge_requests_received; + ULONG nx_ppp_chap_challenge_responses_sent; + ULONG nx_ppp_chap_challenge_responses_received; + ULONG nx_ppp_chap_challenge_successes_sent; + ULONG nx_ppp_chap_challenge_successes_received; + ULONG nx_ppp_chap_challenge_failures_sent; + ULONG nx_ppp_chap_challenge_failures_received; + ULONG nx_ppp_chap_unknown_requests_received; + ULONG nx_ppp_chap_state_machine_unhandled_requests; + ULONG nx_ppp_chap_state_machine_timeouts; +#endif + ULONG nx_ppp_ipcp_frames_received; + ULONG nx_ppp_ipcp_frames_sent; + ULONG nx_ppp_ipcp_configure_requests_sent; + ULONG nx_ppp_ipcp_configure_requests_received; + ULONG nx_ppp_ipcp_configure_acks_sent; + ULONG nx_ppp_ipcp_configure_acks_received; + ULONG nx_ppp_ipcp_configure_naks_sent; + ULONG nx_ppp_ipcp_configure_naks_received; + ULONG nx_ppp_ipcp_configure_rejects_sent; + ULONG nx_ppp_ipcp_configure_rejects_received; + ULONG nx_ppp_ipcp_terminate_requests_sent; + ULONG nx_ppp_ipcp_terminate_requests_received; + ULONG nx_ppp_ipcp_terminate_acks_sent; + ULONG nx_ppp_ipcp_terminate_acks_received; + ULONG nx_ppp_ipcp_unknown_requests_received; + ULONG nx_ppp_ipcp_state_machine_unhandled_requests; + ULONG nx_ppp_ipcp_state_machine_timeouts; + ULONG nx_ppp_ip_frames_received; + ULONG nx_ppp_ip_frames_sent; + ULONG nx_ppp_receive_frames_dropped; + ULONG nx_ppp_transmit_frames_dropped; + ULONG nx_ppp_invalid_frame_id; +#endif + + void (*nx_ppp_byte_send)(UCHAR byte); + +#ifdef NX_PPP_PPPOE_ENABLE + void (*nx_ppp_packet_send)(NX_PACKET *packet_ptr); +#endif /* NX_PPP_PPPOE_ENABLE */ + + void (*nx_ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr); + void (*nx_ppp_nak_authentication_notify)(void); + + void (*nx_ppp_link_up_callback)(struct NX_PPP_STRUCT *ppp_ptr); + void (*nx_ppp_link_down_callback)(struct NX_PPP_STRUCT *ppp_ptr); + + UINT (*nx_ppp_pap_verify_login)(CHAR *name, CHAR *password); + UINT (*nx_ppp_pap_generate_login)(CHAR *name, CHAR *password); + + UINT (*nx_ppp_chap_get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name); + UINT (*nx_ppp_chap_get_responder_values)(CHAR *sys, CHAR *name, CHAR *secret); + UINT (*nx_ppp_chap_get_verification_values)(CHAR *sys, CHAR *name, CHAR *secret); + TX_EVENT_FLAGS_GROUP + nx_ppp_event; + TX_TIMER nx_ppp_timer; + + UCHAR nx_ppp_serial_buffer[NX_PPP_SERIAL_BUFFER_SIZE]; + USHORT nx_ppp_serial_buffer_write_index; + USHORT nx_ppp_serial_buffer_read_index; + USHORT nx_ppp_serial_buffer_byte_count; + + NX_PACKET *nx_ppp_receive_partial_packet; + ULONG nx_ppp_receive_buffer_size; + UCHAR *nx_ppp_receive_buffer_ptr; + + NX_PACKET *nx_ppp_head_packet; + +#ifdef NX_PPP_PPPOE_ENABLE + + /* Define the deferred packet processing queue for driver packet. */ + NX_PACKET *nx_ppp_deferred_received_packet_head, + *nx_ppp_deferred_received_packet_tail; +#endif /* NX_PPP_PPPOE_ENABLE */ + + NX_PACKET *nx_ppp_raw_packet_queue_head; + NX_PACKET *nx_ppp_raw_packet_queue_tail; + ULONG nx_ppp_raw_packet_queue_count; + + NX_PACKET *nx_ppp_ip_packet_queue_head; + NX_PACKET *nx_ppp_ip_packet_queue_tail; + ULONG nx_ppp_ip_packet_queue_count; + + TX_THREAD nx_ppp_thread; + struct NX_PPP_STRUCT + *nx_ppp_created_next, + *nx_ppp_created_previous; + + UCHAR nx_ppp_naked_list[NX_PPP_OPTION_MESSAGE_LENGTH]; + UCHAR nx_ppp_peer_naked_list[NX_PPP_OPTION_MESSAGE_LENGTH]; + UCHAR nx_ppp_rejected_list[NX_PPP_OPTION_MESSAGE_LENGTH]; + +#ifdef NX_PPP_DEBUG_LOG_ENABLE + NX_PPP_DEBUG_ENTRY + nx_ppp_debug_log[NX_PPP_DEBUG_LOG_SIZE]; + UINT nx_ppp_debug_log_oldest_index; +#endif + +} NX_PPP; + + +#ifndef NX_PPP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_ppp_byte_receive _nx_ppp_byte_receive +#define nx_ppp_chap_challenge _nx_ppp_chap_challenge +#define nx_ppp_chap_enable _nx_ppp_chap_enable +#define nx_ppp_create _nx_ppp_create +#define nx_ppp_delete _nx_ppp_delete +#define nx_ppp_dns_address_get _nx_ppp_dns_address_get +#define nx_ppp_dns_address_set _nx_ppp_dns_address_set +#define nx_ppp_secondary_dns_address_get _nx_ppp_secondary_dns_address_get +#define nx_ppp_secondary_dns_address_set _nx_ppp_secondary_dns_address_set +#define nx_ppp_driver _nx_ppp_driver +#define nx_ppp_interface_index_get _nx_ppp_interface_index_get +#define nx_ppp_ip_address_assign _nx_ppp_ip_address_assign +#define nx_ppp_link_down_notify _nx_ppp_link_down_notify +#define nx_ppp_link_up_notify _nx_ppp_link_up_notify +#define nx_ppp_nak_authentication_notify _nx_ppp_nak_authentication_notify +#define nx_ppp_pap_enable _nx_ppp_pap_enable +#define nx_ppp_raw_string_send _nx_ppp_raw_string_send +#define nx_ppp_start _nx_ppp_start +#define nx_ppp_stop _nx_ppp_stop +#define nx_ppp_restart _nx_ppp_restart +#define nx_ppp_status_get _nx_ppp_status_get +#define nx_ppp_ping_request _nx_ppp_ping_request +#ifdef NX_PPP_PPPOE_ENABLE +#define nx_ppp_packet_receive _nx_ppp_packet_receive +#define nx_ppp_packet_send_set _nx_ppp_packet_send_set +#endif /* NX_PPP_PPPOE_ENABLE */ + +#else + +/* Services with error checking. */ + +#define nx_ppp_byte_receive _nxe_ppp_byte_receive +#define nx_ppp_chap_challenge _nxe_ppp_chap_challenge +#define nx_ppp_chap_enable _nxe_ppp_chap_enable +#define nx_ppp_create _nxe_ppp_create +#define nx_ppp_delete _nxe_ppp_delete +#define nx_ppp_dns_address_get _nxe_ppp_dns_address_get +#define nx_ppp_dns_address_set _nxe_ppp_dns_address_set +#define nx_ppp_secondary_dns_address_get _nxe_ppp_secondary_dns_address_get +#define nx_ppp_secondary_dns_address_set _nxe_ppp_secondary_dns_address_set +#define nx_ppp_driver _nx_ppp_driver +#define nx_ppp_interface_index_get _nxe_ppp_interface_index_get +#define nx_ppp_ip_address_assign _nxe_ppp_ip_address_assign +#define nx_ppp_link_down_notify _nxe_ppp_link_down_notify +#define nx_ppp_link_up_notify _nxe_ppp_link_up_notify +#define nx_ppp_nak_authentication_notify _nxe_ppp_nak_authentication_notify +#define nx_ppp_pap_enable _nxe_ppp_pap_enable +#define nx_ppp_raw_string_send _nxe_ppp_raw_string_send +#define nx_ppp_start _nxe_ppp_start +#define nx_ppp_stop _nxe_ppp_stop +#define nx_ppp_restart _nxe_ppp_restart +#define nx_ppp_status_get _nxe_ppp_status_get +#define nx_ppp_ping_request _nxe_ppp_ping_request +#ifdef NX_PPP_PPPOE_ENABLE +#define nx_ppp_packet_receive _nxe_ppp_packet_receive +#define nx_ppp_packet_send_set _nxe_ppp_packet_send_set +#endif /* NX_PPP_PPPOE_ENABLE */ + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); +UINT nx_ppp_chap_challenge(NX_PPP *ppp_ptr); +UINT nx_ppp_chap_enable(NX_PPP *ppp_ptr, + UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), + UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), + UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); +UINT nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, + VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, + NX_PACKET_POOL *pool_ptr, + void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), + void (*ppp_byte_send)(UCHAR byte)); +UINT nx_ppp_delete(NX_PPP *ppp_ptr); +UINT nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); +UINT nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); +UINT nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); +UINT nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); +void nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); +UINT nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); +UINT nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); +UINT nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); +UINT nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); +UINT nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); +UINT nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); +UINT nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); +UINT nx_ppp_start(NX_PPP *ppp_ptr); +UINT nx_ppp_stop(NX_PPP *ppp_ptr); +UINT nx_ppp_restart(NX_PPP *ppp_ptr); +UINT nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); +UINT nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); +#ifdef NX_PPP_PPPOE_ENABLE +UINT nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT nx_ppp_packet_send_set(NX_PPP *ppp_ptr, void (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); +#endif /* NX_PPP_PPPOE_ENABLE */ + +#else /* NX_PPP_SOURCE_CODE */ + +UINT _nxe_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); +UINT _nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); +UINT _nxe_ppp_chap_challenge(NX_PPP *ppp_ptr); +UINT _nx_ppp_chap_challenge(NX_PPP *ppp_ptr); +UINT _nxe_ppp_chap_enable(NX_PPP *ppp_ptr, + UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), + UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), + UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); +UINT _nx_ppp_chap_enable(NX_PPP *ppp_ptr, + UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), + UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), + UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); +UINT _nxe_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, + VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, + NX_PACKET_POOL *pool_ptr, + void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), + void (*ppp_byte_send)(UCHAR byte)); +UINT _nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, + VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, + NX_PACKET_POOL *pool_ptr, + void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), + void (*ppp_byte_send)(UCHAR byte)); +UINT _nxe_ppp_delete(NX_PPP *ppp_ptr); +UINT _nx_ppp_delete(NX_PPP *ppp_ptr); +UINT _nxe_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); +UINT _nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); +UINT _nxe_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); +UINT _nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); +UINT _nxe_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); +UINT _nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); +UINT _nxe_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); +UINT _nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); +UINT _nxe_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); +UINT _nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); +UINT _nxe_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); +UINT _nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); +UINT _nxe_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); +UINT _nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); +UINT _nxe_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); +UINT _nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); +UINT _nxe_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); +UINT _nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); +UINT _nxe_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); +UINT _nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); +UINT _nxe_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); +UINT _nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); +UINT _nxe_ppp_start(NX_PPP *ppp_ptr); +UINT _nx_ppp_start(NX_PPP *ppp_ptr); +UINT _nxe_ppp_stop(NX_PPP *ppp_ptr); +UINT _nx_ppp_stop(NX_PPP *ppp_ptr); +UINT _nxe_ppp_restart(NX_PPP *ppp_ptr); +UINT _nx_ppp_restart(NX_PPP *ppp_ptr); +UINT _nxe_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); +UINT _nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); +UINT _nxe_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); +UINT _nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); +#ifdef NX_PPP_PPPOE_ENABLE +UINT _nxe_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT _nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT _nxe_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); +UINT _nx_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); +#endif /* NX_PPP_PPPOE_ENABLE */ + +/* Define internal PPP services. */ +void _nx_ppp_thread_entry(ULONG ppp_addr); +void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); +void _nx_ppp_receive_packet_get(NX_PPP *ppp_ptr, NX_PACKET **return_packet_ptr); +void _nx_ppp_receive_packet_process(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_timeout(NX_PPP *ppp_ptr); +void _nx_ppp_timer_entry(ULONG id); +void _nx_ppp_netx_packet_transfer(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_process_deferred_raw_string_send(NX_PPP *ppp_ptr); +void _nx_ppp_process_deferred_ip_packet_send(NX_PPP *ppp_ptr); +void _nx_ppp_lcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_lcp_code_reject(NX_PPP *ppp_ptr, UCHAR *lcp_ptr); +void _nx_ppp_lcp_configure_reply_send(NX_PPP *ppp_ptr, UINT configure_status, UCHAR *lcp_ptr, UCHAR *naked_list, UCHAR *rejected_list); +void _nx_ppp_lcp_configure_request_send(NX_PPP *ppp_ptr); +UINT _nx_ppp_lcp_configuration_retrieve(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list); +void _nx_ppp_lcp_nak_configure_list(NX_PPP *ppp_ptr, UCHAR *naked_list); +void _nx_ppp_lcp_terminate_ack_send(NX_PPP *ppp_ptr); +void _nx_ppp_lcp_terminate_request_send(NX_PPP *ppp_ptr); +void _nx_ppp_pap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_pap_authentication_request(NX_PPP *ppp_ptr); +UINT _nx_ppp_pap_login_valid(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_pap_authentication_ack(NX_PPP *ppp_ptr); +void _nx_ppp_pap_authentication_nak(NX_PPP *ppp_ptr); +void _nx_ppp_chap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_chap_challenge_send(NX_PPP *ppp_ptr); +void _nx_ppp_chap_challenge_respond(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT _nx_ppp_chap_challenge_validate(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_ipcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT _nx_ppp_ipcp_configure_check(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list, UCHAR *good_data); +void _nx_ppp_ipcp_configure_request_send(NX_PPP *ppp_ptr, UCHAR *negotiate_list); +void _nx_ppp_ipcp_response_extract(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_ipcp_response_send(NX_PPP *ppp_ptr, UCHAR type, UCHAR *data, UCHAR length, NX_PACKET *cfg_packet_ptr); +void _nx_ppp_ipcp_terminate_send(NX_PPP *ppp_ptr); +void _nx_ppp_ipcp_terminate_ack_send(NX_PPP *ppp_ptr); +void _nx_ppp_packet_transmit(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +UINT _nx_ppp_check_crc(NX_PACKET *packet_ptr); +UINT _nx_ppp_crc_append(NX_PACKET *packet_ptr, UCHAR crc[2]); +void _nx_ppp_debug_log_capture(NX_PPP *ppp_ptr, UCHAR packet_type, NX_PACKET *packet_ptr); +void _nx_ppp_debug_log_capture_protocol(NX_PPP *ppp_ptr); +void _nx_ppp_hash_generator(unsigned char *hvalue, unsigned char id, unsigned char *secret, unsigned char *rand_value, UINT length); +void _nx_ppp_lcp_ping_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); +void _nx_ppp_lcp_ping_process_echo_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); + +#endif /* NX_PPP_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_PPP_H */ diff --git a/addons/pppoe/nx_pppoe_client.c b/addons/pppoe/nx_pppoe_client.c new file mode 100644 index 00000000..bca12f0f --- /dev/null +++ b/addons/pppoe/nx_pppoe_client.c @@ -0,0 +1,3734 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** PPP Over Ethernet (PPPoE) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_PPPOE_CLIENT_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_pppoe_client.h" +#include "tx_thread.h" +#include "tx_timer.h" + +/* Define the PPPoE created list head pointer and count. */ +NX_PPPOE_CLIENT *_nx_pppoe_client_created_ptr = NX_NULL; + + +/* Define internal PPPoE services. */ + +static VOID _nx_pppoe_client_thread_entry(ULONG pppoe_client_ptr_value); +static VOID _nx_pppoe_client_timer_entry(ULONG pppoe_client_address); +static VOID _nx_pppoe_client_packet_receive(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); +static VOID _nx_pppoe_client_discovery_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw); +static VOID _nx_pppoe_client_session_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw); +static UINT _nx_pppoe_client_discovery_send(NX_PPPOE_CLIENT *pppoe_client_ptr, UINT code); +static VOID _nx_pppoe_client_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, UINT command); +static ULONG _nx_pppoe_client_data_get(UCHAR *data, UINT size); +static VOID _nx_pppoe_client_data_add(UCHAR *data, UINT size, ULONG value); +static VOID _nx_pppoe_client_string_add(UCHAR *dest, UCHAR *source, UINT size); +static UINT _nx_pppoe_client_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index); +static UINT _nx_pppoe_client_session_cleanup(NX_PPPOE_CLIENT *pppoe_client_ptr); +static VOID _nx_pppoe_client_session_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +static VOID _nx_pppoe_client_session_thread_resume(TX_THREAD **suspension_list_head, UINT status); +static VOID _nx_pppoe_client_session_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), + NX_PPPOE_CLIENT *pppoe_client_ptr, TX_MUTEX *mutex_ptr, ULONG wait_option); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Client instance create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* name Name of this PPPoE instance */ +/* ip_ptr Pointer to IP control block */ +/* interface_index IP Interface Index */ +/* pool_ptr packet pool */ +/* stack_ptr Pointer stack area for PPPoE */ +/* stack_size Size of PPPoE stack area */ +/* priority Priority of PPPoE thread */ +/* pppoe_link_driver User supplied link driver */ +/* pppoe_packet_receive User supplied function to */ +/* receive PPPoE packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_create Actual PPPoE instance create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id == NX_PPPOE_CLIENT_ID) || + (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || + (stack_ptr == NX_NULL) || (pppoe_link_driver == NX_NULL) || (pppoe_packet_receive == NX_NULL)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Check for invalid interface ID */ + if(interface_index >= NX_MAX_PHYSICAL_INTERFACES) + return(NX_PPPOE_CLIENT_INVALID_INTERFACE); + + /* Check for interface being valid. */ + if(!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) + return(NX_PPPOE_CLIENT_INVALID_INTERFACE); + + /* Check for payload size of packet pool. */ + if (pool_ptr -> nx_packet_pool_payload_size < NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE) + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + + /* Check for a memory size error. */ + if (stack_size < TX_MINIMUM_STACK) + return(NX_PPPOE_CLIENT_MEMORY_SIZE_ERROR); + + /* Check the priority specified. */ + if (priority >= TX_MAX_PRIORITIES) + return(NX_PPPOE_CLIENT_PRIORITY_ERROR); + + /* Call actual PPPoE client instance create function. */ + status = _nx_pppoe_client_create(pppoe_client_ptr, name, ip_ptr, interface_index, + pool_ptr, stack_ptr, stack_size, priority, + pppoe_link_driver, pppoe_packet_receive); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an PPPoE Client instance, including setting */ +/* up all appropriate data structures, creating PPPoE event flag */ +/* object and PPPoE thread. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* name Name of this PPPoE instance */ +/* ip_ptr Pointer to IP control block */ +/* interface_index Interface Index */ +/* pool_ptr packet pool */ +/* stack_ptr Pointer stack area for PPPoE */ +/* stack_size Size of PPPoE stack area */ +/* priority Priority of PPPoE thread */ +/* pppoe_link_driver User supplied link driver */ +/* pppoe_packet_receive User supplied function to */ +/* receive PPPoE packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create IP event flags */ +/* tx_thread_create Create IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Initialize the PPPoE Server control block to zero. */ + memset((void *) pppoe_client_ptr, 0, sizeof(NX_PPPOE_CLIENT)); + + /* Save the PPPoE name. */ + pppoe_client_ptr -> nx_pppoe_name = name; + + /* Save the IP pointer. */ + pppoe_client_ptr -> nx_pppoe_ip_ptr = ip_ptr; + + /* Setup the interface index and interface pointer. */ + pppoe_client_ptr -> nx_pppoe_interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Save the packet pool pointer. */ + pppoe_client_ptr -> nx_pppoe_packet_pool_ptr = pool_ptr; + + /* Setup the link driver address. */ + pppoe_client_ptr -> nx_pppoe_link_driver_entry = pppoe_link_driver; + + /* Setup the function to receive PPPoE packet. */ + pppoe_client_ptr ->nx_pppoe_packet_receive = pppoe_packet_receive; + + /* Create event flag group to control the PPPoE processing thread. */ + tx_event_flags_create(&(pppoe_client_ptr -> nx_pppoe_events), "PPPoE Client EVENTS") ; + + /* Create the PPPoE processing thread. */ + tx_thread_create(&(pppoe_client_ptr -> nx_pppoe_thread), "PPPoE Client THREAD", _nx_pppoe_client_thread_entry, (ULONG) pppoe_client_ptr, + stack_ptr, stack_size, priority, priority, NX_PPPOE_CLIENT_THREAD_TIME_SLICE, TX_AUTO_START); + + /* Create the PPPoE timer. */ + tx_timer_create(&(pppoe_client_ptr -> nx_pppoe_timer), "PPPoE Client timer", + (VOID (*)(ULONG))_nx_pppoe_client_timer_entry, (ULONG)pppoe_client_ptr, + NX_IP_PERIODIC_RATE, NX_IP_PERIODIC_RATE, TX_NO_ACTIVATE); + + /* Otherwise, the PPPoE initialization was successful. Place the + PPPoE control block on created PPPoE instance. */ + TX_DISABLE + + /* Load the PPPoE Client ID field in the PPPoE Client control block. */ + pppoe_client_ptr -> nx_pppoe_id = NX_PPPOE_CLIENT_ID; + + /* Set the pointer of global variable PPPoE. */ + _nx_pppoe_client_created_ptr = pppoe_client_ptr; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Client instance delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_delete Actual PPPoE instance delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE client instance delete function. */ + status = _nx_pppoe_client_delete(pppoe_client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes an PPPoE Client instance. including deleting */ +/* PPPoE event flag object and PPPoE thread. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_terminate Terminate PPPoE helper thread */ +/* tx_thread_delete Delete PPPoE helper thread */ +/* tx_event_flags_delete Delete PPPoE event flags */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Determine if the caller is the PPPoE thread itself. This is not allowed since + a thread cannot delete itself in ThreadX. */ + if (&pppoe_client_ptr -> nx_pppoe_thread == tx_thread_identify()) + { + + /* Invalid caller of this routine, return an error! */ + return(NX_CALLER_ERROR); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Clear the PPPOE ID to show that it is no longer valid. */ + pppoe_client_ptr -> nx_pppoe_id = 0; + + /* Clear the created pointer. */ + _nx_pppoe_client_created_ptr = NX_NULL; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Terminate the thread. */ + tx_thread_terminate(&(pppoe_client_ptr -> nx_pppoe_thread)); + + /* Delete the PPPoE thread. */ + tx_thread_delete(&(pppoe_client_ptr -> nx_pppoe_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(pppoe_client_ptr -> nx_pppoe_events)); + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_service_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE service name set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an service name. */ +/* Service name must be */ +/* Null-terminated string. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_service_name_set Actual PPPoE service name set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE service name set function. */ + status = _nx_pppoe_client_service_name_set(pppoe_client_ptr, service_name); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_service_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the service name for PPPoE Client. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an service name. */ +/* Service name must be */ +/* Null-terminated string. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* _nx_pppoe_client_service_name_set Actual PPPoE service name set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name) +{ +UINT status; +UINT service_name_length = 0; + + + /* Calculate the service_name length. */ + if (_nx_utility_string_length_check((CHAR *)service_name, &service_name_length, NX_MAX_STRING_LENGTH)) + { + return(NX_SIZE_ERROR); + } + + /* Call actual PPPoE service name set function. */ + status = _nx_pppoe_client_service_name_set_extended(pppoe_client_ptr, service_name, service_name_length); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_service_name_set_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE service name set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an service name. */ +/* Service name must be */ +/* Null-terminated string. */ +/* service_name_length Length of service_name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_service_name_set_extended */ +/* Actual PPPoE service name set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE service name set function. */ + status = _nx_pppoe_client_service_name_set_extended(pppoe_client_ptr, service_name, service_name_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_service_name_set_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the service name for PPPoE Client. */ +/* */ +/* Note: The string of service_name must be NULL-terminated and length */ +/* of service_name matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an service name. */ +/* Service name must be */ +/* Null-terminated string. */ +/* service_name_length Length of service_name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length) +{ + +UINT temp_service_name_length = 0; + + /* Get the length of service_name string. */ + if (_nx_utility_string_length_check((CHAR*)service_name, &temp_service_name_length, service_name_length)) + return(NX_SIZE_ERROR); + + /* Check the service_name length. */ + if (service_name_length != temp_service_name_length) + return(NX_SIZE_ERROR); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup service name pointer. */ + pppoe_client_ptr -> nx_pppoe_service_name = service_name; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_host_uniq_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE host uniq set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* host_uniq Pointer to an host unique. */ +/* Host unique must be */ +/* Null-terminated string. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_host_uniq_set Actual PPPoE host uniq set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE host uniq set function. */ + status = _nx_pppoe_client_host_uniq_set(pppoe_client_ptr, host_uniq); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_host_uniq_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the host unique for PPPoE Client. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* host_uniq Pointer to an host unique. */ +/* Host unique must be */ +/* Null-terminated string. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* _nx_pppoe_client_host_uniq_set_extended */ +/* Actual PPPoE host uniq set */ +/* function */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq) +{ +UINT status; +UINT host_uniq_length = 0; + + /* Calculate the host_uniq length. */ + if (_nx_utility_string_length_check((CHAR *)host_uniq, &host_uniq_length, NX_MAX_STRING_LENGTH)) + { + return(NX_SIZE_ERROR); + } + + status = _nx_pppoe_client_host_uniq_set_extended(pppoe_client_ptr, host_uniq, host_uniq_length); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_host_uniq_set_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE host uniq set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* host_uniq Pointer to an host unique. */ +/* Host unique must be */ +/* Null-terminated string. */ +/* host_uniq_length Length of host_uniq */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_host_uniq_set_extended */ +/* Actual PPPoE host uniq set */ +/* function */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE host uniq set function. */ + status = _nx_pppoe_client_host_uniq_set_extended(pppoe_client_ptr, host_uniq, host_uniq_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_host_uniq_set_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the host unique for PPPoE Client. */ +/* */ +/* Note: The string of host_uniq must be NULL-terminated and length */ +/* of host_uniq matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* host_uniq Pointer to an host unique. */ +/* Host unique must be */ +/* Null-terminated string. */ +/* host_uniq_length Length of host_uniq */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length) +{ +UINT temp_host_uniq_length = 0; + + /* Get the length of host_uniq string. */ + if (_nx_utility_string_length_check((CHAR*)host_uniq, &temp_host_uniq_length, host_uniq_length)) + return(NX_SIZE_ERROR); + + /* Check the host_uniq length. */ + if (host_uniq_length != temp_host_uniq_length) + return(NX_SIZE_ERROR); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup service name pointer. */ + pppoe_client_ptr -> nx_pppoe_host_uniq = host_uniq; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_session_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Client session connect */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_session_connect Actual PPPoE connect function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE client instance enable function. */ + status = _nx_pppoe_client_session_connect(pppoe_client_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects the PPPoE session. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_session_connect Actual PPPoE connect function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option) +{ + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check to PPPoE state. */ + if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_INITIAL) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return(NX_PPPOE_CLIENT_INVALID_SESSION); + } + + /* Activate the PPPoE client timer. */ + tx_timer_activate(&pppoe_client_ptr -> nx_pppoe_timer); + + /* Update the state. */ + pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_PADI_SENT; + + /* Set the retransmit timeout and count for PADI. */ + pppoe_client_ptr -> nx_pppoe_rtr_timeout = NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT; + pppoe_client_ptr -> nx_pppoe_rtr_count = NX_PPPOE_CLIENT_PADI_COUNT - 1; + + /* Start to establish the PPPoE session connection. */ + _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADI); + + /* Optionally suspend the thread. If timeout occurs, return a connection timeout status. If + immediate response is selected, return a connection in progress status. Only on a real + connection should success be returned. */ + if ((wait_option) && (_tx_thread_current_ptr != &(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_thread))) + { + + /* Suspend the thread on this socket's connection attempt. */ + /* Note: the IP protection mutex is released inside _nx_pppoe_client_session_thread_suspend(). */ + + _nx_pppoe_client_session_thread_suspend(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), _nx_pppoe_client_session_connect_cleanup, + pppoe_client_ptr, &(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), wait_option); + + /* Just return the completion code. */ + return(_tx_thread_current_ptr -> tx_thread_suspend_status); + } + else + { + + /* No suspension is request, just release protection and return to the caller. */ + + /* Release the IP protection. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return in-progress completion status. */ + return(NX_IN_PROGRESS); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_session_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session packet send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_session_packet_send Actual PPPoE Session data send*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; + + /* Check for invalid packet. */ + if (packet_ptr == NX_NULL) + { + return(NX_PPPOE_CLIENT_PTR_ERROR); + } + + /* Check for minimum packet length (PPP DATA Header). */ + if (packet_ptr -> nx_packet_length < 2) + { + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_CLIENT_PTR_ERROR); + } + + /* Call actual PPPoE session packet_send function. */ + status = _nx_pppoe_client_session_packet_send(pppoe_client_ptr, packet_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE Session packet and calls the */ +/* associated driver to send it out on the network. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* data_ptr Session Data pointer */ +/* data_length Length of Session Data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* nx_packet_release Release packet to packet pool */ +/* nx_packet_data_append Copies the specified data */ +/* _nx_pppoe_client_data_add Add PPPoE data */ +/* _nx_pppoe_client_packet_send Send out PPPoE packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) +{ + +NX_PPPOE_SERVER_SESSION *server_session_ptr; +UCHAR *work_ptr; + + + /* Obtain the IP internal mutex. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check to see if PPPoE session is established. */ + if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_PPPOE_CLIENT_OFFSET_PAYLOAD) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return error code. */ + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + + /* Set the server session pointer. */ + server_session_ptr = &(pppoe_client_ptr -> nx_pppoe_server_session); + + /* Set the work pointer. */ + packet_ptr -> nx_packet_prepend_ptr -= NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + work_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Added the PPPoE header. */ + /* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | VER | TYPE | CODE | SESSION_ID | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | LENGTH | payload + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add version and type. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1, NX_PPPOE_CLIENT_VERSION_TYPE); + + /* Add code. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1, NX_PPPOE_CLIENT_CODE_ZERO); + + /* Add session id. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, server_session_ptr -> nx_pppoe_session_id); + + /* Add length. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2, packet_ptr -> nx_packet_length); + + /* Update the packet length. */ + packet_ptr -> nx_packet_length += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + + /* Send PPPoE session packet. */ + _nx_pppoe_client_packet_send(pppoe_client_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_session_terminate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session terminate */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_session_terminate Actual PPPoE Session terminate*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE session terminate function. */ + status = _nx_pppoe_client_session_terminate(pppoe_client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_terminate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE packet to terminate the session. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_client_discovery_send Send out PPPoE packet */ +/* _nx_pppoe_client_session_cleanup Cleanup PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr) +{ + +UINT status; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check to see if PPPoE is established. */ + if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); + } + + /* Terminate the PPPoE session. */ + status = _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADT); + + /* Check the status. */ + if (status == NX_PPPOE_CLIENT_SUCCESS) + { + + /* Cleanup the session. */ + _nx_pppoe_client_session_cleanup(pppoe_client_ptr); + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_client_session_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session get function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index The index of Client Session */ +/* server_mac_msw Server physical address MSW */ +/* server_mac_lsw Server physical address LSW */ +/* session_id Session ID */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_session_get Actual PPPoE Session get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + return(NX_PPPOE_CLIENT_PTR_ERROR); + + /* Call actual PPPoE session get function. */ + status = _nx_pppoe_client_session_get(pppoe_client_ptr, client_mac_msw, client_mac_lsw, session_id); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE packet to get the session physical */ +/* address and session id. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* session_index The index of Client Session */ +/* server_mac_msw Server physical address MSW */ +/* server_mac_lsw Server physical address LSW */ +/* session_id Session ID */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id) +{ + + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check to see if PPPoE session is established. */ + if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); + } + + /* Yes, get the Server physical address MSW. */ + if (server_mac_msw) + *server_mac_msw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw; + + /* Yes, get the Server physical address LSW. */ + if (server_mac_lsw) + *server_mac_lsw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw; + + /* Yes, get the Session ID. */ + if (session_id) + *session_id = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return status. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_packet_deferred_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a packet from the link driver (usually the */ +/* link driver's input ISR) and places it in the deferred receive */ +/* packet queue. This moves the minimal receive packet processing */ +/* from the ISR to the PPPoE helper thread. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for PPPoE thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Check to see if PPPoE instance is created. */ + if (_nx_pppoe_client_created_ptr == NX_NULL) + { + + /* Release the packet. */; + nx_packet_release(packet_ptr); + + return; + } + + /* Check to see if PPPoE is ready to receive packet. */ + if (_nx_pppoe_client_created_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_INITIAL) + { + + /* Release the packet. */; + nx_packet_release(packet_ptr); + + return; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if the deferred processing queue is empty. */ + if (_nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the queue. */ + (_nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Empty deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the PPPoE helper thread looks at the deferred processing + queue. */ + _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; + _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup PPPoE helper thread to process the PPPoE deferred receive. */ + tx_event_flags_set(&(_nx_pppoe_client_created_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT, TX_OR); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point for each PPPoE's helper thread. */ +/* The PPPoE helper thread is responsible for processing PPPoE packet. */ +/* */ +/* Note that the priority of this function is determined by the PPPoE */ +/* create service. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr_value Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Suspend on event flags that */ +/* are used to signal this */ +/* thread what to do */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_client_packet_receive PPPoE receive packet */ +/* processing */ +/* nx_packet_release Release packet to packet pool */ +/* (pppoe_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_thread_entry(ULONG pppoe_client_ptr_value) +{ + + +TX_INTERRUPT_SAVE_AREA + +#ifdef NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE +NX_IP_DRIVER driver_request; +#endif +NX_PPPOE_CLIENT *pppoe_client_ptr; +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +ULONG pppoe_events; +ULONG timeout = 0; + + + /* Setup the PPPoE pointer. */ + pppoe_client_ptr = (NX_PPPOE_CLIENT *) pppoe_client_ptr_value; + + /* Setup the IP pointer. */ + ip_ptr = pppoe_client_ptr -> nx_pppoe_ip_ptr; + + /* Obtain the IP internal mutex before calling the driver. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + +#ifdef NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE + + /* Initialize and enable the hardware for physical interface. */ + + /* Is this a valid interface with a link driver associated with it? */ + if((pppoe_client_ptr -> nx_pppoe_interface_ptr -> nx_interface_valid) && (pppoe_client_ptr -> nx_pppoe_link_driver_entry)) + { + + /* Yes; attach the interface to the device. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_ATTACH; + driver_request.nx_ip_driver_interface = pppoe_client_ptr -> nx_pppoe_interface_ptr; + (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Call the link driver to initialize the hardware. Among other + responsibilities, the driver is required to provide the + Maximum Transfer Unit (MTU) for the physical layer. The MTU + should represent the actual physical layer transfer size + less the physical layer headers and trailers. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_INITIALIZE; + (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Call the link driver again to enable the interface. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ENABLE; + (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Indicate to the IP software that IP to physical mapping + is not required. */ + pppoe_client_ptr -> nx_pppoe_interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; + } +#endif + + /* Loop to continue processing incoming bytes. */ + while(NX_FOREVER) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Pickup IP event flags. */ + tx_event_flags_get(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_ALL_EVENTS, TX_OR_CLEAR, &pppoe_events, NX_WAIT_FOREVER); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check for PPPoE packet receive event. */ + if (pppoe_events & NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT) + { + + /* Loop to process all deferred packet requests. */ + while (pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + pppoe_client_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Discard the chained packets. */ + if (packet_ptr -> nx_packet_next) + { + nx_packet_release(packet_ptr); + continue; + } +#endif + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < NX_PPPOE_CLIENT_OFFSET_PAYLOAD) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check the packet interface. */ + if ((packet_ptr -> nx_packet_ip_interface != NX_NULL) && + (packet_ptr -> nx_packet_ip_interface != pppoe_client_ptr -> nx_pppoe_interface_ptr)) + { + nx_packet_release(packet_ptr); + continue; + } + + /* Call the actual PPPoE Client packet receive function. */ + _nx_pppoe_client_packet_receive(pppoe_client_ptr, packet_ptr); + } + } + + /* Check for PPPoE periodic timer event. */ + if (pppoe_events & NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT) + { + + /* Check if max number of PADI/PADR messages have been sent. */ + if (pppoe_client_ptr -> nx_pppoe_rtr_timeout != 0) + { + + /* Check on count down timer for sending out next PADI/PADR message. */ + pppoe_client_ptr -> nx_pppoe_rtr_timeout--; + + /* Check the timer. */ + if(pppoe_client_ptr -> nx_pppoe_rtr_timeout == 0) + { + + /* It has expired. Send out a PADI/PADR message. */ + + /* Check if max number of PADI/PADR messages have been sent. */ + if (pppoe_client_ptr -> nx_pppoe_rtr_count) + { + + /* Retransmit PADI/PADR message. */ + + /* When a host does not receive a PADO/PADS packet with in a specified amount of time, + it should resend it's PADI/PADR packet and double the waiting period. RFC2516, Section8, Page8. */ + + /* Check PPPoE state. */ + if (pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADI_SENT) + { + + /* Calculate timeout. */ + timeout = ((ULONG)NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT) << (ULONG)(NX_PPPOE_CLIENT_PADI_COUNT - pppoe_client_ptr -> nx_pppoe_rtr_count); + + /* Send PADI. */ + _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADI); + } + + /* Check PPPoE state. */ + if (pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADR_SENT) + { + + /* Calculate timeout. */ + timeout = ((ULONG)NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT) << (ULONG)(NX_PPPOE_CLIENT_PADR_COUNT - pppoe_client_ptr -> nx_pppoe_rtr_count); + + /* Send PADR. */ + _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADR); + } + + /* Update the retransmit count. */ + pppoe_client_ptr -> nx_pppoe_rtr_count --; + + /* Set the retransmit timeout. */ + pppoe_client_ptr -> nx_pppoe_rtr_timeout = timeout; + } + else + { + + /* Reach the max number of PADI/PADR have been sent. */ + + /* Deactivate the PPPoE client timer. */ + tx_timer_deactivate(&(pppoe_client_ptr -> nx_pppoe_timer)); + + /* Cleanup the PPPoE session. */ + _nx_pppoe_client_session_cleanup(pppoe_client_ptr); + + /* Determine if we need to wake a thread suspended on the connection. */ + if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) + { + + /* Resume the suspended thread. */ + _nx_pppoe_client_session_thread_resume(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); + } + } + } + } + } + + /* Check for PPPoE event. */ + if (pppoe_events & NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT) + { + + if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) + { + _nx_pppoe_client_session_connect_cleanup(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread NX_CLEANUP_ARGUMENT); + } + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles waking up the PPPoE Client helper thread on a */ +/* periodic basis. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_address PPPoE address in a ULONG */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_timer_entry(ULONG pppoe_client_address) +{ + +NX_PPPOE_CLIENT *pppoe_client_ptr; + + + /* Convert input parameter to an PPPoE Client pointer. */ + pppoe_client_ptr = (NX_PPPOE_CLIENT *)pppoe_client_address; + + /* Wakeup this PPPoE Client's helper thread. */ + tx_event_flags_set(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a PPPoE packet from the PPPoE deferred */ +/* processing queue. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_client_data_get Get the PPPoE data */ +/* _nx_pppoe_client_discovery_packet_process */ +/* Process discovery packet */ +/* _nx_pppoe_client_session_packet_process */ +/* Process session packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_client_packet_receive(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR *ethernet_header_ptr; +ULONG dest_mac_msw; +ULONG dest_mac_lsw; +ULONG src_mac_msw; +ULONG src_mac_lsw; +UINT ethernet_type; + + + /* Set up UCHAR pointer to ethernet header to extract client hardware address + which we will use as the client's unique identifier. */ + ethernet_header_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_PPPOE_CLIENT_ETHER_HEADER_SIZE; + + /* Pickup the MSW and LSW of the destination MAC address. */ + dest_mac_msw = (((ULONG) ethernet_header_ptr[0]) << 8) | ((ULONG) ethernet_header_ptr[1]); + dest_mac_lsw = (((ULONG) ethernet_header_ptr[2]) << 24) | (((ULONG) ethernet_header_ptr[3]) << 16) | + (((ULONG) ethernet_header_ptr[4]) << 8) | ((ULONG) ethernet_header_ptr[5]); + + /* Check the destination hardware (mac address) field is filled in. */ + if ((dest_mac_msw == 0) && (dest_mac_lsw == 0)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check if it is a broadcast message. + Only PADI packet with the destination address set to the broadcast address, and PADI only can be sent from PPPoE Client. */ + if ((dest_mac_msw == 0xFFFF) && (dest_mac_lsw == 0xFFFFFFFF)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the MSW and LSW of the source MAC address. */ + src_mac_msw = (((ULONG) ethernet_header_ptr[6]) << 8) | ((ULONG) ethernet_header_ptr[7]); + src_mac_lsw = (((ULONG) ethernet_header_ptr[8]) << 24) | (((ULONG) ethernet_header_ptr[9]) << 16) | + (((ULONG) ethernet_header_ptr[10]) << 8) | ((ULONG) ethernet_header_ptr[11]); + + /* Check the source hardware (mac address) field is filled in. */ + if ((src_mac_msw == 0) && (src_mac_lsw == 0)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Get the ethernet type. */ + ethernet_type = _nx_pppoe_client_data_get(ethernet_header_ptr + 12, 2); + + /* Process the packet according to packet type. */ + if(ethernet_type == NX_PPPOE_CLIENT_ETHER_TYPE_DISCOVERY) + { + + /* Process the discovery packet. */ + _nx_pppoe_client_discovery_packet_process(pppoe_client_ptr, packet_ptr, src_mac_msw, src_mac_lsw); + } + else if(ethernet_type == NX_PPPOE_CLIENT_ETHER_TYPE_SESSION) + { + + /* Process the session packet. */ + _nx_pppoe_client_session_packet_process(pppoe_client_ptr, packet_ptr, src_mac_msw, src_mac_lsw); + } + else + { + + /* Relase the packet. */ + nx_packet_release(packet_ptr); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_discovery_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming discovery packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* is_broadcast Broadcast flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_client_data_get Get the PPPoE data */ +/* _nx_pppoe_client_tag_process Process PPPoE tags */ +/* _nx_pppoe_client_discovery_send Send discovery packet */ +/* _nx_pppoe_client_session_find Find the PPPoE session */ +/* _nx_pppoe_client_session_cleanup Cleanup the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_client_discovery_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw) +{ + + +UCHAR *pppoe_header_ptr; +UINT is_accepted = NX_FALSE; +ULONG ver_type; +ULONG code; +ULONG session_id; +ULONG length; +UCHAR *tag_ptr; +ULONG tag_type; +ULONG tag_length; +UINT tag_index = 0; +UINT tag_ac_name_count = 0; +UINT tag_service_name_count = 0; +UINT tag_service_name_valid = NX_FALSE; +UINT tag_host_uniq_count = 0; +UINT tag_host_uniq_valid = NX_FALSE; + + + /* Setup the PPPoE header. */ + pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the version and type. */ + ver_type = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1); + + /* Check the version and type. */ + if (ver_type != NX_PPPOE_CLIENT_VERSION_TYPE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the code. */ + code = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1); + + /* Check the session state and the code of incoming packet. */ + if (((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADI_SENT) && (code == NX_PPPOE_CLIENT_CODE_PADO)) || + ((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADR_SENT) && (code == NX_PPPOE_CLIENT_CODE_PADS)) || + ((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_ESTABLISHED) && (code == NX_PPPOE_CLIENT_CODE_PADT))) + { + + /* Packet can be accepted. */ + is_accepted = NX_TRUE; + } + + /* Ignore the packet that is not accepted. */ + if (is_accepted != NX_TRUE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the session id. */ + session_id = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2); + + /* Check the session id. + Session ID must be zero for PADO, + Session ID must be not zero for PADS and PADT. + Session ID must be same value for PADT. */ + if (((code == NX_PPPOE_CLIENT_CODE_PADO) && (session_id != 0)) || + ((code != NX_PPPOE_CLIENT_CODE_PADO) && (session_id == 0)) || + ((code == NX_PPPOE_CLIENT_CODE_PADT) && (session_id != pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id))) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check the MAC address for PADS and PADT before process tags. */ + if (code != NX_PPPOE_CLIENT_CODE_PADO) + { + + if ((pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw != server_mac_msw) || + (pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw != server_mac_lsw)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + } + + /* Initialize the value. */ + pppoe_client_ptr -> nx_pppoe_ac_name_size = 0; + pppoe_client_ptr -> nx_pppoe_ac_cookie_size = 0; + pppoe_client_ptr -> nx_pppoe_relay_session_id_size = 0; + pppoe_client_ptr -> nx_pppoe_error_flag = 0; + + /* Pickup the length of tags. */ + length = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2); + + /* Check for valid payload. */ + if (length > packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Set the tag pointer. */ + tag_ptr = pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + + /* Loop to process the tag. */ + while (tag_index < length) + { + + /* Pickup the tag type. */ + tag_type = _nx_pppoe_client_data_get(tag_ptr + tag_index, 2); + + /* Update the index. */ + tag_index += 2; + + /* Pickup the tag length. */ + tag_length = _nx_pppoe_client_data_get(tag_ptr + tag_index, 2); + + /* Update the index. */ + tag_index += 2; + + /* Check for valid tag length. */ + if ((tag_index + tag_length) > length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Process the option type. */ + switch (tag_type) + { + + case NX_PPPOE_CLIENT_TAG_TYPE_END_OF_LIST: + { + + /* End tag. */ + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME: + { + + /* Update the Service-Name count. */ + tag_service_name_count ++; + + /* Check the tag length. */ + if (tag_length == 0) + { + + /* When the tag length is zero this tag is used to indicate that any service is acceptable. */ + tag_service_name_valid = NX_TRUE; + } + else + { + + /* Compare the service name with PPPoE Service name that Client is requesting. */ + if (!memcmp(tag_ptr + tag_index, pppoe_client_ptr -> nx_pppoe_service_name, tag_length)) + { + + /* Update the information. */ + tag_service_name_valid = NX_TRUE; + } + } + + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_AC_NAME: + { + + /* Check the cache for AC-Name. */ + if (tag_length > NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Update the AC-Name count. */ + tag_ac_name_count ++; + + /* Save the AC-Name. */ + memcpy(pppoe_client_ptr -> nx_pppoe_ac_name, tag_ptr + tag_index, tag_length); + + /* Set the AC-Name size. */ + pppoe_client_ptr -> nx_pppoe_ac_name_size = tag_length; + + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ: + { + + /* Update the Host-Uniq count. */ + tag_host_uniq_count ++; + + /* Check the Host-Uniq. */ + if (!memcmp(tag_ptr + tag_index, pppoe_client_ptr -> nx_pppoe_host_uniq, tag_length)) + { + + /* Update the information. */ + tag_host_uniq_valid = NX_TRUE; + } + + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE: + { + + /* Check the cache for AC-Cookie. */ + if (tag_length > NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Save the AC-Cookie. */ + memcpy(pppoe_client_ptr -> nx_pppoe_ac_cookie, tag_ptr + tag_index, tag_length); + + /* Set the AC-Cookie size. */ + pppoe_client_ptr -> nx_pppoe_ac_cookie_size = tag_length; + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_RELAY_SESSION_ID: + { + + /* Check the cache for Relay-Session_Id. */ + if (tag_length > NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Save the Relay-Session_Id. */ + memcpy(pppoe_client_ptr -> nx_pppoe_relay_session_id, tag_ptr + tag_index, tag_length); + + /* Set the Relay-Session_Id size. */ + pppoe_client_ptr -> nx_pppoe_relay_session_id_size = tag_length; + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME_ERROR: + { + + /* Set the service name error flag. */ + pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_SERVICE_NAME; + + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_AC_SYSTEM_ERROR: + { + + /* Set the AC system error flag. */ + pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_AC_SYSTEM; + + break; + } + case NX_PPPOE_CLIENT_TAG_TYPE_GENERIC_ERROR: + { + + /* Set the generic error flag. */ + pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_GENERIC; + + break; + } + default: + break; + } + + /* Move to the next tag. */ + tag_index += tag_length; + } + + /* Now we can release the packet. */ + nx_packet_release(packet_ptr); + + /* Check the code value. */ + if (code == NX_PPPOE_CLIENT_CODE_PADO) + { + + /* PADO packet MUST contain one AC-Name TAG containing the Access Concentrator's name, + a Service-Name TAG indentical to the one in the PADI. RFC2516, Section5.2, Page6. */ + + /* Check AC-Name. */ + if (tag_ac_name_count != 1) + return; + + /* The Host MAY include a Host-Uniq TAG in a PADI or + PADR. If the Access Concentrator receives this TAG, it MUST + include the TAG unmodified in the associated PADO or PADS + response. RFC2516, Appendix A, Page10. */ + if (pppoe_client_ptr -> nx_pppoe_host_uniq) + { + + /* Check if include valid Host-Uniq. */ + if ((tag_host_uniq_count != 1) || (tag_host_uniq_valid != NX_TRUE)) + return; + } + else + { + + /* Check if include the Host-Uniq. */ + if (tag_host_uniq_count) + return; + } + + /* Check Service-Name. */ + if (tag_service_name_valid != NX_TRUE) + return; + + /* Check for error. */ + if (pppoe_client_ptr -> nx_pppoe_error_flag) + return; + + /* Choose one PPPoE Server. + Since the PADI was broadcast, the Host may receive more than one + PADO. The Host looks through the PADO packets it receives and + chooses one. The choice can be based on the AC-Name or the Services + offered. The Host then sends one PADR packet to the Access + Concentrator that it has chosen. RFC2516, Section5.3, Page6. */ + + /* Simplify the logic, we choose the first PPPoE Server sent out PADO. */ + + /* Record server information. */ + pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw = server_mac_msw; + pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw = server_mac_lsw; + + /* Send PPPoE Active Discovery Offer packet. */ + _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADR); + + /* Update the state. */ + pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_PADR_SENT; + + /* Set the retransmit timeout and count for PADR. */ + pppoe_client_ptr -> nx_pppoe_rtr_timeout = NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT; + pppoe_client_ptr -> nx_pppoe_rtr_count = NX_PPPOE_CLIENT_PADR_COUNT - 1; + } + else if (code == NX_PPPOE_CLIENT_CODE_PADS) + { + + /* The PADS packet contains exactly one TAG of TAG_TYPE Service-Name. RFC2516, Section5.4, Page6. */ + + /* Check Service-Name. */ + if ((tag_service_name_count != 1) || (tag_service_name_valid != NX_TRUE)) + return; + + /* Check for error. */ + if (pppoe_client_ptr -> nx_pppoe_error_flag) + return; + + /* Record the session id. */ + pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id = (USHORT)session_id; + + /* Update the state. */ + pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_ESTABLISHED; + + /* Deactivate the PPPoE client timer. */ + tx_timer_deactivate(&(pppoe_client_ptr -> nx_pppoe_timer)); + + /* Determine if we need to wake a thread suspended on the connection. */ + if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) + { + + /* Resume the suspended thread. */ + _nx_pppoe_client_session_thread_resume(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), NX_PPPOE_CLIENT_SUCCESS); + } + } + else if (code == NX_PPPOE_CLIENT_CODE_PADT) + { + + /* Cleanup the PPPoE session. */ + _nx_pppoe_client_session_cleanup(pppoe_client_ptr); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming session packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_client_data_get Get the PPPoE data */ +/* _nx_pppoe_client_session_find Find the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_session_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw) +{ + + +UCHAR *pppoe_header_ptr; +ULONG ver_type; +ULONG code; +ULONG session_id; +ULONG length; +NX_PPPOE_SERVER_SESSION *server_session_ptr; + + + /* Setup the PPPoE header. */ + pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the version and type. */ + ver_type = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1); + + /* Check the version and type. */ + if (ver_type != NX_PPPOE_CLIENT_VERSION_TYPE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the code. */ + code = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1); + + /* Check the code. */ + if (code != NX_PPPOE_CLIENT_CODE_ZERO) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the session id. */ + session_id = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2); + + /* Check the session id. */ + if (session_id == 0) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check the session state. */ + if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Set the server session pointer. */ + server_session_ptr = &(pppoe_client_ptr -> nx_pppoe_server_session); + + /* Check the session id and server MAC address. */ + if ((session_id != server_session_ptr -> nx_pppoe_session_id) || + (server_mac_msw != server_session_ptr -> nx_pppoe_physical_address_msw) || + (server_mac_lsw != server_session_ptr -> nx_pppoe_physical_address_lsw)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Setup the prepend pointer to point the payload of PPPoE. */ + packet_ptr -> nx_packet_prepend_ptr += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + packet_ptr -> nx_packet_length -= NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + + /* Pickup the length of payload. */ + length = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2); + + /* Check for valid payload. */ + if (length > packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Remove the Ethernet padding. */ + if (length < packet_ptr -> nx_packet_length) + { + packet_ptr -> nx_packet_append_ptr -= (packet_ptr -> nx_packet_length - length); + packet_ptr -> nx_packet_length -= (packet_ptr -> nx_packet_length - length); + } + + /* Check the PPPoE receive function. */ + if (pppoe_client_ptr -> nx_pppoe_packet_receive) + { + + /* Call the function to receive the data frame. + Notice: the receive function must release this packet. */ + pppoe_client_ptr -> nx_pppoe_packet_receive(packet_ptr); + } + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_discovery_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a PPPoE discovery packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* client_session_ptr Pointer to Client Session */ +/* code PPPoE code */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate a packet for the */ +/* PPPoE Discovery */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_client_data_add Add PPPoE data */ +/* _nx_pppoe_client_tag_string_add Add PPPoE tag */ +/* _nx_pppoe_client_packet_send Send out PPPoE packet */ +/* _nx_pppoe_client_session_find Find the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_session_terminate Terminate the PPPoE session */ +/* _nx_pppoe_client_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_client_discovery_send(NX_PPPOE_CLIENT *pppoe_client_ptr, UINT code) +{ + + +NX_PACKET *packet_ptr; +UCHAR *work_ptr; +UINT status; +UINT index = 0; +UINT tag_length; + + + /* Allocate a PPPoE packet. */ + status = nx_packet_allocate(pppoe_client_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Set the work pointer. */ + work_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First skip the PPPoE header. */ + index += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; + + /* The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type-length-value) construct and is defined as follows. */ + + /* 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | TAG_TYPE | TAG_LENGTH | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | TAG_VALUE ... + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add the PPPoE tags. */ + if (code == NX_PPPOE_CLIENT_CODE_PADI) + { + + /* The PADI packet MUST contain exactly one TAG of TAG_TYPE Service-Name, indicating the service the host is requesting, + and any number of other TAG types. RFC2516, Section5.1, Page5. */ + if (pppoe_client_ptr -> nx_pppoe_service_name) + { + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_SERVICE_NAME_ERROR); + } + + if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= + (4 + tag_length)) + { + + /* Added the Service-Name tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, tag_length, pppoe_client_ptr -> nx_pppoe_service_name, &index); + } + else + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + } + else + { + + /* Added the Service-Name tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); + } + + /* The Host MAY include a Host-Uniq TAG in a PADI or PADR. */ + if (pppoe_client_ptr -> nx_pppoe_host_uniq) + { + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_host_uniq), &tag_length, NX_MAX_STRING_LENGTH)) + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + + if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= + (4 + tag_length)) + { + + /* Added the Host-Uniq tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, tag_length, pppoe_client_ptr -> nx_pppoe_host_uniq, &index); + } + else + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + } + } + else if (code == NX_PPPOE_CLIENT_CODE_PADR) + { + + /* The PADR packet MUST contain exactly one TAG of TAG_TYPE Service-Name, indicating the service the host is requesting, + and any number of other TAG types. RFC2516, Section5.3, Page6. */ + if (pppoe_client_ptr -> nx_pppoe_service_name) + { + + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_SERVICE_NAME_ERROR); + } + + if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= + (4 + tag_length)) + { + + /* Added the Service-Name tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, tag_length, pppoe_client_ptr -> nx_pppoe_service_name, &index); + } + else + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + } + else + { + + /* Added the Service-Name tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); + } + + /* The Host MAY include a Host-Uniq TAG in a PADI or PADR. */ + if (pppoe_client_ptr -> nx_pppoe_host_uniq) + { + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_host_uniq), &tag_length, NX_MAX_STRING_LENGTH)) + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + + if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= + (4 + tag_length)) + { + + /* Added the Host-Uniq tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, tag_length, pppoe_client_ptr -> nx_pppoe_host_uniq, &index); + } + else + { + + /* Packet too small. */ + nx_packet_release(packet_ptr); + return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); + } + } + + /* If a Host receives AC-Cookie tag, it MUST return the TAG unmodified in the following PADR. */ + if (pppoe_client_ptr -> nx_pppoe_ac_cookie_size) + { + + /* Added the AC-Cookie tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE, pppoe_client_ptr -> nx_pppoe_ac_cookie_size, pppoe_client_ptr -> nx_pppoe_ac_cookie, &index); + } + + /* If either the Host or Access Concentrator receives Relay-Session-Id TAG they MUST include it unmodified in any discovery packet they send as a response. */ + if (pppoe_client_ptr -> nx_pppoe_relay_session_id_size) + { + + /* Added the Host-Uniq tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, pppoe_client_ptr -> nx_pppoe_relay_session_id_size, pppoe_client_ptr -> nx_pppoe_relay_session_id, &index); + } + } + else if (code == NX_PPPOE_CLIENT_CODE_PADT) + { + + /* If either the Host or Access Concentrator receives Relay-Session-Id TAG they MUST include it unmodified in any discovery packet they send as a response. */ + if (pppoe_client_ptr -> nx_pppoe_relay_session_id_size) + { + + /* Added the Host-Uniq tag. */ + _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, pppoe_client_ptr -> nx_pppoe_relay_session_id_size, pppoe_client_ptr -> nx_pppoe_relay_session_id, &index); + } + } + + /* Add the PPPoE header. */ + /* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | VER | TYPE | CODE | SESSION_ID | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | LENGTH | payload + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add version and type. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1, NX_PPPOE_CLIENT_VERSION_TYPE); + + /* Add code. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1, code); + + /* Add the Session id. */ + if (code == NX_PPPOE_CLIENT_CODE_PADT) + { + + /* Add session id. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id); + } + else + { + + /* Add session id. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, 0); + } + + /* Add length. */ + _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2, (index - NX_PPPOE_CLIENT_OFFSET_PAYLOAD)); + + /* Update the append pointer and length. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; + packet_ptr -> nx_packet_length = index; + + /* Send PPPoE session packet. */ + _nx_pppoe_client_packet_send(pppoe_client_ptr, packet_ptr, NX_LINK_PPPOE_DISCOVERY_SEND); + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a PPPoE packet to the appropriate link driver. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_client_ptr Pointer to PPPoE control block*/ +/* client_session_ptr Pointer to Client Session */ +/* packet_ptr Pointer to packet to send */ +/* command Driver command */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ +/* _nx_pppoe_client_session_send Send PPPoE Session packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, UINT command) +{ + +NX_IP_DRIVER driver_request; + + + /* Initialize the driver request. */ + driver_request.nx_ip_driver_command = command; + driver_request.nx_ip_driver_ptr = pppoe_client_ptr -> nx_pppoe_ip_ptr; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = pppoe_client_ptr -> nx_pppoe_interface_ptr; + + /* Check if have the server address. */ + if ((pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw) || + (pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw)) + { + + /* Set the destination address as server address. */ + driver_request.nx_ip_driver_physical_address_msw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw; + driver_request.nx_ip_driver_physical_address_lsw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw; + } + else + { + + /* Set the destination address as boradcast address. */ + driver_request.nx_ip_driver_physical_address_msw = 0x0000FFFF; + driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFF; + } + + /* Sendout the PPPoE packet. */ + (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_data_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the datas of PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ +/* _nx_pppoe_client_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* _nx_pppoe_client_session_packet_process */ +/* Process PPPoE Session packet */ +/* _nx_pppoe_client_tag_process Process PPPoE TAGs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_pppoe_client_data_get(UCHAR *data, UINT size) +{ + +ULONG value = 0; + + + /* Process the data retrieval request. */ + while (size-- > 0) + { + + /* Build return value. */ + value = (value << 8) | *data++; + } + + /* Return value. */ + return(value); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_data_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the datas into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* value Value to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ +/* _nx_pppoe_client_session_send Send PPPoE Session packet */ +/* _nx_pppoe_client_tag_string_add Add PPPoE string TAG */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_data_add(UCHAR *data, UINT size, ULONG value) +{ + + /* Make sure that data is left justified. */ + switch (size) + { + + case 1: + + value <<= 24; + break; + + case 2: + + value <<= 16; + break; + + case 3: + + value <<= 8; + break; + + default: + break; + } + + /* Store the value. */ + while (size-- > 0) + { + + *data = (UCHAR) ((value >> 24) & 0xff); + data++; + value <<= 8; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_string_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the string into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* dest Pointer to destination buffer */ +/* source Pointer to source buffer */ +/* size Number of bytes to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_tag_string_add Add PPPoE string TAG */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_string_add(UCHAR *dest, UCHAR *source, UINT size) +{ + + /* Loop to copy all bytes. */ + while (size-- > 0) + { + + /* Copy a byte. */ + *dest++ = *source++; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_tag_string_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the TAG with string into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data_ptr Pointer to data buffer */ +/* tag_type Type of TAG */ +/* tag_length Length of TAG */ +/* tag_value_string String value of TAG to add */ +/* index Location into data buffer */ +/* to write data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_client_data_add Add PPPoE data */ +/* _nx_pppoe_client_string_add Add PPPoE string data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_client_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index) +{ + + /* Add the tag type. */ + _nx_pppoe_client_data_add(data_ptr + (*index), 2, tag_type); + (*index) += 2; + + /* Add the tag length. */ + _nx_pppoe_client_data_add(data_ptr + (*index), 2, tag_length); + (*index) += 2; + + /* Add the tag value string. */ + _nx_pppoe_client_string_add(data_ptr + (*index), tag_value_string, tag_length); + (*index) += tag_length; + + /* Return a successful completion. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function cleans up the PPPoE session. */ +/* */ +/* INPUT */ +/* */ +/* client_session_ptr Pointer to Client Session */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_client_session_terminate Terminate the PPPoE session */ +/* _nx_pppoe_client_session_packet_process */ +/* Process PPPoE Session packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_client_session_cleanup(NX_PPPOE_CLIENT *client_ptr) +{ + + /* Cleanup the state. */ + client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_INITIAL; + + /* Ceanup the tags. */ + client_ptr -> nx_pppoe_ac_name_size = 0; + client_ptr -> nx_pppoe_ac_cookie_size = 0; + client_ptr -> nx_pppoe_relay_session_id_size = 0; + + /* Cleanup the server information. */ + client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id = NX_NULL; + client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw = NX_NULL; + client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw = NX_NULL; + + /* Return success. */ + return(NX_PPPOE_CLIENT_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_thread_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends a thread on a PPPoE Session connect service */ +/* */ +/* INPUT */ +/* */ +/* suspension_list_head Pointer to the suspension list*/ +/* mutex_ptr Pointer to mutex to release */ +/* suspend_cleanup Suspension cleanup routine */ +/* wait_option Optional timeout value */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_put Release protection */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_session_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), + NX_PPPOE_CLIENT *pppoe_client_ptr, TX_MUTEX *mutex_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup suspension list. */ + if (*suspension_list_head) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = *suspension_list_head; + thread_ptr -> tx_thread_suspended_previous = (*suspension_list_head) -> tx_thread_suspended_previous; + ((*suspension_list_head) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr; + (*suspension_list_head) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + *suspension_list_head = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = suspend_cleanup; + + /* Setup cleanup information, i.e. this pool control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)pppoe_client_ptr; + + /* Set the state to suspended. */ + thread_ptr -> tx_thread_state = TX_TCP_IP; + + /* Set the suspending flag. */ + thread_ptr -> tx_thread_suspending = TX_TRUE; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Save the timeout value. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + + /* Restore interrupts. */ + TX_RESTORE + + /* Release protection. */ + tx_mutex_put(mutex_ptr); + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_thread_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes a thread suspended on a PPPoE Client session */ +/* connect service. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to resume */ +/* status Return status */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_client_session_thread_resume(TX_THREAD **suspension_list_head, UINT status) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the thread pointer. */ + thread_ptr = *suspension_list_head; + + /* Determine if there still is a thread suspended. */ + if (thread_ptr) + { + + /* Determine if there are anymore threads on the suspension list. */ + if (thread_ptr == thread_ptr -> tx_thread_suspended_next) + { + + /* Only this thread is on the suspension list. Simply set the + list head to NULL to reflect an empty suspension list. */ + *suspension_list_head = TX_NULL; + } + else + { + + /* More than one thread is on the suspension list, we need to + adjust the link pointers and move the next entry to the + front of the list. */ + *suspension_list_head = thread_ptr -> tx_thread_suspended_next; + + /* Update the links of the adjacent threads. */ + (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = + thread_ptr -> tx_thread_suspended_previous; + (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr -> tx_thread_suspended_next; + } + + /* Prepare for resumption of the thread. */ + + /* Clear cleanup routine to avoid timeout. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = status; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* Nothing was suspended. Simply restore interrupts. */ + TX_RESTORE + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_client_session_connect_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes PPPoE connect timeout and thread terminate */ +/* actions that require the PPPoE Client data structures to be cleaned */ +/* up. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to suspended thread's */ +/* control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flag */ +/* _tx_thread_system_resume Resume thread service */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_client_session_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PPPOE_CLIENT *pppoe_client_ptr; /* Working PPPoE Client pointer */ + + NX_CLEANUP_EXTENSION + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup pointer to PPPoE Client control block. */ + pppoe_client_ptr = (NX_PPPOE_CLIENT *)thread_ptr -> tx_thread_suspend_control_block; + + /* Determine if the PPPoE Client pointer is valid. */ + if ((!pppoe_client_ptr) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) + { + + /* Restore interrupts. */ + TX_RESTORE + + return; + } + + /* Determine if the cleanup is still required. */ + if (!(thread_ptr -> tx_thread_suspend_cleanup)) + { + + /* Restore interrupts. */ + TX_RESTORE + + return; + } + + /* Determine if the caller is an ISR or the system timer thread. */ +#ifndef TX_TIMER_PROCESS_IN_ISR + if ((TX_THREAD_GET_SYSTEM_STATE()) || (_tx_thread_current_ptr == &_tx_timer_thread)) +#else + if (TX_THREAD_GET_SYSTEM_STATE()) +#endif + { + + /* Yes, defer the processing to the PPPoE Client thread. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Yes, we still have thread suspension! */ + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Clear the suspension pointer. */ + pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread = NX_NULL; + + /* Cleanup the PPPoE session. */ + _nx_pppoe_client_session_cleanup(pppoe_client_ptr); + + /* Now we need to determine if this cleanup is from a terminate, timeout, + or from a wait abort. */ + if (thread_ptr -> tx_thread_state == TX_TCP_IP) + { + + /* Thread still suspended on the PPPoE Client. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume the thread! Check for preemption even though we are executing + from the system timer thread right now which normally executes at the + highest priority. */ + _tx_thread_system_resume(thread_ptr); + + /* Finished, just return. */ + return; + } + } + + /* Restore interrupts. */ + TX_RESTORE +} +#endif /* NX_DISABLE_IPV4 */ + diff --git a/addons/pppoe/nx_pppoe_client.h b/addons/pppoe/nx_pppoe_client.h new file mode 100644 index 00000000..170e69a4 --- /dev/null +++ b/addons/pppoe/nx_pppoe_client.h @@ -0,0 +1,352 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** PPP Over Ethernet (PPPoE) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_pppoe_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX PPP Over Ethernet (PPPoE) Client */ +/* componet, including all data types and external references. It is */ +/* assumed that nx_api.h and nx_port.h have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PPPOE_CLIENT_H +#define NX_PPPOE_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Note: Prerequisite for using PPPoE. + Redefine NX_PHYSICAL_HEADER to 24 to ensure enough space for filling in physical header. + Physical header:14(Ethernet header) + 6(PPPoE header) + 2(PPP header) + 2(four-byte aligment). */ + +/* Define the Driver command for PPPoE packet. */ +#ifndef NX_LINK_PPPOE_DISCOVERY_SEND +#define NX_LINK_PPPOE_DISCOVERY_SEND 51 +#endif +#ifndef NX_LINK_PPPOE_SESSION_SEND +#define NX_LINK_PPPOE_SESSION_SEND 52 +#endif + +/* Define the PPPoE Client ID. */ +#define NX_PPPOE_CLIENT_ID 0x504F4543UL + +/* If the driver is not initialized in other module, enable the feature to initialize the driver in PPPoE module . */ +/* +#define NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE +*/ + +/* Define the PPPoE Thread time slice. */ +#ifndef NX_PPPOE_CLIENT_THREAD_TIME_SLICE +#define NX_PPPOE_CLIENT_THREAD_TIME_SLICE TX_NO_TIME_SLICE +#endif + +/* Define the init timeout for PADI. */ +#ifndef NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT +#define NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT 1 +#endif + +/* Define the maximum number for PADI. */ +#ifndef NX_PPPOE_CLIENT_PADI_COUNT +#define NX_PPPOE_CLIENT_PADI_COUNT 4 +#endif + +/* Define the init timeout for PADR. */ +#ifndef NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT +#define NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT 1 +#endif + +/* Define the maximum number for PADR. */ +#ifndef NX_PPPOE_CLIENT_PADR_COUNT +#define NX_PPPOE_CLIENT_PADR_COUNT 4 +#endif + +/* Define the size of pppoe AC-Name. */ +#ifndef NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE +#define NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE 32 +#endif + +/* Define the size of pppoe AC-Cookie. */ +#ifndef NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE +#define NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE 32 +#endif + +/* Define the size of pppoe Relay-Session-Id. */ +#ifndef NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE +#define NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE 12 +#endif + +/* Define the minimum size of packet payload to avoid packet chained. Maximum Payload Size of Ethernet(1500) + Ethernet Header + CRC + Four-byte alignment. */ + +#ifndef NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE +#define NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE 1520 +#endif + +/* Define PPPoE ethernet header size. */ +#define NX_PPPOE_CLIENT_ETHER_HEADER_SIZE 14 + +/* Define PPPoE ethernet types. */ +#define NX_PPPOE_CLIENT_ETHER_TYPE_DISCOVERY 0x8863 +#define NX_PPPOE_CLIENT_ETHER_TYPE_SESSION 0x8864 + +/* Define PPPoE version and type. */ +#define NX_PPPOE_CLIENT_VERSION_TYPE 0x11 /* Version 1, Type 1. */ + +/* Define PPPoE codes. */ +#define NX_PPPOE_CLIENT_CODE_ZERO 0x00 +#define NX_PPPOE_CLIENT_CODE_PADI 0x09 +#define NX_PPPOE_CLIENT_CODE_PADO 0x07 +#define NX_PPPOE_CLIENT_CODE_PADR 0x19 +#define NX_PPPOE_CLIENT_CODE_PADS 0x65 +#define NX_PPPOE_CLIENT_CODE_PADT 0xa7 + +/* Define the PPPoE Area Offsets. */ +#define NX_PPPOE_CLIENT_OFFSET_VER_TYPE 0 /* 1 byte, version + type: 0x11 */ +#define NX_PPPOE_CLIENT_OFFSET_CODE 1 /* 1 byte, code: Discovery or Session */ +#define NX_PPPOE_CLIENT_OFFSET_SESSION_ID 2 /* 2 bytes, session id: unique session identifieer */ +#define NX_PPPOE_CLIENT_OFFSET_LENGTH 4 /* 2 bytes, length: the length of PPPoE payload */ +#define NX_PPPOE_CLIENT_OFFSET_PAYLOAD 6 /* variable, payload */ + +/* Define the PPPoE Tag Types. */ +#define NX_PPPOE_CLIENT_TAG_TYPE_END_OF_LIST 0x0000 +#define NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME 0x0101 +#define NX_PPPOE_CLIENT_TAG_TYPE_AC_NAME 0x0102 +#define NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ 0x0103 +#define NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE 0x0104 +#define NX_PPPOE_CLIENT_TAG_TYPE_VENDOR_SPECIFIC 0x0105 +#define NX_PPPOE_CLIENT_TAG_TYPE_RELAY_SESSION_ID 0x0110 +#define NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME_ERROR 0x0201 +#define NX_PPPOE_CLIENT_TAG_TYPE_AC_SYSTEM_ERROR 0x0202 +#define NX_PPPOE_CLIENT_TAG_TYPE_GENERIC_ERROR 0x0203 + +/* Define the PPPoE Error flags. */ +#define NX_PPPOE_CLIENT_ERROR_SERVICE_NAME ((ULONG) 0x00000001) /* Service Name Error. */ +#define NX_PPPOE_CLIENT_ERROR_AC_SYSTEM ((ULONG) 0x00000002) /* AC-System Error */ +#define NX_PPPOE_CLIENT_ERROR_GENERIC ((ULONG) 0x00000004) /* Generic Error */ + +/* Define event flags for PPPoE thread control. */ +#define NX_PPPOE_CLIENT_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags */ +#define NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT ((ULONG) 0x00000001) /* PPPoE Client receive packet event */ +#define NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT ((ULONG) 0x00000002) /* PPPoE CLient timer Periodic event */ +#define NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT ((ULONG) 0x00000004) /* PPPoE Client Session cleanup event */ + +/* Define PPPoE Client state. */ +#define NX_PPPOE_CLIENT_STATE_INITIAL 0 +#define NX_PPPOE_CLIENT_STATE_PADI_SENT 1 +#define NX_PPPOE_CLIENT_STATE_PADR_SENT 2 +#define NX_PPPOE_CLIENT_STATE_ESTABLISHED 3 + +/* Define error codes from PPPoE Server operation. */ +#define NX_PPPOE_CLIENT_SUCCESS 0x00 /* Success */ +#define NX_PPPOE_CLIENT_PTR_ERROR 0xD1 /* Invalid input pointers */ +#define NX_PPPOE_CLIENT_INVALID_INTERFACE 0xD2 /* Invalid interface */ +#define NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR 0xD3 /* Invalid payload size of packet */ +#define NX_PPPOE_CLIENT_MEMORY_SIZE_ERROR 0xD4 /* Invalid memory size */ +#define NX_PPPOE_CLIENT_PRIORITY_ERROR 0xD5 /* Invalid priority */ +#define NX_PPPOE_CLIENT_NOT_ENABLED 0xD6 /* PPPoE is not enabled */ +#define NX_PPPOE_CLIENT_INVALID_SESSION 0xD7 /* Invalid Session */ +#define NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED 0xD8 /* PPPoE Session is not established */ +#define NX_PPPOE_CLIENT_SERVICE_NAME_ERROR 0xD9 /* Service name error */ +#define NX_PPPOE_CLIENT_AC_NAME_ERROR 0xDA /* AC Name error */ +#define NX_PPPOE_CLIENT_CLIENT_SESSION_FULL 0xDB /* Client Session full */ +#define NX_PPPOE_CLIENT_CLIENT_SESSION_NOT_FOUND 0xDC /* Not found the client session */ +#define NX_PPPOE_CLIENT_HOST_UNIQ_CACHE_ERROR 0xDD /* The cache is not enough to record the Host Uniq */ +#define NX_PPPOE_CLIENT_RELAY_SESSION_ID_CACHE_ERROR 0xDF /* The cache is not enough to record Relay Session ID*/ + + +/* Define the PPPoE Server Session structure containing the session id and physical address. */ + +typedef struct NX_PPPOE_SERVER_SESSION_STRUCT +{ + + USHORT nx_pppoe_session_id; + USHORT reserved; + ULONG nx_pppoe_physical_address_msw; + ULONG nx_pppoe_physical_address_lsw; +} NX_PPPOE_SERVER_SESSION; + + +/* Define the main PPPoE Server data structure. */ + +typedef struct NX_PPPOE_CLIENT_STRUCT +{ + + ULONG nx_pppoe_id; + UCHAR *nx_pppoe_name; + NX_IP *nx_pppoe_ip_ptr; + NX_INTERFACE *nx_pppoe_interface_ptr; + NX_PACKET_POOL *nx_pppoe_packet_pool_ptr; + TX_EVENT_FLAGS_GROUP nx_pppoe_events; + TX_THREAD nx_pppoe_thread; + TX_TIMER nx_pppoe_timer; + NX_PACKET *nx_pppoe_deferred_received_packet_head, + *nx_pppoe_deferred_received_packet_tail; + UINT nx_pppoe_state; + NX_PPPOE_SERVER_SESSION nx_pppoe_server_session; + UCHAR *nx_pppoe_service_name; + UCHAR *nx_pppoe_host_uniq; + UCHAR nx_pppoe_ac_name[NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE]; + UINT nx_pppoe_ac_name_size; + UCHAR nx_pppoe_ac_cookie[NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE]; + UINT nx_pppoe_ac_cookie_size; + UCHAR nx_pppoe_relay_session_id[NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE]; + UINT nx_pppoe_relay_session_id_size; + UINT nx_pppoe_error_flag; + + /* Define the retransmit timeout and count for PADI and PADR. */ + UINT nx_pppoe_rtr_timeout; + UINT nx_pppoe_rtr_count; + + /* Define the Link Driver entry point. */ + VOID (*nx_pppoe_link_driver_entry)(struct NX_IP_DRIVER_STRUCT *); + + /* Define the function to receive PPPoE packet. */ + VOID (*nx_pppoe_packet_receive)(NX_PACKET *packet_ptr); + + /* Define the PPPoE session connect suspension pointer that contains the pointer to the + thread suspended attempting to establish a PPPoE session connection. */ + TX_THREAD *nx_pppoe_session_connect_suspended_thread; + +} NX_PPPOE_CLIENT; + + +#ifndef NX_PPPOE_CLIENT_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_pppoe_client_create _nx_pppoe_client_create +#define nx_pppoe_client_delete _nx_pppoe_client_delete +#define nx_pppoe_client_host_uniq_set _nx_pppoe_client_host_uniq_set +#define nx_pppoe_client_host_uniq_set_extended _nx_pppoe_client_host_uniq_set_extended +#define nx_pppoe_client_service_name_set _nx_pppoe_client_service_name_set +#define nx_pppoe_client_service_name_set_extended _nx_pppoe_client_service_name_set_extended +#define nx_pppoe_client_session_connect _nx_pppoe_client_session_connect +#define nx_pppoe_client_session_packet_send _nx_pppoe_client_session_packet_send +#define nx_pppoe_client_session_terminate _nx_pppoe_client_session_terminate +#define nx_pppoe_client_session_get _nx_pppoe_client_session_get + +#else + +/* Services with error checking. */ + +#define nx_pppoe_client_create _nxe_pppoe_client_create +#define nx_pppoe_client_delete _nxe_pppoe_client_delete +#define nx_pppoe_client_host_uniq_set _nxe_pppoe_client_host_uniq_set +#define nx_pppoe_client_host_uniq_set_extended _nxe_pppoe_client_host_uniq_set_extended +#define nx_pppoe_client_service_name_set _nxe_pppoe_client_service_name_set +#define nx_pppoe_client_service_name_set_extended _nxe_pppoe_client_service_name_set_extended +#define nx_pppoe_client_session_connect _nxe_pppoe_client_session_connect +#define nx_pppoe_client_session_packet_send _nxe_pppoe_client_session_packet_send +#define nx_pppoe_client_session_terminate _nxe_pppoe_client_session_terminate +#define nx_pppoe_client_session_get _nxe_pppoe_client_session_get + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); +UINT nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); +UINT nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); +UINT nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); +UINT nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); +UINT nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); +UINT nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); +UINT nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); +VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr); + +#else + +UINT _nxe_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); +UINT _nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); +UINT _nxe_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT _nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT _nxe_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); +UINT _nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); +UINT _nxe_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); +UINT _nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); +UINT _nxe_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); +UINT _nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); +UINT _nxe_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); +UINT _nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); +UINT _nxe_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); +UINT _nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); +UINT _nxe_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); +UINT _nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); +UINT _nxe_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT _nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); +UINT _nxe_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); +UINT _nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_server_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); +VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr); + +#endif /* NX_PPPOE_CLIENT_SOURCE_CODE */ + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_PPP_CLIENT_H */ diff --git a/addons/pppoe/nx_pppoe_server.c b/addons/pppoe/nx_pppoe_server.c new file mode 100644 index 00000000..918f1986 --- /dev/null +++ b/addons/pppoe/nx_pppoe_server.c @@ -0,0 +1,4408 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** PPP Over Ethernet (PPPoE) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_PPPOE_SERVER_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#ifndef NX_DISABLE_IPV4 +#include "nx_ip.h" +#include "nx_pppoe_server.h" +#include "nx_packet.h" + +/* Define the PPPoE created list head pointer and count. */ +NX_PPPOE_SERVER *_nx_pppoe_server_created_ptr = NX_NULL; + + +/* Define internal PPPoE services. */ + +static VOID _nx_pppoe_server_thread_entry(ULONG pppoe_server_ptr_value); +static VOID _nx_pppoe_server_packet_receive(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr); +static VOID _nx_pppoe_server_discovery_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, UINT is_broadcast); +static VOID _nx_pppoe_server_session_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw); +static UINT _nx_pppoe_server_discovery_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code); +static VOID _nx_pppoe_server_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, NX_PACKET *packet_ptr, UINT command); +static UINT _nx_pppoe_server_tag_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code, UCHAR *tag_ptr, ULONG length); +static ULONG _nx_pppoe_server_data_get(UCHAR *data, UINT size); +static VOID _nx_pppoe_server_data_add(UCHAR *data, UINT size, ULONG value); +static VOID _nx_pppoe_server_string_add(UCHAR *dest, UCHAR *source, UINT size); +static UINT _nx_pppoe_server_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index); +static UINT _nx_pppoe_server_session_find(NX_PPPOE_SERVER *pppoe_server_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, + ULONG session_id, UINT *session_index, NX_PPPOE_CLIENT_SESSION **client_session_ptr); +static UINT _nx_pppoe_server_session_cleanup(NX_PPPOE_CLIENT_SESSION *client_session_ptr); + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +static UCHAR *nx_pppoe_service_name[1]; +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server instance create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* name Name of this PPPoE instance */ +/* ip_ptr Pointer to IP control block */ +/* interface_index IP Interface Index */ +/* pppoe_link_driver User supplied link driver */ +/* pool_ptr packet pool */ +/* stack_ptr Pointer stack area for PPPoE */ +/* stack_size Size of PPPoE stack area */ +/* priority Priority of PPPoE thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_create Actual PPPoE instance create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT priority) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id == NX_PPPOE_SERVER_ID) || + (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (pppoe_link_driver == NX_NULL) || (pool_ptr == NX_NULL) || + (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || + (stack_ptr == NX_NULL)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check for invalid interface ID */ + if(interface_index >= NX_MAX_PHYSICAL_INTERFACES) + return(NX_PPPOE_SERVER_INVALID_INTERFACE); + + /* Check for interface being valid. */ + if(!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) + return(NX_PPPOE_SERVER_INVALID_INTERFACE); + + /* Check for payload size of packet pool. */ + if (pool_ptr -> nx_packet_pool_payload_size < NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE) + return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); + + /* Check for a memory size error. */ + if (stack_size < TX_MINIMUM_STACK) + return(NX_PPPOE_SERVER_MEMORY_SIZE_ERROR); + + /* Check the priority specified. */ + if (priority >= TX_MAX_PRIORITIES) + return(NX_PPPOE_SERVER_PRIORITY_ERROR); + + /* Call actual PPPoE server instance create function. */ + status = _nx_pppoe_server_create(pppoe_server_ptr, name, ip_ptr, interface_index, + pppoe_link_driver, pool_ptr, stack_ptr, stack_size, priority); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an PPPoE Server instance, including setting */ +/* up all appropriate data structures, creating PPPoE event flag */ +/* object and PPPoE thread. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* name Name of this PPPoE instance */ +/* ip_ptr Pointer to IP control block */ +/* interface_index Interface Index */ +/* pppoe_link_driver User supplied link driver */ +/* pool_ptr packet pool */ +/* stack_ptr Pointer stack area for PPPoE */ +/* stack_size Size of PPPoE stack area */ +/* priority Priority of PPPoE thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create IP event flags */ +/* tx_thread_create Create IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT priority) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Initialize the PPPoE Server control block to zero. */ + memset((void *) pppoe_server_ptr, 0, sizeof(NX_PPPOE_SERVER)); + + /* Save the PPPoE name. */ + pppoe_server_ptr -> nx_pppoe_name = name; + + /* Save the length of PPPoE name to avoid compute strlen repeatedly in _nx_pppoe_server_discovery_send. */ + if (_nx_utility_string_length_check((char *)pppoe_server_ptr -> nx_pppoe_name, + &(pppoe_server_ptr -> nx_pppoe_name_length), + NX_MAX_STRING_LENGTH)) + { + return(NX_PPPOE_SERVER_PTR_ERROR); + } + + /* Save the IP pointer. */ + pppoe_server_ptr -> nx_pppoe_ip_ptr = ip_ptr; + + /* Setup the interface index and interface pointer. */ + pppoe_server_ptr -> nx_pppoe_interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Save the packet pool pointer. */ + pppoe_server_ptr -> nx_pppoe_packet_pool_ptr = pool_ptr; + + /* Setup the enabled flag. */ + pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; + + /* Save the starting Session ID. */ + pppoe_server_ptr -> nx_pppoe_session_id = NX_PPPOE_SERVER_START_SESSION_ID; + + /* Initialize PPPoE notify function pointer */ + pppoe_server_ptr -> nx_pppoe_discover_initiation_notify = NX_NULL; + pppoe_server_ptr -> nx_pppoe_discover_request_notify = NX_NULL; + pppoe_server_ptr -> nx_pppoe_discover_terminate_notify = NX_NULL; + pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm = NX_NULL; + pppoe_server_ptr -> nx_pppoe_data_receive_notify = NX_NULL; + pppoe_server_ptr -> nx_pppoe_data_send_notify = NX_NULL; + + /* Setup the link driver address. */ + pppoe_server_ptr -> nx_pppoe_link_driver_entry = pppoe_link_driver; + + /* Create event flag group to control the PPPoE processing thread. */ + tx_event_flags_create(&(pppoe_server_ptr -> nx_pppoe_events), "PPPoE Server EVENTS") ; + + /* Create the PPPoE processing thread. */ + tx_thread_create(&(pppoe_server_ptr -> nx_pppoe_thread), "PPPoE Server THREAD", _nx_pppoe_server_thread_entry, (ULONG) pppoe_server_ptr, + stack_ptr, stack_size, priority, priority, NX_PPPOE_SERVER_THREAD_TIME_SLICE, TX_DONT_START); + + /* Otherwise, the PPPoE initialization was successful. Place the + PPPoE control block on created PPPoE instance. */ + TX_DISABLE + + /* Load the PPPoE Server ID field in the PPPoE Server control block. */ + pppoe_server_ptr -> nx_pppoe_id = NX_PPPOE_SERVER_ID; + + /* Set the pointer of global variable PPPoE. */ + _nx_pppoe_server_created_ptr = pppoe_server_ptr; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_ac_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server set Access */ +/* Concentrator name function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* ac_name Access Concentrator name */ +/* ac_name_length Length of Name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_ac_name_set Set Access Concentrator */ +/* name function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call Access Concentrator name set function. */ + status = _nx_pppoe_server_ac_name_set(pppoe_server_ptr, ac_name, ac_name_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_ac_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets Access Concentrator name function call. */ +/* */ +/* Note: The string of ac_name must be NULL-terminated and length */ +/* of ac_name matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* ac_name Access Concentrator name */ +/* ac_name_length Length of Name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length) +{ +UINT temp_name_length = 0; + + /* Get the length of ac_name string. */ + if (_nx_utility_string_length_check((CHAR*)ac_name, &temp_name_length, ac_name_length)) + return(NX_SIZE_ERROR); + + /* Check the name length. */ + if (ac_name_length != temp_name_length) + return(NX_SIZE_ERROR); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Save the nx_pppoe_ac_name. */ + pppoe_server_ptr -> nx_pppoe_ac_name = ac_name; + + /* Save the nx_pppoe_ac_name length. */ + pppoe_server_ptr -> nx_pppoe_ac_name_length = ac_name_length; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server instance delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_delete Actual PPPoE instance delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call actual PPPoE server instance delete function. */ + status = _nx_pppoe_server_delete(pppoe_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes an PPPoE Server instance. including deleting */ +/* PPPoE event flag object and PPPoE thread. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_terminate Terminate PPPoE helper thread */ +/* tx_thread_delete Delete PPPoE helper thread */ +/* tx_event_flags_delete Delete PPPoE event flags */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Determine if the caller is the PPPoE thread itself. This is not allowed since + a thread cannot delete itself in ThreadX. */ + if (&pppoe_server_ptr -> nx_pppoe_thread == tx_thread_identify()) + { + + /* Invalid caller of this routine, return an error! */ + return(NX_CALLER_ERROR); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Clear the PPPOE ID to show that it is no longer valid. */ + pppoe_server_ptr -> nx_pppoe_id = 0; + pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; + + /* Clear the created pointer. */ + _nx_pppoe_server_created_ptr = NX_NULL; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Terminate the thread. */ + tx_thread_terminate(&(pppoe_server_ptr -> nx_pppoe_thread)); + + /* Delete the PPPoE thread. */ + tx_thread_delete(&(pppoe_server_ptr -> nx_pppoe_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(pppoe_server_ptr -> nx_pppoe_events)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server enable function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_enable Actual PPPoE enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Make sure the data receive callback function is set before enable. + Setting this function by nx_pppoe_server_callback_notify_set() API. */ + if (pppoe_server_ptr -> nx_pppoe_data_receive_notify == NX_NULL) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call actual PPPoE server instance enable function. */ + status = _nx_pppoe_server_enable(pppoe_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the PPPoE Server feature. */ +/* */ +/* INPUT */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* tx_thread_resume Resume PPPoE helper thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_enable Actual PPPoE enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the enabled flag. */ + pppoe_server_ptr -> nx_pppoe_enabled = NX_TRUE; + + /* Resume the PPPoE server thread. */ + tx_thread_resume(&(pppoe_server_ptr -> nx_pppoe_thread)); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server disable function*/ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_disable Actual PPPoE disable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call actual PPPoE server instance disable function. */ + status = _nx_pppoe_server_disable(pppoe_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the PPPoE Server feature. */ +/* */ +/* INPUT */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* tx_thread_suspend Suspend PPPoE helper thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_enable Actual PPPoE enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr) +{ + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the enabled flag. */ + pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; + + /* Suspend the PPPoE server thread. */ + tx_thread_suspend(&(pppoe_server_ptr -> nx_pppoe_thread)); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_callback_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE Server disable function*/ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* pppoe_discover_initiation_notify Routine to call when discovery*/ +/* initiation data is received */ +/* pppoe_discover_request_notify Routine to call when discovery*/ +/* reques data is received */ +/* pppoe_discover_terminate_notify Routine to call when discovery*/ +/* terminate data is received */ +/* pppoe_discover_terminate_confirm Routine to call when discovery*/ +/* terminate data is sent */ +/* pppoe_data_receive_notify Routine to call when session */ +/* data is received */ +/* pppoe_data_send_notify Routine to call when session */ +/* data is sent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_callback_notify_set Actual PPPoE callback set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, + VOID (* pppoe_discover_initiation_notify)(UINT session_index), + VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), + VOID (* pppoe_discover_terminate_notify)(UINT session_index), + VOID (* pppoe_discover_terminate_confirm)(UINT session_index), + VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), + VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check to see if pppoe_data_receive_notify is set. */ + if (pppoe_data_receive_notify == NX_NULL) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call actual PPPoE service callback notify set function. */ + status = _nx_pppoe_server_callback_notify_set(pppoe_server_ptr, pppoe_discover_initiation_notify, pppoe_discover_request_notify, + pppoe_discover_terminate_notify, pppoe_discover_terminate_confirm, + pppoe_data_receive_notify, pppoe_data_send_notify); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_callback_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the callback notify functions. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* pppoe_discover_initiation_notify Routine to call when discovery*/ +/* initiation data is received */ +/* pppoe_discover_request_notify Routine to call when discovery*/ +/* reques data is received */ +/* pppoe_discover_terminate_notify Routine to call when discovery*/ +/* terminate data is received */ +/* pppoe_discover_terminate_confirm Routine to call when discovery*/ +/* terminate data is sent */ +/* pppoe_data_receive_notify Routine to call when session */ +/* data is received */ +/* pppoe_data_send_notify Routine to call when session */ +/* data is sent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, + VOID (* pppoe_discover_initiation_notify)(UINT session_index), + VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), + VOID (* pppoe_discover_terminate_notify)(UINT session_index), + VOID (* pppoe_discover_terminate_confirm)(UINT session_index), + VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), + VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)) +{ + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Install PPPoE notify function pointer */ + pppoe_server_ptr -> nx_pppoe_discover_initiation_notify = pppoe_discover_initiation_notify; + pppoe_server_ptr -> nx_pppoe_discover_request_notify = pppoe_discover_request_notify; + pppoe_server_ptr -> nx_pppoe_discover_terminate_notify = pppoe_discover_terminate_notify; + pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm = pppoe_discover_terminate_confirm; + pppoe_server_ptr -> nx_pppoe_data_receive_notify = pppoe_data_receive_notify; + pppoe_server_ptr -> nx_pppoe_data_send_notify = pppoe_data_send_notify; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_service_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE service name set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an array service */ +/* names. Each service name */ +/* must be Null-terminated */ +/* string. */ +/* service_name_count The counter of service names */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_service_name_set Actual PPPoE service name set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Call actual PPPoE service name set function. */ + status = _nx_pppoe_server_service_name_set(pppoe_server_ptr, service_name, service_name_count); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_service_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the the PPPoE service name. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* service_name Pointer to an array service */ +/* names. Each service name */ +/* must be Null-terminated */ +/* string. */ +/* service_name_count The counter of service names */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count) +{ + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup service name pointer. */ + pppoe_server_ptr -> nx_pppoe_service_name = service_name; + + /* Setup service name count. */ + pppoe_server_ptr -> nx_pppoe_service_name_count = service_name_count; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_session_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session data send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* data_ptr Session Data pointer */ +/* data_length Length of Session Data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_session_send Actual PPPoE Session data send*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID) || (data_ptr == NX_NULL)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check the service_name_count. */ + if (data_length == 0) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check to see if PPPoE is enabled. */ + if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) + return(NX_PPPOE_SERVER_NOT_ENABLED); + + /* Check for invalid session index. */ + if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return(NX_PPPOE_SERVER_INVALID_SESSION); + + /* Check to see if PPPoE session is established. */ + if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || + (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) + return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); + + /* Call actual PPPoE session send function. */ + status = _nx_pppoe_server_session_send(pppoe_server_ptr, session_index, data_ptr, data_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE Session packet and calls the */ +/* associated driver to send it out on the network. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* data_ptr Session Data pointer */ +/* data_length Length of Session Data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* nx_packet_allocate Allocate a packet for the */ +/* PPPoE Session */ +/* nx_packet_release Release packet to packet pool */ +/* nx_packet_data_append Copies the specified data */ +/* _nx_pppoe_server_data_add Add PPPoE data */ +/* _nx_pppoe_server_packet_send Send out PPPoE packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length) +{ + +NX_PPPOE_CLIENT_SESSION *client_session_ptr; +NX_PACKET *packet_ptr; +UCHAR *work_ptr; +UINT status; + + + /* Allocate a PPPoE packet. */ + status = nx_packet_allocate(pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_PPPOE_SERVER_PACKET_TIMEOUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Obtain the IP internal mutex. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the client session pointer. */ + client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); + + /* Set the work pointer. */ + work_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Added the PPPoE header. */ + /* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | VER | TYPE | CODE | SESSION_ID | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | LENGTH | payload + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add version and type. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); + + /* Add code. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, NX_PPPOE_SERVER_CODE_ZERO); + + /* Add session id. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); + + /* Add length. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, data_length); + + /* Update the pointer to add the payload of PPPoE. */ + packet_ptr -> nx_packet_append_ptr += NX_PPPOE_SERVER_OFFSET_PAYLOAD; + packet_ptr -> nx_packet_length += NX_PPPOE_SERVER_OFFSET_PAYLOAD; + + /* Release the mutex before a blocking call. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Append the data into PPPoE packet. */ + status = nx_packet_data_append(packet_ptr, data_ptr, data_length, pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, NX_PPPOE_SERVER_PACKET_TIMEOUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Relase the packet. */ + nx_packet_release(packet_ptr); + + /* Return status. */ + return(status); + } + + /* Regain obtain the IP internal mutex. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Send PPPoE session packet. */ + _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); + + /* Check the PPPoE send function. */ + if (pppoe_server_ptr -> nx_pppoe_data_send_notify) + { + + /* Call the function to send the data frame. */ + pppoe_server_ptr -> nx_pppoe_data_send_notify(session_index, data_ptr); + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_session_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session packet send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_session_packet_send Actual PPPoE Session data send*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr) +{ + +UINT status; + + /* Check for invalid packet. */ + if (packet_ptr == NX_NULL) + { + return(NX_PPPOE_SERVER_PTR_ERROR); + } + + /* Check for minimum packet length (PPP DATA Header). */ + if (packet_ptr -> nx_packet_length < 2) + { + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); + } + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_SERVER_PTR_ERROR); + } + + /* Check to see if PPPoE is enabled. */ + if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_SERVER_NOT_ENABLED); + } + + /* Check for invalid session index. */ + if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_SERVER_INVALID_SESSION); + } + + /* Check to see if PPPoE session is established. */ + if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || + (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); + } + + /* Call actual PPPoE session packet_send function. */ + status = _nx_pppoe_server_session_packet_send(pppoe_server_ptr, session_index, packet_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE Session packet and calls the */ +/* associated driver to send it out on the network. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* data_ptr Session Data pointer */ +/* data_length Length of Session Data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* nx_packet_release Release packet to packet pool */ +/* nx_packet_data_append Copies the specified data */ +/* _nx_pppoe_server_data_add Add PPPoE data */ +/* _nx_pppoe_server_packet_send Send out PPPoE packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr) +{ + +NX_PPPOE_CLIENT_SESSION *client_session_ptr; +UCHAR *work_ptr; + + + /* Obtain the IP internal mutex. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_PPPOE_SERVER_OFFSET_PAYLOAD) + { + + /* Adjust the packet prepend to remove the PPP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; + + /* Release the packet. */ + nx_packet_transmit_release(packet_ptr); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return error code. */ + return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); + } + + /* Set the client session pointer. */ + client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); + + /* Set the work pointer. */ + packet_ptr -> nx_packet_prepend_ptr -= NX_PPPOE_SERVER_OFFSET_PAYLOAD; + work_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Added the PPPoE header. */ + /* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | VER | TYPE | CODE | SESSION_ID | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | LENGTH | payload + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add version and type. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); + + /* Add code. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, NX_PPPOE_SERVER_CODE_ZERO); + + /* Add session id. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); + + /* Add length. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, packet_ptr -> nx_packet_length); + + /* Update the packet length. */ + packet_ptr -> nx_packet_length += NX_PPPOE_SERVER_OFFSET_PAYLOAD; + + /* Send PPPoE session packet. */ + _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_session_terminate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session terminate */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_session_terminate Actual PPPoE Session terminate*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check to see if PPPoE is enabled. */ + if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) + return(NX_PPPOE_SERVER_NOT_ENABLED); + + /* Check for invalid session index. */ + if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return(NX_PPPOE_SERVER_INVALID_SESSION); + + /* Check to see if PPPoE session is established. */ + if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || + (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) + return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); + + /* Call actual PPPoE session terminate function. */ + status = _nx_pppoe_server_session_terminate(pppoe_server_ptr, session_index); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_terminate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE packet to terminate the session. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index Session index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_server_discovery_send Send out PPPoE packet */ +/* _nx_pppoe_server_session_cleanup Cleanup PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index) +{ + +NX_PPPOE_CLIENT_SESSION *client_session_ptr; +UINT status; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the client session pointer. */ + client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); + + /* Terminate the PPPoE session. */ + status = _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADT); + + /* Check the status. */ + if (status == NX_PPPOE_SERVER_SUCCESS) + { + + /* Cleanup the session. */ + _nx_pppoe_server_session_cleanup(client_session_ptr); + + /* Check the PPPoE terminate confirm function. */ + if (pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm) + { + + /* Call terminate confirm function. */ + pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm(session_index); + } + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_pppoe_server_session_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the PPPoE session get function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index The index of Client Session */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* session_id Session ID */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_session_get Actual PPPoE Session get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return(NX_PPPOE_SERVER_PTR_ERROR); + + /* Check for invalid session index. */ + if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return(NX_PPPOE_SERVER_INVALID_SESSION); + + /* Call actual PPPoE session get function. */ + status = _nx_pppoe_server_session_get(pppoe_server_ptr, session_index, client_mac_msw, client_mac_lsw, session_id); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an PPPoE packet to get the session physical */ +/* address and session id. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* session_index The index of Client Session */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* session_id Session ID */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) +{ + + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check to see if PPPoE session is established. */ + if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || + (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); + } + + /* Yes, get the Client physical address MSW. */ + if (client_mac_msw) + *client_mac_msw = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_physical_address_msw; + + /* Yes, get the Client physical address LSW. */ + if (client_mac_lsw) + *client_mac_lsw = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_physical_address_lsw; + + /* Yes, get the Session ID. */ + if (session_id) + *session_id = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id; + + /* Release the IP internal mutex. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Return status. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + + /**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_packet_deferred_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a packet from the link driver (usually the */ +/* link driver's input ISR) and places it in the deferred receive */ +/* packet queue. This moves the minimal receive packet processing */ +/* from the ISR to the PPPoE helper thread. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for PPPoE thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Check to see if PPPoE instance is created. */ + if (_nx_pppoe_server_created_ptr == NX_NULL) + { + + /* Release the packet. */; + nx_packet_release(packet_ptr); + + return; + } + + /* Check to see if PPPoE is enabled. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) + { + + /* Release the packet. */; + nx_packet_release(packet_ptr); + + return; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if the deferred processing queue is empty. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the queue. */ + (_nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Empty deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the PPPoE helper thread looks at the deferred processing + queue. */ + _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; + _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup PPPoE helper thread to process the PPPoE deferred receive. */ + tx_event_flags_set(&(_nx_pppoe_server_created_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT, TX_OR); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point for each PPPoE's helper thread. */ +/* The PPPoE helper thread is responsible for processing PPPoE packet. */ +/* */ +/* Note that the priority of this function is determined by the PPPoE */ +/* create service. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr_value Pointer to PPPoE control block*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Suspend on event flags that */ +/* are used to signal this */ +/* thread what to do */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_server_packet_receive PPPoE receive packet */ +/* processing */ +/* nx_packet_release Release packet to packet pool */ +/* (pppoe_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_server_thread_entry(ULONG pppoe_server_ptr_value) +{ + +TX_INTERRUPT_SAVE_AREA + +#ifdef NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE +NX_IP_DRIVER driver_request; +#endif +NX_PPPOE_SERVER *pppoe_server_ptr; +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +ULONG pppoe_events; +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +UINT i; +#endif + + + /* Setup the PPPoE pointer. */ + pppoe_server_ptr = (NX_PPPOE_SERVER *) pppoe_server_ptr_value; + + /* Setup the IP pointer. */ + ip_ptr = pppoe_server_ptr -> nx_pppoe_ip_ptr; + + /* Obtain the IP internal mutex before calling the driver. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + +#ifdef NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE + + /* Initialize and enable the hardware for physical interface. */ + + /* Is this a valid interface with a link driver associated with it? */ + if((pppoe_server_ptr -> nx_pppoe_interface_ptr -> nx_interface_valid) && (pppoe_server_ptr -> nx_pppoe_link_driver_entry)) + { + + /* Yes; attach the interface to the device. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_ATTACH; + driver_request.nx_ip_driver_interface = pppoe_server_ptr -> nx_pppoe_interface_ptr; + (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Call the link driver to initialize the hardware. Among other + responsibilities, the driver is required to provide the + Maximum Transfer Unit (MTU) for the physical layer. The MTU + should represent the actual physical layer transfer size + less the physical layer headers and trailers. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_INITIALIZE; + (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Call the link driver again to enable the interface. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ENABLE; + (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); + + /* Indicate to the IP software that IP to physical mapping + is not required. */ + pppoe_server_ptr -> nx_pppoe_interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; + } +#endif + + /* Loop to continue processing incoming bytes. */ + while(NX_FOREVER) + { + + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Pickup IP event flags. */ + tx_event_flags_get(&(pppoe_server_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_ALL_EVENTS, TX_OR_CLEAR, &pppoe_events, NX_WAIT_FOREVER); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Check for PPPoE event. */ + if (pppoe_events & NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT) + { + + /* Loop to process all deferred packet requests. */ + while (pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + pppoe_server_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Discard the chained packets. */ + if (packet_ptr -> nx_packet_next) + { + nx_packet_release(packet_ptr); + continue; + } +#endif + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < NX_PPPOE_SERVER_OFFSET_PAYLOAD) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check the packet interface. */ + if ((packet_ptr -> nx_packet_ip_interface != NX_NULL) && + (packet_ptr -> nx_packet_ip_interface != pppoe_server_ptr -> nx_pppoe_interface_ptr)) + { + nx_packet_release(packet_ptr); + continue; + } + + /* Call the actual PPPoE Server packet receive function. */ + _nx_pppoe_server_packet_receive(pppoe_server_ptr, packet_ptr); + } + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Check for PPPoE Session Receive event. */ + if (pppoe_events & NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT) + { + + for(i = 0; i < NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; i ++) + { + + /* Check if this session is valid. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_valid != NX_TRUE) + continue; + + /* Check if this session is ready to receive the packet. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_packet_receive_stopped == NX_TRUE) + continue; + + /* Check if this session queued the packets. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the flag to stop receive the next packet. */ + pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_packet_receive_stopped = NX_TRUE; + + /* Check the PPPoE receive function. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_data_receive_notify) + { + + /* Call the function to receive the data frame. */ + _nx_pppoe_server_created_ptr -> nx_pppoe_data_receive_notify(i, packet_ptr -> nx_packet_length, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr)); + } + } + } + } +#endif + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a PPPoE packet from the PPPoE deferred */ +/* processing queue. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_server_data_get Get the PPPoE data */ +/* _nx_pppoe_server_discovery_packet_process */ +/* Process discovery packet */ +/* _nx_pppoe_server_session_packet_process */ +/* Process session packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_server_packet_receive(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr) +{ + +UCHAR *ethernet_header_ptr; +ULONG server_mac_msw; +ULONG server_mac_lsw; +ULONG client_mac_msw; +ULONG client_mac_lsw; +UINT ethernet_type; +UINT is_broadcast = NX_FALSE; + + /* Set up UCHAR pointer to ethernet header to extract client hardware address + which we will use as the client's unique identifier. */ + ethernet_header_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_PPPOE_SERVER_ETHER_HEADER_SIZE; + + /* Pickup the MSW and LSW of the destination MAC address. */ + server_mac_msw = (((ULONG) ethernet_header_ptr[0]) << 8) | ((ULONG) ethernet_header_ptr[1]); + server_mac_lsw = (((ULONG) ethernet_header_ptr[2]) << 24) | (((ULONG) ethernet_header_ptr[3]) << 16) | + (((ULONG) ethernet_header_ptr[4]) << 8) | ((ULONG) ethernet_header_ptr[5]); + + /* Check the server hardware (mac address) field is filled in. */ + if ((server_mac_msw == 0) && (server_mac_lsw == 0)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Check if it is a broadcast message. */ + if ((server_mac_msw == 0xFFFF) && (server_mac_lsw == 0xFFFFFFFF)) + is_broadcast = NX_TRUE; + + /* Pickup the MSW and LSW of the source MAC address. */ + client_mac_msw = (((ULONG) ethernet_header_ptr[6]) << 8) | ((ULONG) ethernet_header_ptr[7]); + client_mac_lsw = (((ULONG) ethernet_header_ptr[8]) << 24) | (((ULONG) ethernet_header_ptr[9]) << 16) | + (((ULONG) ethernet_header_ptr[10]) << 8) | ((ULONG) ethernet_header_ptr[11]); + + /* Check the client hardware (mac address) field is filled in. */ + if ((client_mac_msw == 0) && (client_mac_lsw == 0)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Get the ethernet type. */ + ethernet_type = _nx_pppoe_server_data_get(ethernet_header_ptr + 12, 2); + + /* Process the packet according to packet type. */ + if(ethernet_type == NX_PPPOE_SERVER_ETHER_TYPE_DISCOVERY) + { + + /* Process the discovery packet. */ + _nx_pppoe_server_discovery_packet_process(pppoe_server_ptr, packet_ptr, client_mac_msw, client_mac_lsw, is_broadcast); + } + else if(ethernet_type == NX_PPPOE_SERVER_ETHER_TYPE_SESSION) + { + + /* Session Stage, all Ethernet packets are unicast. */ + if (is_broadcast == NX_TRUE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Process the session packet. */ + _nx_pppoe_server_session_packet_process(pppoe_server_ptr, packet_ptr, client_mac_msw, client_mac_lsw); + } + else + { + + /* Relase the packet. */ + nx_packet_release(packet_ptr); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_discovery_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming discovery packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* is_broadcast Broadcast flag */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_server_data_get Get the PPPoE data */ +/* _nx_pppoe_server_tag_process Process PPPoE tags */ +/* _nx_pppoe_server_discovery_send Send discovery packet */ +/* _nx_pppoe_server_session_find Find the PPPoE session */ +/* _nx_pppoe_server_session_cleanup Cleanup the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_pppoe_server_discovery_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, UINT is_broadcast) +{ + +UCHAR *pppoe_header_ptr; +ULONG ver_type; +ULONG code; +ULONG session_id; +ULONG length; +UINT status; +UCHAR *tag_ptr; +UINT session_index = 0; +NX_PPPOE_CLIENT_SESSION *client_session_ptr = NX_NULL; + + + /* Setup the PPPoE header. */ + pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the version and type. */ + ver_type = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1); + + /* Check the version and type. */ + if (ver_type != NX_PPPOE_SERVER_VERSION_TYPE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the code. */ + code = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1); + + /* Check the code. */ + if ((code != NX_PPPOE_SERVER_CODE_PADI) && + (code != NX_PPPOE_SERVER_CODE_PADR) && + (code != NX_PPPOE_SERVER_CODE_PADT)) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* For PADI, the destination address should be broadcast. + For PADR and PART, the destination address should be unicast. */ + if (((code == NX_PPPOE_SERVER_CODE_PADI) && (is_broadcast != NX_TRUE)) || + ((code != NX_PPPOE_SERVER_CODE_PADI) && (is_broadcast == NX_TRUE))) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the session id. */ + session_id = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2); + + /* Check the session id. + Session ID must be zero for PADI and PADR, + Session ID must be not zero for PADT. */ + if (((code != NX_PPPOE_SERVER_CODE_PADT) && (session_id != 0)) || + ((code == NX_PPPOE_SERVER_CODE_PADT) && (session_id == 0))) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Find the PPPoE Session. */ + status = _nx_pppoe_server_session_find(pppoe_server_ptr, client_mac_msw, client_mac_lsw, session_id, &session_index, &client_session_ptr); + + /* Check the status. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the length of tags. */ + length = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2); + + /* Check for valid payload. */ + if (length > packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Set the tag pointer. */ + tag_ptr = pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_PAYLOAD; + + /* Process the tag. */ + status = _nx_pppoe_server_tag_process(pppoe_server_ptr, client_session_ptr, code, tag_ptr, length); + + /* Now we can release the packet. */ + nx_packet_release(packet_ptr); + + /* Check the status. */ + if (status) + { + + /* If the Access Concentrator does not like the Service-Name in the PADR, + then it MUST reply with a PADS containing a TAG of TAG_TYPE Service-Name-Error (and any number of other TAG types). + In this case the SESSION_ID MUST be set to 0x0000. RFC2516, Section5.4, Page6. */ + if ((status == NX_PPPOE_SERVER_SERVICE_NAME_ERROR) && (code == NX_PPPOE_SERVER_CODE_PADR)) + { + + /* Clear the session id. */ + client_session_ptr -> nx_pppoe_session_id = 0; + + /* Send PADS. */ + _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); + } + + /* Cleanup the PPPoE session. */ + _nx_pppoe_server_session_cleanup(client_session_ptr); + + return; + } + + /* Check the code value. */ + if (code == NX_PPPOE_SERVER_CODE_PADI) + { + + /* It is PPPoE Active Discovery Initiation packet. */ + if (pppoe_server_ptr -> nx_pppoe_discover_initiation_notify) + { + + /* Call discover initiation notify function. */ + pppoe_server_ptr -> nx_pppoe_discover_initiation_notify(session_index); + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Send PPPoE Active Discover Offer packet in PppDiscoverCnf(). */ + return; +#endif + } + + /* Send PPPoE Active Discovery Offer packet. */ + _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADO); + } + else if (code == NX_PPPOE_SERVER_CODE_PADR) + { + + /* Generate the unique session id. */ + if (client_session_ptr -> nx_pppoe_session_id == 0) + { + + /* The Session ID should not be zero and 0xFFFF. + RFC2516, Section4, Page4. */ + if ((pppoe_server_ptr -> nx_pppoe_session_id == 0) || + (pppoe_server_ptr -> nx_pppoe_session_id == 0xFFFF)) + pppoe_server_ptr -> nx_pppoe_session_id = 1; + + /* Setup the session id. */ + client_session_ptr -> nx_pppoe_session_id = pppoe_server_ptr -> nx_pppoe_session_id; + + /* Update the session id for next client session. */ + pppoe_server_ptr -> nx_pppoe_session_id++; + } + + /* It is PPPoE Active Discovery Request packet. */ + if (pppoe_server_ptr -> nx_pppoe_discover_request_notify) + { + + /* Call discover reqest notify function. */ + if (client_session_ptr -> nx_pppoe_service_name == NX_NULL) + { + pppoe_server_ptr -> nx_pppoe_discover_request_notify(session_index, 0, NX_NULL); + } + else + { + /* Check service name length. */ + _nx_utility_string_length_check((char*)client_session_ptr -> nx_pppoe_service_name, (UINT *)&length, NX_MAX_STRING_LENGTH); + + pppoe_server_ptr -> nx_pppoe_discover_request_notify(session_index, length, client_session_ptr -> nx_pppoe_service_name); + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Send PPPoE Active Discover Session-confirmation packet in PppOpenCnf(). */ + return; +#endif + } + + /* Send PPPoE Active Discovery Session-confirmation packet. */ + _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); + } + else if (code == NX_PPPOE_SERVER_CODE_PADT) + { + +#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Cleanup the PPPoE session. */ + _nx_pppoe_server_session_cleanup(client_session_ptr); +#endif + + /* It is PPPoE Active Discovery Terminate packet. */ + if (pppoe_server_ptr -> nx_pppoe_discover_terminate_notify) + { + + /* Call discover terminate notify function. */ + pppoe_server_ptr -> nx_pppoe_discover_terminate_notify(session_index); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming session packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* packet_ptr Pointer to packet to receive */ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_server_data_get Get the PPPoE data */ +/* _nx_pppoe_server_session_find Find the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_server_session_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw) +{ + +UCHAR *pppoe_header_ptr; +ULONG ver_type; +ULONG code; +ULONG session_id; +ULONG length; +UINT status; +UINT session_index = 0; +NX_PPPOE_CLIENT_SESSION *client_session_ptr = NX_NULL; + + + /* Setup the PPPoE header. */ + pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the version and type. */ + ver_type = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1); + + /* Check the version and type. */ + if (ver_type != NX_PPPOE_SERVER_VERSION_TYPE) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the code. */ + code = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1); + + /* Check the code. */ + if (code != NX_PPPOE_SERVER_CODE_ZERO) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the session id. */ + session_id = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2); + + /* Check the session id. */ + if (session_id == 0) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Setup the prepend pointer to point the payload of PPPoE. */ + packet_ptr -> nx_packet_prepend_ptr += NX_PPPOE_SERVER_OFFSET_PAYLOAD; + packet_ptr -> nx_packet_length -= NX_PPPOE_SERVER_OFFSET_PAYLOAD; + + /* Look up the PPPoE session by physical address and interface index in Client Records table. */ + status = _nx_pppoe_server_session_find(pppoe_server_ptr, client_mac_msw, client_mac_lsw, session_id, &session_index, &client_session_ptr); + + /* Check the status. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the length of payload. */ + length = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2); + + /* Check for valid payload. */ + if (length > packet_ptr -> nx_packet_length) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Remove the Ethernet padding. */ + if (length < packet_ptr -> nx_packet_length) + { + packet_ptr -> nx_packet_append_ptr -= (packet_ptr -> nx_packet_length - length); + packet_ptr -> nx_packet_length -= (packet_ptr -> nx_packet_length - length); + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + + /* Check to see if the deferred processing queue is empty. */ + if (client_session_ptr -> nx_pppoe_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the queue. */ + (client_session_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + client_session_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + + /* Return. */ + return; + } + else + { + + /* Check the packet receive flag. */ + if (client_session_ptr -> nx_pppoe_packet_receive_stopped == NX_TRUE) + { + + /* Empty deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the PPPoE helper thread looks at the deferred processing queue. */ + client_session_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; + client_session_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Return. */ + return; + } + } + + /* Set the flag to stop receive the next packet. */ + client_session_ptr -> nx_pppoe_packet_receive_stopped = NX_TRUE; +#endif + + /* Check the PPPoE receive function. */ + if (pppoe_server_ptr -> nx_pppoe_data_receive_notify) + { + + /* Call the function to receive the data frame. + Notice: the receive function must release this packet. */ + pppoe_server_ptr -> nx_pppoe_data_receive_notify(session_index, length, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr)); + } + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_discovery_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a PPPoE discovery packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* client_session_ptr Pointer to Client Session */ +/* code PPPoE code */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* nx_packet_allocate Allocate a packet for the */ +/* PPPoE Discovery */ +/* nx_packet_release Release packet to packet pool */ +/* _nx_pppoe_server_data_add Add PPPoE data */ +/* _nx_pppoe_server_tag_string_add Add PPPoE tag */ +/* _nx_pppoe_server_packet_send Send out PPPoE packet */ +/* _nx_pppoe_server_session_find Find the PPPoE session */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_session_terminate Terminate the PPPoE session */ +/* _nx_pppoe_server_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_server_discovery_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code) +{ + +NX_PACKET *packet_ptr; +UCHAR *work_ptr; +UINT status; +UINT index = 0; +UINT tag_length; +UINT service_name_index = 0; +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +UCHAR *service_name_ptr; +#endif + + + /* Release the mutex before a blocking call. */ + tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + /* Allocate a PPPoE packet. */ + status = nx_packet_allocate(pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_PPPOE_SERVER_PACKET_TIMEOUT); + + /* Was the packet allocation successful? */ + if (status != NX_SUCCESS) + { + + /* Return status. */ + return(status); + } + + /* Obtain the IP internal mutex. */ + tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the work pointer. */ + work_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* First skip the PPPoE header. */ + index += NX_PPPOE_SERVER_OFFSET_PAYLOAD; + + /* The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type-length-value) construct and is defined as follows. */ + + /* 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | TAG_TYPE | TAG_LENGTH | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | TAG_VALUE ... + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add the PPPoE tags. */ + if (code == NX_PPPOE_SERVER_CODE_PADO) + { + + /* The PADO packet MUST contain one AC-Name TAG containing the Access Concentrator's name. RFC2516, Section 5.2, Page6. */ + + /* Added the AC-Name tag. */ + if (pppoe_server_ptr -> nx_pppoe_ac_name) + { + + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_AC_NAME, pppoe_server_ptr -> nx_pppoe_ac_name_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_ac_name), &index); + } + else + { + + /* If user does not separately set Access Concentrator name, will use PPPoE server name as Access Concentrator name.*/ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_AC_NAME, pppoe_server_ptr -> nx_pppoe_name_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_name), &index); + } + + /* The PADO packet MUST contain a Service-Name TAG identical to the one in the PADI, + and any number of other Service-Name TAGs indicating other services. RFC2516, Section 5.2, Page6. */ + + /* Added a Service-Name TAG identical to the one in the PADI. */ + if (client_session_ptr -> nx_pppoe_service_name) + { + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Set the service name pointer. */ + service_name_ptr = client_session_ptr -> nx_pppoe_service_name; + + /* Loop to add service name that user configured. */ + while(service_name_index < client_session_ptr -> nx_pppoe_service_name_length) + { + + /* Get the service name. */ + if (_nx_utility_string_length_check((const char *)(service_name_ptr), &tag_length, NX_MAX_STRING_LENGTH)) + { + nx_packet_release(packet_ptr); + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, service_name_ptr, &index); + + /* Update the service name pointer, length + null-terminated. */ + service_name_ptr += (tag_length + 1); + service_name_index += (tag_length + 1); + } +#else + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(client_session_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) + { + nx_packet_release(packet_ptr); + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, client_session_ptr -> nx_pppoe_service_name, &index); +#endif + } + else + { + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); + } + +#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Add any number of other Service-Name TAGs indicating other services. */ + if (pppoe_server_ptr -> nx_pppoe_service_name_count) + { + + /* The PADO packet can contain any number of Service-Name TAGs. */ + for (service_name_index = 0; service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count; service_name_index ++) + { + + /* Check if this Service-Name has been added. */ + if (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index] == client_session_ptr -> nx_pppoe_service_name) + continue; + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), &tag_length, NX_MAX_STRING_LENGTH)) + { + nx_packet_release(packet_ptr); + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), &index); + } + } +#endif + + /* If the Access Concentrator receives this Host-Uniq TAG, it MUST include the TAG unmodified in associated PADO or PADS response. + RFC2516, Appendix A, Host-Uniq. */ + if (client_session_ptr -> nx_pppoe_host_uniq_size) + { + + /* Added the Host-Uniq. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ, client_session_ptr -> nx_pppoe_host_uniq_size, client_session_ptr -> nx_pppoe_host_uniq, &index); + } + + /* If either the Host or Access Concentrator receives this Relay-Session-Id TAG, they MUST include it unmodified in any discovery packet they send as a response. + RFC2516, Appendix A, Relay-Session-Id. */ + if (client_session_ptr -> nx_pppoe_relay_session_id_size) + { + + /* Added the Host-Uniq. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID, client_session_ptr -> nx_pppoe_relay_session_id_size, client_session_ptr -> nx_pppoe_relay_session_id, &index); + } + } + else if (code == NX_PPPOE_SERVER_CODE_PADS) + { + + /* Check the error. */ + if (client_session_ptr -> nx_pppoe_error_flag & NX_PPPOE_SERVER_ERROR_SERVICE_NAME) + { + + /* Added Service-Name-Error tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME_ERROR, 0, NX_NULL, &index); + } + + /* The PADS packet MUST contain one exactly one TAG of TAG_TYPE Service-Name. RFC2516, Section 5.4, Page6 */ + + /* Check the service name. */ + if (client_session_ptr -> nx_pppoe_service_name) + { + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((char *)(client_session_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) + { + nx_packet_release(packet_ptr); + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, client_session_ptr -> nx_pppoe_service_name, &index); + } + else + { + + /* Added the Service-Name tag. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); + } + + /* If the Access Concentrator receives this Host-Uniq TAG, it MUST include the TAG unmodified in associated PADO or PADS response. + RFC2516, Appendix A, Host-Uniq. */ + if (client_session_ptr -> nx_pppoe_host_uniq_size) + { + + /* Added the Host-Uniq. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ, client_session_ptr -> nx_pppoe_host_uniq_size, client_session_ptr -> nx_pppoe_host_uniq, &index); + } + + /* If either the Host or Access Concentrator receives this Relay-Session-Id TAG, they MUST include it unmodified in any discovery packet they send as a response. + RFC2516, Appendix A, Relay-Session-Id. */ + if (client_session_ptr -> nx_pppoe_relay_session_id_size) + { + + /* Added the Host-Uniq. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID, client_session_ptr -> nx_pppoe_relay_session_id_size, client_session_ptr -> nx_pppoe_relay_session_id, &index); + } + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + else if (code == NX_PPPOE_SERVER_CODE_PADT) + { + + /* Check the Generic-Error. */ + if (client_session_ptr -> nx_pppoe_generic_error) + { + + /* Calculate the Generic-Error string length. */ + if (_nx_utility_string_length_check((const char *)(client_session_ptr -> nx_pppoe_generic_error), &tag_length, NX_MAX_STRING_LENGTH)) + { + nx_packet_release(packet_ptr); + return(NX_SIZE_ERROR); + } + + /* Added the Generic-Error. */ + _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_GENERIC_ERROR, tag_length, client_session_ptr -> nx_pppoe_generic_error, &index); + } + } +#endif + + /* Add the PPPoE header. */ + /* + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | VER | TYPE | CODE | SESSION_ID | + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * | LENGTH | payload + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + */ + + /* Add version and type. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); + + /* Add code. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, code); + + /* Add the Session id. */ + if (code == NX_PPPOE_SERVER_CODE_PADO) + { + + /* Add session id. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, 0); + } + else + { + + /* Add session id. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); + } + + /* Add length. */ + _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, (index - NX_PPPOE_SERVER_OFFSET_PAYLOAD)); + + /* Update the append pointer and length. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; + packet_ptr -> nx_packet_length = index; + + /* Send PPPoE session packet. */ + _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_DISCOVERY_SEND); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a PPPoE packet to the appropriate link driver. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* client_session_ptr Pointer to Client Session */ +/* packet_ptr Pointer to packet to send */ +/* command Driver command */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ +/* _nx_pppoe_server_session_send Send PPPoE Session packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_server_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, NX_PACKET *packet_ptr, UINT command) +{ + +NX_IP_DRIVER driver_request; + + + /* Initialize the driver request. */ + driver_request.nx_ip_driver_ptr = pppoe_server_ptr -> nx_pppoe_ip_ptr; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_interface = pppoe_server_ptr -> nx_pppoe_interface_ptr; + driver_request.nx_ip_driver_physical_address_msw = client_session_ptr -> nx_pppoe_physical_address_msw; + driver_request.nx_ip_driver_physical_address_lsw = client_session_ptr -> nx_pppoe_physical_address_lsw; + driver_request.nx_ip_driver_command = command; + + /* Sendout the PPPoE packet. */ + (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_tag_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes tags of PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* client_session_ptr Pointer to Client Session */ +/* code PPPoE code */ +/* tag_ptr Pointer to PPPoE tag */ +/* length Length of PPPoe tags */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_data_get Get the PPPoE data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_server_tag_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code, UCHAR *tag_ptr, ULONG length) +{ + +ULONG tag_type; +ULONG tag_length; +UINT tag_index = 0; +UINT tag_service_name_count = 0; +UINT tag_service_name_valid = NX_FALSE; +UINT service_name_index = 0; +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +UCHAR *service_name_ptr; +UINT service_name_length; +#endif + + /* Initialize the value. */ + client_session_ptr -> nx_pppoe_host_uniq_size = 0; + client_session_ptr -> nx_pppoe_relay_session_id_size = 0; + client_session_ptr -> nx_pppoe_error_flag = 0; +#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + client_session_ptr -> nx_pppoe_service_name = NX_NULL; +#endif + + + /* Loop to process the tag. */ + while (tag_index < length) + { + + /* Pickup the tag type. */ + tag_type = _nx_pppoe_server_data_get(tag_ptr + tag_index, 2); + + /* Update the index. */ + tag_index += 2; + + /* Pickup the tag length. */ + tag_length = _nx_pppoe_server_data_get(tag_ptr + tag_index, 2); + + /* Update the index. */ + tag_index += 2; + + /* Check for valid tag length. */ + if ((tag_index + tag_length) > length) + { + return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); + } + + /* Process the option type. */ + switch (tag_type) + { + + case NX_PPPOE_SERVER_TAG_TYPE_END_OF_LIST: + { + + /* End tag. */ + break; + } + case NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME: + { + + /* Service name tag. */ + tag_service_name_count ++; + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + if (code == NX_PPPOE_SERVER_CODE_PADI) + { + + /* The service name of incoming PADI must match the default service name of PPPoE. */ + /* Check the tag length. */ + if (tag_length == 0) + { + + /* Check the default service name. */ + if (pppoe_server_ptr -> nx_pppoe_service_name_count == 0) + tag_service_name_valid = NX_TRUE; + } + else + { + + /* Loop to find the service name. */ + while (service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count) + { + + /* Compare the same service name with PPPoE Service Name. */ + if (!memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), tag_length)) + { + tag_service_name_valid = NX_TRUE; + client_session_ptr -> nx_pppoe_service_name = pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]; + break; + } + service_name_index ++; + } + } + } + else if (code == NX_PPPOE_SERVER_CODE_PADR) + { + + /* Compare the service name with session service name. */ + /* Check the tag length. */ + if ((tag_length == 0) && (client_session_ptr -> nx_pppoe_service_name_length == 0)) + { + + /* Update the information. */ + tag_service_name_valid = NX_TRUE; + client_session_ptr -> nx_pppoe_service_name = NX_NULL; + client_session_ptr -> nx_pppoe_service_name_length = 0; + break; + } + + /* Set the service name pointer. */ + service_name_ptr = client_session_ptr -> nx_pppoe_service_name; + + /* Loop to compare the service name with session service name. */ + while(service_name_index < client_session_ptr -> nx_pppoe_service_name_length) + { + + /* Get the service name. */ + if (_nx_utility_string_length_check((const char *)(service_name_ptr), &service_name_length, NX_MAX_STRING_LENGTH)) + { + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + + /* Check the tag length. */ + if ((tag_length == 0) && (service_name_length == 0)) + { + tag_service_name_valid = NX_TRUE; + } + else if ((tag_length != 0) && (service_name_length != 0)) + { + + /* Compare the service name. */ + if (!memcmp(tag_ptr + tag_index, service_name_ptr, tag_length)) + tag_service_name_valid = NX_TRUE; + } + + /* Update the service name information for PADS. */ + if (tag_service_name_valid == NX_TRUE) + { + client_session_ptr -> nx_pppoe_service_name = service_name_ptr; + client_session_ptr -> nx_pppoe_service_name_length = service_name_length; + break; + } + + /* Update the service name pointer, length + null-terminated. */ + service_name_ptr += (service_name_length + 1); + service_name_index += (service_name_length + 1); + } + } +#else + + /* Check the tag length. */ + if (tag_length == 0) + { + + /* When the tag length is zero this tag is used to indicate that any service is acceptable. */ + tag_service_name_valid = NX_TRUE; + break; + } + + /* Compare the service name with PPPoE Service name. */ + while (service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count) + { + + /* Find the same service name. */ + if (!memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), tag_length)) + { + + /* Update the information. */ + tag_service_name_valid = NX_TRUE; + client_session_ptr -> nx_pppoe_service_name = pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]; + break; + } + service_name_index ++; + } +#endif + break; + } + case NX_PPPOE_SERVER_TAG_TYPE_AC_NAME: + { + + if (pppoe_server_ptr -> nx_pppoe_ac_name) + { + /* Check the access concentrator name. */ + if (memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_ac_name), tag_length)) + { + + return(NX_PPPOE_SERVER_AC_NAME_ERROR); + } + } + else + { + /* If user does not separately set Access Concentrator name, will use PPPoE server name as Access Concentrator name.*/ + if (memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_name), tag_length)) + { + + return(NX_PPPOE_SERVER_AC_NAME_ERROR); + } + } + break; + } + case NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ: + { + + /* Check the cache for Host-Uniq. */ + if (tag_length> NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE) + return (NX_PPPOE_SERVER_HOST_UNIQ_CACHE_ERROR); + + /* Save the Host-Uniq. */ + memcpy(client_session_ptr -> nx_pppoe_host_uniq, tag_ptr + tag_index, tag_length); + + /* Set the Host-Uniq size. */ + client_session_ptr -> nx_pppoe_host_uniq_size = tag_length; + break; + } + case NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID: + { + + /* Check the cache for Relay-Session_Id. */ + if (tag_length> NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE) + return (NX_PPPOE_SERVER_RELAY_SESSION_ID_CACHE_ERROR); + + /* Save the Relay-Session_Id. */ + memcpy(client_session_ptr -> nx_pppoe_relay_session_id, tag_ptr + tag_index, tag_length); + + /* Set the Relay-Session_Id size. */ + client_session_ptr -> nx_pppoe_relay_session_id_size = tag_length; + break; + } + default: + break; + } + + /* Move to the next tag. */ + tag_index += tag_length; + } + + /* Check the code. */ + if ((code == NX_PPPOE_SERVER_CODE_PADI) || (code == NX_PPPOE_SERVER_CODE_PADR)) + { + + /* The PADI and PADR packet MUST contains exactly one TAG of TAG_TYPE Service- Name, RFC2516 */ + if ((tag_service_name_count != 1) || (tag_service_name_valid != NX_TRUE)) + { + + /* Set the service name error flag. */ + client_session_ptr -> nx_pppoe_error_flag |= NX_PPPOE_SERVER_ERROR_SERVICE_NAME; + + /* Service-Name tag error. */ + return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); + } + } + + /* TAGs processed. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_data_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the datas of PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ +/* _nx_pppoe_server_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* _nx_pppoe_server_session_packet_process */ +/* Process PPPoE Session packet */ +/* _nx_pppoe_server_tag_process Process PPPoE TAGs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static ULONG _nx_pppoe_server_data_get(UCHAR *data, UINT size) +{ + +ULONG value = 0; + + + /* Process the data retrieval request. */ + while (size-- > 0) + { + + /* Build return value. */ + value = (value << 8) | *data++; + } + + /* Return value. */ + return(value); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_data_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the datas into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to buffer data */ +/* size Size of data value */ +/* value Value to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ +/* _nx_pppoe_server_session_send Send PPPoE Session packet */ +/* _nx_pppoe_server_tag_string_add Add PPPoE string TAG */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_server_data_add(UCHAR *data, UINT size, ULONG value) +{ + + /* Make sure that data is left justified. */ + switch (size) + { + + case 1: + + value <<= 24; + break; + + case 2: + + value <<= 16; + break; + + case 3: + + value <<= 8; + break; + + default: + break; + } + + /* Store the value. */ + while (size-- > 0) + { + + *data = (UCHAR) ((value >> 24) & 0xff); + data++; + value <<= 8; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_string_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the string into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* dest Pointer to destination buffer */ +/* source Pointer to source buffer */ +/* size Number of bytes to add */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_tag_string_add Add PPPoE string TAG */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_pppoe_server_string_add(UCHAR *dest, UCHAR *source, UINT size) +{ + + /* Loop to copy all bytes. */ + while (size-- > 0) + { + + /* Copy a byte. */ + *dest++ = *source++; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_tag_string_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds the TAG with string into PPPoE packet. */ +/* */ +/* INPUT */ +/* */ +/* data_ptr Pointer to data buffer */ +/* tag_type Type of TAG */ +/* tag_length Length of TAG */ +/* tag_value_string String value of TAG to add */ +/* index Location into data buffer */ +/* to write data */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_pppoe_server_data_add Add PPPoE data */ +/* _nx_pppoe_server_string_add Add PPPoE string data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_server_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index) +{ + + /* Add the tag type. */ + _nx_pppoe_server_data_add(data_ptr + (*index), 2, tag_type); + (*index) += 2; + + /* Add the tag length. */ + _nx_pppoe_server_data_add(data_ptr + (*index), 2, tag_length); + (*index) += 2; + + /* Add the tag value string. */ + _nx_pppoe_server_string_add(data_ptr + (*index), tag_value_string, tag_length); + (*index) += tag_length; + + /* Return a successful completion. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds a PPPoE session by the client hardware mac */ +/* address and session id. In Discovery Stage, match the client harware*/ +/* address, if not match, mark one available session. In Session Stage,*/ +/* match the client harware address and session id, if not match, */ +/* return NX_PPPOE_CLIENT_SESSION_NOT_FOUND. */ +/* */ +/* INPUT */ +/* */ +/* pppoe_server_ptr Pointer to PPPoE control block*/ +/* client_mac_msw Client physical address MSW */ +/* client_mac_lsw Client physical address LSW */ +/* session_id Session ID */ +/* session_index Session Index */ +/* client_session_ptr Pointer to Client Session */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_discovery_packet_process */ +/* Process PPPoE Discovery packet*/ +/* _nx_pppoe_server_session_packet_process */ +/* Process PPPoE Session packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_server_session_find(NX_PPPOE_SERVER *pppoe_server_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, + ULONG session_id, UINT *session_index, NX_PPPOE_CLIENT_SESSION **client_session_ptr) +{ + +UINT i; +UINT available_index; + + + /* Initialize the value. */ + i = 0; + available_index = NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; + + for(i = 0; i < NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; i ++) + { + + /* Check if this session is valid. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_valid == NX_TRUE) + { + + /* Compare the physical address. */ + if ((pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_physical_address_msw != client_mac_msw) || + (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_physical_address_lsw != client_mac_lsw)) + continue; + + /* If the session id is not zero, means the session has been established. */ + if (session_id != 0) + { + + /* Compare the session id. */ + if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_session_id != session_id) + continue; + } + + /* Yes, find the matched session. */ + *session_index = i; + *client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[i]); + + return(NX_PPPOE_SERVER_SUCCESS); + } + else + { + + /* Set the first available index. */ + if (i < available_index) + available_index = i; + } + } + + /* If the session id is not zero, means the session has been established. */ + if (session_id != 0) + { + return(NX_PPPOE_SERVER_CLIENT_SESSION_NOT_FOUND); + } + + /* Check if there is available room in the table for a new client session. */ + if (available_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + { + + /* No, we cannot add this client session into the server's table. */ + return(NX_PPPOE_SERVER_CLIENT_SESSION_FULL); + } + + /* Set the session. */ + pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_physical_address_msw = client_mac_msw; + pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_physical_address_lsw = client_mac_lsw; + + /* Mark this session is valid. */ + pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_valid = NX_TRUE; + + /* Set local pointer to an available slot. */ + *session_index = available_index; + *client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[available_index]); + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_pppoe_server_session_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function cleans up the PPPoE session. */ +/* */ +/* INPUT */ +/* */ +/* client_session_ptr Pointer to Client Session */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_pppoe_server_session_terminate Terminate the PPPoE session */ +/* _nx_pppoe_server_session_packet_process */ +/* Process PPPoE Session packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_pppoe_server_session_cleanup(NX_PPPOE_CLIENT_SESSION *client_session_ptr) +{ + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +NX_PACKET *next_packet; +NX_PACKET *current_packet; +#endif + + /* Cleanup the client session. */ + client_session_ptr -> nx_pppoe_valid = NX_FALSE; + client_session_ptr -> nx_pppoe_session_id = NX_NULL; + client_session_ptr -> nx_pppoe_physical_address_msw = NX_NULL; + client_session_ptr -> nx_pppoe_physical_address_lsw = NX_NULL; + client_session_ptr -> nx_pppoe_service_name = NX_NULL; + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Loop to release the queued packet. */ + next_packet = client_session_ptr -> nx_pppoe_deferred_received_packet_head; + + /* Release any packets queued up. */ + while (next_packet) + { + + /* Setup the current packet pointer. */ + current_packet = next_packet; + + /* Move to the next packet. */ + next_packet = next_packet -> nx_packet_queue_next; + + /* Release the current packet. */ + nx_packet_release(current_packet); + } + + /* Cleanup the parameters. */ + client_session_ptr -> nx_pppoe_deferred_received_packet_head = NX_NULL; + client_session_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; + client_session_ptr -> nx_pppoe_packet_receive_stopped = NX_FALSE; +#endif + + /* Return success. */ + return(NX_PPPOE_SERVER_SUCCESS); +} + + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppInitInd PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function configures the default Service Namet that the PPPoE */ +/* should use to filter incoming PADI requests. */ +/* */ +/* INPUT */ +/* */ +/* length The number of bytes in aData */ +/* aData Contains PPPoE Service Name */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_pppoe_server_service_name_set Set the service name */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppInitInd(UINT length, UCHAR *aData) +{ + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check the length. */ + if (length == 0) + { + + /* Clean the default service name. */ + nx_pppoe_server_service_name_set(_nx_pppoe_server_created_ptr, NX_NULL, 0); + } + else + { + + /* Transmit the Service. */ + nx_pppoe_service_name[0] = aData; + + /* Set the default service name. */ + nx_pppoe_server_service_name_set(_nx_pppoe_server_created_ptr, nx_pppoe_service_name, 1); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppDiscoverCnf PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function defines the Service Name field of the PADO packet. */ +/* */ +/* INPUT */ +/* */ +/* interfaceHandle The handle of session */ +/* length The number of bytes in aData */ +/* aData Contains PPPoE Service Name */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_server_discovery_send Send PPPoE Discovery */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppDiscoverCnf(UINT length, UCHAR *aData, UINT interfaceHandle) +{ + +NX_PPPOE_CLIENT_SESSION *client_session_ptr; + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check to see if PPPoE is enabled. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) + return; + + /* Check for invalid session index. */ + if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Check to see if PPPoE session is valid. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) + return; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Get the Session pointer. */ + client_session_ptr = &(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle]); + + /* Check if this session is valid. */ + if (client_session_ptr -> nx_pppoe_valid != NX_TRUE) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return; + } + + /* Set the Service Name field. */ + client_session_ptr -> nx_pppoe_service_name = aData; + client_session_ptr -> nx_pppoe_service_name_length = length; + + /* Send PADO packet. */ + _nx_pppoe_server_discovery_send(_nx_pppoe_server_created_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADO); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppOpenCnf PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows PPPoE to accept or reject the PPPoE Session. */ +/* */ +/* INPUT */ +/* */ +/* accept The flag to accept or reject */ +/* interfaceHandle The handle of session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_pppoe_server_discovery_send Send PPPoE Discovery */ +/* _nx_pppoe_server_session_cleanup Cleanup the PPPoE Session */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppOpenCnf(UCHAR accept, UINT interfaceHandle) +{ + +NX_PPPOE_CLIENT_SESSION *client_session_ptr; + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check to see if PPPoE is enabled. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) + return; + + /* Check for invalid session index. */ + if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Check to see if PPPoE session is valid. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) + return; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Get the Session pointer. */ + client_session_ptr = &(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle]); + + /* Check the accept flag. */ + if (accept == NX_TRUE) + { + + /* Send PADS to accept the PPPoE Session. */ + _nx_pppoe_server_discovery_send(_nx_pppoe_server_created_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); + } + else + { + + /* Reject the PPPoE Session. */ + _nx_pppoe_server_session_cleanup(client_session_ptr); + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppCloseInd PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows PPPoE to terminate PPPoE Session. */ +/* */ +/* INPUT */ +/* */ +/* interfaceHandle The handle of session */ +/* causeCode The reason for terminating */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_pppoe_server_session_terminate Terminate the PPPoE Session */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppCloseInd(UINT interfaceHandle, UCHAR *causeCode) +{ + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check to see if PPPoE is enabled. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) + return; + + /* Check for invalid session index. */ + if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Check to see if PPPoE session is established. */ + if ((_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_session_id == 0)) + return; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set the reason for terminating the session. */ + _nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_generic_error = causeCode; + + /* Send PADT to terminate the session. */ + nx_pppoe_server_session_terminate(_nx_pppoe_server_created_ptr, interfaceHandle); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppCloseCnf PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function confirm that the session has been freed. */ +/* */ +/* INPUT */ +/* */ +/* interfaceHandle The handle of session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppCloseCnf(UINT interfaceHandle) +{ + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check for invalid session index. */ + if (interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Cleanup the PPPoE session. */ + _nx_pppoe_server_session_cleanup(&(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle])); + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppTransmitDataCnf PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allows TTP's software to receive new data frame. */ +/* */ +/* INPUT */ +/* */ +/* interfaceHandle The handle of session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* tx_event_flags_set Set events for PPPoE thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppTransmitDataCnf(UINT interfaceHandle, UCHAR *data_ptr, UINT packet_id) +{ + +NX_PACKET *packet_ptr; + + /* Check to see if PPPoE instance is created. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check for invalid session index. */ + if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Release the packet. */ + if (packet_id) + { + packet_ptr = (NX_PACKET *)(packet_id); + nx_packet_release(packet_ptr); + } + + /* Clean the flag to receive the next packet. */ + _nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_packet_receive_stopped = NX_FALSE; + + /* Check if this session queued the packets. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_deferred_received_packet_head) + { + + /* Wakeup PPPoE helper thread to process the PPPoE Session receive. */ + tx_event_flags_set(&(_nx_pppoe_server_created_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT, TX_OR); + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* PppReceiveDataInd PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends data fram over Ethernet. */ +/* */ +/* INPUT */ +/* */ +/* interfaceHandle The handle of session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_pppoe_server_session_send Send PPPoE session data */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID PppReceiveDataInd(UINT interfaceHandle, UINT data_length, UCHAR *data_ptr) +{ + + /* Check for invalid input pointers. */ + if ((_nx_pppoe_server_created_ptr == NX_NULL) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) + return; + + /* Check to see if PPPoE is enabled. */ + if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) + return; + + /* Check for invalid session index. */ + if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) + return; + + /* Check to see if PPPoE session is established. */ + if ((_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) || + (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_session_id == 0)) + return; + + /* Send data. */ + nx_pppoe_server_session_send(_nx_pppoe_server_created_ptr, interfaceHandle, data_ptr, data_length); +} +#endif +#endif /* NX_DISABLE_IPV4 */ diff --git a/addons/pppoe/nx_pppoe_server.h b/addons/pppoe/nx_pppoe_server.h new file mode 100644 index 00000000..acc8db97 --- /dev/null +++ b/addons/pppoe/nx_pppoe_server.h @@ -0,0 +1,376 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** PPP Over Ethernet (PPPoE) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_pppoe_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX PPP Over Ethernet (PPPoE) Server */ +/* componet, including all data types and external references. It is */ +/* assumed that nx_api.h and nx_port.h have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PPPOE_SERVER_H +#define NX_PPPOE_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Note: Prerequisite for using PPPoE. + Redefine NX_PHYSICAL_HEADER to 24 to ensure enough space for filling in physical header. + Physical header:14(Ethernet header) + 6(PPPoE header) + 2(PPP header) + 2(four-byte aligment). */ + +/* Define the Driver command for PPPoE packet. */ +#ifndef NX_LINK_PPPOE_DISCOVERY_SEND +#define NX_LINK_PPPOE_DISCOVERY_SEND 51 +#endif +#ifndef NX_LINK_PPPOE_SESSION_SEND +#define NX_LINK_PPPOE_SESSION_SEND 52 +#endif + +/* Define the PPPoE Server ID. */ +#define NX_PPPOE_SERVER_ID 0x50505045UL + +/* Enable the feature to control the session established. */ +/* +#define NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +*/ + +/* If the driver is not initialized in other module, enable the feature to initialize the driver in PPPoE module . */ +/* +#define NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE +*/ + +/* Define the PPPoE Thread time slice. */ +#ifndef NX_PPPOE_SERVER_THREAD_TIME_SLICE +#define NX_PPPOE_SERVER_THREAD_TIME_SLICE TX_NO_TIME_SLICE +#endif + +/* Define the number of pppoe clients. */ +#ifndef NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER +#define NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER 10 +#endif + +/* Define the size of pppoe Host-Uniq. */ +#ifndef NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE +#define NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE 32 +#endif + +/* Define the size of pppoe Relay-Session-Id. */ +#ifndef NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE +#define NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE 12 +#endif + +/* Define the minimum size of packet payload to avoid packet chained. Maximum Payload Size of Ethernet(1500) + Ethernet Header + CRC + Four-byte alignment. */ + +#ifndef NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE +#define NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE 1520 +#endif + +/* The time out in timer ticks on allocating packets or appending data into packets. */ +#ifndef NX_PPPOE_SERVER_PACKET_TIMEOUT +#define NX_PPPOE_SERVER_PACKET_TIMEOUT (NX_IP_PERIODIC_RATE) /* 1 second */ +#endif + +/* Set the start Session ID for assigning to the PPPoE session. */ +#ifndef NX_PPPOE_SERVER_START_SESSION_ID +#define NX_PPPOE_SERVER_START_SESSION_ID 0x4944 +#endif + +/* Define PPPoE ethernet header size. */ +#define NX_PPPOE_SERVER_ETHER_HEADER_SIZE 14 + +/* Define PPPoE ethernet types. */ +#define NX_PPPOE_SERVER_ETHER_TYPE_DISCOVERY 0x8863 +#define NX_PPPOE_SERVER_ETHER_TYPE_SESSION 0x8864 + +/* Define PPPoE version and type. */ +#define NX_PPPOE_SERVER_VERSION_TYPE 0x11 /* Version 1, Type 1. */ + +/* Define PPPoE codes. */ +#define NX_PPPOE_SERVER_CODE_ZERO 0x00 +#define NX_PPPOE_SERVER_CODE_PADI 0x09 +#define NX_PPPOE_SERVER_CODE_PADO 0x07 +#define NX_PPPOE_SERVER_CODE_PADR 0x19 +#define NX_PPPOE_SERVER_CODE_PADS 0x65 +#define NX_PPPOE_SERVER_CODE_PADT 0xa7 + +/* Define the PPPoE Area Offsets. */ +#define NX_PPPOE_SERVER_OFFSET_VER_TYPE 0 /* 1 byte, version + type: 0x11 */ +#define NX_PPPOE_SERVER_OFFSET_CODE 1 /* 1 byte, code: Discovery or Session */ +#define NX_PPPOE_SERVER_OFFSET_SESSION_ID 2 /* 2 bytes, session id: unique session identifieer */ +#define NX_PPPOE_SERVER_OFFSET_LENGTH 4 /* 2 bytes, length: the length of PPPoE payload */ +#define NX_PPPOE_SERVER_OFFSET_PAYLOAD 6 /* variable, payload */ + +/* Define the PPPoE Tag Types. */ +#define NX_PPPOE_SERVER_TAG_TYPE_END_OF_LIST 0x0000 +#define NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME 0x0101 +#define NX_PPPOE_SERVER_TAG_TYPE_AC_NAME 0x0102 +#define NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ 0x0103 +#define NX_PPPOE_SERVER_TAG_TYPE_AC_COOKIE 0x0104 +#define NX_PPPOE_SERVER_TAG_TYPE_VENDOR_SPECIFIC 0x0105 +#define NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID 0x0110 +#define NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME_ERROR 0x0201 +#define NX_PPPOE_SERVER_TAG_TYPE_AC_SYSTEM_ERROR 0x0202 +#define NX_PPPOE_SERVER_TAG_TYPE_GENERIC_ERROR 0x0203 + +/* Define the PPPoE Error flags. */ +#define NX_PPPOE_SERVER_ERROR_SERVICE_NAME ((ULONG) 0x00000001) /* Service Name Error. */ +#define NX_PPPOE_SERVER_ERROR_AC_SYSTEM ((ULONG) 0x00000002) /* AC-System Error */ +#define NX_PPPOE_SERVER_ERROR_GENERIC ((ULONG) 0x00000004) /* Generic Error */ + +/* Define event flags for PPPoE thread control. */ +#define NX_PPPOE_SERVER_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags */ +#define NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT ((ULONG) 0x00000001) /* PPPoE Server receive packet event */ +#define NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT ((ULONG) 0x00000002) /* PPPoE Session receive packet event */ + +/* Define error codes from PPPoE Server operation. */ +#define NX_PPPOE_SERVER_SUCCESS 0x00 /* Success */ +#define NX_PPPOE_SERVER_PTR_ERROR 0xC1 /* Invalid input pointers */ +#define NX_PPPOE_SERVER_INVALID_INTERFACE 0xC2 /* Invalid interface */ +#define NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR 0xC3 /* Invalid payload size of packet */ +#define NX_PPPOE_SERVER_MEMORY_SIZE_ERROR 0xC4 /* Invalid memory size */ +#define NX_PPPOE_SERVER_PRIORITY_ERROR 0xC5 /* Invalid priority */ +#define NX_PPPOE_SERVER_NOT_ENABLED 0xC6 /* PPPoE is not enabled */ +#define NX_PPPOE_SERVER_INVALID_SESSION 0xC7 /* Invalid Session */ +#define NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED 0xC8 /* PPPoE Session is not established */ +#define NX_PPPOE_SERVER_SERVICE_NAME_ERROR 0xC9 /* Service name error */ +#define NX_PPPOE_SERVER_AC_NAME_ERROR 0xCA /* AC Name error */ +#define NX_PPPOE_SERVER_CLIENT_SESSION_FULL 0xCB /* Client Session full */ +#define NX_PPPOE_SERVER_CLIENT_SESSION_NOT_FOUND 0xCC /* Not found the client session */ +#define NX_PPPOE_SERVER_HOST_UNIQ_CACHE_ERROR 0xCD /* The cache is not enough to record the Host Uniq */ +#define NX_PPPOE_SERVER_RELAY_SESSION_ID_CACHE_ERROR 0xCF /* The cache is not enough to record Relay Session ID*/ + +/* Define the PPPoE Client Session structure containing the session id and physical address. */ + +typedef struct NX_PPPOE_CLIENT_SESSION_STRUCT +{ + + USHORT nx_pppoe_valid; + USHORT nx_pppoe_session_id; + ULONG nx_pppoe_physical_address_msw; + ULONG nx_pppoe_physical_address_lsw; + UCHAR *nx_pppoe_service_name; +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + UINT nx_pppoe_service_name_length; + UINT nx_pppoe_packet_receive_stopped; + NX_PACKET *nx_pppoe_deferred_received_packet_head, + *nx_pppoe_deferred_received_packet_tail; + UCHAR *nx_pppoe_generic_error; +#endif + UCHAR nx_pppoe_host_uniq[NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE]; + UINT nx_pppoe_host_uniq_size; + UCHAR nx_pppoe_relay_session_id[NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE]; + UINT nx_pppoe_relay_session_id_size; + UINT nx_pppoe_error_flag; +} NX_PPPOE_CLIENT_SESSION; + + + +/* Define the main PPPoE Server data structure. */ + +typedef struct NX_PPPOE_SERVER_STRUCT +{ + + ULONG nx_pppoe_id; + UINT nx_pppoe_enabled; + UCHAR *nx_pppoe_name; + UINT nx_pppoe_name_length; + UCHAR *nx_pppoe_ac_name; + UINT nx_pppoe_ac_name_length; + NX_IP *nx_pppoe_ip_ptr; + NX_INTERFACE *nx_pppoe_interface_ptr; + NX_PACKET_POOL *nx_pppoe_packet_pool_ptr; + TX_EVENT_FLAGS_GROUP nx_pppoe_events; + TX_THREAD nx_pppoe_thread; + NX_PACKET *nx_pppoe_deferred_received_packet_head, + *nx_pppoe_deferred_received_packet_tail; + UCHAR **nx_pppoe_service_name; + UINT nx_pppoe_service_name_count; + USHORT nx_pppoe_session_id; + USHORT nx_pppoe_reserved[2]; + NX_PPPOE_CLIENT_SESSION nx_pppoe_client_session[NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER]; + + /* Define the callback nofiy function. */ + VOID (*nx_pppoe_discover_initiation_notify)(UINT session_index); + VOID (*nx_pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data); + VOID (*nx_pppoe_discover_terminate_notify)(UINT session_index); + VOID (*nx_pppoe_discover_terminate_confirm)(UINT session_index); + VOID (*nx_pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id); + VOID (*nx_pppoe_data_send_notify)(UINT session_index, UCHAR *data); + + /* Define the Link Driver entry point. */ + VOID (*nx_pppoe_link_driver_entry)(struct NX_IP_DRIVER_STRUCT *); + +} NX_PPPOE_SERVER; + + +#ifndef NX_PPPOE_SERVER_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_pppoe_server_create _nx_pppoe_server_create +#define nx_pppoe_server_delete _nx_pppoe_server_delete +#define nx_pppoe_server_enable _nx_pppoe_server_enable +#define nx_pppoe_server_disable _nx_pppoe_server_disable +#define nx_pppoe_server_callback_notify_set _nx_pppoe_server_callback_notify_set +#define nx_pppoe_server_ac_name_set _nx_pppoe_server_ac_name_set +#define nx_pppoe_server_service_name_set _nx_pppoe_server_service_name_set +#define nx_pppoe_server_session_send _nx_pppoe_server_session_send +#define nx_pppoe_server_session_packet_send _nx_pppoe_server_session_packet_send +#define nx_pppoe_server_session_terminate _nx_pppoe_server_session_terminate +#define nx_pppoe_server_session_get _nx_pppoe_server_session_get + +#else + +/* Services with error checking. */ + +#define nx_pppoe_server_create _nxe_pppoe_server_create +#define nx_pppoe_server_delete _nxe_pppoe_server_delete +#define nx_pppoe_server_enable _nxe_pppoe_server_enable +#define nx_pppoe_server_disable _nxe_pppoe_server_disable +#define nx_pppoe_server_callback_notify_set _nxe_pppoe_server_callback_notify_set +#define nx_pppoe_server_ac_name_set _nxe_pppoe_server_ac_name_set +#define nx_pppoe_server_service_name_set _nxe_pppoe_server_service_name_set +#define nx_pppoe_server_session_send _nxe_pppoe_server_session_send +#define nx_pppoe_server_session_packet_send _nxe_pppoe_server_session_packet_send +#define nx_pppoe_server_session_terminate _nxe_pppoe_server_session_terminate +#define nx_pppoe_server_session_get _nxe_pppoe_server_session_get + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, + VOID (* pppoe_discover_initiation_notify)(UINT session_index), + VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), + VOID (* pppoe_discover_terminate_notify)(UINT session_index), + VOID (* pppoe_discover_terminate_confirm)(UINT session_index), + VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), + VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); +UINT nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); +UINT nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); +UINT nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); +UINT nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); +UINT nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); +UINT nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); +VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr); + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE +VOID PppInitInd(UINT length, UCHAR *aData); +VOID PppDiscoverCnf(UINT length, UCHAR *aData, UINT interfaceHandle); +VOID PppOpenCnf(UCHAR accept, UINT interfaceHandle); +VOID PppCloseInd(UINT interfaceHandle, UCHAR *causeCode); +VOID PppCloseCnf(UINT interfaceHandle); +VOID PppTransmitDataCnf(UINT interfaceHandle, UCHAR *aData, UINT packet_id); +VOID PppReceiveDataInd(UINT interfaceHandle, UINT length, UCHAR *aData); +#endif + +#else + +UINT _nxe_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT _nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, + VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, + VOID *stack_ptr, ULONG stack_size, UINT priority); +UINT _nxe_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nxe_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nxe_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); +UINT _nxe_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, + VOID (* pppoe_discover_initiation_notify)(UINT session_index), + VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), + VOID (* pppoe_discover_terminate_notify)(UINT session_index), + VOID (* pppoe_discover_terminate_confirm)(UINT session_index), + VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), + VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); +UINT _nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, + VOID (* pppoe_discover_initiation_notify)(UINT session_index), + VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), + VOID (* pppoe_discover_terminate_notify)(UINT session_index), + VOID (* pppoe_discover_terminate_confirm)(UINT session_index), + VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), + VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); +UINT _nxe_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); +UINT _nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); +UINT _nxe_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); +UINT _nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); +UINT _nxe_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); +UINT _nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); +UINT _nxe_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); +UINT _nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); +UINT _nxe_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); +UINT _nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); +UINT _nxe_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); +UINT _nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); +VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr); + +#endif /* NX_PPPOE_SERVER_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_PPP_SERVER_H */ diff --git a/addons/smtp/nxd_smtp_client.c b/addons/smtp/nxd_smtp_client.c new file mode 100644 index 00000000..e8c46093 --- /dev/null +++ b/addons/smtp/nxd_smtp_client.c @@ -0,0 +1,4752 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** */ +/** NetX SMTP Client Component */ +/** */ +/** Simple Mail Transfer Protocol (SMTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_smtp_client.c PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Simple Mail Transfer Protocol (SMTP) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + + +#define NX_SMTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module. */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + + + +#include "ctype.h" +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_ipv4.h" +#include "nxd_smtp_client.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_ipv6.h" +#endif +#include "nx_tcp.h" + +/* Necessary for threadx thread state macros. */ +extern TX_THREAD *_tx_thread_current_ptr; +extern TX_THREAD _tx_timer_thread; +extern volatile ULONG _tx_thread_system_state; + +#define NX_SMTP_BUFFER_SIZE 512 +static CHAR _nx_smtp_buffer[NX_SMTP_BUFFER_SIZE]; + + +/* Define internal SMTP Client functions. */ + +static VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT reverse); +static VOID _nx_smtp_base64_encode(UCHAR *name, UCHAR *base64name, UINT length); +static VOID _nx_smtp_base64_decode(UCHAR *base64name, UCHAR *name); +static UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr); +static UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines); +static UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout); +static UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer_ptr, UINT length); +static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout) ; +static UINT _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr); +static UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code); +static UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT arguement_index, + UINT buffer_length, UCHAR *arguement, UINT arguement_length, + UINT include_crlf); + +static NX_SMTP_CLIENT_STATES protocol_states[] = +{ + {_nx_smtp_cmd_idle , _nx_smtp_rsp_idle}, + {_nx_smtp_cmd_greeting , _nx_smtp_rsp_greeting}, + {_nx_smtp_cmd_ehlo , _nx_smtp_rsp_ehlo}, + {_nx_smtp_cmd_helo , _nx_smtp_rsp_helo}, + {_nx_smtp_cmd_mail , _nx_smtp_rsp_mail}, + {_nx_smtp_cmd_rcpt , _nx_smtp_rsp_rcpt}, + {_nx_smtp_cmd_data , _nx_smtp_rsp_data}, + {_nx_smtp_cmd_message , _nx_smtp_rsp_message}, + {_nx_smtp_cmd_rset , _nx_smtp_rsp_rset}, + {_nx_smtp_cmd_quit , _nx_smtp_rsp_quit}, + {_nx_smtp_cmd_noop , _nx_smtp_rsp_noop}, + {_nx_smtp_cmd_auth , _nx_smtp_rsp_auth}, + {_nx_smtp_cmd_auth_challenge , _nx_smtp_rsp_auth_challenge}, +}; + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_smtp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the client create service. */ +/* */ +/* Note: The string lengths of username,password,from_address and */ +/* client_domain are limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* client_ptr Pointer to SMTP Client instance */ +/* ip_ptr Pointer to IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* username Pointer to username */ +/* password Pointer to password */ +/* from_address Pointer to Client email address */ +/* client_domain Pointer to client domain */ +/* authentication_type SMTP authentication type */ +/* server_address Pointer to server address */ +/* server_port SMTP server TCP port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_SMTP_INVALID_PARAM Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_smtp_client_create Actual SMTP client create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, + CHAR *username, CHAR *password, CHAR *from_address, + CHAR *client_domain, UINT authentication_type, + NXD_ADDRESS *server_address, UINT port) +{ + +UINT status; + + + if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (client_packet_pool_ptr == NX_NULL) || + (from_address == NX_NULL) || (username == NX_NULL) || (password == NX_NULL) || + (client_domain == NX_NULL) || (server_address == NX_NULL)) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + + return NX_SMTP_INVALID_PARAM; + } + + + /* Make sure the IP version is set correctly. */ + if((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && + (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Call the actual client create service. */ + status = _nxd_smtp_client_create(client_ptr, ip_ptr, client_packet_pool_ptr, username, password, + from_address, client_domain, authentication_type, + server_address, port); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_smtp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a SMTP client instance for sending mail to an */ +/* SMTP Server over IPv4 or IPv6 networks. It also creates the TCP */ +/* socket for making connections with the SMTP server, sets the */ +/* server IP address and port, and sets the Client username and SMTP */ +/* address (from address) used in all SMTP mail transmissions. */ +/* */ +/* Note: The string lengths of username,password,from_address and */ +/* client_domain are limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SMTP Client instance */ +/* ip_ptr Pointer to IP instance */ +/* packet_pool_ptr Pointer to client packet pool */ +/* username Pointer to username */ +/* password Pointer to password */ +/* from_address Pointer to Client email address */ +/* client_domain Pointer to client domain */ +/* authentication_type SMTP authentication type */ +/* server_address Pointer to server address */ +/* server_port SMTP server TCP port */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* memset Clear area of memory */ +/* memcpy Copy data to area of memory */ +/* nx_tcp_socket_create Create a NetX TCP socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, + CHAR *username, CHAR *password, CHAR *from_address, + CHAR *client_domain, UINT authentication_type, + NXD_ADDRESS *server_address, UINT port) +{ + +UINT status = NX_SUCCESS; +UINT str_length; +NX_SMTP_CLIENT_MAIL *mail_ptr; + + + /* Initialize client as not ready for SMTP yet. */ + client_ptr -> nx_smtp_client_init_status = NX_FALSE; + + mail_ptr = &client_ptr -> nx_smtp_client_mail; + + /* Clear the Client and session memory. */ + memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT)); + + /* Configure client with input parameters. */ + status = _nx_utility_string_length_check(username, &str_length, NX_SMTP_CLIENT_MAX_USERNAME); + if (status) + { + return(status); + } + + memcpy(client_ptr -> nx_smtp_username, username, str_length); + + status = _nx_utility_string_length_check(password, &str_length, NX_SMTP_CLIENT_MAX_PASSWORD); + if (status) + { + return(status); + } + + memcpy(client_ptr -> nx_smtp_password, password, str_length); + + status = _nx_utility_string_length_check(client_domain, &str_length, NX_SMTP_CLIENT_MAX_USERNAME); + if (status) + { + return(status); + } + + memcpy(client_ptr -> nx_smtp_client_domain, client_domain, str_length); + + /* Set the mail server IP address and port number. */ + +#ifdef FEATURE_NX_IPV6 + client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version; + client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[0] = server_address -> nxd_ip_address.v6[0] ; + client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[1] = server_address -> nxd_ip_address.v6[1] ; + client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[2] = server_address -> nxd_ip_address.v6[2] ; + client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[3] = server_address -> nxd_ip_address.v6[3] ; +#else + + client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version; + client_ptr -> nx_smtp_server_address.nxd_ip_address.v4 = server_address -> nxd_ip_address.v4; +#endif + client_ptr -> nx_smtp_server_port = (port & 0xFFFF); + + /* Set up the "from" address. */ + mail_ptr -> nx_smtp_client_mail_from_address = from_address; + + /* Check if authentication type is specified. */ + if ((authentication_type != NX_SMTP_CLIENT_AUTH_PLAIN) && + (authentication_type != NX_SMTP_CLIENT_AUTH_LOGIN) && + (authentication_type != NX_SMTP_CLIENT_AUTH_NONE)) + { + + /* No. Set the default authentication type. */ + authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; + } + + client_ptr -> nx_smtp_client_authentication_type = authentication_type; + + /* Configure client IP options. */ + client_ptr -> nx_smtp_client_ip_ptr = ip_ptr; + client_ptr -> nx_smtp_client_packet_pool_ptr = client_packet_pool_ptr; + + /* Set the Client ID to indicate the SMTP client thread is ready. */ + client_ptr -> nx_smtp_client_id = NX_SMTP_CLIENT_ID; + + /* Create a tcp socket to send/receive SMTP data. */ + status = nx_tcp_socket_create(client_ptr -> nx_smtp_client_ip_ptr, + &client_ptr -> nx_smtp_client_socket, "SMTP Client socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, + NX_SMTP_CLIENT_TCP_WINDOW_SIZE, + NX_NULL, NX_NULL); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Initialize client as ready for conducting an SMTP session. */ + client_ptr -> nx_smtp_client_init_status = NX_TRUE; + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_smtp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors on the client delete service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_client_delete Actual SMTP client delete service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_smtp_client_delete(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for the validity of input parameter. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_smtp_client_id != NX_SMTP_CLIENT_ID)) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + /* Call the actual client create service. */ + status = _nx_smtp_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created SMTP client and releases */ +/* all client resources (sockets, packet pools). */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SMTP Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_session_delete Delete the SMTP Client session */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_client_delete(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + if ((client_ptr -> nx_smtp_client_socket).nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, NX_SMTP_CLIENT_DISCONNECT_TIMEOUT); + + nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); + } + + status = nx_tcp_socket_delete(&(client_ptr -> nx_smtp_client_socket)); + + /* Check status. */ + if (status) + { + return status; + } + + /* Clear client memory. */ + memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT)); + + /* Return success status. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_smtp_mail_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors on the mail send service. */ +/* */ +/* Note: The string lengths of recipient_address and subject are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client instance */ +/* recipient_address Pointer to recipient (To) address */ +/* priority Mail send priority level */ +/* subject Pointer to mail subject text */ +/* mail_body Pointer to mail message text */ +/* mail_body_length Size of mail message text */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_mail_send Actual SMTP mail send service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, + CHAR *subject, CHAR *mail_body, UINT mail_body_length) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if((client_ptr == NX_NULL) || (recipient_address == NX_NULL) || + (mail_body == NX_NULL) || (subject == NX_NULL)) + + { + return NX_PTR_ERROR; + } + + if (mail_body_length == 0) + { + return NX_SMTP_INVALID_PARAM; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_smtp_mail_send(client_ptr, recipient_address, priority, + subject, mail_body, mail_body_length); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_mail_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates and sends an SMTP mail item with the input */ +/* parameters for a previously created SMTP Client. It supports IPv4 */ +/* and IPv6 connections. */ +/* */ +/* Before calling this service, the SMTP application must initialize */ +/* the SMTP Client (nx_smtp_client_init). Thereafter it need not */ +/* reinitialize the SMTP Client to send subsequent mail items. */ +/* */ +/* This service assumes the syntax of the from_address is correct. */ +/* */ +/* Note: The string lengths of recipient_address and subject are */ +/* limited by internal buffer size. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client instance */ +/* recipient_address Pointer to recipient (To) address */ +/* priority Mail send priority level */ +/* subject Pointer to mail subject text */ +/* mail_body Pointer to mail message text */ +/* mail_body_length Size of mail message text */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Success completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear data in memory */ +/* _nx_smtp_client_process Conducts SMTP session for */ +/* transmitting mail message */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, + CHAR *recipient_address, + UINT priority, CHAR *subject, + CHAR *mail_body, UINT mail_body_length) +{ + +UINT status; +NX_SMTP_CLIENT_MAIL *mail_ptr; + + + client_ptr -> nx_smtp_client_mute = NX_FALSE; + + /* Verify Client is properly set up and ready to conduct an SMTP session. */ + if (client_ptr -> nx_smtp_client_init_status != NX_TRUE) + { + return NX_SMTP_CLIENT_NOT_INTIALIZED; + } + + /* Initialize the Client to idle. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + + /* Set local variables for convenience. */ + mail_ptr = &client_ptr -> nx_smtp_client_mail; + + /* Did we get a valid priority type? */ + if ((priority != NX_SMTP_MAIL_PRIORITY_LOW) && + (priority != NX_SMTP_MAIL_PRIORITY_NORMAL) && + (priority != NX_SMTP_MAIL_PRIORITY_HIGH)) + { + + /* No, default priority to normal. */ + mail_ptr -> nx_smtp_client_mail_priority = NX_SMTP_MAIL_PRIORITY_NORMAL; + } + else + { + + /* Yes, apply it to the session priority. */ + mail_ptr -> nx_smtp_client_mail_priority = priority; + } + mail_ptr -> nx_smtp_client_mail_subject = subject; + mail_ptr -> nx_smtp_client_mail_body = mail_body; + mail_ptr -> nx_smtp_client_mail_body_length = mail_body_length; + mail_ptr -> nx_smtp_client_mail_recipient_address = recipient_address; + + /* Mark mail item as unsent */ + client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS; + + /* Set up the recipient. */ + + /* Set up a local pointer to the session for convenience. */ + + /* Set session members to initial values. */ + client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED; + client_ptr -> nx_smtp_client_reply_code_status = 0; + + /* Start this session by setting the state to the first step in SMTP Protocol, greeting. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_GREETING; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_GREETING; + + status = _nx_smtp_client_process(client_ptr); + + /* Return success status. */ + return(status); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_client_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function executes the SMTP client state machine to transmit a */ +/* previously created mail item to an SMTP server. For more details, */ +/* See nx_smtp_mail_send. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SMTP Client instance */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Success completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* nx_tcp_client_socket_bind Bind NetX TCP socket to local port */ +/* nx_tcp_client_socket_unbind Release port from NetX TCP socket */ +/* nx_tcp_client_socket_connect Connect to a TCP server socket */ +/* nx_tcp_client_socket_disconnect Disconnect from TCP server socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT close_connection = NX_FALSE; + + + /* Initialize completion status to successful outcome. */ + status = NX_SUCCESS; + + /* Run the SMTP protocol state machine till session terminates. */ + while (status == NX_SUCCESS) + { + + /* Check if we are starting a mail transaction. */ + if (client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_GREETING) + { + + /* We are so we need to set up a connection. Bind the socket to client port. */ + status = nx_tcp_client_socket_bind(&client_ptr -> nx_smtp_client_socket, NX_ANY_PORT, 100); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Reset the Client to idle. The caller must resend the email. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + return status; + } + + /* Connect to the SMTP server using our tcp socket. */ + status = nxd_tcp_client_socket_connect(&client_ptr -> nx_smtp_client_socket, + &client_ptr -> nx_smtp_server_address, + client_ptr -> nx_smtp_server_port, + NX_SMTP_CLIENT_CONNECTION_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); + + /* Reset the Client to idle. The caller must resend the email.*/ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + return status; + } + + /* Successful connection set up. Now let the Client task process the GREETING command. */ + } + + /* Is the next command waiting the outcome of the previous reply handler? */ + if ((client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_AWAITING_REPLY) && + /* Do not advance the state if the client is in mute. */ + (!client_ptr -> nx_smtp_client_mute)) + { + + /* Yes, update the session state to the next command to send. */ + client_ptr -> nx_smtp_client_cmd_state = client_ptr -> nx_smtp_client_rsp_state; + } + + if (!client_ptr -> nx_smtp_client_mute) + { + + /* Execute the next command in the SMTP state machine. */ + status = (*protocol_states[client_ptr -> nx_smtp_client_cmd_state].cmd)(client_ptr); + + /* Check for internal error state in the SMTP state machine. */ + if (status != NX_SUCCESS) + { + + /* This is likely an internal error and we need to break off the connection, reset the Client state + to an idle state. */ + + /* Set the status to close the connection down. */ + close_connection = NX_TRUE; + } + } + + /* Reset server reply to null. */ + client_ptr -> nx_smtp_client_reply_code_status = 0; + + /* Wait for a response unless we are closing the connection, or have + encountered an internal error (packet allocation error for example). */ + if (close_connection == NX_FALSE) + { + + /* Awaiting the server reply to the command just sent. */ + status = (*protocol_states[client_ptr -> nx_smtp_client_rsp_state].rsp)(client_ptr); + + /* Check for internal error state in the SMTP state machine. */ + if (status != NX_SUCCESS) + { + + /* This is an internal error or invalid server reply of some kind. Just shut down the + connection, notify the host application and set the Client to idle. */ + + /* Set the status to close the connection down. */ + close_connection = NX_TRUE; + } + + /* Are we at the end of the Client state (received a reply to our QUIT message to the server)? */ + else if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY) + { + + /* Yes, time to close it down and return to an idle state. */ + close_connection = NX_TRUE; + } + /* else keep the connection open... */ + } + + /* Check again if we need to break down the connection. */ + if (close_connection == NX_TRUE) + { + + UINT timeout = 0; + + /* We do. Depending on the reason for closing the connection, set the timeout. If we experienced + an internal error, e.g. packet allocation error, we probably won't be able to send + a fin or rst packet anyway, so set the timeout to zero and close down the connection. + + RFC 2821 Section 3.9: if client must abort processing due to internal conditions or socket reset, + it should handle as error code 451 from the server which is to abort processing immediately. + */ + if (status != NX_SUCCESS) + { + timeout = NX_NO_WAIT; + } + else + { + timeout = NX_SMTP_CLIENT_DISCONNECT_TIMEOUT; + } + + /* Disconnect client socket from server. */ + nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, timeout); + + /* Unbind the port from client socket. */ + nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); + + /* Indicate the Client is idle. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + /* Did the session terminate normally (e.g. no internal errors)? */ + if (status == NX_SUCCESS) + { + + /* Yes, so set the mail transmit status as the completion status. */ + status = client_ptr -> nx_smtp_client_mail_status; + } + + return status; + } + + /* Clear the abort status. */ + close_connection = NX_FALSE; + } + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_greeting PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This is the start of the SMTP Client process for sending an mail */ +/* item. It sets the client state to send a greeting command to the */ +/* server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr) +{ + + + /* Set session state to wait on the outcome of the greeting response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return successful session status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_idle PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Execute the idle state of the SMTP Client (do nothing while waiting */ +/* for the next send mail request. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr) +{ + + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + + /* Return successful session status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_idle PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Execute the idle state of the SMTP Client (waiting for the next */ +/* send mail request). The state machine has a 'response' state for */ +/* every command state, so this is the response handler for the idle */ +/* state. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr) +{ + + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + /* Return successful session status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_greeting PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This handles the server's response to the client greeting and set */ +/* the next session state and next command to send to the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code */ +/* Extracts the server reply code and */ +/* stores reply text to session buffer */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get the server greeting message. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_GREETING_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return (status); + } + + /* Process based on the reply protocol code from server. */ + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_GREETING_OK) + { + + /* Yes, set session state to next state, EHLO. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_EHLO; + } + else + { + + /* All other codes. */ + + /* Server did not accept the greeting, exit session gracefully. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_GREET_REPLY_ERROR; + + + } + + if (client_ptr -> nx_smtp_server_packet) + { + nx_packet_release(client_ptr -> nx_smtp_server_packet); + } + /* Return successful session state. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_helo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* Create the HELO command text and send to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status. */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Sends data to server. */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; +UINT domain_length; + + + memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); + + if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME)) + { + return(NX_SIZE_ERROR); + } + + if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_HELO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) + { + + /* Buffer size too small. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + /* Format the HELO command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_HELO, sizeof(NX_SMTP_COMMAND_HELO) - 1); + index = sizeof(NX_SMTP_COMMAND_HELO) - 1; + + _nx_smtp_buffer[index++] = ' '; + + memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); + index += domain_length; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the HELO command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait next response from server. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_helo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the server reply to the HELO command and set */ +/* the next session state and next command to send to the server. This*/ +/* is the GREETING state where we do not initiate the greeting. */ +/* Instead we wait for the server's 'greeting' message. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* _nx_smtp_parse_response Parse specified argument from buffer */ +/* _nx_smtp_rsp_hello_command Handle HELO/EHLO reply from Server */ +/* nx_packet_release Release NetX receive packet */ +/* memcpy Copy data to specified area of memory */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + /* Get the server response to the EHLO command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* This is either no packet received or an invalid server response. */ + + /* Return error status. */ + return status; + } + + /* Update session with specific services offered, if any, by server. */ + _nx_smtp_utility_parse_server_services(client_ptr); + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* if server rejected hello, set the session state to terminate */ + if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) + { + + /* Return successful session status to execute QUIT command. */ + return NX_SUCCESS; + } + + /* Handle the server reply code first. */ + _nx_smtp_rsp_hello_command(client_ptr); + + /* if server rejected hello, set the session state to terminate */ + if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) + { + + /* Return successful session status to execute QUIT command. */ + return NX_SUCCESS; + } + + /* Server accepted the HELO command. Continue the SMTP session. */ + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_ehlo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the EHLO command and sends it to the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; +UINT domain_length; + + + memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); + + if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME)) + { + return(NX_SIZE_ERROR); + } + + if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_EHLO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) + { + + /* Buffer size too small. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + /* Format the EHLO command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_EHLO, sizeof(NX_SMTP_COMMAND_EHLO) - 1); + index = sizeof(NX_SMTP_COMMAND_EHLO) - 1; + + _nx_smtp_buffer[index++] = ' '; + memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); + index += domain_length; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the EHLO command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait on the outcome of the EHLO response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_ehlo PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This handles the server reply to the EHLO command and determines the*/ +/* next session state and next command to send to the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_parse_server_services Parser for extracting server */ +/* services and reply code */ +/* _nx_smtp_utility_read_server_code Parse the server replies */ +/* code and text */ +/* _nx_smtp_rsp_hello_command Server HELO/EHLO reply */ +/* handler */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get the server response to the EHLO command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* This is either no packet received or an invalid server response. */ + + /* Return error status. */ + return status; + } + + /* Update session with specific services offered, if any, by server. */ + _nx_smtp_utility_parse_server_services(client_ptr); + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + if (client_ptr -> nx_smtp_client_mute) + { + /* We expect another response packet from the server... + keep the same state, don't send anything. */ + return NX_SUCCESS; + } + + /* Handle the server reply code first. */ + _nx_smtp_rsp_hello_command(client_ptr); + + /* if server rejected hello, set the session state to terminate */ + if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) + { + + /* Return successful session status to execute QUIT command. */ + return NX_SUCCESS; + } + + /* Determine if we go to authenticatio next (otherwise we go to the MAIL state). */ + if (client_ptr -> nx_smtp_client_authentication_type != NX_SMTP_CLIENT_AUTH_NONE) + { + + /* Yes, set session to the AUTH state before going on to MAIL. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH; + } + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_hello_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the server response to HELO and EHLO commands */ +/* common to both command states. If server accepts the EHLO/HELO */ +/* command, proceed with the session */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* Session server EHLO reply handler */ +/* _nx_smtp_rsp_ehlo Session server HELO reply handler */ +/* _nx_smtp_rsp_helo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr) +{ + +UINT first_digit_server_reply; + + first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status/ 100; + + /* Process the server reply starting with the first digit. */ + if (first_digit_server_reply == 2) + { + + + /* Did server accept the EHLO/HELO command? */ + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) + { + + /* Set session to the next state (MAIL). */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; + + /* Return successful session status. */ + return NX_SUCCESS; + } + } + + /* If we are here, an error occurred. Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_HELLO_REPLY_ERROR; + + /* Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Return successful session status. */ + return NX_SUCCESS; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_auth PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the text of the SMTP AUTH command text and */ +/* sends it to the SMTP server. If the session is already */ +/* authenticated, this function proceeds to the MAIL state (next stage */ +/* of the SMTP protocol) instead. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_cmd_mail Send MAIL command to server */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* memset Clear area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP session */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status = NX_SUCCESS; +UINT index; + + memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); + + /* Is session already successfully authenticated? */ + if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_SUCCEEDED) + { + + /* Yes, server will reject any authentication command; skip to MAIL state. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_MAIL; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; + + /* Call the session MAIL service. */ + _nx_smtp_cmd_mail(client_ptr); + + /* Return successful session status. */ + return NX_SUCCESS; + } + + /* Mark the session authentication as in progress. */ + client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_IN_PROGRESS; + + /* Set the authentication prompt depending on the Client authentication type. */ + if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN) + { + + memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_LOGIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1); + index = sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1; + } + else if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_CRAM_MD5) + { + + memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1); + index = sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1; + } + else + { + + memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_PLAIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1); + index = sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1; + } + + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the AUTH command to the server. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait on the outcome of the EHLO response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_auth PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the server reply to the AUTH command and set */ +/* determine the next session state and next command to send to the */ +/* server. */ +/* */ +/* During the authentication process, it attempts to find a match for */ +/* the server authentication type and decodes each server */ +/* authentication challenge (e.g. USERNAME, PASSWORD). It then sets the*/ +/* session authentication state depending on server acceptance of its */ +/* replies to its challenges. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parser for server reply */ +/* _nx_smtp_utility_authentication_challenge */ +/* Respond to server */ +/* authentication challenge*/ +/* _nx_smtp_rsp_auth When called by itself,respond */ +/* to server authentication */ +/* challenge */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* nx_packet_release Release NetX receive packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT server_reply_first_digit; +UCHAR *carriage_return_linefeed_ptr; +UINT auth_length; + + + /* Initialize authentication flags. */ + carriage_return_linefeed_ptr = (CHAR)0x0; + + /* Get the server response to the AUTH command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* This is an server response or no packet received. */ + + /* Return error status. */ + return(status); + } + + /* Use the first digit to group possible server replies. */ + server_reply_first_digit = client_ptr -> nx_smtp_client_reply_code_status / 100; + + /* Process the reply code from server. */ + if (server_reply_first_digit == 2) + { + + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_AUTHENTICATION_SUCCESSFUL) + { + + /* Advance to the MAIL state. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; + + /* Mark the session as authenticated successfully. */ + client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_SUCCEEDED; + } + else + { + + /* The server returns a 2xx code. Determine if it is an error code. */ + if ((client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_CANNOT_VERIFY_RECIPIENT) || + (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_ACKNOWLEDGE_QUIT)) + { + + /* It is. Abort. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; + } + else + { + /* It is not the code expected. Discard and keep the SMTP Client in the same state. */ + } + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + return NX_SUCCESS; + } + } + else if (server_reply_first_digit == 3) + { + + /* Check if the server accepted our authentication type. */ + if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_AUTHENTICATION_TYPE_ACCEPTED) + { + + /* It did not. Or we may be out of synch with the SMTP Server, if we get a + 354 message for example. Abort the mail session. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + return NX_SUCCESS; + } + /* Authentication in progress. */ + + } + else + { + + /* Set session to the QUIT state. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + return NX_SUCCESS; + } + + /* Is authentication in progress? */ + if (client_ptr -> nx_smtp_client_authentication_state != NX_SMTP_AUTHENTICATION_SUCCEEDED) + { + + /* Set allowed authentication string length. */ + auth_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; + + /* Find the end (e.g. CRLF) of the server reply. */ + _nx_smtp_find_crlf(client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr, + auth_length, &carriage_return_linefeed_ptr, NX_FALSE); + + /* Check for invalid server reply (e.g. missing CRLF). */ + if (carriage_return_linefeed_ptr== NX_NULL) + { + + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return completion status. */ + return NX_SUCCESS; + } + + /* Yes, process (decode) the server's challenge. */ + status = _nx_smtp_utility_authentication_challenge(client_ptr, client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr, + (UINT)(carriage_return_linefeed_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr)); + + /* Did the session successfully handle server challenge? */ + if (status == NX_SUCCESS) + { + + /* Yes, set session to respond to the next server challenge. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH_CHALLENGE; + } + /* Did the session have problems parsing the server challenge? */ + else + { + + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; + + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return completion status. */ + return NX_SUCCESS; + } + } + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful status. */ + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_auth_challenge PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a reply to the server authentication challenge*/ +/* It determines which challenge the server sent (e.g Username, */ +/* Password) and encodes the session response using base64 encryption. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* _nx_smtp_base64_encode Base64 encode specified text */ +/* memcpy Copy data to area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP session */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; +UCHAR auth_reply_encoded[NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE + 1]; +UINT length; +UINT password_length; + + /* Initialize the encoded reply to NULL. */ + memset(auth_reply_encoded, 0, sizeof(auth_reply_encoded)); + + /* Verify string length. */ + if (_nx_utility_string_length_check(client_ptr -> nx_smtp_password, &password_length, NX_SMTP_CLIENT_MAX_PASSWORD)) + { + return(NX_SIZE_ERROR); + } + + /* Did the server send us the Username prompt? */ + if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT) + { + if (_nx_utility_string_length_check(client_ptr -> nx_smtp_username, &length, NX_SMTP_CLIENT_MAX_USERNAME)) + { + return(NX_SIZE_ERROR); + } + + + if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN) + { + + UCHAR plain_auth_buffer[NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE]; + + if (NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE < (length + 1 + length + password_length)) + { + + /* Buffer size too small. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + memset(&plain_auth_buffer[0], 0, NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE); + + /* Process the client name as per AUTH PLAIN syntax: authorization-id\0authentication-id\0password. */ + memcpy(&plain_auth_buffer[0], client_ptr -> nx_smtp_username, length); + length++; + memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_username, length); + length += length; + memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_password, password_length); + length += password_length; + + /* Now encode the combined client username/password. */ + _nx_smtp_base64_encode(&plain_auth_buffer[0], auth_reply_encoded, length); + + } + else + { + /* Just encode the client username. */ + _nx_smtp_base64_encode((UCHAR *)client_ptr -> nx_smtp_username, auth_reply_encoded, + length); + } + + } + /* Or did the server send us the Password prompt? */ + else if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT) + { + + /* Encode the client password. */ + _nx_smtp_base64_encode((UCHAR *)client_ptr -> nx_smtp_password, auth_reply_encoded, + password_length); + } + + else + { + + /* Unknown prompt: Send the '*' to terminate the authentication process. */ + memcpy(auth_reply_encoded, NX_SMTP_CANCEL_AUTHENTICATION, sizeof(NX_SMTP_CANCEL_AUTHENTICATION)); + } + + if (_nx_utility_string_length_check((CHAR *)auth_reply_encoded, &length, sizeof(auth_reply_encoded) - 1)) + { + return(NX_SIZE_ERROR); + } + + if (sizeof(_nx_smtp_buffer) < (length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) + { + + /* Buffer size too small. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + /* Format the encoded response. */ + memcpy(&_nx_smtp_buffer[0],auth_reply_encoded, length); + index = length; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the response back to the server. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for successful. */ + if (status == NX_SUCCESS) + { + + /* Set session state to wait on the outcome of the AUTH challenge handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + } + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_auth_challenge PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This receives the server's response to the AUTH challenge sent by */ +/* the session previously and actually just calls the same session */ +/* AUTH server reply handler again. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_rsp_auth AUTH server reply handler */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Run the session AUTH server reply handler directly. */ + status = _nx_smtp_rsp_auth(client_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_mail PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the MAIL command and sets the Client state to */ +/* send it to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr) +{ + +UINT index; +UINT status; +UINT mail_from_length; +NX_SMTP_CLIENT_MAIL *mail_ptr = &client_ptr -> nx_smtp_client_mail; + + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE)) + { + return(NX_SIZE_ERROR); + } + + /* Check if authentication status still left as 'in progress'. */ + if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_IN_PROGRESS) + { + + /* For some reason, authentication did not complete. Reset status here. */ + client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED; + } + + /* Validate message size. */ + if((sizeof(NX_SMTP_COMMAND_MAIL) + mail_from_length + + sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE) + { + /* Message size exceeds buffer size. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + /* Create the command text. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_MAIL, sizeof(NX_SMTP_COMMAND_MAIL) - 1); + index = sizeof(NX_SMTP_COMMAND_MAIL) - 1; + + _nx_smtp_buffer[index++] = ':'; + _nx_smtp_buffer[index++] = '<'; + memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_from_address, mail_from_length); + index += mail_from_length; + _nx_smtp_buffer[index++] = '>'; + + _nx_smtp_buffer[index++] = ' '; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the session command we constructed above. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status.*/ + return status; + } + + /* Set session state to wait on the outcome of the MAIL response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return successful session status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_mail PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This receives the server's response to the MAIL command; it */ +/* extracts the server reply code and reply text and store both to the */ +/* Client session. It will also set the next SMTP command to send to */ +/* the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + /* Get the server response to the MAIL command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* This is an invalid line or corrupted transmission from the server. */ + + /* Return error status. */ + return(status); + } + + /* Did server accept the MAIL command? */ + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) + { + + /* Yes, set the session to the RCPT state. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_RCPT; + } + else + { + + /* Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MAIL_REPLY_ERROR; + } + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful session status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_rcpt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the RCPT command and sets the Client state to */ +/* send it to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; +UINT recipient_length; +NX_SMTP_CLIENT_MAIL *mail_ptr; + + + mail_ptr = &(client_ptr -> nx_smtp_client_mail); + + if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE)) + { + return(NX_SIZE_ERROR); + } + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + /* Validate message size. */ + if((sizeof(NX_SMTP_COMMAND_RCPT) + recipient_length + + sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE) + { + /* Message size exceeds buffer size. */ + return(NX_SMTP_INTERNAL_ERROR); + } + + /* Create the command text. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RCPT, sizeof(NX_SMTP_COMMAND_RCPT) - 1); + index = sizeof(NX_SMTP_COMMAND_RCPT) - 1; + + _nx_smtp_buffer[index++] = ':'; + _nx_smtp_buffer[index++] = '<'; + memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_recipient_address, + recipient_length); + index += recipient_length; + _nx_smtp_buffer[index++] = '>'; + _nx_smtp_buffer[index++] = ' '; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the RCPT command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait next response from server. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_rcpt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This service handles the server's response to the RCPT command and */ +/* set the next session state and next command to send to the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get server response to RCPT command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Did server accept RCPT command? */ + if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE) + { + /* NO, Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_RCPT_REPLY_ERROR; + } + else + { + + /* Ok for server to send the mail message */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_DATA; + } + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the DATA command text, verifies the mail to send */ +/* has a valid recipient and sends it to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send SMTP commend to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; + + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + /* Format the DATA command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_DATA, sizeof(NX_SMTP_COMMAND_DATA) - 1); + index = sizeof(NX_SMTP_COMMAND_DATA) - 1; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the DATA command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait next response from server. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the server reply to the DATA command and set */ +/* the next SMTP Client command to send to the server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get the response to DATA command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return (status); + } + + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_SEND_MAIL_INPUT) + { + + /* Yes, set session state to next step. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MESSAGE; + } + else + { + + /* No, any other 3xy code in inappropriate. Quit the session. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_DATA_REPLY_ERROR; + } + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the mail message text handling for message */ +/* text. It attempts to fit as much of each message into each packet */ +/* as possible. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NOT_ENABLED IPv6 not enabled */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +ULONG data_left_to_transmit; +ULONG packet_payload; +CHAR *data_to_send; +NX_PACKET_POOL *pool_ptr; +NX_SMTP_CLIENT_MAIL *mail_ptr; + + + /* Set local variable for convenience. */ + mail_ptr = &client_ptr -> nx_smtp_client_mail; + + /* Set session state to wait next response from server. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr; + + /* Compute packet payload after IP and TCP headers are subtracted. */ + if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV4_HEADER); +#else + return NX_NOT_ENABLED; +#endif /* NX_DISABLE_IPV4 */ + } + else + { +#ifdef FEATURE_NX_IPV6 + packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV6_HEADER); +#else + return NX_NOT_ENABLED; +#endif + } + + + /* Send the Mail header */ + status = _nx_smtp_utility_send_header_to_server(client_ptr, NX_SMTP_CLIENT_SEND_TIMEOUT); + if(status) + return(status); + + /* Set up local variable of size of mail message. */ + data_left_to_transmit = mail_ptr -> nx_smtp_client_mail_body_length; + + /* Set a local pointer to (rest of) mail message to send. */ + data_to_send = mail_ptr -> nx_smtp_client_mail_body; + + /* Send the next chunk of mail text buffer till nothing is left. */ + while(data_left_to_transmit) + { + + /* Check if remaining mail text will fit in a packet.*/ + if (packet_payload >= data_left_to_transmit) + { + + /* Yes, send it off! This will load the specified data into an packet from the SMTP client packet pool. */ + status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, data_left_to_transmit, + NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + break; + } + + /* No, break up mail message into multiple packets. */ + else + { + + /* Fill up the packet with as much data as it will hold and send it off! */ + status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, packet_payload, + NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Update pointer to remainder of message to send, update how much is left to send. */ + data_left_to_transmit -= packet_payload; + data_to_send += packet_payload; + } + } + + /* Send end of message (EOM) to server or it will handle subsequent commands as message text. */ + status = _nx_smtp_utility_send_to_server(client_ptr, NX_SMTP_EOM, sizeof(NX_SMTP_EOM) - 1, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Return normal session status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This receives the server's response to sending it mail message data.*/ +/* It extracts the server reply code and reply text and store both to */ +/* the Client session. It then sets the next session state, sets up */ +/* the next command to send to the server. */ +/* */ +/* If the server accepts the mail message, this function determines if */ +/* if there is more session mail to transact, and if so sets the next */ +/* Client mail. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply code */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get the server reply to receiving session mail message data. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_MESSAGE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error status. */ + return(status); + } + + /* Process server reply code by first digit. */ + if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) + { + + /* Message accepted by server. Mark the Client mail as sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS; + } + else + { + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MESSAGE_REPLY_ERROR; + } + + /* We're done with this session */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful session status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_quit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the QUIT command text and and sends the Quit */ +/* command to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; + + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + /* Format the QUIT command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_QUIT, sizeof(NX_SMTP_COMMAND_QUIT) - 1); + index = sizeof(NX_SMTP_COMMAND_QUIT) - 1; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR)); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the QUIT command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Set session state to wait on the outcome of the EHLO response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_quit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the server reply to the SMTP QUIT command and */ +/* sets the session state to the session has terminated normally. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get server response to QUIT command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error status. */ + if (status != NX_SUCCESS) + { + + /* Return the error status. */ + return(status); + } + + /* Set the session state to normal termination. Normal is when the SMTP Client can + receive SMTP server replies and regardless if mail can be sent, can at least + terminate the session with the Quit command and normal TCP socket disconnect. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY; + + /* We are done with the packet now. */ + nx_packet_release(client_ptr -> nx_smtp_server_packet); + + /* Return successful session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_rset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This functions creates the RSET command for the Client task to send */ +/* it to the SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr) +{ + +ULONG timeout; +UINT status; +UINT index; + + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + /* Get TCP send timeout. */ + timeout = NX_SMTP_ENVELOPE_TIMEOUT; + + /* Format the RSET command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RSET, sizeof(NX_SMTP_COMMAND_RSET) - 1); + index = sizeof(NX_SMTP_COMMAND_RSET) - 1; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof( NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the RSET command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, timeout); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait on the outcome of the EHLO response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_rset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the RSET server reply. */ +/* */ +/* Resetting an SMTP session means clearing the Client mail transaction*/ +/* including recipients and mail text. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get server response to RSET command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return(status); + } + + /* Did the session receive the 250 OK from the server? */ + if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE) + { + + /* Yes, set the session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED; + } + else + { + + /* Yes, session accepted the RSET command with the 250 code. + Reset session state back to MAIL. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; + + } + + /* Return successful session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_cmd_noop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates the SMTP NOOP command text and sends it to the*/ +/* SMTP server. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr SMTP Session for sending mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_send_to_server Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT index; + + + memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); + + /* Format the NOOP command. */ + memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_NOOP, sizeof(NX_SMTP_COMMAND_NOOP) - 1); + index = sizeof(NX_SMTP_COMMAND_NOOP) - 1; + memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); + index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; + + /* Send the NOOP command. */ + status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Set session state to wait on the outcome of the EHLO response handler. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; + + /* Return normal session status. */ + return NX_SUCCESS; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_rsp_noop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the NOOP server reply. It will not */ +/* automatically advance the session state like most other SMTP client */ +/* commands. However, an indication of server problems will set the */ +/* session state to QUIT. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr TCP connection to send mail */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_utility_read_server_code Parse the server reply */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_client_process Runs the SMTP state machine */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr) +{ + +UINT status; +UINT first_digit_server_reply; + + + /* Get the response for NOOP command. */ + status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error status. */ + return(status); + } + + /* Get category of server reply from the first digit. */ + first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status / 100; + + /* Is the server experiencing problems forcing the session to abort? */ + if (first_digit_server_reply == 4) + { + + /* Yes, set the session state to quit. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED; + } + + /* Return successful session status. */ + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_utility_read_server_code PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the 3 digit SMTP server code and stores the */ +/* text of the server reply if there is any to the session buffer. */ +/* Its use is intended primarily for session server reply handlers. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* timeout Timeout on receiving server reply */ +/* receive_all_lines Indicates if SMTP Client should expect*/ +/* one packet or multiple packets e.g. */ +/* a multi packet server reply. */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_parse_response Parse an argument from text */ +/* nx_tcp_socket_receive Receive data over TCP socket */ +/* nx_packet_release Release packet to packet pool */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Session server reply handlers Handle server replies to SMTP */ +/* commands in the session */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines) +{ + +UINT status; +NX_PACKET *packet_ptr; +UCHAR server_code[NX_SMTP_SERVER_REPLY_CODE_SIZE + 1]; +UCHAR *work_ptr; +UINT buffer_length; + + NX_PARAMETER_NOT_USED(receive_all_lines); + + /* Initialize argument to NULL. */ + memset(server_code, 0, NX_SMTP_SERVER_REPLY_CODE_SIZE + 1); + + /* Process all packets received as part of server reply. A server response may + have several 'lines' in it e.g. 250-EHLO\r\n250-AUTH LOGIN\r\n250 HELP, + and this may be spread over multiple packets. */ + + /* Wait to receive the next packet. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_smtp_client_socket), &packet_ptr, timeout); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Return error status. */ + return status; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(packet_ptr); + + /* Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; + + /* While there was an error with the packet, the SMTP Client is ok. So just return + completion status and we quit the session. */ + return NX_SUCCESS; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Save the location of the server response buffer. */ + client_ptr -> nx_smtp_server_packet = packet_ptr; + + work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr; + buffer_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; + + /* Yes, parse the server code. Note that with SMTP protocol, the server reply + may be multiple lines/packets. To determine if we have the end of the reply + we look for the command code followed by a space (not a hyphen). */ + status = _nx_smtp_parse_response(client_ptr, work_ptr, 1, buffer_length, &server_code[0], + NX_SMTP_SERVER_REPLY_CODE_SIZE, NX_FALSE); + + /* Was a server reply code found in the first line? */ + if (status != NX_SUCCESS) + { + + /* No, it wasn't. */ + nx_packet_release(packet_ptr); + + /* Set session state to QUIT. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; + + /* Indicate mail cannot be sent. */ + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; + + /* While there was an error with the packet, the SMTP Client is ok. So just return + completion status and we quit the session. */ + return NX_SUCCESS; + } + + /* Convert server code from text to unsigned int and store to session. */ + client_ptr -> nx_smtp_client_reply_code_status = strtoul((const char *)server_code, NULL, 10); + + /* Return completion status. */ + return (NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_utility_send_to_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compiles the message/command to send the SMTP server. */ +/* It returns a non success status if packet allocation fails or an */ +/* error results from creating the SMTP command packet. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* buffer_ptr Pointer to buffer for to send */ +/* buffer_length Size of buffer */ +/* timeout Timeout for sending data out */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from specified pool */ +/* nx_packet_data_append Appends buffer to packet data */ +/* nx_packet_release Releases send packet back to pool */ +/* nx_tcp_socket_send Sends packet out over TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_session_run Runs the SMTP state machine */ +/* Session server reply handlers Handle server reply so SMTP command */ +/* Session SMTP command services Send SMTP commands to server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout) +{ + +UINT status; +NX_PACKET *packet_ptr; +UINT packet_type; + + + if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_smtp_client_packet_pool_ptr, + &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_PACKET_ALLOCATE_ERROR; + + /* Return error status. */ + return(status); + } + + /* Add message to packet data. */ + status = nx_packet_data_append(packet_ptr, buffer_ptr, buffer_length, + client_ptr -> nx_smtp_client_packet_pool_ptr, + NX_SMTP_CLIENT_PACKET_TIMEOUT); + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Abort further processing. This error is most likely a packet allocate. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR; + + /* Return error status. */ + return(status); + } + + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Abort further processing. If we are unable to send, we won't be able to send a quit message either. */ + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + + /* Return error status. */ + return(status); + } + + /* Return successful session status. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_utility_send_to_server PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compiles the message/command to send the SMTP server. */ +/* It returns a non success status if packet allocation fails or an */ +/* error results from creating the SMTP command packet. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* buffer_ptr Pointer to buffer for to send */ +/* buffer_length Size of buffer */ +/* timeout Timeout for sending data out */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from specified pool */ +/* nx_packet_data_append Appends buffer to packet data */ +/* nx_packet_release Releases send packet back to pool */ +/* nx_tcp_socket_send Sends packet out over TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_session_run Runs the SMTP state machine */ +/* Session server reply handlers Handle server reply so SMTP command */ +/* Session SMTP command services Send SMTP commands to server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout) +{ + +UINT status; +NX_PACKET *packet_ptr = NX_NULL; +UINT packet_type; +NX_SMTP_CLIENT_MAIL *mail_ptr; +NX_PACKET_POOL *pool_ptr; +UINT recipient_length; +UINT mail_from_length; +UINT subject_length; + + + mail_ptr = &client_ptr -> nx_smtp_client_mail; + + if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6) + packet_type = NX_IPv6_TCP_PACKET; + else + packet_type = NX_IPv4_TCP_PACKET; + + /* Verify string length. */ + if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE)) + { + return(NX_SIZE_ERROR); + } + + if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE)) + { + return(NX_SIZE_ERROR); + } + + if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_subject, &subject_length, NX_SMTP_BUFFER_SIZE)) + { + return(NX_SIZE_ERROR); + } + + + pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr; + + /* Allocate a packet. */ + status = nx_packet_allocate(pool_ptr, &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status == NX_SUCCESS) + { + if (/* Add "To: CRLF" */ + (nx_packet_data_append(packet_ptr, NX_SMTP_TO_STRING, sizeof(NX_SMTP_TO_STRING) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_recipient_address, + recipient_length, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + /* Add "From: CRLF" */ + (nx_packet_data_append(packet_ptr, NX_SMTP_FROM_STRING, sizeof(NX_SMTP_FROM_STRING) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_from_address, + mail_from_length, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + /* Add "Subject: Subject_line CRLF" */ + (nx_packet_data_append(packet_ptr, NX_SMTP_SUBJECT_STRING, sizeof(NX_SMTP_SUBJECT_STRING) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_subject, + subject_length, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && + /* Add the rest of the mail header components. */ + (nx_packet_data_append(packet_ptr, NX_SMTP_MAIL_HEADER_COMPONENTS, sizeof(NX_SMTP_MAIL_HEADER_COMPONENTS) - 1, + pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS)) + { + /* Send the packet out. */ + status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout); + + if(status) + { + /* Send failed. */ + status = NX_SMTP_INTERNAL_ERROR; + } + } + else + { + /* One of the Mail header components failed to be appended. */ + status = NX_SMTP_INTERNAL_ERROR; + } + } + + if(status) + { + + /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */ + client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; + client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; + + client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR; + + if(packet_ptr) + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + } + + + /* Return successful session status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_utility_authentication_challenge PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles parsing and decoding the server challenge, */ +/* and setting up the client response to the challenge. It does not */ +/* alter the session state or determine the next session command. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* server_challenge Buffer containing server challenge */ +/* length Size of server challenge buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SMTP_PARAM_ERROR Server parsing (parameter) error */ +/* */ +/* CALLS */ +/* */ +/* _nx_smtp_parse_response Parses argument from buffer text */ +/* _nx_smtp_base64_decode Decodes base64 text */ +/* memset Clears specified area of memory */ +/* memcmp Compares data between areas of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_rsp_auth AUTH server reply handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *server_challenge, UINT length) +{ + +UCHAR encrypted_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1]; +UCHAR decoded_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1]; + + if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN) + { + /* Set the session to reply to a username challenge. */ + client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT; + + /* Return successful session status. */ + return NX_SUCCESS; + } + + /* Clear buffers for storing encrypted and decoded server challenges. */ + memset(encrypted_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1); + memset(decoded_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1); + + /* Parse the 2nd argument for the server challenge we need to decode. */ + _nx_smtp_parse_response(client_ptr, &server_challenge[0], 2, length, &encrypted_server_prompt[0], + NX_SMTP_SERVER_CHALLENGE_MAX_STRING, NX_FALSE); + + /* Was a valid argument parsed? */ + if (*encrypted_server_prompt == NX_NULL) + { + + /* No , unable to parse server prompt. */ + + /* Return error status. */ + return NX_SMTP_INVALID_SERVER_REPLY; + } + + /* Decode the parsed server challenge. */ + _nx_smtp_base64_decode(encrypted_server_prompt, decoded_server_prompt); + + /* Is this a username prompt? */ + if (((decoded_server_prompt[0] == 'U') || (decoded_server_prompt[0] == 'u')) && + ((decoded_server_prompt[1] == 'S') || (decoded_server_prompt[1] == 's')) && + ((decoded_server_prompt[2] == 'E') || (decoded_server_prompt[2] == 'e')) && + ((decoded_server_prompt[3] == 'R') || (decoded_server_prompt[3] == 'r')) && + ((decoded_server_prompt[4] == 'N') || (decoded_server_prompt[4] == 'n')) && + ((decoded_server_prompt[5] == 'A') || (decoded_server_prompt[5] == 'a')) && + ((decoded_server_prompt[6] == 'M') || (decoded_server_prompt[6] == 'm')) && + ((decoded_server_prompt[7] == 'E') || (decoded_server_prompt[7] == 'e')) && + (decoded_server_prompt[8] == ':')) + { + + /* Yes, set the session to reply to a username challenge. */ + client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT; + } + /* Is this a password prompt? */ + else if (((decoded_server_prompt[0] == 'P') || (decoded_server_prompt[0] == 'p')) && + ((decoded_server_prompt[1] == 'A') || (decoded_server_prompt[1] == 'a')) && + ((decoded_server_prompt[2] == 'S') || (decoded_server_prompt[2] == 's')) && + ((decoded_server_prompt[3] == 'S') || (decoded_server_prompt[3] == 's')) && + ((decoded_server_prompt[4] == 'W') || (decoded_server_prompt[4] == 'w')) && + ((decoded_server_prompt[5] == 'O') || (decoded_server_prompt[5] == 'o')) && + ((decoded_server_prompt[6] == 'R') || (decoded_server_prompt[6] == 'r')) && + ((decoded_server_prompt[7] == 'D') || (decoded_server_prompt[7] == 'd')) && + (decoded_server_prompt[8] == ':')) + { + + /* Yes, set the session to reply to a password challenge. */ + client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT; + } + else + { + + /* Indicate invalid authentication from server. */ + return NX_SMTP_CLIENT_REPLY_TO_UNKNOWN_PROMPT; + } + + /* Return successful session status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_utility_parse_server_services PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for the AUTH option in the server response. If */ +/* authentication is offered, it attempts to find a match between */ +/* authentication options offered by the server and the client */ +/* authentication type. If no match between client and server is found,*/ +/* or no authentication is listed in the server response, it sets the */ +/* client authentication type to PLAIN. */ +/* */ +/* INPUT */ +/* */ +/* session_ptr Session to send mail to SMTP Server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* strstr Search for a string within a string */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_rsp_ehlo EHLO server reply handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr) +{ + +UINT plain_option = NX_FALSE; +UINT login_option = NX_FALSE; +UCHAR *work_ptr; +UCHAR *temp_ptr; +ULONG length, new_length; +UINT i; +UINT found = NX_FALSE; + + + /* Does the server list an authentication type, and does the client want authentication? */ + + /* Set local variable for convenience. */ + length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; + + /* Find the location of the AUTH command. */ + work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr; + + for (i = 0; i < length - 4; i++) + { + if ( + ((*work_ptr == 'A') || (*work_ptr == 'a')) && + ((*(work_ptr + 1) == 'U') || (*(work_ptr + 1) == 'u')) && + ((*(work_ptr + 2) == 'T') || (*(work_ptr + 2) == 't')) && + ((*(work_ptr + 3) == 'H') || (*(work_ptr + 3) == 'h')) + ) + { + + found = NX_TRUE; + work_ptr += 4; + break; + } + + work_ptr++; + } + + /* Check if this packet has the AUTH keyword. */ + if (!found ) + { + + /* It does not. So leave the Client authentication type as is. */ + return NX_SUCCESS; + } + + /* Check if the client prefers no authentication. */ + if (found && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_NONE)) + { + + /* There is an AUTH keyword but the client prefers not to authenticate. */ + return NX_SUCCESS; + } + + /* Save the location where the search stopped. */ + temp_ptr = work_ptr; + + found = NX_FALSE; + new_length = (length - 5) - (ULONG)(temp_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr); + + /* Search for supported authentication types. */ + for (i = 0; i < new_length; i++) + { + if ( + ((*work_ptr == 'L') || (*work_ptr == 'l')) && + ((*(work_ptr + 1) == 'O') || (*(work_ptr + 1) == 'o')) && + ((*(work_ptr + 2) == 'G') || (*(work_ptr + 2) == 'g')) && + ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) && + ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n')) + ) + { + found = NX_TRUE; + break; + } + + work_ptr++; + } + + /* Is there a LOGIN option offered? */ + if (found) + { + /* Yes, set the login option flag. */ + login_option = NX_TRUE; + } + + found = NX_FALSE; + + /* Restore the location for a new search. */ + work_ptr = temp_ptr; + + for (i = 0; i < new_length; i++) + { + if ( + ((*work_ptr == 'P') || (*work_ptr == 'p')) && + ((*(work_ptr + 1) == 'L') || (*(work_ptr + 1) == 'l')) && + ((*(work_ptr + 2) == 'A') || (*(work_ptr + 2) == 'a')) && + ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) && + ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n')) + ) + { + found = NX_TRUE; + break; + } + + work_ptr++; + } + + /* Is there a PLAIN option offered? */ + if (found) + { + /* Yes, set the plain option flag. */ + plain_option = NX_TRUE; + } + + /* Compare Server list of authentication types to client preferred authentication type. */ + + /* Handle the case of the client prefers LOGIN authentication. */ + if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN) + { + + /* Yes; Check if server supports offers LOGIN authentication. */ + if (login_option) + { + + return NX_SUCCESS; + } + else + { + /* Switch client to plain authentication. */ + client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; + + return NX_SUCCESS; + } + } + + /* Check if server listed PLAIN authentication. */ + if (plain_option && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN)) + { + /* Yes, and there's a match, we're done here. */ + return NX_SUCCESS; + } + + /* If we are here, the server offers LOGIN authentication but the Client preference is something else. */ + if (login_option) + { + + /* Switch client to LOGIN authentication. */ + client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_LOGIN; + + return NX_SUCCESS; + } + + /* Handle the case of no matches between server/client. Assume the server requires authentication + and set Client type to plain. */ + client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; + + /* Return successful completion of checking options. */ + return NX_SUCCESS; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_parse_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses the argument specified by the argument index */ +/* from the supplied buffer. The first argument is at index 1. */ +/* If the specified argument can't be found the argument pointer at NULL.*/ +/* */ +/* Carriage return/line feeds can be treated as word word separator if */ +/* specified by the crlf_are_word_breaks parameter. For OK TO CONTINUE */ +/* messages (250), this function searches the whole message for the last */ +/* occurance of the server code e.g. code followed by a space. */ +/* */ +/* Carriage return/line feeds are removed if found on the end of the */ +/* parsed argument. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client instance */ +/* buffer Pointer to buffer to parse */ +/* argument_index Identify which argument to parse */ +/* buffer_length Size of buffer to parse */ +/* argument Argument to parse from buffer */ +/* argument_length Size of argument buffer */ +/* crlf_are_word_breaks Treat \r\n's as word breaks */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successfully parsed reply code or */ +/* authentication challenge */ +/* NX_SMTP_INVALID_PARAM Invalid input */ +/* */ +/* CALLS */ +/* */ +/* toupper Convert chars to upper case */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT argument_index, + UINT buffer_length, UCHAR *argument, + UINT argument_length, UINT crlf_are_word_breaks) +{ + + +UINT i = 0; +UINT j = 0; +UINT argument_char_count = 0; +UCHAR *work_ptr; +UINT is_last_code; + + + memset(&argument[0], 0, argument_length); + work_ptr = argument; + + /* Check for invalid input parameters. */ + if ((buffer == NX_NULL) || (argument == NX_NULL) || (buffer_length == 0) || + (argument_length == 0) || (argument_index == 0)) + { + + return NX_SMTP_INVALID_PARAM; + } + + /* Is this the first word? + The first word is the reply code, not an SMTP command parameter */ + if (argument_index == 1) + { + + /* Yes, search each character up to the end of the buffer for + the first separator. */ + while (i < buffer_length) + { + + /* Have we reached a word break? */ + if ( + (argument[0] != 0) && + ((*buffer == ' ') || (*buffer == '-')) + ) + { + /* Yes, this marks the end of the first argument (word). */ + break; + } + + /* Are we starting a number? */ + else if ((*buffer >= 0x30) && (*buffer <= 0x39)) + { + + /* Yes, copy to buffer. */ + *work_ptr = *buffer; + work_ptr++; + } + else + { + /* Not a number. make sure the argument buffer is reset */ + memset(&argument[0], 0, argument_length); + work_ptr = argument; + } + + /* Get the next character in the buffer. */ + buffer++; + i++; + } + + /* Are we at the end of the buffer? */ + if (i == buffer_length) + { + + /* Yes, is there a line terminator? */ + if (*(argument - 2) == 0x0D && *(argument - 1) == 0x0A) + { + + /* Yes, remove it with a null character */ + *(argument - 2) = (CHAR) 0x0; + } + } + } + else + { + /* No, we're not parsing the first argument. This is a special case for parsing + the server authentication challenge, not just the reply code. */ + + /* Mark the start of the argument at the separator after + the end of the previous argument. */ + while ((j < argument_index) && (i < buffer_length)) + { + + /* Keep track of the number of separators in the buffer */ + /* OD0A marks the end of a line usually in SMTP */ + + /* Did we hit a line terminator? */ + if ((*buffer == 0x0D) && (*(buffer + 1) == 0x0A)) + { + + /* Yes, Update the count of separators. */ + j++; + + /* Are line terminators as word breaks? */ + if (crlf_are_word_breaks == NX_FALSE) + { + + /* No, this is the end of the search buffer. + Argument not parsed from buffer, return error. */ + return NX_SMTP_INVALID_SERVER_REPLY; + } + + /* Get the next character after '\n' byte in the buffer. */ + i++; + buffer++; + } + /* Did we hit a space or a dash in the first argument? */ + else if ((*buffer == ' ') || ((*buffer == '-') && (j == 0))) + { + + /* Yes; these are counted as separators (note that dashes found in arguments + after the first argument are NOT considered separators. */ + j++; + } + else + { + + /* No, is this the argument to parse? */ + if (j == (argument_index - 1)) + { + /* Yes; did we go past the argument size limit before the next word break? */ + if (argument_char_count >= argument_length) + { + + /* Yes, unable to finish parsing this buffer. Return error. */ + return NX_SMTP_INVALID_SERVER_REPLY; + } + + /* No, copy the next character into the argument. */ + argument_char_count++; + + /* Convert to uppercase if the caller requests. */ + *argument++ = *buffer; + } + } + + /* Get the next character in the buffer. */ + buffer++; + i++; + } + } + + /* Determine if this is the last 250 in the message (e.g. followed by a space, not hyphen) */ + work_ptr = buffer - 3; + + if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == '-')) + { + + UINT status; + + /* Parse the rest of the buffer to see if this packet contains the last 250 code. */ + status = _nx_smtp_parse_250_response(buffer, buffer_length - i, &is_last_code); + if (status) + { + /* Error with parsing response. */ + return status; + } + + /* Did we parse the whole 250 response? */ + if (is_last_code != NX_TRUE) + { + /* NO, so we are waiting for another 250 packet. */ + client_ptr -> nx_smtp_client_mute = NX_TRUE; + } + else + { + + /* YES, so we are NOT waiting for a packet with the last 250 code. */ + client_ptr -> nx_smtp_client_mute = NX_FALSE; + } + } + else if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == ' ')) + { + client_ptr -> nx_smtp_client_mute = NX_FALSE; + } + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_parse_250_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called to search the rest of the message for the last*/ +/* instance of the server code 250. The first 250 has been found but */ +/* followed by a hyphen, indicating more 250's in the message. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to buffer to parse */ +/* buffer_length Size of buffer to parse */ +/* is_last_code Indicate if last 250 found */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successfully parsed last code */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_parse_response Parse (any) code in server message */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code) +{ + + *is_last_code = NX_FALSE; + + /* Are there more 250 codes in this buffer? Advance the buffer + pointer and search for a 250 followed by a space. */ + + while (buffer_length > 3) + { + /* Find next 250[sp] in the buffer */ + if ((*buffer_ptr == '2') && + (*(buffer_ptr + 1) == '5') && + (*(buffer_ptr + 2) == '0') && + (*(buffer_ptr + 3) == ' ')) + { + *is_last_code = NX_TRUE; + break; + } + else + { + buffer_ptr++; + buffer_length--; + } + } + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_find_crlf PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns a pointer to the first carriage return/line */ +/* feed (CRLF) sequence found in the buffer. If no CRLF is found within */ +/* length specified, the CRLF pointer is left at NULL. If specified the */ +/* search can start at the end of the buffer and work backwards to the */ +/* first CRLF found. */ +/* */ +/* INPUT */ +/* */ +/* buffer Pointer to buffer to search */ +/* length Size of buffer to search */ +/* CRLF Pointer to CRLF found in buffer */ +/* in_reverse Search buffer in reverse direction */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT in_reverse) +{ + +UINT i = 0; + + *CRLF = NULL; + + if ((buffer == NX_NULL) || (length == 0)) + { + return; + } + + + /* Search for CRLF from end to start of buffer (reverse) */ + if (in_reverse == NX_TRUE) + { + + /* Move pointer out to the end of the buffer. */ + buffer += length - 1; + + while (i < length - 1) + { + if (*(buffer - 1) == 0x0D && *buffer == 0x0A) + { + /* Set the location of CRLF sequence. */ + *CRLF = buffer - 1; + break; + } + + /* Move the pointer back one. */ + buffer--; + + /* Keep track how many bytes we've gone. */ + i++; + } + } + /* Search for CRLF starting at the beginning of the buffer */ + else + { + while( i < length - 1) + { + if (*buffer == 0x0D && *(buffer + 1) == 0x0A) + { + /* Set the location of CRLF sequence. */ + *CRLF = buffer; + + break; + } + i++; + buffer++; + } + } + + return ; +} + + +CHAR _nx_smtp_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_base64_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the input string into a base64 */ +/* representation. It is the caller's responsibility to match the */ +/* name and base64name buffers in size to avoid overwriting memory. */ +/* */ +/* INPUT */ +/* */ +/* name Pointer to name to encode */ +/* base64name Pointer to name base64 encoded */ +/* length Size of input buffer to encode */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_smtp_base64_encode(UCHAR *name, UCHAR *base64name, UINT length) +{ + +UINT pad; +UINT i, j; +UINT step; + + + /* Adjust the length to represent the base64 name. */ + length = ((length * 8) / 6); + + /* Default padding to none. */ + pad = 0; + + /* Determine if an extra conversion is needed. */ + if ((length * 6) % 24) + { + /* Some padding is needed. */ + + /* Calculate the number of pad characters. */ + pad = (length * 6) % 24; + pad = (24 - pad) / 6; + pad = pad - 1; + + /* Adjust the length to pickup the character fraction. */ + length++; + } + + /* Setup index into the base64name. */ + j = 0; + + /* Compute the base64name. */ + step = 0; + i = 0; + while (j < length) + { + /* Determine which step we are in. */ + if (step == 0) + { + /* Use first 6 bits of name character for index. */ + base64name[j++] = (UCHAR)_nx_smtp_base64_array[((UINT) name[i]) >> 2]; + step++; + } + else if (step == 1) + { + + /* Use last 2 bits of name character and first 4 bits of next name character for index. */ + base64name[j++] = (UCHAR)_nx_smtp_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; + i++; + step++; + } + else if (step == 2) + { + + /* Use last 4 bits of name character and first 2 bits of next name character for index. */ + base64name[j++] = (UCHAR)_nx_smtp_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; + i++; + step++; + } + else /* Step 3 */ + { + + /* Use last 6 bits of name character for index. */ + base64name[j++] = (UCHAR)_nx_smtp_base64_array[(((UINT) name[i]) & 0x3F)]; + i++; + step = 0; + } + } + + /* Determine if the index needs to be advanced. */ + if (step != 3) + i++; + + /* Now add the PAD characters. */ + while ((pad--) && (j < NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE)) + { + + /* Pad base64name with '=' characters. */ + base64name[j++] = '='; + } + + /* Put a NULL character in. */ + base64name[j] = NX_NULL; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_smtp_base64_decode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decodes the input base64 ASCII string and converts */ +/* it into a standard ASCII representation. It is the caller's */ +/* responsibility to match the name and base64name buffers in size to */ +/* avoid overwriting memory. */ +/* */ +/* INPUT */ +/* */ +/* base64name Encoded base64 name string */ +/* name Name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Get length of string */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_smtp_server_basic_authenticate Basic authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_smtp_base64_decode(UCHAR *base64name, UCHAR *name) +{ + +UINT length; +UINT i, j; +UINT value1, value2; +UINT step; + + + /* Calculate the name length. */ + if (_nx_utility_string_length_check((CHAR *)base64name, &length, NX_SMTP_SERVER_CHALLENGE_MAX_STRING)) + { + name[0] = NX_NULL; + return; + } + + /* Adjust the length to represent the ASCII name. */ + length = ((length * 6) / 8); + + /* Setup index into the ASCII name. */ + j = 0; + + /* Compute the ASCII name. */ + step = 0; + i = 0; + + while ((j < length) && (base64name[i]) && (base64name[i] != '=') && (j < NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE)) + { + + /* Derive values of the Base64 name. */ + if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) + value1 = (UINT) (base64name[i] - 'A'); + else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) + value1 = (UINT) (base64name[i] - 'a') + 26; + else if ((base64name[i] >= '0') && (base64name[i] <= '9')) + value1 = (UINT) (base64name[i] - '0') + 52; + else if (base64name[i] == '+') + value1 = 62; + else if (base64name[i] == '/') + value1 = 63; + else + value1 = 0; + + /* Derive value for the next character. */ + if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) + value2 = (UINT) (base64name[i+1] - 'A'); + else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) + value2 = (UINT) (base64name[i+1] - 'a') + 26; + else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) + value2 = (UINT) (base64name[i+1] - '0') + 52; + else if (base64name[i+1] == '+') + value2 = 62; + else if (base64name[i+1] == '/') + value2 = 63; + else + value2 = 0; + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first value and first 2 bits of second value. */ + name[j++] = (UCHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); + i++; + step++; + } + else if (step == 1) + { + + /* Use last 4 bits of first value and first 4 bits of next value. */ + name[j++] = (UCHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); + i++; + step++; + } + else if (step == 2) + { + + /* Use first 2 bits and following 6 bits of next value. */ + name[j++] = (UCHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); + i++; + i++; + step = 0; + } + } + + /* Put a NULL character in. */ + name[j] = NX_NULL; + + return; +} + diff --git a/addons/smtp/nxd_smtp_client.h b/addons/smtp/nxd_smtp_client.h new file mode 100644 index 00000000..d055d598 --- /dev/null +++ b/addons/smtp/nxd_smtp_client.h @@ -0,0 +1,433 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX SMTP Client Component */ +/** */ +/** Simple Mail Transfer Protocol (SMTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_smtp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Simple Mail Transfer Protocol (SMTP) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +#ifndef NXD_SMTP_CLIENT_H +#define NXD_SMTP_CLIENT_H + + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +/* NX SMTP Client configurable options. */ + +/* Set the TCP socket window size. */ + +#ifndef NX_SMTP_CLIENT_TCP_WINDOW_SIZE +#define NX_SMTP_CLIENT_TCP_WINDOW_SIZE 1460 +#endif + +/* Set timeout on Client packet allocation in ticks. */ + +#ifndef NX_SMTP_CLIENT_PACKET_TIMEOUT +#define NX_SMTP_CLIENT_PACKET_TIMEOUT (2 * NX_IP_PERIODIC_RATE) +#endif + +/* Set Client TCP connection timeout in seconds. */ + +#ifndef NX_SMTP_CLIENT_CONNECTION_TIMEOUT +#define NX_SMTP_CLIENT_CONNECTION_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +/* Set Client TCP disconnect timeout in seconds. */ + +#ifndef NX_SMTP_CLIENT_DISCONNECT_TIMEOUT +#define NX_SMTP_CLIENT_DISCONNECT_TIMEOUT (5 * NX_IP_PERIODIC_RATE) +#endif + +/* Set Client timeout in seconds for waiting for server reply to client greeting. */ + +#ifndef NX_SMTP_GREETING_TIMEOUT +#define NX_SMTP_GREETING_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + + +/* Set Client 'envelope' timeout in seconds for waiting for server reply to client commands. */ + +#ifndef NX_SMTP_ENVELOPE_TIMEOUT +#define NX_SMTP_ENVELOPE_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + + +/* Set Client timeout in seconds for waiting to receive server acceptance of client message data. */ + +#ifndef NX_SMTP_MESSAGE_TIMEOUT +#define NX_SMTP_MESSAGE_TIMEOUT (30 * NX_IP_PERIODIC_RATE) +#endif + + +/* Set timeout for TCP socket send completion. */ + +#ifndef NX_SMTP_CLIENT_SEND_TIMEOUT +#define NX_SMTP_CLIENT_SEND_TIMEOUT (5 * NX_IP_PERIODIC_RATE) +#endif + + +/* Define size for Client profile data. */ + +#ifndef NX_SMTP_CLIENT_MAX_USERNAME +#define NX_SMTP_CLIENT_MAX_USERNAME 40 +#endif + +#ifndef NX_SMTP_CLIENT_MAX_PASSWORD +#define NX_SMTP_CLIENT_MAX_PASSWORD 20 +#endif + + + +/* Define size of the buffer to extract the server challenge for authentication. + There is no specific size here so 200 bytes is sufficient to cover all digest string handling. */ +#ifndef NX_SMTP_SERVER_CHALLENGE_MAX_STRING +#define NX_SMTP_SERVER_CHALLENGE_MAX_STRING 200 +#endif + + +/* Define size for handling data for authentication (LOGIN, PLAIN): + PLAIN requires rooms for authorization-id\0authentication-id\0passwd'. + The two bytes are for the NULL byte between the first two auth id and + between auth id and password. */ + +#define NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE (NX_SMTP_CLIENT_MAX_USERNAME + NX_SMTP_CLIENT_MAX_USERNAME + NX_SMTP_CLIENT_MAX_PASSWORD + 2) +#define NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE (NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE * 4 / 3 + 1) + + +/* These define the states of the protocol state machine */ + +#define NX_SMTP_CLIENT_STATE_AWAITING_REPLY 0xFFFFFFFF /* Session state depends on outcome of current response handler. */ +#define NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY 0xFFFFFFFE /* No internal errors, session completed normally. */ +#define NX_SMTP_CLIENT_STATE_ERROR 0xFFFFFFFD /* Internal errors e.g. TCP send or receive fails; session terminated abnormally. */ + + +#define NX_SMTP_INVALID_PARAM 0xA5 /* Invalid non pointer input in an SMTP service call */ +#define NX_SMTP_INTERNAL_ERROR 0xA3 /* Internal processing error */ +#define NX_SMTP_AUTHENTICATION_ERROR 0xA0 /* Invalid input for creating Client authentication. */ +#define NX_SMTP_OVERSIZE_MAIL_DATA 0xA1 /* Mail message exceeds buffer size */ +#define NX_SMTP_INVALID_SERVER_REPLY 0xA2 /* Unknown or invalid server reply */ +#define NX_SMTP_SERVER_ERROR_CODE_RECEIVED 0xA4 /* Received an SMTP Server error code */ +#define NX_SMTP_PACKET_ALLOCATE_ERROR 0xA6 /* Error allocating packet for SMTP message transmission */ +#define NX_SMTP_GREET_REPLY_ERROR 0xA7 /* Error in response to Client SMTP GREET command */ +#define NX_SMTP_HELLO_REPLY_ERROR 0xA8 /* Error in response to Client SMTP HELO or EHLO command */ +#define NX_SMTP_MAIL_REPLY_ERROR 0xA9 /* Error in response to Client SMTP MAIL command */ +#define NX_SMTP_RCPT_REPLY_ERROR 0xAA /* Error in response to Client SMTP RCPT command */ +#define NX_SMTP_MESSAGE_REPLY_ERROR 0xAB /* Error in response to Client SMTP MESSAGE data sent */ +#define NX_SMTP_DATA_REPLY_ERROR 0xAC /* Error in response to Client SMTP DATA command */ +#define NX_SMTP_AUTH_REPLY_ERROR 0xAD /* Error in response to Client SMTP AUTH command */ +#define NX_SMTP_SERVER_ERROR_REPLY 0xAE /* Error in parsing Server reply code (not found or unknown) */ +#define NX_SMTP_TRANSMIT_ERROR 0xAF /* Error occurred during TCP packet transmission e.g. send queue full */ +#define NX_SMTP_INVALID_SERVER_CHALLENGE 0xB0 /* Invalid server challenge (e.g. missing enclosing angle brackets). */ +#define NX_SMTP_OVERSIZE_SERVER_REPLY 0xB1 /* Server reply exceeds client session buffer size */ +#define NX_SMTP_CLIENT_NOT_INTIALIZED 0xB2 /* Client not created successfully e.g. socket create failed. Cannot transmit mail. */ + +/* Basic SMTP commands supported by this NetX SMTP API. */ + +#define NX_SMTP_COMMAND_EHLO "EHLO" +#define NX_SMTP_COMMAND_HELO "HELO" +#define NX_SMTP_COMMAND_MAIL "MAIL FROM" +#define NX_SMTP_COMMAND_RCPT "RCPT TO" +#define NX_SMTP_COMMAND_AUTH "AUTH" +#define NX_SMTP_COMMAND_NOOP "NOOP" +#define NX_SMTP_COMMAND_DATA "DATA" +#define NX_SMTP_COMMAND_RSET "RSET" +#define NX_SMTP_COMMAND_QUIT "QUIT" + +/* List of common SMTP server reply codes */ + +#define NX_SMTP_CODE_GREETING_OK 220 +#define NX_SMTP_CODE_ACKNOWLEDGE_QUIT 221 +#define NX_SMTP_CODE_AUTHENTICATION_SUCCESSFUL 235 +#define NX_SMTP_CODE_OK_TO_CONTINUE 250 +#define NX_SMTP_CODE_CANNOT_VERIFY_RECIPIENT 252 +#define NX_SMTP_CODE_AUTHENTICATION_TYPE_ACCEPTED 334 +#define NX_SMTP_CODE_SEND_MAIL_INPUT 354 +#define NX_SMTP_CODE_SERVICE_NOT_AVAILABLE 421 +#define NX_SMTP_CODE_SERVICE_INTERNAL_SERVER_ERROR 451 +#define NX_SMTP_CODE_INSUFFICIENT_STORAGE 452 +#define NX_SMTP_CODE_AUTH_FAILED_INTERNAL_SERVER_ERROR 454 +#define NX_SMTP_CODE_COMMAND_SYNTAX_ERROR 500 +#define NX_SMTP_CODE_PARAMETER_SYNTAX_ERROR 501 +#define NX_SMTP_CODE_COMMAND_NOT_IMPLEMENTED 502 +#define NX_SMTP_CODE_BAD_SEQUENCE 503 +#define NX_SMTP_CODE_PARAMETER_NOT_IMPLEMENTED 504 +#define NX_SMTP_CODE_AUTH_REQUIRED 530 +#define NX_SMTP_CODE_AUTH_FAILED 535 +#define NX_SMTP_CODE_REQUESTED_ACTION_NOT_TAKEN 550 +#define NX_SMTP_CODE_USER_NOT_LOCAL 551 +#define NX_SMTP_CODE_OVERSIZE_MAIL_DATA 552 +#define NX_SMTP_CODE_BAD_MAILBOX 553 +#define NX_SMTP_CODE_TRANSACTION_FAILED 554 +#define NX_SMTP_CODE_BAD_SERVER_CODE_RECEIVED 555 + + +/* Common components of SMTP command messages */ + +#define NX_SMTP_LINE_TERMINATOR "\r\n" +#define NX_SMTP_EOM "\r\n.\r\n" +#define NX_SMTP_MESSAGE_ID "Message-ID" +#define NX_SMTP_TO_STRING "To: " +#define NX_SMTP_FROM_STRING "From: " +#define NX_SMTP_SUBJECT_STRING "Subject: " +#define NX_SMTP_MAIL_HEADER_COMPONENTS "MIME-Version: 1.0\r\n" \ + "Content-Type: text/plain;\r\n" \ + " charset=\"utf-8\"\r\n" \ + "Content-Transfer-Encoding: 8bit\r\n" \ + "\r\n" + + +/* Enumerated states of the protocol state machine. These MUST be in the + same order as the list of protocol states in NX_SMTP_CLIENT_STATES.*/ + +typedef enum NX_SMTP_CLIENT_STATE_ENUM +{ + NX_SMTP_CLIENT_STATE_IDLE = 0, + NX_SMTP_CLIENT_STATE_GREETING, /*1*/ + NX_SMTP_CLIENT_STATE_EHLO, /*2 */ + NX_SMTP_CLIENT_STATE_HELO, /*3*/ + NX_SMTP_CLIENT_STATE_MAIL, /*4*/ + NX_SMTP_CLIENT_STATE_RCPT, /*5*/ + NX_SMTP_CLIENT_STATE_DATA, /*6*/ + NX_SMTP_CLIENT_STATE_MESSAGE, /*7*/ + NX_SMTP_CLIENT_STATE_RSET, /*8*/ + NX_SMTP_CLIENT_STATE_QUIT, /*9*/ + NX_SMTP_CLIENT_STATE_NOOP, /*10 */ + NX_SMTP_CLIENT_STATE_AUTH, /*11*/ + NX_SMTP_CLIENT_STATE_AUTH_CHALLENGE /*12*/ + +} NX_SMTP_CLIENT_STATE; + + +/* Enumeration of common server challenges to the client */ + +#define NX_SMTP_CLIENT_REPLY_TO_UNKNOWN_PROMPT 1 +#define NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT 2 +#define NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT 3 +#define NX_SMTP_CLIENT_REPLY_SERVER_CHALLENGE_PROMPT 4 + +/* Common server challenges from the SMTP server. */ + +#define NX_SMTP_USERNAME_PROMPT "Username:" +#define NX_SMTP_PASSWORD_PROMPT "Password:" + +/* ID for identifying as an SMTP client */ + +#define NX_SMTP_CLIENT_ID 0x534D5450UL + +/* Define the character to cancel authentication process (RFC mandated). */ + +#define NX_SMTP_CANCEL_AUTHENTICATION "*" + + +/* Enumeration of the state of authentication between server and client */ + +typedef enum NX_SMTP_AUTHENTICATION_STATE_ENUM +{ + NX_SMTP_NOT_AUTHENTICATED, + NX_SMTP_AUTHENTICATION_IN_PROGRESS, + NX_SMTP_AUTHENTICATION_FAILED, + NX_SMTP_AUTHENTICATION_SUCCEEDED + +} NX_SMTP_AUTHENTICATION_STATE; + + +/* Defines for deciding priority of mail. */ + +#define NX_SMTP_MAIL_PRIORITY_LOW 0x01 +#define NX_SMTP_MAIL_PRIORITY_NORMAL 0x02 +#define NX_SMTP_MAIL_PRIORITY_HIGH 0x04 + + +/* Defines for type of mail recipient. */ + +#define NX_SMTP_RECIPIENT_TO 0x01 +#define NX_SMTP_RECIPIENT_CC 0x02 +#define NX_SMTP_RECIPIENT_BCC 0x04 + + +/* Define size of SMTP reply status codes (RFC mandated). */ + +#define NX_SMTP_SERVER_REPLY_CODE_SIZE 3 + +#define NX_SMTP_CLIENT_AUTH_NONE 0xFFFF +#define NX_SMTP_CLIENT_AUTH_LOGIN 1 +#define NX_SMTP_CLIENT_AUTH_LOGIN_TEXT "AUTH LOGIN" +#define NX_SMTP_CLIENT_AUTH_CRAM_MD5 2 +#define NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT "AUTH CRAM-MD5" +#define NX_SMTP_CLIENT_AUTH_PLAIN 3 +#define NX_SMTP_CLIENT_AUTH_PLAIN_TEXT "AUTH PLAIN" + +/* Define the NetX SMTP RECIPIENT structure */ + +/* Define the NetX SMTP MAIL structure */ + +typedef struct NX_SMTP_CLIENT_MAIL_STRUCT +{ + CHAR *nx_smtp_client_mail_recipient_address; /* Recipient's mailbox address */ + CHAR *nx_smtp_client_mail_from_address; /* Sender's mailbox address. */ + UINT nx_smtp_client_mail_priority; /* Mail item priority level */ + CHAR *nx_smtp_client_mail_subject; + CHAR *nx_smtp_client_mail_body; /* Pointer to text of mail to send. */ + UINT nx_smtp_client_mail_body_length; /* Size of mail buffer. */ +} NX_SMTP_CLIENT_MAIL; + + +/* Define the SMTP client structure */ + +typedef struct NX_SMTP_CLIENT_STRUCT +{ + ULONG nx_smtp_client_id; /* SMTP ID for identify client service. */ + CHAR nx_smtp_username[NX_SMTP_CLIENT_MAX_USERNAME + 1]; /* Client name (may be used in authentication) */ + CHAR nx_smtp_password[NX_SMTP_CLIENT_MAX_PASSWORD + 1]; /* Client password (used in authentication) */ + CHAR nx_smtp_client_domain[NX_SMTP_CLIENT_MAX_USERNAME + 1]; /* Client domain of the client (and sender) */ + UINT nx_smtp_client_authentication_type; /* Default Client authentication. */ + NX_IP *nx_smtp_client_ip_ptr; /* Client IP instance */ + NX_PACKET_POOL *nx_smtp_client_packet_pool_ptr; /* Client packet pool for sending data packets to the server */ + NX_SMTP_CLIENT_MAIL nx_smtp_client_mail; /* Session mail is the collection of parameters required to create an SMTP mail message. */ + UINT nx_smtp_client_init_status; /* If true SMTP client successfully created and ready for transmitting mail. */ + NXD_ADDRESS nx_smtp_server_address; /* Server IP address (IPv4 or IPv6). */ + USHORT nx_smtp_server_port; /* Server port. */ + NX_TCP_SOCKET nx_smtp_client_socket; /* Client NetX TCP socket. */ + UINT nx_smtp_client_cmd_state; /* Command state of the SMTP session. */ + UINT nx_smtp_client_rsp_state; /* Response state of the SMTP session. */ + UINT nx_smtp_client_reply_code_status; /* Reply code received from SMTP server. */ + NX_PACKET *nx_smtp_server_packet; /* Packet containing server reply. */ + UINT nx_smtp_client_authentication_reply; /* Buffer holding server reply text during authentication process */ + NX_SMTP_AUTHENTICATION_STATE nx_smtp_client_authentication_state; /* State of the authentication process */ + UINT nx_smtp_client_data_transparency_bytes; /* Extra bytes allowed for data transparency processing to add to message data. */ + UINT nx_smtp_client_mail_status; /* Status of mail acceptance by the server */ + UINT nx_smtp_client_mute; /* Mute command state; client waits for another packet in same SMTP state */ + +} NX_SMTP_CLIENT; + + +typedef struct NX_SMTP_CLIENT_STATES_STRUCT +{ + UINT (*cmd) (NX_SMTP_CLIENT *client_ptr); + UINT (*rsp) (NX_SMTP_CLIENT *client_ptr); + +} NX_SMTP_CLIENT_STATES; + + +#ifndef NX_SMTP_SOURCE_CODE + +/* Define the system API mappings based on the error checking + selected by the user. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + + +#ifdef NX_SMTP_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nxd_smtp_client_create _nxd_smtp_client_create +#define nx_smtp_client_delete _nx_smtp_client_delete +#define nx_smtp_mail_send _nx_smtp_mail_send +#else + +/* Services with error checking. */ +#define nxd_smtp_client_create _nxde_smtp_client_create +#define nx_smtp_client_delete _nxe_smtp_client_delete +#define nx_smtp_mail_send _nxe_smtp_mail_send + + +#endif /* NX_SMTP_DISABLE_ERROR_CHECKING */ + + +/* Define the prototypes accessible to the application software. */ +UINT nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, + CHAR *username, CHAR *password, CHAR *from_address, + CHAR *client_domain, UINT authentication_type, + NXD_ADDRESS *server_address, UINT port); + +UINT nx_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); +UINT nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, + CHAR *subject, CHAR *mail_body, UINT mail_body_length); + + +#else /* NX_SMTP_SOURCE_CODE */ + + +/* SMTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, + CHAR *username, CHAR *password, CHAR *from_address, + CHAR *client_domain, UINT authentication_type, + NXD_ADDRESS *server_address, UINT port); +UINT _nxde_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, + CHAR *username, CHAR *password, CHAR *from_address, + CHAR *client_domain, UINT authentication_type, + NXD_ADDRESS *server_address, UINT port); + +UINT _nx_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); +UINT _nxe_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); + +UINT _nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, + CHAR *subject, CHAR *mail_body, UINT mail_body_length); + +UINT _nxe_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, + CHAR *subject, CHAR *mail_body, UINT mail_body_length); + + + + + +#endif /* NX_SMTP_SOURCE_CODE */ + +/* If a C++ compiler is being used....*/ +#ifdef __cplusplus +} +#endif + + +#endif /* NXD_SMTP_CLIENT_H */ diff --git a/addons/snmp/nx_des.c b/addons/snmp/nx_des.c new file mode 100644 index 00000000..2054bd64 --- /dev/null +++ b/addons/snmp/nx_des.c @@ -0,0 +1,546 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** DES Encryption Standard (DES) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "nx_api.h" +#include "nx_des.h" + + +/* Define macros for the DES transform function. */ + + +/* Define the eight S-box data structures used in the permutation. Keep them static, since there is no + reason to have these symbols referenced outside this file. */ + +static ULONG sb1[64] = +{ + + 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, + 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, + 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, + 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, + 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, + 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, + 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL +}; + +static ULONG sb2[64] = +{ + + 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, + 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, + 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, + 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, + 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, + 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, + 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, + 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL +}; + +static ULONG sb3[64] = +{ + + 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, + 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, + 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, + 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, + 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, + 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, + 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, + 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL +}; + +static ULONG sb4[64] = +{ + + 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, + 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, + 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, + 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, + 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, + 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, + 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, + 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL +}; + +static ULONG sb5[64] = +{ + + 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, + 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, + 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, + 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, + 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, + 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, + 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, + 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL +}; + +static ULONG sb6[64] = +{ + + 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, + 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, + 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, + 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, + 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, + 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, + 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, + 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL +}; + +static ULONG sb7[64] = +{ + + 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, + 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, + 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, + 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, + 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, + 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, + 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, + 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL +}; + +static ULONG sb8[64] = +{ + + 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, + 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, + 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, + 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, + 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, + 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, + 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, + 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL +}; + + +/* Define the left half bit swap table. */ + +static ULONG left_half_bit_swap[16] = +{ + + 0x00000000UL, 0x00000001UL, 0x00000100UL, 0x00000101UL, + 0x00010000UL, 0x00010001UL, 0x00010100UL, 0x00010101UL, + 0x01000000UL, 0x01000001UL, 0x01000100UL, 0x01000101UL, + 0x01010000UL, 0x01010001UL, 0x01010100UL, 0x01010101UL +}; + +/* Define the right half bit swap table. */ + +static ULONG right_half_bit_swap[16] = +{ + 0x00000000UL, 0x01000000UL, 0x00010000UL, 0x01010000UL, + 0x00000100UL, 0x01000100UL, 0x00010100UL, 0x01010100UL, + 0x00000001UL, 0x01000001UL, 0x00010001UL, 0x01010001UL, + 0x00000101UL, 0x01000101UL, 0x00010101UL, 0x01010101UL +}; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_des_key_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the 32 encryption keys as well as the 32 */ +/* decryption keys for the DES algorithm. It must be called before */ +/* either _nx_des_encrypt or _nx_des_decrypt can be called. */ +/* destination. */ +/* */ +/* INPUT */ +/* */ +/* context DES context pointer */ +/* key 8-byte (64-bit) key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_des_key_set(NX_DES *context, UCHAR key[8]) +{ + +ULONG left, right, temp; +ULONG *encrypt_keys_ptr; +ULONG *decrypt_keys_ptr; +UINT round; + + + /* Determine if the context is non-null. */ + if (context == NX_NULL) + return(NX_PTR_ERROR); + + /* First, convert the 8-byte raw key into two ULONG halves, in an endian neutral fashion. */ + left = (((ULONG) key[0]) << 24) | (((ULONG) key[1]) << 16) | (((ULONG) key[2]) << 8) | ((ULONG) key[3]); + right = (((ULONG) key[4]) << 24) | (((ULONG) key[5]) << 16) | (((ULONG) key[6]) << 8) | ((ULONG) key[7]); + + /* Perform permutation on the key halves. */ + temp = ((right >> 4) ^ left) & 0x0F0F0F0FUL; + left = left ^ temp; + right = right ^ (temp << 4); + temp = (right ^ left) & 0x10101010; + left = left ^ temp; + right = right ^ temp; + + left = (left_half_bit_swap[(left) & 0xf] << 3) | (left_half_bit_swap[(left >> 8) & 0xf] << 2) | + (left_half_bit_swap[(left >> 16) & 0xf] << 1) | (left_half_bit_swap[(left >> 24) & 0xf]) | + (left_half_bit_swap[(left >> 5) & 0xf] << 7) | (left_half_bit_swap[(left >> 13) & 0xf] << 6) | + (left_half_bit_swap[(left >> 21) & 0xf] << 5) | (left_half_bit_swap[(left >> 29) & 0xf] << 4); + left = left & 0x0fffffff; + + right = (right_half_bit_swap[(right >> 1) & 0xf] << 3) | (right_half_bit_swap[(right >> 9) & 0xf] << 2) | + (right_half_bit_swap[(right >> 17) & 0xf] << 1) | (right_half_bit_swap[(right >> 25) & 0xf]) | + (right_half_bit_swap[(right >> 4) & 0xf] << 7) | (right_half_bit_swap[(right >> 12) & 0xf] << 6) | + (right_half_bit_swap[(right >> 20) & 0xf] << 5) | (right_half_bit_swap[(right >> 28) & 0xf] << 4); + right = right & 0x0fffffff; + + /* Setup encryption keys pointer. */ + encrypt_keys_ptr = context -> nx_des_encryption_keys; + + /* Calculate the encryption keys. */ + for (round = 0; round < 16; round++) + { + + /* Modify the left and right portions of the keys. */ + if ((round < 2) || (round == 8) || (round == 15)) + { + + left = ((left << 1) | (left >> 27)) & 0x0FFFFFFFUL; + right = ((right << 1) | (right >> 27)) & 0x0FFFFFFFUL; + } + else + { + + left = ((left << 2) | (left >> 26)) & 0x0FFFFFFFUL; + right = ((right << 2) | (right >> 26)) & 0x0FFFFFFFUL; + } + + /* Setup the key. */ + *encrypt_keys_ptr++ = ((left << 4) & 0x24000000UL) | ((left << 28) & 0x10000000UL) | + ((left << 14) & 0x08000000UL) | ((left << 18) & 0x02080000UL) | + ((left << 6) & 0x01000000UL) | ((left << 9) & 0x00200000UL) | + ((left >> 1) & 0x00100000UL) | ((left << 10) & 0x00040000UL) | + ((left << 2) & 0x00020000UL) | ((left >> 10) & 0x00010000UL) | + ((right >> 13) & 0x00002000UL) | ((right >> 4) & 0x00001000UL) | + ((right << 6) & 0x00000800UL) | ((right >> 1) & 0x00000400UL) | + ((right >> 14) & 0x00000200UL) | (right & 0x00000100UL) | + ((right >> 5) & 0x00000020UL) | ((right >> 10) & 0x00000010UL) | + ((right >> 3) & 0x00000008UL) | ((right >> 18) & 0x00000004UL) | + ((right >> 26) & 0x00000002UL) | ((right >> 24) & 0x00000001UL); + + /* Setup the next key. */ + *encrypt_keys_ptr++ = ((left << 15) & 0x20000000UL) | ((left << 17) & 0x10000000UL) | + ((left << 10) & 0x08000000UL) | ((left << 22) & 0x04000000UL) | + ((left >> 2) & 0x02000000UL) | ((left << 1) & 0x01000000UL) | + ((left << 16) & 0x00200000UL) | ((left << 11) & 0x00100000UL) | + ((left << 3) & 0x00080000UL) | ((left >> 6) & 0x00040000UL) | + ((left << 15) & 0x00020000UL) | ((left >> 4) & 0x00010000UL) | + ((right >> 2) & 0x00002000UL) | ((right << 8) & 0x00001000UL) | + ((right >> 14) & 0x00000808UL) | ((right >> 9) & 0x00000400UL) | + ((right) & 0x00000200UL) | ((right << 7) & 0x00000100UL) | + ((right >> 7) & 0x00000020UL) | ((right >> 3) & 0x00000011UL) | + ((right << 2) & 0x00000004UL) | ((right >> 21) & 0x00000002UL); + } + + /* Reposition the encryption key pointer. */ + encrypt_keys_ptr = encrypt_keys_ptr - 2; + + /* Setup decryption pointer. */ + decrypt_keys_ptr = context -> nx_des_decryption_keys; + + /* Now setup decryption keys. */ + for (round = 0; round < 16; round++) + { + + /* Copy the reverse of the encryption keys. */ + *decrypt_keys_ptr++ = *encrypt_keys_ptr; + *decrypt_keys_ptr++ = *(encrypt_keys_ptr + 1); + + /* Adjust the encryption keys pointer. */ + encrypt_keys_ptr = encrypt_keys_ptr - 2; + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_des_encrypt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses the DES algorithm to encrypt 8-bytes (64-bits). */ +/* The result is 8 encrypted bytes. Note that the caller must make */ +/* sure the source and destination are 8-bytes in size! */ +/* */ +/* INPUT */ +/* */ +/* context DES context pointer */ +/* source 8-byte source */ +/* destination 8-byte destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_des_process_block Encrypt 8-bytes of source */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_des_encrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]) +{ + + /* Determine if the context is non-null. */ + if (context == NX_NULL) + return(NX_PTR_ERROR); + + /* Encrypt the block by supplying the encryption key set. */ + _nx_des_process_block(source, destination, context -> nx_des_encryption_keys); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_des_decrypt PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses the DES algorithm to decrypt 8-bytes (64-bits). */ +/* The result is 8 original source bytes. Note that the caller must */ +/* make sure the source and destination are 8-bytes in size! */ +/* */ +/* INPUT */ +/* */ +/* context DES context pointer */ +/* source 8-byte source */ +/* destination 8-byte destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_des_process_block Decrypt 8-bytes of source */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_des_decrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]) +{ + + /* Determine if the context is non-null. */ + if (context == NX_NULL) + return(NX_PTR_ERROR); + + /* Decrypt the block by supplying the decryption key set. */ + _nx_des_process_block(source, destination, context -> nx_des_decryption_keys); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_des_process_block PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function uses the DES algorithm to decrypt 8-bytes (64-bits). */ +/* The result is 8 original source bytes. Note that the caller must */ +/* make sure the source and destination are 8-bytes in size! */ +/* */ +/* INPUT */ +/* */ +/* source 8-byte source */ +/* destination 8-byte destination */ +/* keys Pointer to either the encrypt */ +/* or decrypt keys */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_des_process_block(UCHAR source[8], UCHAR destination[8], ULONG keys[32]) +{ + +ULONG left, right, temp; +ULONG *key_ptr; +UINT round; + + + /* First, convert the 8-byte source into two ULONG halves, in an endian neutral fashion. */ + left = (((ULONG) source[0]) << 24) | (((ULONG) source[1]) << 16) | (((ULONG) source[2]) << 8) | ((ULONG) source[3]); + right = (((ULONG) source[4]) << 24) | (((ULONG) source[5]) << 16) | (((ULONG) source[6]) << 8) | ((ULONG) source[7]); + + /* Compute the initial permutation. */ + temp = ((left >> 4) ^ right) & 0x0F0F0F0FUL; + right = right ^ temp; + left = left ^ (temp << 4); + temp = ((left >> 16) ^ right) & 0x0000FFFFUL; + right = right ^ temp; + left = left ^ (temp << 16); + temp = ((right >> 2) ^ left) & 0x33333333UL; + left = left ^ temp; + right = right ^ (temp << 2); + temp = ((right >> 8) ^ left) & 0x00FF00FFUL; + left = left ^ temp; + right = right ^ (temp << 8); + right = ((right << 1) | (right >> 31)) & 0xFFFFFFFFUL; + temp = (left ^ right) & 0xAAAAAAAAUL; + right = right ^ temp; + left = left ^ temp; + left = ((left << 1) | (left >> 31)) & 0xFFFFFFFFUL; + + /* Setup pointer to input keys. */ + key_ptr = keys; + + /* Now process the 16 rounds of the DES computation. There are two rounds per + loop. */ + for (round = 0; round < 8; round++) + { + + /* Calculate the left half. */ + temp = *key_ptr++ ^ right; + left = left ^ sb8[temp & 0x3F] ^ sb6[(temp >> 8) & 0x3F] ^ sb4[(temp >> 16) & 0x3F] ^ sb2[(temp >> 24) & 0x3F]; + + temp = *key_ptr++ ^ ((right << 28) | (right >> 4)); + left = left ^ sb7[temp & 0x3F] ^ sb5[(temp >> 8) & 0x3F] ^ sb3[(temp >> 16) & 0x3F] ^ sb1[(temp >> 24) & 0x3F]; + + /* Calculate the right half. */ + temp = *key_ptr++ ^ left; + right = right ^ sb8[temp & 0x3F] ^ sb6[(temp >> 8) & 0x3F] ^ sb4[(temp >> 16) & 0x3F] ^ sb2[(temp >> 24) & 0x3F]; + + temp = *key_ptr++ ^ ((left << 28) | (left >> 4)); + right = right ^ sb7[temp & 0x3F] ^ sb5[(temp >> 8) & 0x3F] ^ sb3[(temp >> 16) & 0x3F] ^ sb1[(temp >> 24) & 0x3F]; + } + + /* Now compute the final permutation. */ + right = ((right << 31) | (right >> 1)) & 0xFFFFFFFFUL; + temp = (right ^ left) & 0xAAAAAAAAUL; + right = right ^ temp; + left = left ^ temp; + left = ((left << 31) | (left >> 1)) & 0xFFFFFFFFUL; + temp = ((left >> 8) ^ right) & 0x00FF00FFUL; + right = right ^ temp; + left = left ^ (temp << 8); + temp = ((left >> 2) ^ right) & 0x33333333UL; + right = right ^ temp; + left = left ^ (temp << 2); + temp = ((right >> 16) ^ left) & 0x0000FFFFUL; + left = left ^ temp; + right = right ^ (temp << 16); + temp = ((right >> 4) ^ left) & 0x0F0F0F0FUL; + left = left ^ temp; + right = right ^ (temp << 4); + + /* Finally, build the output. */ + destination[0] = (UCHAR) (right >> 24); + destination[1] = (UCHAR) (right >> 16); + destination[2] = (UCHAR) (right >> 8); + destination[3] = (UCHAR) (right); + destination[4] = (UCHAR) (left >> 24); + destination[5] = (UCHAR) (left >> 16); + destination[6] = (UCHAR) (left >> 8); + destination[7] = (UCHAR) (left); +} + diff --git a/addons/snmp/nx_des.h b/addons/snmp/nx_des.h new file mode 100644 index 00000000..eab9a3f9 --- /dev/null +++ b/addons/snmp/nx_des.h @@ -0,0 +1,75 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** DES Encryption Standard (DES) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_des.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX DES encryption algorithm, derived */ +/* principally from FIPS-46. From an 8 bytes of raw input, the DES */ +/* encryption routine produces an 8-byte encryption of the input. */ +/* Conversely, from an 8-byte encryption, the decryption routine */ +/* produces the original 8 bytes of input. Note that the caller must */ +/* ensure 8 bytes of input and output are provided. */ +/* */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_DES_H +#define NX_DES_H + +/* Define the DES context structure. */ + +typedef struct NX_DES_STRUCT +{ + + ULONG nx_des_encryption_keys[32]; /* Contains the encryption keys */ + ULONG nx_des_decryption_keys[32]; /* Contains the decryption keys */ +} NX_DES; + + +/* Define the function prototypes for DES. */ + +UINT _nx_des_key_set(NX_DES *context, UCHAR key[8]); +UINT _nx_des_encrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]); +UINT _nx_des_decrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]); +VOID _nx_des_process_block(UCHAR source[8], UCHAR destination[8], ULONG keys[32]); + +#endif + diff --git a/addons/snmp/nx_sha1.c b/addons/snmp/nx_sha1.c new file mode 100644 index 00000000..05379076 --- /dev/null +++ b/addons/snmp/nx_sha1.c @@ -0,0 +1,494 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + ""AS IS"" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +*/ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** SHA1 Digest Algorithm (SHA1) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "nx_api.h" +#include "nx_sha1.h" + +/* Define macros for the SHA1 transform function. */ + +/* Define the SHA1 basic F1, F2, F3, and F4 functions. */ + +#define F1(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define F2(x, y, z) ((x) ^ (y) ^ (z)) +#define F3(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define F4(x, y, z) ((x) ^ (y) ^ (z)) + + +/* Define the SHA1 left shift circular function. */ + +#define LEFT_SHIFT_CIRCULAR(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + + +/* Define the padding array. This is used to pad the message such that its length is + 64 bits shy of being a multiple of 512 bits long. */ + +static UCHAR _nx_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sha1_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the SHA1 context. It must be called prior */ +/* to creating the SHA1 digest. */ +/* */ +/* INPUT */ +/* */ +/* context SHA1 context pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sha1_initialize(NX_SHA1 *context) +{ + + /* Determine if the context is non-null. */ + if (context == NX_NULL) + return(NX_PTR_ERROR); + + /* First, clear the bit count for this context. */ + context -> nx_sha1_bit_count[0] = 0; /* Clear the lower 32-bits of the count */ + context -> nx_sha1_bit_count[1] = 0; /* Clear the upper 32-bits of the count */ + + /* Finally, setup the context states. */ + context -> nx_sha1_states[0] = 0x67452301UL; /* Setup state A */ + context -> nx_sha1_states[1] = 0xEFCDAB89UL; /* Setup state B */ + context -> nx_sha1_states[2] = 0x98BADCFEUL; /* Setup state C */ + context -> nx_sha1_states[3] = 0x10325476UL; /* Setup state D */ + context -> nx_sha1_states[4] = 0xC3D2E1F0UL; /* Setup state E */ + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sha1_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the digest calculation with new input from */ +/* the caller. */ +/* */ +/* INPUT */ +/* */ +/* context SHA1 context pointer */ +/* input_ptr Pointer to byte(s) of input */ +/* input_length Length of bytes of input */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sha1_process_buffer Process complete buffer, */ +/* which is 64-bytes in size */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sha1_update(NX_SHA1 *context, UCHAR *input_ptr, UINT input_length) +{ + +ULONG current_bytes; +ULONG needed_fill_bytes; + + + /* Determine if the context is non-null. */ + if (context == NX_NULL) + return(NX_PTR_ERROR); + + /* Determine if there is a length. */ + if (input_length == 0) + return(NX_SUCCESS); + + /* Calculate the current byte count mod 64. Note the reason for the + shift by 3 is to account for the 8 bits per byte. */ + current_bytes = (context -> nx_sha1_bit_count[0] >> 3) & 0x3F; + + /* Calculate the current number of bytes needed to be filled. */ + needed_fill_bytes = 64 - current_bytes; + + /* Update the total bit count based on the input length. */ + context -> nx_sha1_bit_count[0] += (input_length << 3); + + /* Determine if there is roll-over of the bit count into the MSW. */ + if (context -> nx_sha1_bit_count[0] < (input_length << 3)) + { + + /* Yes, increment the MSW of the bit count. */ + context -> nx_sha1_bit_count[1]++; + } + + /* Update upper total bit count word. */ + context -> nx_sha1_bit_count[1] += (input_length >> 29); + + /* Check for a partial buffer that needs to be transformed. */ + if ((current_bytes) && (input_length >= needed_fill_bytes)) + { + + /* Yes, we can complete the buffer and transform it. */ + + /* Copy the appropriate portion of the input buffer into the internal + buffer of the context. */ + memcpy((void *) &(context -> nx_sha1_buffer[current_bytes]), (void *) input_ptr, needed_fill_bytes); + + /* Process the 64-byte (512 bit) buffer. */ + _nx_sha1_process_buffer(context, context -> nx_sha1_buffer); + + /* Adjust the pointers and length accordingly. */ + input_length = input_length - needed_fill_bytes; + input_ptr = input_ptr + needed_fill_bytes; + + /* Clear the remaining bits, since the buffer was processed. */ + current_bytes = 0; + } + + /* Process any and all whole blocks of input. */ + while (input_length >= 64) + { + + /* Process this 64-byte (512 bit) buffer. */ + _nx_sha1_process_buffer(context, input_ptr); + + /* Adjust the pointers and length accordingly. */ + input_length = input_length - 64; + input_ptr = input_ptr + 64; + } + + /* Determine if there is anything left. */ + if (input_length) + { + + /* Save the remaining bytes in the internal buffer after any remaining bytes + that it is processed later. */ + memcpy((void *) &(context -> nx_sha1_buffer[current_bytes]), (void *) input_ptr, input_length); + } + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sha1_digest_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finishes calculation of the SHA1 digest. It is called */ +/* where there is no further input needed for the digest. The resulting*/ +/* 20-byte (160-bit) SHA1 digest is returned to the caller. */ +/* */ +/* INPUT */ +/* */ +/* context SHA1 context pointer */ +/* digest Pointer to return digest in */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sha1_update Update the digest with padding*/ +/* and length of digest */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sha1_digest_calculate(NX_SHA1 *context, UCHAR digest[20]) +{ + +UCHAR bit_count_string[8]; +ULONG current_byte_count; +ULONG padding_bytes; + + + /* Move the lower portion of the bit count into the array. */ + bit_count_string[0] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 24); + bit_count_string[1] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 16); + bit_count_string[2] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 8); + bit_count_string[3] = (UCHAR) (context -> nx_sha1_bit_count[1]); + bit_count_string[4] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 24); + bit_count_string[5] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 16); + bit_count_string[6] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 8); + bit_count_string[7] = (UCHAR) (context -> nx_sha1_bit_count[0]); + + /* Calculate the current byte count. */ + current_byte_count = (context -> nx_sha1_bit_count[0] >> 3) & 0x3F; + + /* Calculate the padding bytes needed. */ + padding_bytes = (current_byte_count < 56) ? (56 - current_byte_count) : (120 - current_byte_count); + + /* Add any padding required. */ + _nx_sha1_update(context, _nx_sha1_padding, padding_bytes); + + /* Add the in the length. */ + _nx_sha1_update(context, bit_count_string, 8); + + /* Now store the digest in the caller specified destination. */ + digest[ 0] = (UCHAR) (context -> nx_sha1_states[0] >> 24); + digest[ 1] = (UCHAR) (context -> nx_sha1_states[0] >> 16); + digest[ 2] = (UCHAR) (context -> nx_sha1_states[0] >> 8); + digest[ 3] = (UCHAR) (context -> nx_sha1_states[0]); + digest[ 4] = (UCHAR) (context -> nx_sha1_states[1] >> 24); + digest[ 5] = (UCHAR) (context -> nx_sha1_states[1] >> 16); + digest[ 6] = (UCHAR) (context -> nx_sha1_states[1] >> 8); + digest[ 7] = (UCHAR) (context -> nx_sha1_states[1]); + digest[ 8] = (UCHAR) (context -> nx_sha1_states[2] >> 24); + digest[ 9] = (UCHAR) (context -> nx_sha1_states[2] >> 16); + digest[10] = (UCHAR) (context -> nx_sha1_states[2] >> 8); + digest[11] = (UCHAR) (context -> nx_sha1_states[2]); + digest[12] = (UCHAR) (context -> nx_sha1_states[3] >> 24); + digest[13] = (UCHAR) (context -> nx_sha1_states[3] >> 16); + digest[14] = (UCHAR) (context -> nx_sha1_states[3] >> 8); + digest[15] = (UCHAR) (context -> nx_sha1_states[3]); + digest[16] = (UCHAR) (context -> nx_sha1_states[4] >> 24); + digest[17] = (UCHAR) (context -> nx_sha1_states[4] >> 16); + digest[18] = (UCHAR) (context -> nx_sha1_states[4] >> 8); + digest[19] = (UCHAR) (context -> nx_sha1_states[4]); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sha1_process_buffer PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function actually uses the SHA1 algorithm to process a 64-byte */ +/* (512 bit) buffer. */ +/* */ +/* INPUT */ +/* */ +/* context SHA1 context pointer */ +/* buffer Pointer to 64-byte buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Applications */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sha1_process_buffer(NX_SHA1 *context, UCHAR buffer[64]) +{ + +ULONG *w; +UINT t; +ULONG temp; +ULONG a, b, c, d, e; + + + /* Setup pointers to the word array. */ + w = context -> nx_sha1_word_array; + + /* Initialize the first 16 words of the word array, taking care of the + endian issues at the same time. */ + for (t = 0; t < 16; t++) + { + + /* Setup each entry. */ + w[t] = (((ULONG) buffer[t * 4]) << 24) | (((ULONG) buffer[(t * 4) + 1]) << 16) | (((ULONG) buffer[(t * 4) + 2]) << 8) | ((ULONG) buffer[(t * 4) + 3]); + } + + /* Setup the remaining entries of the word array. */ + for (t = 16; t < 80; t++) + { + + /* Setup each entry. */ + w[t] = LEFT_SHIFT_CIRCULAR((w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]), 1); + } + + /* Initialize the state variables. */ + a = context -> nx_sha1_states[0]; + b = context -> nx_sha1_states[1]; + c = context -> nx_sha1_states[2]; + d = context -> nx_sha1_states[3]; + e = context -> nx_sha1_states[4]; + + /* Now, perform Round 1 operations. */ + for (t = 0; t < 20; t++) + { + + /* Compute round 1 (t = 0 through t = 19). */ + temp = LEFT_SHIFT_CIRCULAR(a, 5) + F1(b, c, d) + e + w[t] + 0x5A827999UL; + e = d; + d = c; + c = LEFT_SHIFT_CIRCULAR(b, 30); + b = a; + a = temp; + } + + /* Now, perform Round 2 operations. */ + for (t = 20; t < 40; t++) + { + + /* Compute round 2 (t = 20 through t = 39). */ + temp = LEFT_SHIFT_CIRCULAR(a, 5) + F2(b, c, d) + e + w[t] + 0x6ED9EBA1UL; + e = d; + d = c; + c = LEFT_SHIFT_CIRCULAR(b, 30); + b = a; + a = temp; + } + + /* Now, perform Round 3 operations. */ + for (t = 40; t < 60; t++) + { + + /* Compute round 3 (t = 40 through t = 59). */ + temp = LEFT_SHIFT_CIRCULAR(a, 5) + F3(b, c, d) + e + w[t] + 0x8F1BBCDCUL; + e = d; + d = c; + c = LEFT_SHIFT_CIRCULAR(b, 30); + b = a; + a = temp; + } + + /* Finally, perform Round 4 operations. */ + for (t = 60; t < 80; t++) + { + + /* Compute round 4 (t = 60 through t = 79). */ + temp = LEFT_SHIFT_CIRCULAR(a, 5) + F4(b, c, d) + e + w[t] + 0xCA62C1D6UL; + e = d; + d = c; + c = LEFT_SHIFT_CIRCULAR(b, 30); + b = a; + a = temp; + } + + /* Save the resulting in this SHA1 context. */ + context -> nx_sha1_states[0] += a; + context -> nx_sha1_states[1] += b; + context -> nx_sha1_states[2] += c; + context -> nx_sha1_states[3] += d; + context -> nx_sha1_states[4] += e; +} + diff --git a/addons/snmp/nx_sha1.h b/addons/snmp/nx_sha1.h new file mode 100644 index 00000000..f265ed58 --- /dev/null +++ b/addons/snmp/nx_sha1.h @@ -0,0 +1,114 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/* + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + ""AS IS"" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. +*/ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** SHA1 Digest Algorithm (SHA1) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_sha1.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX SHA1 algorithm, derived principally from */ +/* RFC3174. From a user-specified number of input bytes, this routine */ +/* produces a 20-byte (160-bit) digest or sometimes called a hash */ +/* value. The resulting digest is returned in a 20-byte array supplied */ +/* by the caller. */ +/* */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_SHA1_H +#define NX_SHA1_H + + +/* Define the SHA1 context structure. */ + +typedef struct NX_SHA1_STRUCT +{ + + ULONG nx_sha1_states[5]; /* Contains each state (A,B,C,D) */ + ULONG nx_sha1_bit_count[2]; /* Contains the 64-bit total bit */ + /* count, where index 0 holds the */ + /* least significant bit count and*/ + /* index 1 contains the most */ + /* significant portion of the bit */ + /* count */ + UCHAR nx_sha1_buffer[64]; /* Working buffer for SHA1 algorithm*/ + /* where partial buffers are */ + /* accumulated until a full block */ + /* can be processed */ + ULONG nx_sha1_word_array[80]; /* Working 80 word array */ +} NX_SHA1; + + +/* Define the function prototypes for SHA1. */ + +UINT _nx_sha1_initialize(NX_SHA1 *context); +UINT _nx_sha1_update(NX_SHA1 *context, UCHAR *input_ptr, UINT input_length); +UINT _nx_sha1_digest_calculate(NX_SHA1 *context, UCHAR digest[20]); +VOID _nx_sha1_process_buffer(NX_SHA1 *context, UCHAR buffer[64]); + +#endif diff --git a/addons/snmp/nxd_snmp.c b/addons/snmp/nxd_snmp.c new file mode 100644 index 00000000..dc0ee3ee --- /dev/null +++ b/addons/snmp/nxd_snmp.c @@ -0,0 +1,23756 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** Simple Network Management Protocol (SNMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SNMP_SOURCE_CODE + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nxd_snmp.h" + +#ifndef NX_IPV6_UTIL_INLINE +extern void COPY_NXD_ADDRESS(NXD_ADDRESS *copy_from, NXD_ADDRESS *copy_to); +#endif + + +/* To enable debug output, define this option. +#define NX_SNMPV3_PRINT_DEBUG_MESSAGE +*/ + +#define NX_SNMP_REQUEST_AUTH_SIZE 50 + +#ifndef NX_SNMP_DISABLE_V3 +/* Define locations in request buffer PDU in the event we need + to return the message e.g. error message response. */ +static UINT pdu_length; +static UCHAR *pdu_buffer_ptr; +static UCHAR *pdu_auth_parm_ptr; +static UCHAR *pdu_privacy_ptr; +#endif + +/* Enable or disable SNMPv3 debug message printout. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + #define NX_SNMPV3_DBG_PRINTF printf +#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE */ + + +/* Define global SNMP variables and strings. */ + +/* If the array size of _nx_snmp_v2_trap_ids is changed, these upper limit MUST by updated! */ +#define TRAP_ID_MAX 5 +UCHAR *_nx_snmp_v2_trap_ids[] = { (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss) */ + }; + + + +#ifndef NX_SNMP_DISABLE_V3 + +UCHAR *_nx_snmp_v3_trap_ids[] = { (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure) */, + (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss) */ + }; + +/* Define the default context engine information. This will be setup when the SNMP agent is + created. Note that this information isn't used for SNMP v1 and v2. Note the host application + should use the nx_snmp_agent_context_engine_set() service to set its own IPv4 (or MAC address + depending on format type) when creating the Engine ID. The engine size must match the total engine + data including the input context engine data as well. See documentation for more details. + + Note that this information isn't used for SNMP v1 and v2. */ + +UCHAR _nx_snmp_default_context_engine[NX_SNMP_MAX_CONTEXT_STRING] = {0x80, 0x00, 0x03, 0x10, 0x01, 0xc0, 0xa8, 0x64, 0xaf}; +UINT _nx_snmp_default_context_engine_size = 9; + +CHAR _nx_snmp_default_initial_user_name[] = "initial"; + +#endif + +/* As per RFC 3414 for SNMPv3 the discovery report must include the usmStats variables. */ +#define NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC "1.3.6.1.6.3.15.1.1.1.0" +#define NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM 1 +#define NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME "1.3.6.1.6.3.15.1.1.2.0" +#define NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM 2 +#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME "1.3.6.1.6.3.15.1.1.3.0" +#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM 3 +#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID "1.3.6.1.6.3.15.1.1.4.0" +#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM 4 + +/* Define the maximum difference between local time (in seconds) and browser notion of + local time recommended by RFC 3413. */ +#define NX_SNMP_TIME_WINDOW 150 + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_authenticate_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP authentication key */ +/* specification function call. To disable authentication, set */ +/* the key pointer to null. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Authenticate key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_authenticate_key_use Actual authentication key */ +/* setup function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + { + + return(NX_PTR_ERROR); + } + + if (key != NX_NULL) + { + + /* Check for valid authentication type. */ + if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) + { + return NX_SNMP_UNSUPPORTED_AUTHENTICATION; + } + } + + /* Call actual service. */ + status = _nx_snmp_agent_authenticate_key_use(agent_ptr, key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_authenticate_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the authenticate key to use for checking the */ +/* digest of the request. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Authenticate key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +#ifdef NX_SNMP_NO_SECURITY + return NX_NOT_ENABLED; +#else + + /* Set the authenticate pointer so authentication will use the specified key. Note this + key must have been created prior to calling this routine. */ + agent_ptr -> nx_snmp_agent_v3_authentication_key = key; + + /* Return success to the caller. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trap_auth_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the error checking service for the setting the trap*/ +/* message authentication key. To disable trap key authentication, set */ +/* the key pointer to null. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Authenticate key for traps */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_auth_trap_key_use Actual set trap authentication*/ +/* key service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + { + + return(NX_PTR_ERROR); + } + + if (key != NX_NULL) + { + + /* Check for invalid authentication type. */ + if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) + { + + return NX_SNMP_UNSUPPORTED_AUTHENTICATION; + } + } + + /* Call actual service. */ + status = _nx_snmp_agent_auth_trap_key_use(agent_ptr, key); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_auth_trap_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the authenticate key to use for creating */ +/* authentication parameters in SNMPv3 trap messages. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Authenticate key for traps */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +#ifdef NX_SNMP_NO_SECURITY + return NX_NOT_ENABLED; +#else + + + /* Set the authenticate pointer so authentication will use the specified key. Note this + key must have been created prior to calling this routine. */ + agent_ptr -> nx_snmp_agent_v3_auth_trap_key = key; + + /* Return success to the caller. */ + return(NX_SUCCESS); + +#endif +} +#endif /* NX_SNMP_DISABLE_V3 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_community_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP community get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string_ptr Pointer to the community */ +/* string destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_community_get Actual community get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (community_string_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_community_get(agent_ptr, community_string_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_community_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the community string. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string_ptr Pointer to the community */ +/* string destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr) +{ + + /* Set a pointer to the community string for the caller. */ + *community_string_ptr = agent_ptr -> nx_snmp_agent_current_community_string; + + /* Return successful status. */ + return(NX_SUCCESS); +} + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_context_engine_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP context engine set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* context_engine Pointer to context engine */ +/* context_engine_size Number of bytes in the */ +/* context engine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_context_engine_set Actual context engine set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (context_engine == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for an invalid size. */ + if ((context_engine_size == 0) || (context_engine_size >= NX_SNMP_MAX_CONTEXT_STRING)) + return(NX_SNMP_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_context_engine_set(agent_ptr, context_engine, context_engine_size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_context_engine_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the context engine of the specified SNMP agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* context_engine Pointer to context engine */ +/* context_engine_size Number of bytes in the */ +/* context engine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size) +{ + +UINT i; + + + /* Verify V3 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) + { + return NX_NOT_ENABLED; + } + + /* Determine if the context engine is the correct size. */ + if (context_engine_size > NX_SNMP_MAX_CONTEXT_STRING) + { + + /* Return an error. */ + return(NX_SNMP_ERROR); + } + + /* Otherwise, store the context engine. */ + for (i = 0; i < context_engine_size; i++) + { + + /* Store a byte of the context engine. */ + agent_ptr -> nx_snmp_agent_v3_context_engine[i] = context_engine[i]; + } + + /* Set the context engine length. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_size = context_engine_size; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_context_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP context name set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* context_name Pointer to context name */ +/* context_name_size Number of bytes in the */ +/* context name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_context_name_set Actual context name set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (context_name == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for an invalid size. */ + if ((context_name_size == 0) || (context_name_size >= NX_SNMP_MAX_USER_NAME)) + return(NX_SNMP_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_context_name_set(agent_ptr, context_name, context_name_size); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_context_name_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the context name of the specified SNMP agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* context_name Pointer to context name */ +/* context_name_size Number of bytes in the */ +/* context name */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size) +{ + +UINT i; + + /* Determine if the context name is the correct size. */ + if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING) + { + + /* Return an error. */ + return(NX_SNMP_ERROR); + } + + /* Otherwise, store the context name. */ + for (i = 0; i < context_name_size; i++) + { + + /* Store a byte of the context name. */ + agent_ptr -> nx_snmp_agent_v3_context_name[i] = context_name[i]; + } + + /* Set the context name length. */ + agent_ptr -> nx_snmp_agent_v3_context_name_size = context_name_size; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_v3_context_boots_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP context boots set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* boots Value to set agent boots to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_SNMP_ERROR Invalid boot count input */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_v3_context_boots_set Actual context boots set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if (agent_ptr == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_v3_context_boots_set(agent_ptr, boots); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_v3_context_boots_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the context boot count of the specified SNMP */ +/* agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* boots Value to set agent boots to */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNMP_ERROR Invalid boot count input */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots) +{ + + /* Set the context name length. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boots = boots; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* snmp_agent_name Name of SNMP agent */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to stack for SNMP */ +/* thread */ +/* stack_size Size in bytes of thread stack */ +/* pool_ptr Default packet pool */ +/* snmp_agent_username_process Username callback routine */ +/* snmp_agent_get_process Get callback routine */ +/* snmp_agent_getnext_process Getnext callback routine */ +/* snmp_agent_set_process Set callback routine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_create Actual agent create function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), + UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id == NX_SNMP_ID) || (ip_ptr == NX_NULL) || (stack_ptr == NX_NULL) || + (pool_ptr == NX_NULL) || (!snmp_agent_username_process) || (!snmp_agent_get_process) || (!snmp_agent_getnext_process) || (!snmp_agent_set_process)) + return(NX_PTR_ERROR); + + /* Check for an invalid size. */ + if (stack_size == 0) + return(NX_SNMP_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_create(agent_ptr, snmp_agent_name, ip_ptr, stack_ptr, stack_size, pool_ptr, + snmp_agent_username_process, snmp_agent_get_process, snmp_agent_getnext_process, snmp_agent_set_process); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an SNMP agent. */ +/* */ +/* Note: The string length of username in snmp_agent_username_process */ +/* callback is limited by NX_SNMP_MAX_USER_NAME. */ +/* The string length of object_requested in snmp_agent_get_process, */ +/* snmp_agent_getnext_process and snmp_agent_set_process callback is */ +/* limited by NX_SNMP_MAX_OCTET_STRING. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* snmp_agent_name Name of SNMP agent */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Pointer to stack for SNMP */ +/* thread */ +/* stack_size Size in bytes of thread stack */ +/* pool_ptr Default packet pool */ +/* snmp_agent_username_process Username callback routine */ +/* snmp_agent_get_process Get callback routine */ +/* snmp_agent_getnext_process Getnext callback routine */ +/* snmp_agent_set_process Set callback routine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_bind Bind SNMP agent socket */ +/* nx_udp_socket_create Create SNMP agent socket */ +/* nx_udp_socket_delete Delete SNMP agent socket */ +/* nx_udp_socket_unbind Unbind SNMP agent socket */ +/* tx_thread_create Create SNMP agent thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), + UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)) +{ + +UINT status; + +#ifndef NX_SNMP_DISABLE_V3 +UINT i; +#endif + + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF( "Creating snmp agent of size %d\n\r", stack_size); +#endif + + /* Clear the SNMP agent structure. */ + memset((void *) agent_ptr, 0, sizeof(NX_SNMP_AGENT)); + + /* Create the agent's UDP socket. */ + status = nx_udp_socket_create(ip_ptr, &(agent_ptr -> nx_snmp_agent_socket), snmp_agent_name, + NX_SNMP_TYPE_OF_SERVICE, NX_SNMP_FRAGMENT_OPTION, + NX_SNMP_TIME_TO_LIVE, NX_SNMP_QUEUE_DEPTH); + + /* Determine if an error occurred. */ + if (status) + { + + /* Yes, return error code. */ + return(NX_SNMP_ERROR); + } + + /* Now create the SNMP Server thread. */ + status = tx_thread_create(&(agent_ptr -> nx_snmp_agent_thread), "SNMP Agent Thread", _nx_snmp_agent_thread_entry, + (ULONG) agent_ptr, stack_ptr, stack_size, NX_SNMP_AGENT_PRIORITY, NX_SNMP_AGENT_PRIORITY, + TX_NO_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred creating the thread. */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); + + /* Yes, return error code. */ + return(NX_SNMP_ERROR); + } + + /* Save the Server name. */ + agent_ptr -> nx_snmp_agent_name = snmp_agent_name; + + /* Save the IP pointer address. */ + agent_ptr -> nx_snmp_agent_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + agent_ptr -> nx_snmp_agent_packet_pool_ptr = pool_ptr; + + /* Default the SNMP network interface to the primary interface. */ + agent_ptr -> nx_snmp_agent_interface_index = 0; + + /* Initialize the agent as configured for all versions. + + Note that the #define options for disabling version support override dynamic version status. + + For example if NX_SNMP_DISABLE_V2 is disabled, setting nx_snmp_agent_v2_enabled + to NX_TRUE has no effect. If NX_SNMP_DISABLE_V2 is not disabled, then + nx_snmp_agent_v2_enabled determines at run time if the SNMP is enabled for V2.*/ + + agent_ptr -> nx_snmp_agent_v1_enabled = NX_TRUE; + agent_ptr -> nx_snmp_agent_v2_enabled = NX_TRUE; + agent_ptr -> nx_snmp_agent_v3_enabled = NX_TRUE; + + +#ifndef NX_SNMP_DISABLE_V3 + + /* Setup the SNMP v3 information. */ + + /* Setup the default context engine. */ + for (i = 0; i < _nx_snmp_default_context_engine_size; i++) + { + + /* Copy byte of default context engine. */ + agent_ptr -> nx_snmp_agent_v3_context_engine[i] = _nx_snmp_default_context_engine[i]; + } + + /* Set the default context engine size. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_size = _nx_snmp_default_context_engine_size; + + /* Start the time (in ticks) since the previous reboot. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + +#endif /* NX_SNMP_DISABLE_V3 */ + + /* Save the application request processing callback routines. */ + agent_ptr -> nx_snmp_agent_get_process = snmp_agent_get_process; + agent_ptr -> nx_snmp_agent_getnext_process = snmp_agent_getnext_process; + agent_ptr -> nx_snmp_agent_set_process = snmp_agent_set_process; + agent_ptr -> nx_snmp_agent_username_process = snmp_agent_username_process; + + /* Set the agent ID to indicate the SNMP agent thread is ready. */ + agent_ptr -> nx_snmp_agent_id = NX_SNMP_ID; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_request_get_type_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent get current */ +/* request type. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* is_get_type Pointer to request type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_request_get_type_test Actual request type service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type) +{ +UINT status; + + if ((agent_ptr == NX_NULL) || (is_get_type == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_request_get_type_test(agent_ptr, is_get_type); + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_request_get_type_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function indicates if the current request recieved from the */ +/* SNMP manager is a Get type (GET, GETNEXT etc) of a SET type. It is */ +/* intended for use in the username_callback for the host application */ +/* to process the request for matching community string (private for */ +/* set requests, public for get requests). */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* is_get_type Pointer to request type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type) +{ + + *is_get_type = agent_ptr -> nx_snmp_agent_request_get_type; + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_delete Actual agent delete function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_delete(agent_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes the previously created SNMP agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_delete Delete SNMP agent socket */ +/* nx_udp_socket_unbind Unbind SNMP agent socket */ +/* tx_thread_delete Delete SNMP agent thread */ +/* tx_thread_terminate Terminate SNMP agent thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr) +{ + + /* Terminate the SNMP thread. */ + tx_thread_terminate(&(agent_ptr -> nx_snmp_agent_thread)); + + /* Delete the SNMP thread. */ + tx_thread_delete(&(agent_ptr -> nx_snmp_agent_thread)); + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); + + /* Clear the agent ID to indicate the SNMP agent is deleted. */ + agent_ptr -> nx_snmp_agent_id = 0; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_current_version_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get the received */ +/* packet SNMP version service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* version Pointer to packet SNMP version*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_current_version_get Actual get version service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version) +{ +UINT status; + + if ((agent_ptr == NX_NULL) || (version == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_current_version_get(agent_ptr, version); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_current_version_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the received packet's SNMP version. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* version Pointer to packet SNMP version*/ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version) +{ + + *version = agent_ptr -> nx_snmp_agent_current_version; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_set_version PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for (dis)enabling the SNMP */ +/* agent for SNMPV1, SNMPV2 and SNMPV3. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* enabled_v1 V1 enable status */ +/* enabled_v2 V2 enable status */ +/* enabled_v3 V3 enable status */ +/* Enable = 1 (NX_TRUE) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3) +{ +UINT status; + + /* Check for invalid input */ + if (agent_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Call the actual service. */ + status = _nx_snmp_agent_version_set(agent_ptr, enabled_v1, enable_v2, enable_v3); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_version_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the SNMP agent status for SNMPV1, SNMPV2 and */ +/* SNMPV3. */ +/* */ +/* Note that the #define options for disabling version support override*/ +/* dynamic version status. */ +/* */ +/* For example if NX_SNMP_DISABLE_V2 is disabled, setting */ +/* nx_snmp_agent_v2_enabled to NX_TRUE has no effect. If */ +/* NX_SNMP_DISABLE_V2 is not disabled, then nx_snmp_agent_v2_enabled */ +/* determines at run time if the SNMP is enabled for V2. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* enabled_v1 V1 enable status */ +/* enabled_v2 V2 enable status */ +/* enabled_v3 V3 enable status */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3) +{ + + /* Set the agent status for each of the SNMP versions. */ + agent_ptr -> nx_snmp_agent_v1_enabled = enabled_v1; + + agent_ptr -> nx_snmp_agent_v2_enabled = enable_v2; + + agent_ptr -> nx_snmp_agent_v3_enabled = enable_v3; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the SNMP network interface for the SNMP agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* if_index SNMP network interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index) +{ +UINT status; + + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_set_interface(agent_ptr, if_index); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the SNMP network interface for the SNMP agent. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* if_index SNMP network interface index */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index) +{ + + agent_ptr -> nx_snmp_agent_interface_index = if_index; + + return NX_SUCCESS; +} + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_md5_key_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP md5 key create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the MD5 key */ +/* destination_key Destination for the MD5 key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_md5_key_create Actual agent MD5 key create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (password == NX_NULL) || (destination_key == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_md5_key_create(agent_ptr, password, destination_key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_md5_key_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an MD5 key. */ +/* */ +/* Note: new API nx_snmp_agent_md5_key_create_extended is encouraged */ +/* to use. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the MD5 key */ +/* destination_key Destination for the MD5 key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* _nx_snmp_agent_md5_key_create_extended Agent MD5 key create function*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) +{ + + +/* Verify SNMP security is not disabled for this project. */ +#ifdef NX_SNMP_NO_SECURITY + /* Security is not supported, clear the key and return an error. */ + destination_key -> nx_snmp_security_key_type = 0; + destination_key -> nx_snmp_security_key_size = 0; + + /* Return an error. */ + return(NX_NOT_ENABLED); +#else + +UINT status; +UINT password_length; + + + /* Calculate the password length. */ + if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH)) + { + return(NX_SIZE_ERROR); + } + + /* Check length of password. */ + if (password_length == 0) + { + return(NX_SNMP_FAILED); + } + + /* Call actual service. */ + status = _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key); + + /* Return status to the caller. */ + return(status); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_md5_key_create_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP md5 key create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the MD5 key */ +/* password_length Length of password */ +/* destination_key Destination for the MD5 key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_md5_key_create_extended */ +/* Actual agent MD5 key create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_md5_key_create_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an MD5 key. */ +/* */ +/* Note: The string of password must be NULL-terminated and length */ +/* of string matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the MD5 key */ +/* password_length Length of password */ +/* destination_key Destination for the MD5 key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_md5_initialize Initialize the MD5 algorithm */ +/* _nx_md5_update MD5 algorithm update */ +/* _nx_md5_digest_calculate Calculate the MD5 key */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) +{ + + +/* Verify SNMP security is not disabled for this project. */ +#ifdef NX_SNMP_NO_SECURITY + /* Security is not supported, clear the key and return an error. */ + destination_key -> nx_snmp_security_key_type = 0; + destination_key -> nx_snmp_security_key_size = 0; + + /* Return an error. */ + return(NX_NOT_ENABLED); +#else + +NX_MD5 MD; +UCHAR *cp, password_buf[64]; +ULONG password_index = 0; +ULONG count = 0, i; +UINT temp_password_length; + + + /* Get the length of password string. */ + if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length)) + return(NX_SNMP_FAILED); + + /* Check the password string length. */ + if (password_length != temp_password_length) + return(NX_SNMP_FAILED); + + /* Initialize MD5. */ + _nx_md5_initialize(&MD); + + /* Use while loop until we've done 1 Megabyte. */ + while (count < 1048576) + { + + cp = password_buf; + for (i = 0; i < 64; i++) + { + + /* Take the next octet of the password, wrapping + to the beginning of the password as necessary. */ + *cp++ = password[password_index++ % password_length]; + } + _nx_md5_update(&MD, password_buf, 64); + count += 64; + } + _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key); /* tell MD5 we're done */ + + /* Now localize the key with the engineID and pass + through MD5 to produce final key + May want to ensure that engineLength <= 32, + otherwise need to use a buffer larger than 64 */ + if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32) + return(NX_SNMP_FAILED); + + memcpy(password_buf, destination_key -> nx_snmp_security_key, 16); + memcpy(password_buf+16, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size); + memcpy(password_buf+16+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 16); + + _nx_md5_initialize(&MD); + _nx_md5_update(&MD, password_buf, 32+agent_ptr -> nx_snmp_agent_v3_context_engine_size); + _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key); + + /* Setup other information in the key structure. */ + destination_key -> nx_snmp_security_key_type = NX_SNMP_MD5_KEY; + destination_key -> nx_snmp_security_key_size = 16; + + /* Return successful completion to the caller. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_privacy_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP privacy key */ +/* specification function call. To disable encryption, set the */ +/* key pointer to null. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Pointer to key to use for */ +/* privacy (encryption) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_privacy_key_use Actual privacy key setup */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + return(NX_PTR_ERROR); + + if (key != NX_NULL) + { + + /* Check for valid privacy key type. */ + if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) + { + return NX_SNMP_INVALID_PDU_ENCRYPTION; + } + } + + /* Call actual service. */ + status = _nx_snmp_agent_privacy_key_use(agent_ptr, key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_privacy_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the specified key to use for privacy. To */ +/* disable authentication, set the key pointer to null. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Pointer to key to use for */ +/* privacy (encryption) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +#ifdef NX_SNMP_NO_SECURITY + return NX_NOT_ENABLED; +#else + + + /* Set the privacy pointer so encryption/decryption will use the specified key. Note this + key must have been created prior to calling this routine. */ + agent_ptr -> nx_snmp_agent_v3_privacy_key = key; + + /* Return success to the caller. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_priv_trap_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for setting the privacy key */ +/* for SNMPv3 trap messages. To disable trap key encryption, set */ +/* the key pointer to null. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Pointer to key to use for */ +/* privacy (encryption) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_priv_trap_key_use Actual set privacy key for */ +/* SNMPv3 trap messages service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + { + return(NX_PTR_ERROR); + } + + if (key != NX_NULL) + { + + /* Check for valid privacy key type. */ + if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) + { + return(NX_SNMP_INVALID_PDU_ENCRYPTION); + } + } + + /* Call actual service. */ + status = _nx_snmp_agent_priv_trap_key_use(agent_ptr, key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_priv_trap_key_use PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the specified key to use for privacy for */ +/* sending SNMPv3 trap messages. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* key Pointer to key to use for */ +/* privacy (encryption) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) +{ + +#ifdef NX_SNMP_NO_SECURITY + return NX_NOT_ENABLED; +#else + + /* Set the privacy pointer so encryption/decryption will use the specified key. Note this + key must have been created prior to calling this routine. */ + agent_ptr -> nx_snmp_agent_v3_priv_trap_key = key; + + /* Return success to the caller. */ + return(NX_SUCCESS); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_sha_key_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP SHA key create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the SHA key */ +/* destination_key Destination for the SHA key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_sha_key_create Actual agent SHA key create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (password == NX_NULL) || (destination_key == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_sha_key_create(agent_ptr, password, destination_key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_sha_key_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an SHA key. */ +/* */ +/* Note: new API nx_snmp_agent_sha_key_create_extended is encouraged */ +/* to use. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the SHA key */ +/* destination_key Destination for the SHA key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) +{ + +/* Verify SNMP security is not disabled for this project. */ +#ifdef NX_SNMP_NO_SECURITY + + /* Security is not supported, clear the key and return an error. */ + destination_key -> nx_snmp_security_key_type = 0; + destination_key -> nx_snmp_security_key_size = 0; + + /* Return an error. */ + return(NX_NOT_ENABLED); +#else + +UINT status; +UINT password_length; + + + /* Calculate the password length. */ + if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH)) + { + return(NX_SIZE_ERROR); + } + + /* Check length of password. */ + if (password_length == 0) + { + return(NX_SNMP_FAILED); + } + + /* Call actual service. */ + status = _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key); + + /* Return status. */ + return(status); +#endif /* NX_SNMP_NO_SECURITY */ + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_sha_key_create_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP SHA key create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the SHA key */ +/* password_length Length of password */ +/* destination_key Destination for the SHA key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_sha_key_create_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an SHA key. */ +/* */ +/* Note: The string of password must be NULL-terminated and length */ +/* of string matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* password Password for the SHA key */ +/* password_length Length of password */ +/* destination_key Destination for the SHA key */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sha1_initialize Initialize the SHA algorithm */ +/* _nx_sha1_update SHA algorithm update */ +/* _nx_sha1_digest_calculate Calculate the SHA key */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) +{ + +/* Verify SNMP security is not disabled for this project. */ +#ifdef NX_SNMP_NO_SECURITY + + /* Security is not supported, clear the key and return an error. */ + destination_key -> nx_snmp_security_key_type = 0; + destination_key -> nx_snmp_security_key_size = 0; + + /* Return an error. */ + return(NX_NOT_ENABLED); +#else + +NX_SHA1 SH; +UCHAR *cp, password_buf[72]; +ULONG password_index = 0; +ULONG count = 0, i; +UINT temp_password_length; + + + /* Get the length of password string. */ + if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length)) + return(NX_SNMP_FAILED); + + /* Check the password string length. */ + if (password_length != temp_password_length) + return(NX_SNMP_FAILED); + + memset(&SH, 0, sizeof(NX_SHA1)); + memset(&password_buf[0], 0, 72); + memset(destination_key, 0, sizeof(NX_SNMP_SECURITY_KEY)); + + /* Initialize SHA. */ + _nx_sha1_initialize(&SH); + + /* Use while loop until we've done 1 Megabyte. */ + while (count < 1048576) + { + + cp = password_buf; + for (i = 0; i < 64; i++) + { + + /* Take the next octet of the password, wrapping + to the beginning of the password as necessary. */ + *cp++ = password[password_index++ % password_length]; + } + _nx_sha1_update(&SH, password_buf, 64); + count += 64; + } + _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key); /* tell SHA we're done */ + + /* Now localize the key with the engineID and pass + through SHA to produce final key + May want to ensure that engineLength <= 32, + otherwise need to use a buffer larger than 72. */ + if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32) + return(NX_SNMP_FAILED); + + memcpy(password_buf, destination_key -> nx_snmp_security_key, 20); + memcpy(password_buf+20, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size); + memcpy(password_buf+20+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 20); + + _nx_sha1_initialize(&SH); + _nx_sha1_update(&SH, password_buf, 40+agent_ptr -> nx_snmp_agent_v3_context_engine_size); + _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key); + + /* Setup other information in the key structure. */ + destination_key -> nx_snmp_security_key_type = NX_SNMP_SHA_KEY; + destination_key -> nx_snmp_security_key_size = 20; + + /* Return successful completion to the caller. */ + return(NX_SUCCESS); +#endif /* NX_SNMP_NO_SECURITY */ + +} +#endif /* NX_SNMP_DISABLE_V3 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_public_string_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the check of community */ +/* string against the agent's public community string. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to public string */ +/* is_public Pointer to outcome */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agents_public_string_test Check public string service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public) +{ + +UINT status; + + if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_public == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_public_string_test(agent_ptr, community_string, is_public); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_public_string_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs checks the input community string against the*/ +/* agent's public community string. */ +/* */ +/* Note: The string length of community_string is limited by */ +/* NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to public string */ +/* is_public Pointer to outcome */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public) +{ +UINT string_length1, string_length2; + + + if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME)) + { + return(NX_SIZE_ERROR); + } + + if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_public_community_string, &string_length2, NX_SNMP_MAX_USER_NAME)) + { + return(NX_SIZE_ERROR); + } + + /* Initialize the outcome */ + *is_public = NX_TRUE; + + if (string_length1 != string_length2) + { + /* Input string not the same as agent's public string. */ + *is_public = NX_FALSE; + return(NX_SUCCESS); + } + + /* The string lengths match, now match the actual strings. */ + if (memcmp(community_string, agent_ptr -> nx_snmp_agent_public_community_string, string_length1)) + { + + /* Input string not the same as agent's public string. */ + *is_public = NX_FALSE; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_private_string_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the nx_snmp_agent_receive_*/ +/* _private_string service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to received string */ +/* is_private Pointer to outcome */ +/* NX_TRUE if strings match */ +/* NX_FALSE if strings do not */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_private_string_test */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private) +{ + +UINT status; + + if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_private == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_private_string_test(agent_ptr, community_string, is_private); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_private_string_test PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the community string of the received */ +/* SNMP packet matches the SNMP agent's private community string. */ +/* */ +/* Note: The string length of community_string is limited by */ +/* NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to received string */ +/* is_private Pointer to outcome */ +/* NX_TRUE if strings match */ +/* NX_FALSE if strings do not */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private) +{ +UINT string_length1, string_length2; + + if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME)) + { + return(NX_SIZE_ERROR); + } + + if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_private_community_string, &string_length2, NX_SNMP_MAX_USER_NAME)) + { + return(NX_SIZE_ERROR); + } + + /* Initialize the outcome */ + *is_private = NX_TRUE; + + if (string_length1 != string_length2) + { + /* Input string not the same as agent's private string. */ + *is_private = NX_FALSE; + return(NX_SUCCESS); + } + + /* The string lengths match, now match the actual strings. */ + if (memcmp(community_string, agent_ptr -> nx_snmp_agent_private_community_string, string_length1)) + { + + /* Input string not the same as agent's private string. */ + *is_private = NX_FALSE; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_private_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the nx_snmp_agent_set_ */ +/* _private_string service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to private string */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_private_string_set Set private string service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if ((agent_ptr == NX_NULL) || (community_string == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Call the actual service. */ + status = _nx_snmp_agent_private_string_set(agent_ptr, community_string); + + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_private_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the input string and size input as the Agent's */ +/* private string and private string size. */ +/* */ +/* Note: The string length of community_string is limited by */ +/* NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to private string */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) +{ + +UINT i; +UINT length; + + + /* Verify the string is not too large, leaving room for the null terminating string. */ + if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) + { + return NX_SNMP_ERROR_TOOBIG; + } + + /* Copy the string to the SNMP agent private community string. */ + for (i = 0; i < length; i++) + { + agent_ptr -> nx_snmp_agent_private_community_string[i] = *community_string; + community_string++; + } + + /* Null terminate the string. */ + agent_ptr -> nx_snmp_agent_private_community_string[i] = 0x0; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_public_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the nx_snmp_agent_set_ */ +/* _public_string service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to public string */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_public_string_set Set public string service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) +{ + +UINT status; + + if ((agent_ptr == NX_NULL) || (community_string == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_snmp_agent_public_string_set(agent_ptr, community_string); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_public_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the input string and size input as the Agent's */ +/* public string and public string size. */ +/* */ +/* Note: The string length of community_string is limited by */ +/* NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* community_string Pointer to public string */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) +{ +UINT i; +UINT length; + + + /* Verify the string is not too large, leaving room for the null terminating character. */ + if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) + { + return NX_SNMP_ERROR_TOOBIG; + } + + /* Copy the string to the SNMP agent public community string. */ + for (i = 0; i < length; i++) + { + agent_ptr -> nx_snmp_agent_public_community_string[i] = *community_string; + community_string++; + } + + /* Null terminate the string. */ + agent_ptr -> nx_snmp_agent_public_community_string[i] = 0x0; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent start */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_start Actual agent start function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_start(NX_SNMP_AGENT *agent_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_start(agent_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the SNMP agent thread. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_resume Resume SNMP agent thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr) +{ + +UINT status; + + /* Bind the socket to a the well known SNMP UDP port number. */ + status = nx_udp_socket_bind(&(agent_ptr -> nx_snmp_agent_socket), NX_SNMP_AGENT_PORT, NX_NO_WAIT); + + /* Determine if an error occurred. */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); + + /* Yes, return error code. */ + return(NX_SNMP_ERROR); + } + + /* Start the SNMP agent thread. */ + tx_thread_resume(&(agent_ptr -> nx_snmp_agent_thread)); + + + /* Return successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent stop */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_stop Actual agent stop function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_stop(agent_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops the SNMP agent thread. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend SNMP agent thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr) +{ + + /* Stop the SNMP agent thread. */ + tx_thread_suspend(&(agent_ptr -> nx_snmp_agent_thread)); + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket)); + + /* Return successful status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry function of the SNMP agent thread. */ +/* */ +/* INPUT */ +/* */ +/* snmp_agent_address Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy SNMP packet */ +/* nx_packet_release Release original SNMP packet */ +/* _nx_snmp_utility_sequence_get Get sequence number in packet */ +/* _nx_snmp_utility_version_get Get SNMP version number */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* nx_udp_socket_receive Receive SNMP request */ +/* nx_udp_source_extract Extract source IP and port */ +/* from request */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_agent_thread_entry(ULONG snmp_agent_address) +{ + +NX_SNMP_AGENT *agent_ptr; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT length; +UINT version; +UINT status; +UINT sequence_length; +INT buffer_length; +#ifndef NX_DISABLE_PACKET_CHAIN +NX_PACKET *new_packet_ptr; +#endif + + + /* Setup the agent pointer. */ + agent_ptr = (NX_SNMP_AGENT *) snmp_agent_address; + + /* Loop to process SNMP Manager requests. */ + while(1) + { + + /* Wait for a SNMP Manager request. */ + status = nx_udp_socket_receive(&(agent_ptr -> nx_snmp_agent_socket), &packet_ptr, NX_WAIT_FOREVER); + + /* Check for a successful packet reception. */ + if (status) + { + + /* If the error is other than no packet received, update the internal error count. */ + if (status != NX_NO_PACKET) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + } + + /* Go back and wait for another packet. */ + continue; + } + + + /* Pickup the source information for the packet - do this before the packet copy since the information + prior to the prepend pointer is not copied! */ + nxd_udp_source_extract(packet_ptr, &(agent_ptr -> nx_snmp_agent_current_manager_ip), + &(agent_ptr -> nx_snmp_agent_current_manager_port)); + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Determine if we have to copy the packet into a packet from the SNMP pool. */ + if (packet_ptr -> nx_packet_next) + { + + /* Copy the packet into a packet from the SNMP pool. */ + status = nx_packet_copy(packet_ptr, &new_packet_ptr, agent_ptr -> nx_snmp_agent_packet_pool_ptr, NX_SNMP_AGENT_TIMEOUT); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Determine if the copy was successful. */ + if (status || (new_packet_ptr -> nx_packet_next != NX_NULL)) + { + + /* No, the packet copy was not successful. */ + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Go back and wait for another packet. */ + continue; + } + + /* Otherwise, copy the new packet pointer to the standard packet pointer. */ + packet_ptr = new_packet_ptr; + } + +#endif /*NX_DISABLE_PACKET_CHAIN */ + + buffer_length = (INT)(packet_ptr -> nx_packet_length); + + /* Setup a pointer to the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the SEQUENCE field. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the unknown command error. */ + agent_ptr -> nx_snmp_agent_unknown_requests++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Go back and wait for another packet. */ + continue; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP VERSION field. */ + length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the unknown command error. */ + agent_ptr -> nx_snmp_agent_unknown_requests++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Go back and wait for another packet. */ + continue; + } + + /* Increment the total number of packets received. */ + agent_ptr -> nx_snmp_agent_packets_received++; + + /* We have a valid SNMP version, process relative to the type of SNMP version. */ + if (version == NX_SNMP_VERSION_1) + { + +#ifndef NX_SNMP_DISABLE_V1 + /* Verify V1 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE) + { + + /* It is not. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); + } + else + { + + /* Update the SNMP agent's version. */ + agent_ptr -> nx_snmp_agent_current_version = version; + + /* Process SNMP Version 1 request. */ + _nx_snmp_version_1_process(agent_ptr, packet_ptr); + } +#else + + + /* Invalid version. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); +#endif + } +#ifdef NX_SNMP_V2C_ONLY + else if (version == NX_SNMP_VERSION_2C) +#else + else if ((version == NX_SNMP_VERSION_2) || (version == NX_SNMP_VERSION_2C)) +#endif + { + +#ifndef NX_SNMP_DISABLE_V2 + + /* Verify V2 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE) + { + /* It is not. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); + } + else + { + /* Update the SNMP agent's version. */ + agent_ptr -> nx_snmp_agent_current_version = version; + + + /* Process SNMP Version 2 request. */ + _nx_snmp_version_2_process(agent_ptr, packet_ptr); + } +#else + + /* Invalid version. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); +#endif + } + else if (version == NX_SNMP_VERSION_3) + { + +#ifndef NX_SNMP_DISABLE_V3 + + /* Verify V3 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) + { + + /* It is not. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); + } + else + { + /* Update the SNMP agent's version. */ + agent_ptr -> nx_snmp_agent_current_version = version; + + /* Process SNMP Version 3 request. */ + _nx_snmp_version_3_process(agent_ptr, packet_ptr); + } +#else + + /* Invalid version. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); +#endif + } + else + { + + /* Invalid version. Increment error counter. */ + agent_ptr -> nx_snmp_agent_invalid_version++; + + /* Release packet. */ + nx_packet_release(packet_ptr); + } + } +} + + +#ifndef NX_SNMP_DISABLE_V1 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trap_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMPv1 trap send service. */ +/* */ +/* Developers are encouraged to use the nxd_snmp_agent_trap_send */ +/* service which supports IPv4 and IPv6 types. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* community Community string */ +/* enterprise Identifies the device that is */ +/* generating the trap */ +/* trap_type Type of trap */ +/* trap_code Additional trap information */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_trap_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, + UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL) || (enterprise == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid IP address. */ + if (ip_address == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_trap_send(agent_ptr, ip_address, community, enterprise, trap_type, trap_code, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(enterprise); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(trap_code); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_trap_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores the input IPv4 destination IP address in a NetX*/ +/* Duo data type that supports IPv4 and IPv6 address formats, and */ +/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ +/* and send the SNMPv1 trap message. */ +/* */ +/* Developers are encouraged to use nxd_snmp_agent_trap_send. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* community Community string */ +/* enterprise Identifies the device that is */ +/* generating the trap */ +/* trap_type Type of trap */ +/* trap_code Additional trap information */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_NOT_ENABLED Agent not enabled for V1 */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trap_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, + UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS ip_netxduo_address; + + + ip_netxduo_address.nxd_ip_address.v4 = ip_address; + ip_netxduo_address.nxd_ip_version = NX_IP_VERSION_V4; + + status = _nxd_snmp_agent_trap_send(agent_ptr, &ip_netxduo_address, community, enterprise, + trap_type, trap_code, elapsed_time, object_list_ptr); + + return status; +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(enterprise); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(trap_code); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_snmp_agent_trap_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMPv1 trap send service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community string */ +/* enterprise Identifies the device that is */ +/* generating the trap */ +/* trap_type Type of trap */ +/* trap_code Additional trap information */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trap_send Actual SNMPv1 trap send */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, + UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (community == NX_NULL) || (enterprise == NX_NULL) || (ip_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nxd_snmp_agent_trap_send(agent_ptr, ip_address, community, enterprise, trap_type, trap_code, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_snmp_agent_trap_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v1 trap message to the input */ +/* destination address. This service supports both IPv4 and IPv6 */ +/* addresses. */ +/* */ +/* Note: The string length of community and enterprise are limited by */ +/* the packet payload and NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community string */ +/* enterprise Identifies the device that is */ +/* generating the trap */ +/* trap_type Type of trap */ +/* trap_code Additional trap information */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate SNMP trap packet */ +/* nx_packet_release Release SNMP packet */ +/* nx_udp_socket_send Send SNMP trap via UDP */ +/* _nx_snmp_object_copy Copy object */ +/* _nx_snmp_utility_community_set Set the community name */ +/* _nx_snmp_utility_object_data_set Set the data value */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_version_set Set the SNMP v1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, + UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; +UINT trap_length; +UCHAR *trap_object_ptr; +NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; +NX_SNMP_OBJECT_DATA trap_object_data; +NX_PACKET *trap_packet_ptr; +UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; +UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; +UINT packet_type; + + + /* Verify V1 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE) + { + + return NX_NOT_ENABLED; + } + + /* Now prepare trap message so we can process the variables one by one. */ + + + /* Determine which packet type we allocate based on the destination address type. */ + if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif /* FEATURE_NX_IPV6 */ + } + else + { + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; + } + + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a trap packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the trap packet. */ + trap_sequence_length = 0; + trap_type_length = 0; + trap_variable_list_length = 0; + + /* Setup a pointer to the trap packet's buffer area. */ + trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the trap sequence pointer. Remember it since we are going to have to + update it later with the actual length of the trap. */ + trap_sequence_ptr = trap_buffer_ptr; + + /* First, write the sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Now set the Version ID in the trap message. */ + trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_1, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the community in the trap message. */ + trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Remember the request type pointer, since it will need to be updated later. */ + trap_type_ptr = trap_buffer_ptr; + + /* Now set the request type in the trap message. */ + trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the enterprise ID in the trap message. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, enterprise, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the agent's IP address. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_IP_ADDRESS; + + +#ifndef NX_DISABLE_IPV4 + trap_object_data.nx_snmp_object_data_msw = + (LONG)(agent_ptr -> nx_snmp_agent_ip_ptr) -> nx_ip_interface[agent_ptr -> nx_snmp_agent_interface_index].nx_interface_ip_address; +#else + trap_object_data.nx_snmp_object_data_msw = 0; +#endif /* NX_DISABLE_IPV4 */ + + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Check that we have a valid trap type requested. */ + if (trap_type > TRAP_ID_MAX) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Set the trap type. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_INTEGER; + trap_object_data.nx_snmp_object_data_msw = (LONG)trap_type; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + if (trap_length == 0) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the specific trap type. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_INTEGER; + trap_object_data.nx_snmp_object_data_msw = (LONG)trap_code; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the specific time-stamp. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; + trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the trap's variable list field. */ + trap_variable_list_ptr = trap_buffer_ptr; + + /* Set up the variable list. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if an object is specified. */ + if (object_list_ptr) + { + + /* Setup object pointers from the supplied object list. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + + /* Loop to process all the objects in the list. */ + while (trap_object_ptr) + { + + /* Clear the trap variable length. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the object into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if there are more objects to insert into the trap message. */ + if (object_list_ptr) + { + + /* Move to the next object in the list. */ + object_list_ptr++; + + if (object_list_ptr == NX_NULL) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Determine if there is another object. */ + if (object_list_ptr -> nx_snmp_object_string_ptr) + { + + /* Setup the object and object data pointers. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + } + } + + /* At this point, several trap fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); + + /* Now the trap packet's pointers must be setup so it can be sent. */ + trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); + trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_traps_sent++; + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Send the trap packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, + ip_address, NX_SNMP_MANAGER_TRAP_PORT); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + } + + /* Return completion status. */ + return(status); +} +#endif /* NX_SNMP_DISABLE_V1 */ + + +#ifndef NX_SNMP_DISABLE_V2 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trapv2_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMPv2 trap send service. */ +/* */ +/* Developers are encouraged to use the nxd_snmp_agent_trapv2_send */ +/* service which supports IPv4 and IPv6 types. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* community Community name */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_trapv2_send Actual NetX (IPv4) SNMP trap */ +/* send service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (community == NX_NULL) || (ip_address == 0)) + return(NX_PTR_ERROR); + + /* Call actual netx service. */ + status = _nx_snmp_agent_trapv2_send(agent_ptr, ip_address, community, trap_type, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_trapv2_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores the input IPv4 destination IP address in a NetX*/ +/* Duo data type that supports IPv4 and IPv6 address formats, and */ +/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ +/* and send the SNMPv2 trap message. */ +/* */ +/* Developers are encouraged to use nxd_snmp_agent_trapv2_send. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* community Community name */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_NOT_ENABLED Agent not enabled for V2 */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv2_send Actual NetX Duo SNMP trap */ +/* send service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, + NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS ip_nxduo_address; + + + ip_nxduo_address.nxd_ip_version = NX_IP_VERSION_V4; + ip_nxduo_address.nxd_ip_address.v4 = ip_address; + + status = _nxd_snmp_agent_trapv2_send(agent_ptr, &ip_nxduo_address, community, trap_type, elapsed_time, object_list_ptr); + + return status; +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_snmp_agent_trapv2_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMPv2 trap send service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv2_send Actual SNMPv2 trap send */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, + NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || + (community == NX_NULL) || (ip_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nxd_snmp_agent_trapv2_send(agent_ptr, ip_address, community, trap_type, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_snmp_agent_trapv2_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMPv2 trap message to the input */ +/* destination address. This service supports both IPv4 and IPv6 */ +/* addresses. */ +/* */ +/* Note: The string length of community is limited by the packet */ +/* payload and NX_SNMP_MAX_USER_NAME. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate SNMP trap packet */ +/* nx_packet_release Release SNMP packet */ +/* nx_udp_socket_send Send SNMP trap via UDP */ +/* _nx_snmp_object_copy Copy object */ +/* _nx_snmp_utility_community_set Set the community name */ +/* _nx_snmp_utility_error_info_set Set error information */ +/* _nx_snmp_utility_object_data_set Set the data value */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ +/* _nx_snmp_utility_request_id_set Set the Trap ID */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_version_set Set the SNMP v1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, + ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; +UINT trap_length; +UCHAR *trap_object_ptr; +NX_SNMP_OBJECT_DATA trap_object_data; +NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; +NX_PACKET *trap_packet_ptr; +UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; +UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; +UINT packet_type; + + + /* Verify V2 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE) + { + return NX_NOT_ENABLED; + } + + /* Determine which packet type we allocate based on the destination address type. */ + if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) + { +#ifndef FEATURE_NX_IPV6 + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif + } + else + { + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; + } + + + /* Now prepare trap message so we can process the variables one by one. */ + + /* Allocate the packet for the SNMP v2 trap. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a trap packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the trap packet. */ + trap_sequence_length = 0; + trap_type_length = 0; + trap_variable_list_length = 0; + trap_variable_length = 0; + + /* Setup a pointer to the trap packet's buffer area. */ + trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the trap sequence pointer. Remember it since we are going to have to + update it later with the actual length of the trap. */ + trap_sequence_ptr = trap_buffer_ptr; + + /* First, write the sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Now set the Version ID in the trap message. */ + trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the community in the trap message. */ + trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Remember the request type pointer, since it will need to be updated later. */ + trap_type_ptr = trap_buffer_ptr; + + /* Now set the request type in the trap message. */ + trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the trap ID in the trap message. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the trap error information. */ + trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the trap's variable list field. */ + trap_variable_list_ptr = trap_buffer_ptr; + + /* Setup the variable list. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the sysUpTime object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", + trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the SysTimerTicks into the trap buffer as the first item in the variable binding list. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; + trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Clear the trap variable size. */ + trap_variable_length = 0; + + /* Check that we have a valid trap type requested. */ + if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM)) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Check that we have a trap list if a custom trap is requested. */ + if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM)) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Check if this is an enumerated trap event. */ + if (trap_type <= TRAP_ID_MAX) + { + + /* Set up the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the snmpTrapOID object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", + trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Set an Object ID for the data. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; + trap_object_data.nx_snmp_object_data_msw = 0; + + /* Copy the object specified by the trap_type index. */ + _nx_snmp_object_copy(_nx_snmp_v2_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string); + + /* Add trap object data to trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + } + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if an object is specified. */ + if (object_list_ptr) + { + + /* Setup object pointers from the supplied object list. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + + /* Loop to process all the objects in the list. */ + while (trap_object_ptr) + { + + /* Clear the trap variable length. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the object into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if there are more objects to insert into the trap message. */ + if (object_list_ptr) + { + + /* Move to the next object in the list. */ + object_list_ptr++; + + if (object_list_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Determine if there is another object. */ + if (object_list_ptr -> nx_snmp_object_string_ptr) + { + + /* Setup the object and object data pointers. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + } + } + + /* At this point, several trap fields need to be updated with actual lengths. */ + + _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); + + /* Update the trap packet's pointers. */ + trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); + trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_traps_sent++; + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Send the trap packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, + ip_address, NX_SNMP_MANAGER_TRAP_PORT); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return an error. */ + return(NX_SNMP_ERROR); + } + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trapv2_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent v2 trap send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* OID OID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_trapv2_oid_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid IP address. */ + if (ip_address == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_trapv2_oid_send(agent_ptr, ip_address, community, oid, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(oid); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_trapv2__oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v2 trap message using the OID */ +/* directly from the caller. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* OID OID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv2_oid_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS ipduo_address; + + + ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; + ipduo_address.nxd_ip_address.v4 = ip_address; + + status = _nxd_snmp_agent_trapv2_oid_send(agent_ptr, &ipduo_address, community, oid, elapsed_time, object_list_ptr); + + return status; +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(community); + NX_PARAMETER_NOT_USED(oid); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_snmp_agent_trapv2_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent v2 trap send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* OID OID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv2_oid_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL) || + (ipduo_address == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Call actual service. */ + status = _nxd_snmp_agent_trapv2_oid_send(agent_ptr, ipduo_address, community, oid, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_snmp_agent_trapv2_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v2 trap message using the OID */ +/* directly from the caller. Supports IPv6 and IPv4 connections. */ +/* */ +/* Note: The string length of community is limited by the packet */ +/* payload and NX_SNMP_MAX_USER_NAME. The string length of oid is */ +/* limited by the packet payload and NX_SNMP_MAX_OCTET_STRING. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* OID OID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate SNMP trap packet */ +/* nx_packet_release Release SNMP packet */ +/* nx_udp_socket_send Send SNMP trap via UDP */ +/* _nx_snmp_object_copy Copy object */ +/* _nx_snmp_utility_community_set Set the community name */ +/* _nx_snmp_utility_error_info_set Set error information */ +/* _nx_snmp_utility_object_data_set Set the data value */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ +/* _nx_snmp_utility_request_id_set Set the Trap ID */ +/* _nx_snmp_utility_sequence_set_1byte */ +/* Set trap sequence */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_version_set Set the SNMP v1 */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; +UINT trap_length; +UCHAR *trap_object_ptr; +NX_SNMP_OBJECT_DATA trap_object_data; +NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; +NX_PACKET *trap_packet_ptr; +UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; +UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; +UINT packet_type = NX_UDP_PACKET; + + + if (ipduo_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + packet_type = NX_IPv6_UDP_PACKET; + } + else + { + packet_type = NX_IPv4_UDP_PACKET; + } + + /* Allocate the packet for the SNMP v2 trap. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a trap packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Now prepare trap message so we can process the variables one by one. */ + + /* Initialize the counters required for the length fields of the trap packet. */ + trap_sequence_length = 0; + trap_type_length = 0; + trap_variable_list_length = 0; + trap_variable_length = 0; + + /* Setup a pointer to the trap packet's buffer area. */ + trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the trap sequence pointer. Remember it since we are going to have to + update it later with the actual length of the trap. */ + trap_sequence_ptr = trap_buffer_ptr; + + /* First, write the sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Now set the Version ID in the trap message. */ + trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the community in the trap message. */ + trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Remember the request type pointer, since it will need to be updated later. */ + trap_type_ptr = trap_buffer_ptr; + + /* Now set the request type in the trap message. */ + trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now set the trap ID in the trap message. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the trap error information. */ + trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the trap's variable list field. */ + trap_variable_list_ptr = trap_buffer_ptr; + + /* Setup the variable list. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the sysUpTime object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; + trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Clear the trap variable size. */ + trap_variable_length = 0; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the snmpTrapOID object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Set a Object ID for the data. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; + trap_object_data.nx_snmp_object_data_msw = 0; + + /* Check oid length. */ + if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING)) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string); + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if an object is specified. */ + if (object_list_ptr) + { + + /* Setup object pointers from the supplied object list. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + + /* Loop to process all the objects in the list. */ + while (trap_object_ptr) + { + + /* Clear the trap variable length. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the object into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if there are more objects to insert into the trap message. */ + if (object_list_ptr) + { + + /* Move to the next object in the list. */ + object_list_ptr++; + + if (object_list_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Determine if there is another object. */ + if (object_list_ptr -> nx_snmp_object_string_ptr) + { + + /* Setup the object and object data pointers. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + } + } + + /* At this point, several trap fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); + + /* Now the trap packet's pointers must be setup so it can be sent. */ + trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); + trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_traps_sent++; + agent_ptr -> nx_snmp_agent_packets_sent++; + + + /* Send the trap packet back to the requesting SNMP manager. */ + + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ipduo_address, NX_SNMP_MANAGER_TRAP_PORT); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return an error. */ + return(NX_SNMP_ERROR); + } + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +#endif /* NX_SNMP_DISABLE_V2 */ + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trapv3_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the NetX (IPv4) SNMP agent v3 */ +/* trap send service. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* username Username */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_trapv3_send Actual NetX (IPv4) SNMP agent */ +/* trap send service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, + ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) + || (username == NX_NULL) || (ip_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_trapv3_send(agent_ptr, ip_address, username, trap_type, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_trapv3_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stores the input IPv4 destination IP address in a NetX*/ +/* Duo data type that supports IPv4 and IPv6 address formats, and */ +/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ +/* and send the SNMPv3 trap message. */ +/* */ +/* Developers are encouraged to use nxd_snmp_agent_trapv3_send. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IPv4 address */ +/* username Username */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_NOT_ENABLED Agent not enabled for V3 */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv3_send Actual SNMPv3 trap send */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, + ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS ip_nxduo_address; + + ip_nxduo_address.nxd_ip_version = NX_IP_VERSION_V4; + ip_nxduo_address.nxd_ip_address.v4 = ip_address; + + status = _nxd_snmp_agent_trapv3_send(agent_ptr, &ip_nxduo_address, username, trap_type, elapsed_time, object_list_ptr); + return status; +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(trap_type); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_snmp_agent_trapv3_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMPv3 trap send service. */ +/* */ +/* Developers are encouraged to use the nxd_snmp_agent_trapv3_send */ +/* service which supports IPv4 and IPv6 types. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* username Username */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv3_send Actual NetX Duo SNMP agent */ +/* trap send service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, + ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) + || (username == NX_NULL) || (ip_address == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nxd_snmp_agent_trapv3_send(agent_ptr, ip_address, username, trap_type, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_snmp_agent_trapv3_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v3 trap message to the input */ +/* destination address. This service supports both IPv4 and IPv6 */ +/* addresses. */ +/* */ +/* Note: The string length of username is limited by the packet */ +/* payload and NX_SNMP_MAX_OCTET_STRING. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* username Username */ +/* trap_type Type of trap */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_des_key_set Setup DES encryption */ +/* _nx_des_encrypt Encrypt bytes */ +/* _nx_md5_digest_calculate MD5 algorithm completion */ +/* _nx_md5_initialize MD5 algorithm initialization */ +/* _nx_md5_update MD5 algorithm computation */ +/* nx_packet_allocate Allocate SNMP trap packet */ +/* nx_packet_release Release SNMP packet */ +/* nx_udp_socket_send Send SNMP trap via UDP */ +/* _nx_snmp_object_copy Copy object */ +/* _nx_snmp_utility_error_info_set Set error information */ +/* _nx_snmp_utility_octet_set Set octet string */ +/* _nx_snmp_utility_object_data_set Set the data value */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ +/* _nx_snmp_utility_request_id_set Set the Request ID */ +/* _nx_snmp_utility_request_type_set_1byte Set trap request type */ +/* _nx_snmp_utility_version_set Set the SNMP v3 */ +/* _nx_sha1_digest_calculate SHA algorithm completion */ +/* _nx_sha1_initialize SHA algorithm initialization */ +/* _nx_sha1_update SHA algorithm computation */ +/* tx_time_get Get time */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, + NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; +UINT trap_length; +UCHAR *trap_object_ptr; +NX_SNMP_OBJECT_DATA trap_object_data; +NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; +NX_PACKET *trap_packet_ptr; +UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; +UINT trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length; +UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; +UINT i; +UCHAR *temp_ptr; +UINT j, padding; +UCHAR *trap_encryption_size_ptr = NX_NULL; +UCHAR *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; +UINT packet_type; +UCHAR message_security_options = 0; +UINT username_length; + + + /* Verify V3 is currently enabled for this agent. */ + if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) + { + + return NX_NOT_ENABLED; + } + + /* Determine which packet type we allocate based on the destination address type. */ + if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) + { +#ifndef FEATURE_NX_IPV6 + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif + } + else + { + return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; + } + + /* Allocate the packet for the SNMP response. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a trap packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the trap packet. */ + trap_sequence_length = 0; + trap_header_length = 0; + trap_security_length = 0; + trap_pdu_length = 0; + trap_type_length = 0; + trap_variable_list_length = 0; + trap_variable_length = 0; + + /* Setup a pointer to the trap packet's buffer area. */ + trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap buffer response at 0x%x\n", trap_buffer_ptr); +#endif + /* This is also the trap sequence pointer. Remember it since we are going to have to + update it later with the actual length of the response. */ + trap_sequence_ptr = trap_buffer_ptr; + + /* First, write the sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + + /* Now set the Version ID in the trap message. */ + trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Save the pointer to the global header. */ + trap_header_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap3 header header at 0x%x\n", trap_header_ptr); +#endif + + /* Write the sequence for the global header in the trap packet. A zero is written for now. + This will be updated later. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /***************8 Now set the request ID. *********************8*/ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /********************* Now set the maximum message size. ***************************8*/ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /********************** Now set the security options e.g. Flags. ****************************/ + + /* Determine what the trap message security options are. These are not the same as + the general get/set request PDU options. */ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + message_security_options = NX_SNMP_SECURITY_AUTHORIZE; + } + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + message_security_options |= NX_SNMP_SECURITY_PRIVACY; + } + + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /******************* Now set the security type (always USM model). *********************/ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /* At this point, we have successfully built the security header. */ + + + /************************** Start the security parameters field. ************************/ + + /* First set up the octet string field. For now just put in zeros... we will update when + the actual size is known. */ + trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + trap_buffer_ptr[1] = 0; + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + 2; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + 2; + + /* Remember the security header length pointer. */ + trap_security_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap3 security header 0x%x\n", trap_security_ptr); +#endif + /* Now set the sequence of the USM security parameters. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /************************** Now set the context engine. ***************************/ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /****************** ***************** **********************/ + /* Now set BOOT COUNT. */ + /****************** ***************** **********************/ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /****************** ***************** **********************/ + /* Now set BOOT TIME. */ + /****************** ***************** **********************/ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Check username length. */ + if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING)) + { + return(NX_SIZE_ERROR); + } + + /****************** ***************** **********************/ + /* Now set USER NAME. */ + /****************** ***************** **********************/ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Initialize the temporary string to zero. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + temp_string[i] = 0; + + /****************** ***************** **********************/ + /* Now set AUTHENTICATION PARAMETER. */ + /****************** ***************** **********************/ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + + /* We have a valid authentication key, so initialize the string to zero. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end); + + trap_authentication_ptr = trap_buffer_ptr + 2; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr); +#endif + } + else + { + /* No security enabled so set this as an empty parameter. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + + /****************** ***************** **********************/ + /* Now set 8 char PRIVACY PARAMETER. */ + /****************** ***************** **********************/ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + + /* We will encrypt the message, so set to all zeros field initially. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end); + + trap_privacy_ptr = trap_buffer_ptr + 2; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr); +#endif + } + else + { + /* Not encrypting, so set the privacy field as an empty parameter. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* If privacy is required, set the response to have an encryption header. */ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + + /* Now setup the trap buffer to encapsulate the encrypted PDU. Note that + the actual encryption will be done after the complete trap has been + formed. */ + trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + trap_buffer_ptr[1] = 0x82; + trap_buffer_ptr[2] = 0x00; + trap_buffer_ptr[3] = 0x00; + + /* Save the trap encryption size pointer. This will be filled in below + as we build the message. */ + trap_encryption_size_ptr = trap_buffer_ptr + 2; + + /* Move the trap buffer forward. */ + trap_buffer_ptr = trap_buffer_ptr + 4; + + /* Increase the length of the total trap message. */ + trap_sequence_length = trap_sequence_length + 4; + } + + /* Save the trap pdu sequence pointer. */ + trap_pdu_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_pdu_ptr: 0x%x\n", trap_pdu_ptr); +#endif + + /****************** ***************** **********************/ + /* Now start the PDU SEQUENCE. */ + /****************** ***************** **********************/ + + /* A zero is written for now. This will be updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Increment the number of trap sequence bytes. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /****************************************************/ + /* Set the PDU engine ID */ + /****************************************************/ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (trap_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap pointer forward. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Increment the sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /****************************************************/ + /* Set the PDU engine name */ + /****************************************************/ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (trap_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap pointer forward. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Save the pointer to the trap type. */ + trap_type_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_type_ptr: 0x%x\n", trap_type_ptr); +#endif + + /* Increment the sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /****************************************************/ + /* Set the PDU request type */ + /****************************************************/ + trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /****************************************************/ + /* Set the PDU request ID */ + /****************************************************/ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up (this assumes two bytes but we may need more) . */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /****************************************************/ + /* Get the PDU error information */ + /****************************************************/ + + /* Assume everything is okay at this point. */ + trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the response's variable list field. */ + trap_variable_list_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_variable_list_ptr: 0x%x\n", trap_variable_list_ptr); +#endif + /* Setup the variable list. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_variable_ptr: 0x%x\n", trap_variable_ptr); +#endif + + /****************************************************/ + /* Start the PDU variable list length */ + /****************************************************/ + + /* Initialize the length to zero. We will update with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /****************************************************/ + /* Set the sysUpTime object ID */ + /****************************************************/ + + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", + trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /****************************************************/ + /* Set the sysUpTime Timer Ticks */ + /****************************************************/ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; + trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Clear the trap variable size. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Check for valid trap type. */ + if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM)) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Check that we have a trap list if a custom trap is requested. */ + if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM)) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Check if this is an enumerated trap type. */ + if (trap_type <= TRAP_ID_MAX) + { + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the snmpTrapOID object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", + trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Set a Object ID for the data. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; + trap_object_data.nx_snmp_object_data_msw = 0; + _nx_snmp_object_copy(_nx_snmp_v3_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string); + + /* Add trap object data to trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + } + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if an object is specified. */ + if (object_list_ptr) + { + + /* Setup object pointers from the supplied object list. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + + /* Loop to process all the objects in the list. */ + while (trap_object_ptr) + { + + /* Clear the trap variable length. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the object into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if there are more objects to insert into the trap message. */ + if (object_list_ptr) + { + + /* Move to the next object in the list. */ + object_list_ptr++; + + if (object_list_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Determine if there is another object. */ + if (object_list_ptr -> nx_snmp_object_string_ptr) + { + + /* Setup the object and object data pointers. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Next trap3 object data at 0x%x\n", trap_object_data_ptr); +#endif + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + } + } + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("\nSet trap3 sequence length at 0x%x to 0x%x\n Set global sequence length at 0x%x to 0x%x\n Set trap3 security length at 0x%x to 0x%x\n Set trap3 pdu length at 0x%x to 0x%x\n Set trap3 variable list length at 0x%x to 0x%x\n Set trap3 type length at 0x%x to 0x%x\n", + trap_sequence_ptr, trap_sequence_length, trap_header_ptr, trap_header_length, + trap_security_ptr, trap_security_length, trap_pdu_ptr, trap_pdu_length, + trap_variable_list_ptr, trap_variable_list_length, trap_type_ptr, trap_type_length); +#endif + + /* At this point, several trap fields need to be updated with actual lengths. */ + + _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set_1byte(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end); + + /* Setup the security OCTET string length. */ + + /* Backup to the OCTET string for the security size. */ + trap_security_ptr = trap_security_ptr - 2; +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Move trap3 security pointer by 2 0x%x (length %u)\n", trap_security_ptr, trap_security_length); +#endif + /* Account for the 2 byte Security Sequence field. */ + trap_security_length = trap_security_length + 2; + + /* Store the security size. */ + trap_security_ptr[1] = (UCHAR) (trap_security_length & 0xFF); + + /* Determine if privacy is required. If so, encrypt the PDU and setup the response + to have an encryption header. */ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + + /* Determine if any padding needs to be applied - account for the + two bytes of sequence information on the PDU. */ + trap_pdu_length = trap_pdu_length + 2; + padding = ((trap_pdu_length+7)/8)*8 - trap_pdu_length; + + /* Add the padding the trap PDU length and the trap sequence length. */ + trap_pdu_length = trap_pdu_length + padding; + trap_sequence_length = trap_sequence_length + padding; + + /* Clear the end of the trap message... just to be nice! */ + for (i = 0; i < padding; i++) + { + + /* Clear byte at the end of the response. */ + *trap_buffer_ptr++ = 0; + } + + /* Setup the size of the encrypted PDU. */ + trap_encryption_size_ptr[0] = (UCHAR) ((trap_pdu_length >> 8) & 0xFF); + trap_encryption_size_ptr[1] = (UCHAR) (trap_pdu_length & 0xFF); + + /* Update the total trap sequence length again. */ + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + + /* Increment the salt counter. */ + agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; + + /* Build the salt value for the decryption. */ + key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); + key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); + key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); + key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); + key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); + key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); + key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); + key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); + + /* Loop to store the salt in the privacy field. */ + for (i = 0; i < 8; i++) + { + + /* Store a byte of the salt. */ + trap_privacy_ptr[i] = key1[i]; + } + + /* Setup pointer to the actual PDU. */ + temp_ptr = trap_encryption_size_ptr + 2; + + /* Make the Initialization Vector (IV). */ + for (i = 0; i < 8; i++) + { + + key2[i] = (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i]; + } + + /* Setup the DES. */ + _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) -> nx_snmp_security_key); + + /* Setup the first input block - use the IV for the first block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[i] ^ key2[i]; + } + + /* Encrypt the first 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); + + /* Loop to encrypt the rest of the PDU. */ + j = 8; + do + { + + /* Setup the next input block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; + } + + /* Encrypt the next 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); + + /* Move the major index forward. */ + j = j + 8; + } while (j < trap_pdu_length); + } + + /* Now the trap packet's pointers must be setup so it can be sent. */ + trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); + trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; + + /* Determine if authentication is required. */ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + + /* Yes, authentication is required. */ + + /* Now determine which authentication is required. */ + if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) + { + + /* Copy the base MD5 key into key1. */ + for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base MD5 key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Calculate prepend Key1. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Prepend Key2 to the result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); + } + else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) + { + + /* Copy the base SHA key into key1. */ + for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base SHA key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Calculate prepend Key1. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Prepend Key2 to the result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); + } + else + { + + /* Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* At this point, key2 contains the computed digest of the message. This needs to be + place in the outgoing message. */ + + /* Loop to setup the outgoing digest. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + { + + /* Copy one byte of digest. */ + trap_authentication_ptr[i] = key2[i]; + } + } + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_traps_sent++; + agent_ptr -> nx_snmp_agent_packets_sent++; + agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length; + + /* Send the trap packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ip_address, NX_SNMP_MANAGER_TRAP_PORT); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return error. */ + return(NX_SNMP_ERROR); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_agent_trapv3_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent v3 trap send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* username Username */ +/* oid Enterprise ID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_agent_trapv3_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (username == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid IP address. */ + if (ip_address == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Call actual service. */ + status = _nx_snmp_agent_trapv3_oid_send(agent_ptr, ip_address, username, oid, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(oid); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_trapv3_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v3 trap message. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* username Username */ +/* OID Enterprise ID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv3_oid_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS ipduo_address; + + + ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; + ipduo_address.nxd_ip_address.v4 = ip_address; + + status = _nxd_snmp_agent_trapv3_oid_send(agent_ptr, &ipduo_address, username, oid, elapsed_time, object_list_ptr); + + return status; +#else + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(ip_address); + NX_PARAMETER_NOT_USED(username); + NX_PARAMETER_NOT_USED(oid); + NX_PARAMETER_NOT_USED(elapsed_time); + NX_PARAMETER_NOT_USED(object_list_ptr); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_snmp_agent_trapv3_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent v2 trap send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* community Community name */ +/* OID OID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_snmp_agent_trapv3_oid_send Actual agent trap send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (username == NX_NULL) || + (ipduo_address == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Call actual service. */ + status = _nxd_snmp_agent_trapv3_oid_send(agent_ptr, ipduo_address, username, oid, elapsed_time, object_list_ptr); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_snmp_agent_trapv3_oid_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends a SNMP v3 trap message. */ +/* */ +/* Note: The string length of username and oid are limited by the */ +/* packet payload and NX_SNMP_MAX_OCTET_STRING. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* ip_address Destination IP address */ +/* username Username */ +/* OID Enterprise ID to send */ +/* elapsed_time Elapsed time from last boot */ +/* of the device (sysUpTime) */ +/* object_list_ptr Variable list of application */ +/* objects to present with the */ +/* trap */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_des_key_set Setup DES encryption */ +/* _nx_des_encrypt Encrypt bytes */ +/* _nx_md5_digest_calculate MD5 algorithm completion */ +/* _nx_md5_initialize MD5 algorithm initialization */ +/* _nx_md5_update MD5 algorithm computation */ +/* nx_packet_allocate Allocate SNMP trap packet */ +/* nx_packet_release Release SNMP packet */ +/* nx_udp_socket_send Send SNMP trap via UDP */ +/* _nx_snmp_object_copy Copy object */ +/* _nx_snmp_utility_error_info_set Set error information */ +/* _nx_snmp_utility_octet_set Set octet string */ +/* _nx_snmp_utility_object_data_set Set the data value */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ +/* _nx_snmp_utility_request_id_set Set the Request ID */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_version_set Set the SNMP v3 */ +/* _nx_sha1_digest_calculate SHA algorithm completion */ +/* _nx_sha1_initialize SHA algorithm initialization */ +/* _nx_sha1_update SHA algorithm computation */ +/* tx_time_get Get time */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) +{ + +UINT status; +UINT trap_length; +UCHAR *trap_object_ptr; +NX_SNMP_OBJECT_DATA trap_object_data; +NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; +NX_PACKET *trap_packet_ptr; +UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; +UINT trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length; +UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; +UINT i; +#ifndef NX_SNMP_NO_SECURITY +UINT j, padding; +UCHAR *temp_ptr; +UCHAR *trap_encryption_size_ptr = NX_NULL; +UCHAR *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; +#endif +UINT packet_type = NX_UDP_PACKET; +UCHAR message_security_options; +UINT username_length; + + + if (ipduo_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else + { + packet_type = NX_IPv6_UDP_PACKET; + } + + /* Allocate the packet for the SNMP response. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a trap packet was allocated. */ + if (status != NX_SUCCESS) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return(NX_SNMP_ERROR); + + } + + + /* Initialize the counters required for the length fields of the trap packet. */ + trap_sequence_length = 0; + trap_header_length = 0; + trap_security_length = 0; + trap_pdu_length = 0; + trap_type_length = 0; + trap_variable_list_length = 0; + trap_variable_length = 0; + + /* Setup a pointer to the trap packet's buffer area. */ + trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the trap sequence pointer. Remember it since we are going to have to + update it later with the actual length of the response. */ + trap_sequence_ptr = trap_buffer_ptr; + + /* First, write the sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Now set the Version ID in the trap message. */ + trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Save the pointer to the global header. */ + trap_header_ptr = trap_buffer_ptr; + + /* Write the sequence for the global header in the trap packet. A zero is written for now. + This will be updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now setup the request ID. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /* Now setup the maximum message size. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /* Now setup the security options. */ + message_security_options = 0; + + /* Determine what the trap message security options are. These are not the same as + the general get/set request PDU options. */ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + message_security_options = NX_SNMP_SECURITY_AUTHORIZE; + } + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + message_security_options |= NX_SNMP_SECURITY_PRIVACY; + } + + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end); + + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /* Now setup the security type. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the header sequence length. */ + trap_header_length = trap_header_length + trap_length; + + /* At this point, we have successfully built the security header. Now, we need to build + the security parameters field. */ + + /* First setup the octet string field. */ + trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + trap_buffer_ptr[1] = 0x0; + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + 2; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + 2; + + /* Remember the security header length pointer. */ + trap_security_ptr = trap_buffer_ptr; + + /* Now set the sequence of the USM security parameters. */ + trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now setup the context engine. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Now setup the number of engine boots. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Now setup the relative time since the last engine boot. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Check username length. */ + if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING)) + { + return(NX_SIZE_ERROR); + } + + /* Now setup the user name, as specified by the input parameter. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Now setup the authentication parameter - it is a 12 character field set to zeros initially. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + temp_string[i] = 0; + + /****************** ***************** **********************/ + /* Now set AUTHENTICATION PARAMETER. */ + /****************** ***************** **********************/ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + + /* We have a valid authentication key, so initialize the string to zero. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end); + + trap_authentication_ptr = trap_buffer_ptr + 2; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr); +#endif + } + else + { + /* No security enabled so set this as an empty parameter. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /****************** ***************** **********************/ + /* Now set 8 char PRIVACY PARAMETER. */ + /****************** ***************** **********************/ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + + /* We will encrypt the message, so set to all zeros field initially. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end); + + trap_privacy_ptr = trap_buffer_ptr + 2; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr); +#endif + } + else + { + /* Not encrypting, so set the privacy field as an empty parameter. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Adjust the security sequence length. */ + trap_security_length = trap_security_length + trap_length; + + /* Determine if privacy is required. If so, decrypt the source PDU and setup the response + to have an encryption header. */ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + +#ifndef NX_SNMP_NO_SECURITY + + /* Now setup the trap buffer to encapsulate the encrypted PDU. Note that + the actual encryption will be done after the complete trap has been + formed. */ + trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + trap_buffer_ptr[1] = 0x82; + trap_buffer_ptr[2] = 0x00; + trap_buffer_ptr[3] = 0x00; + + /* Save the trap encryption size pointer. This will be filled in below + as we build the message. */ + trap_encryption_size_ptr = trap_buffer_ptr + 2; + + /* Move the trap buffer forward. */ + trap_buffer_ptr = trap_buffer_ptr + 4; + + /* Increase the length of the total trap message. */ + trap_sequence_length = trap_sequence_length + 4; + +#else + /* Encryption is not supported by this agent but is + specified in the request or by the agent. Simply + discard the message. */ + + /* Increment the privacy error counter. */ + agent_ptr -> nx_snmp_agent_privacy_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); +#endif + } + + /* Save the trap pdu sequence pointer. */ + trap_pdu_ptr = trap_buffer_ptr; + + /* First, write the PDU sequence in the trap packet. A zero is written for now. This will be + updated later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Increment the number of trap sequence bytes. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Now store the PDU context engine in the trap packet. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (trap_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap pointer forward. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Increment the sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Now store the PDU context name in the trap packet. */ + trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (trap_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap pointer forward. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Save the pointer to the trap type. */ + trap_type_ptr = trap_buffer_ptr; + + /* Increment the sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Setup the trap request type field. */ + trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Now set the request ID in the trap message. */ + trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Set the trap error information. Assume everything is okay at this point. */ + trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the response's variable list field. */ + trap_variable_list_ptr = trap_buffer_ptr; + + /* Setup the variable list. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the sysUpTime object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; + trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Clear the trap variable size. */ + trap_variable_length = 0; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the snmpTrapOID object ID into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Set a Object ID for the data. */ + trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; + trap_object_data.nx_snmp_object_data_msw = 0; + + /* Check oid length. */ + if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING)) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string); + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if an object is specified. */ + if (object_list_ptr) + { + + /* Setup object pointers from the supplied object list. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + + /* Loop to process all the objects in the list. */ + while (trap_object_ptr) + { + + /* Clear the trap variable length. */ + trap_variable_length = 0; + + /* Remember the start of the variable. */ + trap_variable_ptr = trap_buffer_ptr; + + /* Setup the variable trap sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Place the object into the trap buffer. */ + trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Insert the object's data into the trap buffer. */ + trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (trap_length == 0) + { + + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Move the trap buffer pointer up. */ + trap_buffer_ptr = trap_buffer_ptr + trap_length; + + /* Adjust the trap sequence length. */ + trap_sequence_length = trap_sequence_length + trap_length; + + /* Increment the pdu length. */ + trap_pdu_length = trap_pdu_length + trap_length; + + /* Adjust the trap request type length. */ + trap_type_length = trap_type_length + trap_length; + + /* Adjust the trap variable list size. */ + trap_variable_list_length = trap_variable_list_length + trap_length; + + /* Adjust the trap variable size. */ + trap_variable_length = trap_variable_length + trap_length; + + /* Now update the trap variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); + + /* Default the object pointer to NULL. */ + trap_object_ptr = NX_NULL; + + /* Determine if there are more objects to insert into the trap message. */ + if (object_list_ptr) + { + + /* Move to the next object in the list. */ + object_list_ptr++; + + if (object_list_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + + /* Determine if there is another object. */ + if (object_list_ptr -> nx_snmp_object_string_ptr) + { + + /* Setup the object and object data pointers. */ + trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; + trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; + + /* Check for a valid operation. */ + if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) + { + /* Release the trap packet. */ + nx_packet_release(trap_packet_ptr); + + /* Done, return to caller. */ + return(NX_SNMP_ERROR); + } + } + } + } + + /* At this point, several trap fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); + + /* Setup the security OCTET string length. */ + + /* Backup to the OCTET string for the security size. */ + trap_security_ptr = trap_security_ptr - 2; + + /* Account for the 2 byte Security Sequence field. */ + trap_security_length = trap_security_length + 2; + + /* Store the security size. */ + trap_security_ptr[1] = (UCHAR) (trap_security_length & 0xFF); + + /* Determine if privacy is required. If so, encrypt the PDU and setup the response + to have an encryption header. */ + if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) + { + +#ifndef NX_SNMP_NO_SECURITY + + /* Determine if any padding needs to be applied - account for the + four bytes of header information on the PDU. */ + trap_pdu_length = trap_pdu_length + 4; + padding = ((trap_pdu_length+7)/8)*8 - trap_pdu_length; + + /* Add the padding the trap PDU length and the trap sequence length. */ + trap_pdu_length = trap_pdu_length + padding; + trap_sequence_length = trap_sequence_length + padding; + + /* Clear the end of the trap message... just to be nice! */ + for (i = 0; i < padding; i++) + { + + /* Clear byte at the end of the response. */ + *trap_buffer_ptr++ = 0; + } + + /* Setup the size of the encrypted PDU. */ + trap_encryption_size_ptr[0] = (UCHAR) ((trap_pdu_length >> 8) & 0xFF); + trap_encryption_size_ptr[1] = (UCHAR) (trap_pdu_length & 0xFF); + + /* Update the total trap sequence length again. */ + _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); + + /* Increment the salt counter. */ + agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; + + /* Build the salt value for the decryption. */ + key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); + key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); + key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); + key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); + key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); + key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); + key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); + key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); + + /* Loop to store the salt in the privacy field. */ + for (i = 0; i < 8; i++) + { + + /* Store a byte of the salt. */ + trap_privacy_ptr[i] = key1[i]; + } + + /* Setup pointer to the actual PDU. */ + temp_ptr = trap_encryption_size_ptr + 2; + + /* Make the Initialization Vector (IV). */ + for (i = 0; i < 8; i++) + { + + key2[i] = (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i]; + } + + /* Setup the DES. */ + _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key); + + /* Setup the first input block - use the IV for the first block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[i] ^ key2[i]; + } + + /* Encrypt the first 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); + + /* Loop to encrypt the rest of the PDU. */ + j = 8; + do + { + + /* Setup the next input block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; + } + + /* Encrypt the next 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); + + /* Move the major index forward. */ + j = j + 8; + } while (j < trap_pdu_length); + +#else + + /* Increment the privacy error counter. */ + agent_ptr -> nx_snmp_agent_privacy_errors++; + + /* Release the trap packet too. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return NX_SNMP_ERROR; +#endif + } + + /* Now the trap packet's pointers must be setup so it can be sent. */ + trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); + trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; + +#ifndef NX_SNMP_NO_SECURITY + + /* Determine if authentication is required. */ + if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) + { + + /* Yes, authentication is required. */ + + /* Now determine which authentication is required. */ + if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) + { + + /* Copy the base MD5 key into key1. */ + for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base MD5 key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Calculate prepend Key1. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Prepend Key2 to the result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); + } + else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) + { + + /* Copy the base SHA key into key1. */ + for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base SHA key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Calculate prepend Key1. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Prepend Key2 to the result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); + } + else + { + + /* Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return to caller. */ + return(NX_SNMP_ERROR); + } + + /* At this point, key2 contains the computed digest of the message. This needs to be + place in the outgoing message. */ + + /* Loop to setup the outgoing digest. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + { + + /* Copy one byte of digest. */ + trap_authentication_ptr[i] = key2[i]; + } + } +#endif + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_traps_sent++; + agent_ptr -> nx_snmp_agent_packets_sent++; + agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length; + + /* Send the trap packet back to the requesting SNMP manager. */ + + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ipduo_address, NX_SNMP_MANAGER_TRAP_PORT); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(trap_packet_ptr); + + /* Return error. */ + return(NX_SNMP_ERROR); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +#endif /* NX_SNMP_DISABLE_V3 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_compare PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object compare */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* requested_object Pointer to requested object */ +/* actual_object Pointer to actual object */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_compare Actual agent object compare */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((requested_object == NX_NULL) || (actual_object == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_compare(requested_object, actual_object); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_compare PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares two objects. */ +/* */ +/* Note: new API nx_snmp_object_compare_extended is encouraged to use. */ +/* */ +/* INPUT */ +/* */ +/* requested_object Pointer to requested object */ +/* actual_object Pointer to actual object */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_compare_extended Call actual compare service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object) +{ + +UINT status; +UINT requested_object_length; +UINT actual_object_length; + + + /* Calculate the object length. */ + if ((_nx_utility_string_length_check((CHAR *)requested_object, &requested_object_length, NX_MAX_STRING_LENGTH)) || + (_nx_utility_string_length_check((CHAR *)actual_object, &actual_object_length, NX_MAX_STRING_LENGTH))) + { + return(NX_SIZE_ERROR); + } + + /* Call actual service. */ + status = _nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length); + + /* Return status to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_compare_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object compare */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* requested_object Pointer to requested object */ +/* requested_object_length Length of object requested */ +/* actual_object Pointer to actual object */ +/* actual_object_length Length of object requested */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_compare_extended Actual agent object compare */ +/* extended function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length) +{ + + + /* Check for invalid input pointers. */ + if ((requested_object == NX_NULL) || (actual_object == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + return(_nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_compare_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares two objects. */ +/* */ +/* Note: The strings of requested object and actual object must be */ +/* NULL-terminated and length of each string matches the length */ +/* */ +/* INPUT */ +/* */ +/* requested_object Pointer to requested object */ +/* requested_object_length Length of object requested */ +/* actual_object Pointer to actual object */ +/* actual_object_length Length of object requested */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length) +{ + +UINT i, j; +UINT request_value; +UINT actual_value; +UINT temp_requested_object_length; +UINT temp_actual_object_lenght; + + + /* Check object string and get the actual string length. */ + if ((_nx_utility_string_length_check((CHAR *)requested_object, &temp_requested_object_length, requested_object_length)) || + (_nx_utility_string_length_check((CHAR *)actual_object, &temp_actual_object_lenght, actual_object_length))) + return(NX_SNMP_ERROR); + + /* Check the actual string length. */ + if ((requested_object_length != temp_requested_object_length) || + (actual_object_length != temp_actual_object_lenght)) + return(NX_SNMP_ERROR); + + /* Loop to compare the first and second object name. Stop at the first NULL. */ + i = 0; + request_value = 0; + actual_value = 0; + while ((requested_object[i]) && (actual_object[i])) + { + + /* Update the requested object value. */ + if (requested_object[i] == '.') + request_value = 0; + else + request_value = (request_value * 10) + (UINT) (requested_object[i] - '0'); + + /* Update the actual object value. */ + if (actual_object[i] == '.') + actual_value = 0; + else + actual_value = (actual_value * 10) + (UINT) (actual_object[i] - '0'); + + /* Determine if the names are different. */ + if (requested_object[i] != actual_object[i]) + { + + /* Calculate the remainder - if any - of the requested value. */ + j = i; + while ((requested_object[j]) && (requested_object[j] != '.')) + { + + /* Update the request value. */ + request_value = (request_value * 10) + (UINT) (requested_object[j] - '0'); + + /* Move to next entry. */ + j++; + } + + + /* Calculate the remainder - if any - of the actual value. */ + j = i; + while ((actual_object[j]) && (actual_object[j] != '.')) + { + + /* Update the actual value. */ + actual_value = (actual_value * 10) + (UINT) (actual_object[j] - '0'); + + /* Move to next entry. */ + j++; + } + + /* Determine if the requested object name is less than the actual object name. */ + if (request_value < actual_value) + return(NX_SNMP_NEXT_ENTRY); + else + break; + } + + /* Move to next character. */ + i++; + } + + /* Now compare the names to check for a successful match. */ + if ((requested_object[i] == NX_NULL) && (actual_object[i] == NX_NULL)) + return(NX_SUCCESS); + + /* If the actual object is NULL, that means that everything else matched exactly. */ + if (actual_object[i] == NX_NULL) + return(NX_SUCCESS); + + /* Determine if the requested object name is NULL. This case is considered the next entry. */ + if (requested_object[i] == NX_NULL) + return(NX_SNMP_NEXT_ENTRY); + + /* Return an error condition. */ + return(NX_SNMP_ERROR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_copy PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object copy */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* source_object_name Pointer to source object */ +/* destination_object_name Pointer to destination object */ +/* */ +/* OUTPUT */ +/* */ +/* size If error, returns zero, else */ +/* returns number of bytes */ +/* copied */ +/* CALLS */ +/* */ +/* _nx_snmp_object_copy Actual agent object copy */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_object_name == NX_NULL) || (destination_object_name == NX_NULL)) + return(0); + + /* Call actual service. */ + status = _nx_snmp_object_copy(source_object_name, destination_object_name); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_copy PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies the source object to the destination object. */ +/* */ +/* Note: new API nx_snmp_object_copy_extended is encouraged to use. */ +/* */ +/* INPUT */ +/* */ +/* source_object_name Pointer to source object */ +/* destination_object_name Pointer to destination object */ +/* */ +/* OUTPUT */ +/* */ +/* size If error, returns zero, else */ +/* returns number of bytes */ +/* copied */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name) +{ + +UINT i; + + + /* Calculate the object length. */ + if (_nx_utility_string_length_check((CHAR *)source_object_name, NX_NULL, NX_MAX_STRING_LENGTH)) + return(0); + + /* Loop to copy the name. */ + i = 0; + + while (source_object_name[i]) + { + + /* Copy a byte of the name. */ + destination_object_name[i] = source_object_name[i]; + + /* Move to next byte. */ + i++; + } + + /* Ensure name is null terminated. */ + destination_object_name[i] = NX_NULL; + + /* Return the size of the name. */ + return(i); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_copy_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object copy */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* source_object_name Pointer to source object */ +/* source_object_name_length Length of source object */ +/* destination_object_name_buffer Pointer to destination object */ +/* destination_object_name_buffer_size Size of destination object */ +/* */ +/* OUTPUT */ +/* */ +/* size If error, returns zero, else */ +/* returns number of bytes */ +/* copied */ +/* CALLS */ +/* */ +/* _nx_snmp_object_copy_extended Actual agent object copy */ +/* extended function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, + UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size) +{ + + + /* Check for invalid input pointers. */ + if ((source_object_name == NX_NULL) || (destination_object_name_buffer == NX_NULL)) + return(0); + + /* Call actual service. */ + return(_nx_snmp_object_copy_extended(source_object_name, source_object_name_length, destination_object_name_buffer, destination_object_name_buffer_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_copy_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies the source object to the destination object. */ +/* */ +/* Note: the object name must be NULL-terminated, the size of */ +/* destination object buffer must be larger than source object length. */ +/* */ +/* INPUT */ +/* */ +/* source_object_name Pointer to source object */ +/* source_object_name_length Length of source object */ +/* destination_object_name_buffer Pointer to destination object */ +/* destination_object_name_buffer_size Size of destination object */ +/* */ +/* OUTPUT */ +/* */ +/* size If error, returns zero, else */ +/* returns number of bytes */ +/* copied */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, + UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size) +{ + +UINT temp_object_name_length; + + + /* Check the string length, the destination oject name buffer size must be larger than source object name length. */ + if ((source_object_name_length == 0) || (destination_object_name_buffer_size <= source_object_name_length)) + return(0); + + /* Check name string. */ + if (_nx_utility_string_length_check((CHAR *)source_object_name, &temp_object_name_length, source_object_name_length)) + return(0); + + /* Check the actual string length. */ + if (source_object_name_length != temp_object_name_length) + return(0); + + /* Copy the name and null-terminator. */ + memcpy(destination_object_name_buffer, source_object_name, source_object_name_length + 1); + + /* Return the size of the name. */ + return(source_object_name_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_counter_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object counter */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to counter source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_counter_get Actual agent object counter */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_counter_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_counter_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object counter from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to counter source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_COUNTER; + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_counter_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object counter */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to counter destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_counter_set Actual agent object counter */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_counter_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_counter_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object counter from the object data */ +/* structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to counter destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) destination_ptr; + + /* Copy the value into the object data structure. */ + *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_counter64_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent 64-bit object */ +/* counter get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to counter source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_counter64_get Actual agent object counter */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_counter64_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_counter64_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the 64-bit object counter from the */ +/* specified source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to counter source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_COUNTER64; + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG)value_ptr[0]; + object_data -> nx_snmp_object_data_lsw = (LONG)value_ptr[1]; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_counter64_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent 64-bit object */ +/* counter set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to counter destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_counter64_set Actual agent object counter */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_counter64_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_counter64_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the 64-bit object counter from the object */ +/* data structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to counter destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; +LONG temp = 0; + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER64) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) destination_ptr; + + if (object_data -> nx_snmp_object_data_lsw == 0) + { + temp = object_data -> nx_snmp_object_data_msw; + value_ptr[0] = 0; + + } + if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFFFF00) == 0) + { + temp = object_data -> nx_snmp_object_data_msw << 8; + value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 24) & (0x000000FF)); + } + else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFF0000) == 0) + { + + temp = object_data -> nx_snmp_object_data_msw << 16; + value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 16) & (0x0000FFFF)); + } + else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFF000000) == 0) + { + + temp = object_data -> nx_snmp_object_data_msw << 24; + value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 8) & (0x00FFFFFF)); + } + else + { + value_ptr[0] = (ULONG)(object_data -> nx_snmp_object_data_msw); + } + + value_ptr[1] = (ULONG)(object_data -> nx_snmp_object_data_lsw + temp); + + /* Value_ptr udpates the MIB data but we also need to display the data correctly in object. */ + + /* Update the object data to make the display correct as well. */ + object_data -> nx_snmp_object_data_lsw = (LONG)value_ptr[1]; + object_data -> nx_snmp_object_data_msw = (LONG)value_ptr[0]; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_end_of_mib PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent end-of-mib object */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_end_of_mib Actual agent object end-of-mib*/ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if (object_data == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_end_of_mib(not_used_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_end_of_mib PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places an end-of-mib value in the object data */ +/* structure. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_END_OF_MIB_VIEW; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_gauge_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object gauge */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to gauge source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_gauge_get Actual agent object gauge */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_gauge_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_gauge_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object gauge from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to gauge source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_GAUGE; + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_gauge_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object gauge */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to gauge destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_gauge_set Actual agent object gauge */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_gauge_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_gauge_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object gauge from the object data */ +/* structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to gauge destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_GAUGE) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) destination_ptr; + + /* Copy the value into the object data structure. */ + *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_id_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object ID */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to ID source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_id_get Actual agent object ID */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_id_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_id_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object ID from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to object ID source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT length; +UCHAR c; +CHAR *copy_source = (CHAR*)source_ptr; + + c = *((UCHAR *)source_ptr); + + /* Check if this is an empty string. */ + if ((c == 0x0) || (c == '0')) + { + copy_source = "0.0.0"; + } + + /* Check string length. */ + if (_nx_utility_string_length_check((CHAR *)copy_source, &length, NX_SNMP_MAX_OCTET_STRING)) + { + /* Incoming object data is too big to fit in. */ + return(NX_SNMP_ERROR); + } + + object_data -> nx_snmp_object_data_type = NX_SNMP_OBJECT_ID; + + memcpy(&object_data -> nx_snmp_object_octet_string[0], copy_source, length); + + /* NULL-terminate the string. */ + object_data -> nx_snmp_object_octet_string[length] = 0x0; + + /* Calculate the length. */ + object_data -> nx_snmp_object_octet_string_size = length; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_id_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object ID */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to ID destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_id_set Actual agent object ID */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_id_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_id_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object ID from the object data */ +/* structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to ID destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_OBJECT_ID) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Copy the object id into the destination string. */ + _nx_snmp_object_copy(object_data -> nx_snmp_object_octet_string, (UCHAR *) destination_ptr); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_integer_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object integer */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to integer source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_integer_get Actual agent integer */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_integer_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_integer_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object integer from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to integer source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +LONG *value_ptr; + + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_INTEGER; + + /* Setup pointer to the value. */ + value_ptr = (LONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = *value_ptr; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_integer_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object integer */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to integer destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_integer_set Actual agent object integer */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_integer_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_integer_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object integer from the object data */ +/* structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to integer destination*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +LONG *value_ptr; + + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_INTEGER) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (LONG *) destination_ptr; + + /* Copy the value into the object data structure. */ + *value_ptr = object_data -> nx_snmp_object_data_msw; + + /* Return success. */ + return(NX_SUCCESS); +} + +#ifdef FEATURE_NX_IPV6 + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_ipv6_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the set the IPv6 address */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to IPv6 address */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_ipv6_address_set Actual set address service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_ipv6_address_set(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + /* Determine if the correct type is specified. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + { + + /* Return an invalid pointer input. */ + return(NX_PTR_ERROR); + } + + status = _nx_snmp_object_ipv6_address_set(source_ptr, object_data); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_ipv6_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object IPv6 address from the object data*/ +/* structure and places it in the destination. Note that 1) the data */ +/* type is really an octet string of unspecified size and format, and */ +/* 2) the caller must set the nx_snmp_object_string_size before calling*/ +/* this function since it supplies the length of the octet data. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to IPv6 address */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UCHAR *string_ptr; + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + string_ptr = destination_ptr; + + /* Copy the object data structure into the destination pointer. */ + /* Copy this string into the destination. */ + for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) + { + + /* Determine if the string is too big. */ + if (i >= NX_SNMP_MAX_OCTET_STRING) + { + + /* Error, source string is too large. */ + string_ptr[0] = NX_NULL; + return(NX_SNMP_ERROR); + } + + /* Copy character. */ + string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; + } + + return NX_SUCCESS; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_ipv6_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the IPv6 address get */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to IPv6 address */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_ipv6_address_get Actual get IPv6 service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_ipv6_address_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_ipv6_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object IPv6 address from the object data*/ +/* structure and places it in the destination. Note that the caller */ +/* must set the length of the octet string (object -> */ +/* (nx_snmp_octet_string_size) before calling this service. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to IPv6 address */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UCHAR *source_string; + + + /* Setup pointer to source string. */ + source_string = (UCHAR *) source_ptr; + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_IPV6_ADDRESS; + + /* Copy this string into the destination. */ + for (i = 0; i < object_data->nx_snmp_object_octet_string_size; i++) + { + + /* Copy character. */ + object_data -> nx_snmp_object_octet_string[i] = source_string[i]; + } + + /* Return success. */ + return(NX_SUCCESS); + +} + +#endif /* FEATURE_NX_IPV6 */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_ip_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object IP address */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to IP address source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_ip_address_get Actual agent IP address */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_ip_address_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_ip_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object IP address from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to IP address source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + +ULONG *value_ptr; + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_IP_ADDRESS; + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_ip_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object IP address */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to IP address */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_ip_address_set Actual agent object IP address*/ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_ip_address_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_ip_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object IP address from the object data */ +/* structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to IP address */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + +ULONG *value_ptr; + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_IP_ADDRESS) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) destination_ptr; + + /* Copy the value into the object data structure. */ + *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_no_instance PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object no-instance*/ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used pointer */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_no_instance Actual agent object */ +/* no-instance set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (object_data == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_no_instance(not_used_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_no_instance PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places a no-instance value in the object data */ +/* structure. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NO_SUCH_INSTANCE; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_not_found PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent object not-found */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used pointer */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_not_found Actual agent object */ +/* not-found set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if (object_data == NX_NULL) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_not_found(not_used_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_not_found PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places an not-found value in the object data */ +/* structure. */ +/* */ +/* INPUT */ +/* */ +/* not_used_ptr Not used */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NO_SUCH_OBJECT; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_octet_string_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent octet string */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to octet string source*/ +/* object_data Pointer to object data struct */ +/* length Length of octet string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_octet_string_get Actual agent octet string */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_octet_string_get(source_ptr, object_data, length) ; + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_octet_string_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object octet string from the specified */ +/* source location. Note that while this does have a length field */ +/* the caller must set the nx_snmp_object_string_size before calling */ +/* this function since it supplies the length. */ +/* */ +/* The length field is deprecated. It is only included for legacy code.*/ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to octet string source*/ +/* object_data Pointer to object data struct */ +/* length Length of octet string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length) +{ + +UINT i; +UCHAR *source_string; + + + NX_PARAMETER_NOT_USED(length); + + /* Setup pointer to source string. */ + source_string = (UCHAR *) source_ptr; + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_OCTET_STRING; + + if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) + { + return NX_SNMP_ERROR_TOOBIG; + } + + /* Copy this string into the destination. */ + for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) + { + + /* Copy character. */ + object_data -> nx_snmp_object_octet_string[i] = source_string[i]; + } + + /* The length input is deprecated. The caller sets the length from the MIB table + entry to the object_data instance before calling this function. */ + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_octet_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent octet string */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to octet string */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_octet_string_set Actual agent octet string */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_octet_string_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_octet_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object octet string from the object */ +/* data structure and places it in the destination. Note that the */ +/* length of the octet string must be set in the object string size. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to octet string */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UCHAR *string_ptr; + + + /* Check for the proper type. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) + { + return NX_SNMP_ERROR_TOOBIG; + } + + /* Setup pointer to the destination string. */ + string_ptr = (UCHAR *) destination_ptr; + + /* Copy this string into the destination. */ + for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) + { + + /* Determine if the string is too big. */ + if (i >= NX_SNMP_MAX_OCTET_STRING) + { + + /* Error, source string is too large. */ + string_ptr[0] = NX_NULL; + return(NX_SNMP_ERROR); + } + + /* Copy character. */ + string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; + } + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_string_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent string */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to string source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_string_get Actual agent string */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_string_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_string_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object ASCII string from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to ASCII string source*/ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UCHAR *source_string; + + + /* Setup pointer to source string. */ + source_string = (UCHAR *) source_ptr; + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_OCTET_STRING; + + /* Copy this string into the destination. */ + i = 0; + while (source_string[i]) + { + + /* Copy character. */ + object_data -> nx_snmp_object_octet_string[i] = source_string[i]; + + /* Move to next character. */ + i++; + + /* Check for size of source string. */ + if (i >= NX_SNMP_MAX_OCTET_STRING) + { + + /* Error, source string is too large. */ + object_data -> nx_snmp_object_octet_string[0] = NX_NULL; + object_data -> nx_snmp_object_octet_string_size = 0; + return(NX_SNMP_ERROR); + } + } + + /* Store the length of the string in the object data area. */ + object_data -> nx_snmp_object_octet_string_size = i; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent string */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to string */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_string_set Actual agent string */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_string_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_string_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object ASCII string from the object */ +/* data structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to ASCII string */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UCHAR *string_ptr; + + + /* Check for the proper type. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the destination string. */ + string_ptr = (UCHAR *) destination_ptr; + + /* Copy this string into the destination. */ + for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) + { + + /* Determine if the string is too big. */ + if (i >= NX_SNMP_MAX_OCTET_STRING) + { + + /* Error, source string is too large. */ + return(NX_SNMP_ERROR); + } + + /* Copy character. */ + string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; + } + + /* Null terminate the destination. */ + string_ptr[i] = NX_NULL; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_timetics_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent timetics */ +/* get function call. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to timetics source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_timetics_get Actual agent timetics */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_timetics_get(source_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_timetics_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object timetics from the specified */ +/* source location. */ +/* */ +/* INPUT */ +/* */ +/* source_ptr Pointer to timetics source */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Setup the object data structure. */ + object_data -> nx_snmp_object_data_type = NX_SNMP_TIME_TICS; + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) source_ptr; + + /* Copy the value into the object data structure. */ + object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_snmp_object_timetics_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the SNMP agent timetics */ +/* set function call. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to timetics */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_object_timetics_set Actual agent timetics */ +/* set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual service. */ + status = _nx_snmp_object_timetics_set(destination_ptr, object_data); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_object_timetics_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object timetics from the object */ +/* data structure and places it in the destination. */ +/* */ +/* INPUT */ +/* */ +/* destination_ptr Pointer to timetics */ +/* destination */ +/* object_data Pointer to object data struct */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) +{ + +ULONG *value_ptr; + + + /* Determine if the correct type is specified. */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_TIME_TICS) + { + + /* Return an invalid type message. */ + return(NX_SNMP_ERROR_WRONGTYPE); + } + + /* Setup pointer to the value. */ + value_ptr = (ULONG *) destination_ptr; + + /* Copy the value into the object data structure. */ + *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_community_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the community string from the supplied */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* community_string Pointer to place community */ +/* string */ +/* buffer_length Size of input buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process SNMP v1 request processing */ +/* _nx_snmp_version_2_process SNMP v2 request processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_community_get(UCHAR *buffer_ptr, UCHAR *community_string, INT buffer_length) +{ + +UINT i; +UINT length; +UINT total; + + + /* Buffer size must be at least 2 bytes. */ + if (buffer_length < 2) + { + return(0); + } + + /* Set community string to NULL. */ + *community_string = NX_NULL; + + /* First see if the ANS1 string type is present. */ + if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) + { + + /* Return a zero length. */ + return(0); + } + + if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) + { + + /* Get the type of length of the string */ + UINT temp = (UINT)(buffer_ptr[1] & 0x7F); + + if (temp == 2) + { + + /* Check the buffer length. */ + if (buffer_length < 4) + { + return(0); + } + + /* Length is in the next two bytes. Example: 0x04 0x82 0x98 0x01 */ + total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 4; + + /* Initialize the length. */ + length = 4; + } + + else if (temp == 1) + { + + /* Check the buffer length. */ + if (buffer_length < 3) + { + return(0); + } + + /* Length is in the next byte. Example: 0x04 0x81 0x98 */ + total = (UINT)(buffer_ptr[2]) ; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 3; + + /* Initialize the length. */ + length = 3; + } + else + { + + /* String is either null or too big, return a zero length to indicate an error. */ + return(0); + } + } + else + { + + /* Otherwise, assume we have one byte. Example: 0x04 0x98 */ + + /* Pickup the total length of the community character string. */ + total = (UINT) buffer_ptr[1]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 2; + + /* Initialize the length. */ + length = 2; + } + + if ((INT)(length + total) > buffer_length) + { + + /* Buffer is too small. */ + return(0); + } + + /* Determine if the length is within the maximum. */ + if (total > (NX_SNMP_MAX_USER_NAME-1)) + { + + /* String is too big, return a zero length to indicate an error. */ + return(0); + } + + /* Loop to pickup the remaining characters in the community string. */ + for (i = 0; i < total; i++) + { + + /* Move character from buffer into community string. */ + *community_string++ = *buffer_ptr++; + + /* Adjust the length. */ + length++; + } + + /* NULL-terminate the community string. */ + *community_string = NX_NULL; + + /* Return the length of the ANS1 string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_community_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the community string into the supplied */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* community_string Pointer to source of the */ +/* community string */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_community_set(UCHAR *buffer_ptr, UCHAR *community_string, UCHAR *buffer_end) +{ + +UINT i; +UINT header_size; +UINT length; + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* First, set the OCTET byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; + + /* Calculate the length byte. */ + if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) + { + + /* Error, community length is too large. */ + return(0); + } + + /* Check for a length greater than 128. */ + if (length >= 128) + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < (3 + length)) + return(0); + + /* Indicate there are two length bytes. */ + *buffer_ptr++ = (UCHAR) 0x82; + + /* Set the first length byte. */ + *buffer_ptr++ = (UCHAR) (length >> 8); + + /* Set the second length byte. */ + *buffer_ptr++ = (UCHAR) (length & 0xFF); + + /* Set the header size. */ + header_size = 4; + } + else + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < (1 + length)) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) length; + + /* The header is 2 bytes. */ + header_size = 2; + } + + /* Loop to store rest of the community string. */ + for (i = 0; i < length; i++) + { + + /* Store the SNMP community string. */ + *buffer_ptr++ = (UCHAR) community_string[i]; + } + + /* Return the length of the community string. */ + return(length+header_size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_error_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the error information from the supplied */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* error_code Pointer to place error code */ +/* error_index Pointer to place error index */ +/* buffer_length Size of input buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_error_info_get(UCHAR *buffer_ptr, UINT *error_code, UINT *error_index, INT buffer_length) +{ + + /* Check for invalid input. */ + if (buffer_length < 6) + { + /* Invalid input. */ + *error_code = 0; + *error_index = 0; + + /* Return a zero length. */ + return(0); + } + + /* Determine if the error code and error index is correct. */ + if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) && + (buffer_ptr[1] == 1) && + (buffer_ptr[3] == NX_SNMP_ANS1_INTEGER) && + (buffer_ptr[4] == 1)) + { + + /* Yes, the SNMP version string is correct. */ + + /* Return the error code and error index. */ + *error_code = (UINT) buffer_ptr[2]; + *error_index = (UINT) buffer_ptr[5]; + + /* Return the length of the error code/index string. */ + return(6); + } + else + { + + /* No, the SNMP error code/index is invalid. */ + + /* Clear both. */ + *error_code = 0; + *error_index = 0; + + /* Return a zero length. */ + return(0); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_error_info_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the error information into the supplied */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* error_code Error code */ +/* error_index Error index */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_error_response Send error response to Manager*/ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_error_info_set(UCHAR *buffer_ptr, UINT error_code, UINT error_index, UCHAR *buffer_end) +{ + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 6) + return(0); + + /* First, set the INTEGER byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 1; + + /* Store the error code. */ + *buffer_ptr++ = (UCHAR) (error_code & 0xFF); + + /* Set the INTEGER byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 1; + + /* Store the error index. */ + *buffer_ptr++ = (UCHAR) (error_index & 0xFF); + + /* Return the length of the error info. */ + return(6); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_object_id_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object ID from the supplied buffer */ +/* and converts the object ID to an ASCII format. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* object_string Pointer to place object string*/ +/* buffer_length Size of input buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_utility_object_data_get Get object data */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_object_id_get(UCHAR *buffer_ptr, UCHAR *object_string, INT buffer_length) +{ + +UINT i; +UINT length; +ULONG value; +ULONG temp; +ULONG multiply; +UINT total; +UINT size; +UCHAR byte; +UCHAR saved_byte; +UCHAR *saved_ptr; +UINT string_length; + + + /* Buffer size must be at least 4 bytes. */ + if (buffer_length < 4) + { + return 0; + } + + /* Set object string to NULL. */ + *object_string = NX_NULL; + + /* Initialize the string length to 0. */ + string_length = 0; + + /* Initialize the sequence byte value to NULL. */ + value = 0; + + /* First see if the ANS1 object type is present. */ + if (buffer_ptr[0] != NX_SNMP_ANS1_OBJECT_ID) + { + + /* Return a zero length. */ + return(0); + } + + if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) + { + + temp = buffer_ptr[1] & 0x7F; + + /* Determine if a two byte length is present. */ + if (temp == 2) + { + + /* Check the buffer length. */ + if (buffer_length < 5) + { + return(0); + } + + /* Pickup the total length of the object string. */ + total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); + + /* Pickup the first byte. */ + byte = buffer_ptr[4]; + + /* Save the pointer to the first byte. */ + saved_ptr = &buffer_ptr[4]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 4; + + /* Initialize the length. */ + length = 4; + } + else if (temp == 1) + { + + /* Pickup the total length of the object string. */ + total = buffer_ptr[2]; + + /* Pickup the first byte. */ + byte = buffer_ptr[3]; + + /* Save the pointer to the first byte. */ + saved_ptr = &buffer_ptr[3]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 3; + + /* Initialize the length. */ + length = 3; + } + else + { + + /* This is out of range or null. Invalid SNMP sequence. */ + return(0); + } + } + else + { + + /* Otherwise, assume one byte. */ + + /* Pickup the total length of the object string. */ + total = (UINT) buffer_ptr[1]; + + /* Check for invalid data size */ + if ((INT)total > (buffer_length - 1)) + { + /* Indicate an invalid request is received. */ + return 0; + } + + /* Pickup the first byte. */ + byte = buffer_ptr[2]; + + /* Save the index. */ + saved_ptr = &buffer_ptr[2]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 2; + + /* Initialize the length. */ + length = 2; + } + + /* Save the original byte. */ + saved_byte = byte; + + /* Calculate the first two characters of object string. */ + if (byte >= 80) + { + + /* This form starts with 2 as the first identifier. */ + *object_string++ = '2'; + + /* Increment the string length. */ + string_length++; + + /* Adjust the byte. */ + byte = (UCHAR)(byte - 80); + } + else if (byte >= 40) + { + + /* This form starts with 1 as the first identifier. */ + *object_string++ = '1'; + + /* Increment the string length. */ + string_length++; + + /* Adjust the byte. */ + byte = (UCHAR)(byte - 40); + } + else + { + + /* This form starts with 0 as the first identifier. */ + *object_string++ = '0'; + + /* Increment the string length. */ + string_length++; + } + + /* Always place a '.'. */ + *object_string++ = '.'; + + /* Increment the string length. */ + string_length++; + + /* Determine if the second identifier is legal. */ + if (byte & NX_SNMP_ANS1_MULTI_BYTES) + { + + /* Second identifier too large, return a zero length. */ + return(0); + } + + /* Write the byte back. */ + buffer_ptr[0] = byte; + + /* Loop to pickup the remaining characters in the object string. */ + while (total) + { + + /* Move the buffer pointer forward. */ + byte = *buffer_ptr++; + + /* Decrement the total. */ + total--; + + /* Increment the length. */ + length++; + + /* Determine if the next byte has the additional bytes + bit set (BIT 7). */ + if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) + { + + /* The specified sequence value is less than 128 and is actually in this byte! */ + value = (UINT) byte; + } + else + { + + /* Otherwise, we have a more complicated value that we must loop through + to calculate. */ + + /* Loop to calculate how many bytes there are representing the value. */ + i = 0; + multiply = 128; + while (buffer_ptr[i] & NX_SNMP_ANS1_MULTI_BYTES) + { + + /* Increment count. */ + i++; + + /* Adjust the multiplier. */ + multiply = multiply * 128; + } + + /* Determine if the count is reasonable. */ + if (i > 3) + { + + /* Restore the saved byte. */ + *saved_ptr = saved_byte; + + /* Nope, too big! */ + return(0); + } + + /* Loop to calculate the value. */ + do + { + + /* Pickup the number of bytes required to represent this value. */ + temp = (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); + + /* Calculate the temporary value. */ + temp = temp * multiply; + + /* Calculate total value. */ + value = value + temp; + + /* Adjust the multiply value. */ + multiply = multiply/128; + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Decrement the total. */ + if (total == 0) + { + + /* Restore the saved byte. */ + *saved_ptr = saved_byte; + + return(0); + } + else + total--; + + /* Increment the length. */ + length++; + + } while (byte & NX_SNMP_ANS1_MULTI_BYTES); + + /* Add in the remainder. */ + temp = (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); + value = value + temp; + } + + /* Loop to convert value into ASCII. */ + size = 0; + do + { + + /* Shift the current digits over one. */ + for (i = size; i != 0; i--) + { + + /* Move each digit over one place. */ + object_string[i] = object_string[i-1]; + } + + /* Compute the next decimal digit. */ + byte = (UCHAR) (value % 10); + + /* Update the input number. */ + value = value / 10; + + /* Store the new digit in ASCII form. */ + object_string[0] = (UCHAR)(byte + 0x30); + + /* Increment the size. */ + size++; + + /* Increment the string length. */ + string_length++; + + /* Determine if the length is too long. */ + if (string_length >= NX_SNMP_MAX_OCTET_STRING) + { + + /* String is too long. */ + + /* Null-terminate the string. */ + *object_string = NX_NULL; + + /* Return the length. */ + return(length); + } + + } while ((size < 10) && (value)); + + /* Adjust the object string. */ + object_string = object_string + size; + + /* Determine if there are more tokens. */ + if (total) + { + + /* Still more nodes, place a dot in the string. */ + *object_string++ = '.'; + + /* Increment the string length. */ + string_length++; + + /* Determine if the length is too long. */ + if (string_length >= NX_SNMP_MAX_OCTET_STRING) + { + + /* String is too long. */ + + /* Null-terminate the string. */ + object_string--; + *object_string = NX_NULL; + + /* Return the length. */ + return(length); + } + } + } + + /* Restore the saved byte. */ + *saved_ptr = saved_byte; + + /* NULL-terminate the object string. */ + *object_string = NX_NULL; + + /* Return the length of the ANS1 string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_object_id_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the ASCII representation of the object into */ +/* ASN.1 format and then places it in the ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* object_string Object string in ASCII */ +/* buffer_end End of ASN.1 buffer for error */ +/* checking */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send SNMP v1 trap send */ +/* _nx_snmp_agent_trapv2_send SNMP v2 trap send */ +/* _nx_snmp_agent_trapv3_send SNMP v3 trap send */ +/* _nx_snmp_utility_object_data_set Object data set */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_object_id_set(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end) +{ + +UINT length; +UINT i; +ULONG value; +UCHAR *length_ptr; +UCHAR encoding_started; +UINT object_string_length; + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Check object string length. */ + if (_nx_utility_string_length_check((CHAR*)object_string, &object_string_length, (UINT)(buffer_end - buffer_ptr))) + return(0); + + /* Set the OBJECT byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_OBJECT_ID; + + /* Remember length pointer. */ + length_ptr = buffer_ptr; + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the length byte to zero for now. */ + *buffer_ptr++ = 0; + + /* Check object string length. */ + if (object_string_length < 2) + return(0); + + /* Determine if the object string is legal. */ + if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) || + (object_string[1] != '.')) + { + + /* Invalid object ID. */ + return(0); + } + + /* Calculate the value of the second identifier. */ + i = 2; + value = 0; + + while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) + { + + /* Compute the value. */ + value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); + + /* Move to the next character. */ + i++; + } + + if (object_string[i] == '.') + { + /* Move to the next character. */ + i++; + } + + /* The second identifier must be less that 128. */ + if (value >= 128) + { + + /* Invalid object ID. */ + return(0); + } + + /* Now determine how to set the first byte of the object ID. */ + if (object_string[0] == '1') + { + + /* Increment value by 40 per spec. */ + value = value + 40; + } + else if (object_string[0] == '2') + { + + /* Increment value by 40 per spec. */ + value = value + 80; + } + + /* Set the first byte, which is the combination of the first two bytes. */ + *buffer_ptr++ = (UCHAR) value; + + /* Set the length. */ + length = 1; + + /* Process all the characters in the ID. For now, the limit will be 128 characters in the + ID specification string. */ + while (object_string[i]) + { + + UCHAR *value_ptr; + UCHAR byte0; + ULONG mod_value; + + /* Initialize the encoding started flag. */ + encoding_started = NX_FALSE; + + /* Pickup the next value. */ + value = 0; + while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) + { + + /* Compute the value. */ + value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); + + /* Move to the next character. */ + i++; + } + + /* At this point we have a value to store in the ID string. */ + + /* Determine if it is simple encoding. */ + if (value < 128) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Place the value directly in the buffer. */ + *buffer_ptr++ = (UCHAR) value; + + /* Increment the length. */ + length++; + } + else + { + + /* Otherwise, we need to encode the numeric value such that it has + more bytes to represent it. */ + + if (value/268435456) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/268435456; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 268435456; + + /* Increment the length. */ + length++; + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value/2097152) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/2097152; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 2097152; + + /* Increment the length. */ + length++; + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value / 16384) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/16384; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 16384; + + /* Increment the length. */ + length++; + + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value /128) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/128; /* (0x100) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 128; + + /* Increment the length. */ + length++; + } + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Place the value directly in the buffer. */ + *buffer_ptr++ = (UCHAR) value; + + /* Increment the length. */ + length++; + } + + /* Determine if we are sitting on a dot. */ + if (object_string[i] == '.') + i++; + } + + /* Update the length. */ + length_ptr[0] = (UCHAR) (length & 0xFF); + + /* Return the length plus the header information. */ + return(length + 2); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_object_id_set_1byte PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the ASCII representation of the object into */ +/* ASN.1 format and then places it in the ASN.1 buffer. */ +/* */ +/* The difference with _nx_snmp_utility_object_id_set is that */ +/* this uses only a single byte length field e.g. 0x30 xx instead of */ +/* 0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* object_string Object string in ASCII */ +/* buffer_end End of ASN.1 buffer for error */ +/* checking */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_object_id_set_1byte(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end) +{ + +UINT length; +UINT i; +ULONG value; +UCHAR *length_ptr; +UCHAR encoding_started; + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the OBJECT byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_OBJECT_ID; + + /* Remember length pointer. */ + length_ptr = buffer_ptr; + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the length byte to zero for now. */ + *buffer_ptr++ = 0; + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Determine if the object string is legal. */ + if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) || + (object_string[1] != '.')) + { + + /* Invalid object ID. */ + return(0); + } + + /* Calculate the value of the second identifier. */ + i = 2; + value = 0; + + while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) + { + + /* Compute the value. */ + value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); + + /* Move to the next character. */ + i++; + } + + if (object_string[i] == '.') + { + /* Move to the next character. */ + i++; + } + + /* The second identifier must be less that 128. */ + if (value >= 128) + { + + /* Invalid object ID. */ + return(0); + } + + /* Now determine how to set the first byte of the object ID. */ + if (object_string[0] == '1') + { + + /* Increment value by 40 per spec. */ + value = value + 40; + } + else if (object_string[0] == '2') + { + + /* Increment value by 40 per spec. */ + value = value + 80; + } + + /* Set the first byte, which is the combination of the first two bytes. */ + *buffer_ptr++ = (UCHAR) value; + + /* Set the length. */ + length = 1; + + /* Process all the characters in the ID. For now, the limit will be 128 characters in the + ID specification string. */ + while (object_string[i]) + { + + UCHAR *value_ptr; + UCHAR byte0; + ULONG mod_value; + + /* Initialize the encoding started flag. */ + encoding_started = NX_FALSE; + + /* Pickup the next value. */ + value = 0; + while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) + { + + /* Compute the value. */ + value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); + + /* Move to the next character. */ + i++; + } + + /* At this point we have a value to store in the ID string. */ + + /* Determine if it is simple encoding. */ + if (value < 128) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Place the value directly in the buffer. */ + *buffer_ptr++ = (UCHAR) value; + + /* Increment the length. */ + length++; + } + else + { + + /* Otherwise, we need to encode the numeric value such that it has + more bytes to represent it. */ + + if (value/268435456) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/268435456; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + + /* Update the value. */ + value = value % 268435456; + + /* Increment the length. */ + length++; + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value/2097152) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/2097152; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 2097152; + + /* Increment the length. */ + length++; + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value / 16384) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/16384; /* (0x10000000) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 16384; + + /* Increment the length. */ + length++; + + + /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the + next 128 divisor. */ + encoding_started = NX_TRUE; + } + + if ((value /128) || (encoding_started == NX_TRUE)) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), + use an intermediate ULONG pointer. */ + + mod_value = value/128; /* (0x100) */ + + value_ptr = (UCHAR *)(&mod_value); + + /* A UCHAR will not hold more than one byte. */ + byte0 = *(value_ptr); + + *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; + + buffer_ptr++; + + /* Update the value. */ + value = value % 128; + + /* Increment the length. */ + length++; + } + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Place the value directly in the buffer. */ + *buffer_ptr++ = (UCHAR) value; + + /* Increment the length. */ + length++; + } + + /* Determine if we are sitting on a dot. */ + if (object_string[i] == '.') + i++; + } + + /* Update the length. */ + length_ptr[0] = (UCHAR) (length & 0xFF); + + /* Return the length plus the header information. */ + return(length + 2); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_object_data_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object data from the supplied ASN.1 */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* object_data Pointer to place object data */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_utility_object_id_get Get object ID */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_object_data_get(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, INT buffer_length) +{ + + +UINT i; +UINT length; +LONG data; +UINT total; +CHAR byte; +LONG temp = 0; +USHORT tlv_type, tlv_tag_class; +UCHAR *tlv_data; +UCHAR *work_ptr; +UINT status; + + + /* Check the buffer length. */ + if (buffer_length < 1) + { + return(0); + } + + work_ptr = buffer_ptr; + + /* First, pickup the request byte. */ + byte = (CHAR)(*buffer_ptr); + + /* Clear several value words. */ + object_data -> nx_snmp_object_data_msw = 0; + object_data -> nx_snmp_object_data_lsw = 0; + + /* Determine if a NULL is present. */ + if (byte == NX_SNMP_ANS1_NULL) + { + + /* Return NULL values in the input object, and set length to 2 (0x05 00). */ + object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NULL; + object_data -> nx_snmp_object_data_msw = 0; + return(2); + } + + /* Determine if the object is a standard type. */ + else if ((byte == NX_SNMP_ANS1_OCTET_STRING) || (byte == NX_SNMP_ANS1_INTEGER) || + (byte == NX_SNMP_ANS1_TIME_TICS) || (byte == NX_SNMP_ANS1_GAUGE) || + (byte == NX_SNMP_ANS1_COUNTER) || (byte == NX_SNMP_ANS1_COUNTER64) || + (byte == NX_SNMP_IP_ADDRESS) || (byte == NX_SNMP_ANS1_NSAP_ADDRESS)) + { + + /* Standard object type. */ + + /* Check the buffer length. */ + if (buffer_length < 3) + { + return(0); + } + + /* If this is an integer, determine if we have a negative number (msb is set). */ + if ((*buffer_ptr == NX_SNMP_ANS1_INTEGER) && (*(buffer_ptr + 2) & 0x80)) + { + + /* This only applies if short form (size of length =1), not long form (size of length field > 1 byte) */ + if (((*(buffer_ptr + 1) & 0x80)== 0)) + temp = -1; + + /* We can only check the sign for long form data after we compute the length of length field below */ + } + + /* Update the object with the data type. */ + object_data -> nx_snmp_object_data_type = (UINT)byte; + + /* Extract the length of the length field and tag class. This sill update the pointer past the type + * and length fields to the actual data. */ + status = _nx_snmp_utility_tlv_block_parse(work_ptr, buffer_length, &tlv_type, &tlv_tag_class, (ULONG *)(&total), &tlv_data, (ULONG *)(&length)); + + if (status) + { + return 0; + } + + work_ptr = tlv_data; + + /* Initialize working data. */ + data = temp; + object_data -> nx_snmp_object_octet_string_size = 0; + + i = 0; + + /* handle the special case of a leading zero e.g. 00 DD 2F C9 CE 69 52 74 8D where total is 9 */ + if ((total == 9) && (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING)) + { + /* Skip the first byte and decrement total */ + work_ptr++; + total = total - 1; + } + + + /* Loop through the remaining request length bytes. */ + while (i < total) + { + + /* Pickup next byte. */ + byte = (CHAR)(*work_ptr++); + + /* Determine the type of the data. */ + if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) + { + + /* Check for string size. */ + if ((i) >= NX_SNMP_MAX_OCTET_STRING) + { + return(0); + } + + /* Copy byte into the string. */ + object_data -> nx_snmp_object_octet_string[i] = (UCHAR)byte; + + /* Increment the length. */ + object_data -> nx_snmp_object_octet_string_size++; + } + else + { + + /* Compute the request id based on the next value. */ + data = (data << 8) | ((LONG) (0x000000FF & byte)); + } + + /* Increment the length. */ + length++; + + i++; + + /* If we are dealing with a 64 bit number, store the rest (least) significant bytes in lsw. */ + if ((i == 4) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) + { + object_data -> nx_snmp_object_data_msw = data; + + data = 0x0; + + /* Finish the rest of the data into lsw */ + while(i < total) + { + /* Pickup next byte. */ + byte = (CHAR)(*work_ptr++); + + /* Compute the request id based on the next value. */ + data = (data << 8) | ((LONG) (0x000000FF & byte)); + + i++; + } + + object_data -> nx_snmp_object_data_lsw = data; + } + } + + /* If dealing with a 32 bit data type or less, store the data to msw */ + if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) + { + object_data -> nx_snmp_object_data_msw = data; + } + else + { + /* Otherwise (e.g. this is a 64 bit data type) store the least significant bytes in the lsw */ + object_data -> nx_snmp_object_data_lsw = data; + } + /* Null terminate the data string. */ + if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) + { + + /* Null terminate string. */ + if ((i > 0) && (i < NX_SNMP_MAX_OCTET_STRING)) + { + object_data -> nx_snmp_object_octet_string[i] = NX_NULL; + } + } + + /* Return the length of the request id string. */ + return(length); + } + else if (byte == NX_SNMP_ANS1_OBJECT_ID) + { + + /* Setup the data type. */ + object_data -> nx_snmp_object_data_type = (UINT)byte; + + /* Convert the object ID to a string. */ + length = _nx_snmp_utility_object_id_get(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_length); + + /* Return length of the object id. */ + return(length); + } + + /* Error; return zero length. */ + return(0); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_object_data_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the object data and then places it in the */ +/* ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* object_data Object data structure */ +/* buffer_end End of ASN.1 buffer for error */ +/* checking */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* _nx_snmp_utility_object_id_set Set object ID */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send Send SNMP v1 Trap */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 Trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 Trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_object_data_set(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, UCHAR *buffer_end) +{ + +UINT i; +UINT length; +UINT data_msw; +UINT data_lsw; + + + /* Process relative to the type of request. */ + + /* See if the request is a NULL. */ + if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NULL) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_OBJECT) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_INSTANCE) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 2) >= buffer_end) + return(0); + + /* Set the NULL type byte. */ + *buffer_ptr++ = (UCHAR) object_data -> nx_snmp_object_data_type; + *buffer_ptr = 0; + + /* Set the length. */ + length = 2; + } + + /* See if the request is an INTEGER. */ + else if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_INTEGER) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_UINTEGER32) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_TIME_TICS) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_GAUGE) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS) || + (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NSAP_ADDRESS)) + { + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the type byte. */ + *buffer_ptr++ = (UCHAR)object_data -> nx_snmp_object_data_type; + + /* Pickup the data most significant word. */ + data_msw = (UINT)(object_data -> nx_snmp_object_data_msw); + + /* Pickup the data least significant word. */ + data_lsw = (UINT)(object_data -> nx_snmp_object_data_lsw); + + /* Determine the size of the encoding. */ + if (((data_msw & 0xFF000000) || (data_msw & 0x00800000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 9) >= buffer_end) + return(0); + + /* Four bytes are required. */ + *buffer_ptr++ = ((UCHAR) 8); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); + + /* Update the length. */ + length = 10; + return(length); + } + else if (((data_msw & 0x00FF0000) || (data_msw & 0x00008000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 8) >= buffer_end) + return(0); + + /* Three bytes are required. */ + *buffer_ptr++ = ((UCHAR) 7); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); + + /* Update the length. */ + length = 9; + return(length); + } + else if (((data_msw & 0x0000FF00) || (data_msw & 0x00000080)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 7) >= buffer_end) + return(0); + + /* Two bytes are required. */ + *buffer_ptr++ = ((UCHAR) 6); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); + + /* Update the length. */ + length = 8; + return(length); + } + else if (((data_msw & 0x000000FF) || (data_lsw & 0x80000000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 6) >= buffer_end) + return(0); + + /* One byte is required. */ + *buffer_ptr++ = ((UCHAR) 5); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); + + /* Update the length. */ + length = 7; + return(length); + } + else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64) + { + + /* Make the least significant word the most significant to use the normal integer processing below. */ + data_msw = data_lsw; + } + + /* Determine the size of the encoding. */ + if ((data_msw & 0xFF000000) || (data_msw & 0x00800000) || (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 5) >= buffer_end) + return(0); + + /* Four bytes are required. */ + *buffer_ptr++ = ((UCHAR) 4); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + + /* Update the length. */ + length = 6; + } + else if ((data_msw & 0x00FF0000) || (data_msw & 0x00008000)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 4) >= buffer_end) + return(0); + + /* Three bytes are required. */ + *buffer_ptr++ = ((UCHAR) 3); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + + /* Update the length. */ + length = 5; + } + else if ((data_msw & 0x0000FF00) || (data_msw & 0x00000080)) + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 3) >= buffer_end) + return(0); + + /* Two bytes are required. */ + *buffer_ptr++ = ((UCHAR) 2); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + + /* Update the length. */ + length = 4; + } + else + { + + /* Check for the end of the buffer. */ + if ((buffer_ptr + 2) >= buffer_end) + return(0); + + /* One byte is required. */ + *buffer_ptr++ = ((UCHAR) 1); + + /* Set the value in successive bytes. */ + *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); + + /* Update the length. */ + length = 3; + } + } + + /* See if the request is an octet string. Note that this includes the IPv6 address type. */ + else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the OCTET type byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Determine if a two byte length is required. */ + if (object_data -> nx_snmp_object_octet_string_size >= 128) + { + + /* A two byte length is required. */ + + /* Set the two byte length. */ + *buffer_ptr++ = 0x82; + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the first byte of the length. */ + *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size >> 8); + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the second byte of the length. */ + *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF); + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the length to represent the 4 byte header. */ + length = 4; + } + else + { + + /* Set the length byte. */ + *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF); + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Set the length to represent the 2 byte header. */ + length = 2; + } + + /* Loop to process the string. */ + i = 0; + while (i < object_data -> nx_snmp_object_octet_string_size) + { + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* Place octet string into buffer. */ + *buffer_ptr++ = object_data -> nx_snmp_object_octet_string[i++]; + } + + /* Account for the leading bytes in the length. */ + length = length + i; + } + + else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OBJECT_ID) + { + + /* Call the object set routine. */ + length = _nx_snmp_utility_object_id_set(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_end); + } + else + { + + /* Unhandled, return an error by setting length to 0. */ + length = 0; + } + + /* Return the length. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_octet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the octet string from the supplied ASN.1 */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* octet_string Pointer to destination for */ +/* the octet string */ +/* max_octet_length Size of octet string buffer */ +/* octet_length Pointer to length for octet */ +/* string */ +/* buffer_length Size of input buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_octet_get(UCHAR *buffer_ptr, UCHAR *octet_string, UINT max_octet_length, UINT *octet_length, INT buffer_length) +{ + +UINT i; +UINT length; +UINT total; + + + /* Buffer size must be at least 2 bytes. */ + if (buffer_length < 2) + { + return(0); + } + + /* Set the octet length to zero. */ + *octet_length = 0; + + /* First see if the ANS1 string type is present. */ + if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) + { + + /* Return a zero length. */ + return(0); + } + + /* Determine if a two byte length is present. */ + if (*(buffer_ptr + 1) & NX_SNMP_ANS1_MULTI_BYTES) + { + + UINT temp = *(buffer_ptr + 1) & 0x7F; + + if (temp == 2) + { + + /* A two byte length is present. */ + + /* Check the buffer length. */ + if (buffer_length < 4) + { + return(0); + } + + /* Pickup the length. */ + total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 4; + + /* Initialize the length. */ + length = 4; + } + else if (temp == 1) + { + + /* Check the buffer length. */ + if (buffer_length < 3) + { + return(0); + } + + /* Otherwise, pickup the total length of the octet string. */ + total = (UINT) buffer_ptr[2]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 3; + + /* Initialize the length. */ + length = 3; + } + else + { + + /* Invalid sequence. Too big or null size type. */ + return(0); + } + } + else + { + + /* Otherwise, assume 1 byte. Pickup the total length of the octet string. */ + total = (UINT) buffer_ptr[1]; + + /* Move the buffer pointer forward. */ + buffer_ptr = buffer_ptr + 2; + + /* Initialize the length. */ + length = 2; + } + + /* Check for invalid buffer size. */ + if ((INT)(length + total) > buffer_length) + { + /* Indicate an invalid request or packet is received. */ + return 0; + } + + /* Determine if the octet string is too large. */ + if (total > max_octet_length) + { + + /* Yes, the octet string is too large. Return an error. */ + return(0); + } + + /* Loop to pickup the remaining characters in the community string. */ + for (i = 0; i < total; i++) + { + + /* Move character from buffer into community string. */ + *octet_string++ = *buffer_ptr++; + + /* Adjust the length. */ + length++; + } + + /* return the length of the octet string. */ + *octet_length = total; + + /* Return the length of the ANS1 string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_octet_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the supplied octet string into the ASN.1 */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* octet_string Pointer to octet string */ +/* octet_length Length of the octet string */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_octet_set(UCHAR *buffer_ptr, UCHAR *octet_string, UINT octet_length, UCHAR *buffer_end) +{ + +UINT i; +UINT header_size; + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* First, set the OCTET byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; + + /* Check for a length greater than the maximum. */ + if (octet_length > NX_SNMP_MAX_OCTET_STRING) + { + + /* Error, octet string is too large. */ + return(0); + } + + /* Determine if a two byte length is required. */ + if (octet_length >= 128) + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < (3 + octet_length)) + return(0); + + /* Set the two byte length flag. */ + *buffer_ptr++ = (UCHAR) 0x82; + + /* Set the first length byte. */ + *buffer_ptr++ = (UCHAR) (octet_length >> 8); + + /* Set the second length byte. */ + *buffer_ptr++ = (UCHAR) (octet_length & 0xFF); + + /* Set the header size. */ + header_size = 4; + } + else + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < (1 + octet_length)) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) octet_length; + + /* Set the header size. */ + header_size = 2; + } + + /* Loop to store rest of the community string. */ + for (i = 0; i < octet_length; i++) + { + + /* Store the SNMP octet string. */ + *buffer_ptr++ = (UCHAR) octet_string[i]; + } + + /* Return the length of the community string. */ + return(octet_length+header_size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_sequence_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the ASN.1 sequence from the supplied ASN.1 */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* sequence_value Pointer to destination for */ +/* the sequence value */ +/* buffer_length Size of buffer data */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_thread_entry SNMP Agent's thread entry */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_sequence_get(UCHAR *buffer_ptr, UINT *sequence_value, INT buffer_length) +{ + +UINT i; +UINT length; +UINT value; +UINT total; +UCHAR byte; + + + /* Buffer size must be at least 2 bytes. */ + if (buffer_length < 2) + { + return(0); + } + + /* First, pickup the sequence byte. */ + byte = *buffer_ptr++; + + /* Determine if the byte is a sequence byte (0x30). */ + if (byte != NX_SNMP_ANS1_SEQUENCE) + { + + /* Error, not a sequence byte, return a NULL. */ + *sequence_value = 0; + return(0); + } + + /* Otherwise, we have a valid sequence byte. */ + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Initialize the length of the sequence field to 2. */ + length = 2; + + /* Determine if the next byte has the additional bytes + bit set (BIT 7). */ + if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) + { + + /* The specified sequence value is less than 128 and is actually in this byte! */ + *sequence_value = (UINT) byte; + + /* Return the actual length of the ANS1 sequence string. */ + return(length); + } + + /* Otherwise, we have a more complicated sequence length that we must loop through + to calculate the actual sequence length. */ + + /* Pickup the number of bytes required to represent the sequence length. */ + total = (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); + + /* Check for invalid buffer size. */ + if ((INT)(length + total) > buffer_length) + { + /* Indicate an invalid request or packet is received. */ + return 0; + } + + value = 0; + + /* Loop through the remaining sequence bytes. */ + for (i = 0; i < total; i++) + { + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Compute the sequence based on the next value. */ + value = (value << 8) | ((UINT) byte); + + /* Increment the length. */ + length++; + } + + /* Return the calculated sequence value. */ + *sequence_value = value; + + /* Return the length of the sequence string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_sequence_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the sequence number into the ASN.1 */ +/* buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* sequence_value Sequence value */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_sequence_set(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end) +{ + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 4) + return(0); + + /* First, set the sequence byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_SEQUENCE; + + /* Next set the continue bit to force two additional bytes for length. */ + *buffer_ptr++ = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; + + /* Store the MSB. */ + *buffer_ptr++ = (UCHAR) ((sequence_value >> 8) & 0xFF); + + /* Store the LSB. */ + *buffer_ptr = (UCHAR) (sequence_value & 0xFF); + + /* Return the length of the sequence string. */ + return(4); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_sequence_set_1byte PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the sequence number into the ASN.1 */ +/* buffer. The difference with _nx_snmp_utility_sequence_set is that */ +/* this uses only a single byte length field e.g. 0x30 xx instead of */ +/* 0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* sequence_value Sequence value */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_snmp_utility_sequence_set_1byte(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end) +{ + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 2) + return(0); + + /* First, set the sequence byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_SEQUENCE; + + /* Store the value. */ + *buffer_ptr = (UCHAR) (sequence_value & 0xFF); + + /* Return the length of the sequence string. */ + return(2); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_request_id_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the ASN.1 request ID from the supplied */ +/* ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* request_id Pointer to destination for */ +/* the request ID */ +/* buffer_length Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_request_id_get(UCHAR *buffer_ptr, ULONG *request_id, INT buffer_length) +{ + +UINT i; +UINT length; +ULONG value; +UINT total; +UCHAR byte; + + + /* Buffer size must be at least 2 bytes. */ + if (buffer_length < 2) + { + return(0); + } + + /* First, pickup the request byte. */ + byte = *buffer_ptr++; + + /* Determine if the byte is a valid SNMP request type. */ + if (byte != NX_SNMP_ANS1_INTEGER) + { + + /* Error, not request id, return a NULL. */ + *request_id = 0; + return(0); + } + + /* Otherwise, we have a valid request id. */ + + /* Pickup the ANS1 length byte. */ + total = (UINT) *buffer_ptr++; + + /* Initialize the length of the request field to 2. */ + length = 2; + + /* Check the length specified in the buffer against buffer size. */ + if ((INT)(length + total) > buffer_length) + { + *request_id = 0; + return(0); + } + + /* Initialize working request length. */ + value = 0; + + /* Loop through the remaining request length bytes. */ + for (i = 0; i < total; i++) + { + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Compute the request id based on the next value. */ + value = (value << 8) | ((ULONG) byte); + + /* Increment the length. */ + length++; + } + + /* Return the calculated request id. */ + *request_id = value; + + /* Return the length of the request id string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_request_id_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the request ID into the ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* request_id Request ID */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_request_id_set(UCHAR *buffer_ptr, ULONG request_id, UCHAR *buffer_end) +{ + +UINT length; + + + /* Check for the end of the buffer. */ + if (buffer_ptr >= buffer_end) + return(0); + + /* First, set the INTEGER byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; + + /* Determine how big the ID is. */ + if ((request_id & 0xFF000000UL) || (request_id & 0x00800000)) + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 5) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 4; + + /* Set the request ID in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((request_id >> 24) & 0xFF); + *buffer_ptr++ = (UCHAR) ((request_id >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (request_id & 0xFF); + + /* Update the length. */ + length = 6; + } + else if ((request_id & 0x00FF0000UL) || (request_id & 0x00008000)) + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 4) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 3; + + /* Set the request ID in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((request_id >> 16) & 0xFF); + *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (request_id & 0xFF); + + /* Update the length. */ + length = 5; + } + else if ((request_id & 0x0000FF00UL) || (request_id & 0x00000080)) + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 3) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 2; + + /* Set the request ID in successive bytes. */ + *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); + *buffer_ptr++ = (UCHAR) (request_id & 0xFF); + + /* Update the length. */ + length = 4; + } + else + { + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 2) + return(0); + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 1; + + /* Set the request ID in successive bytes. */ + *buffer_ptr++ = (UCHAR) (request_id & 0xFF); + + /* Update the length. */ + length = 3; + } + + /* Return the length of the request ID. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_request_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the ASN.1 request type from the supplied */ +/* ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* request_type Pointer to destination for */ +/* the request type */ +/* request_length Pointer to destination for */ +/* the request length */ +/* buffer_length Size of input buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_request_type_get(UCHAR *buffer_ptr, UINT *request_type, UINT *request_length, INT buffer_length) +{ + +UINT i; +UINT length; +UINT value; +UINT total; +UCHAR byte; + + + /* Buffer size must be at least 2 bytes. */ + if (buffer_length < 2) + { + return(0); + } + + /* First, pickup the request byte. */ + byte = *buffer_ptr++; + + /* Determine if the byte is a valid SNMP request type. */ + if ((byte < NX_SNMP_ANS1_SEQUENCE) || (byte > NX_SNMP_ANS1_TRAP2_REQUEST)) + { + + /* Error, not request, return a NULL. */ + *request_type = 0; + *request_length = 0; + return(0); + } + + /* Otherwise, we have a valid request. */ + + /* Store the request in the destination. */ + *request_type = (UINT) byte; + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Initialize the length of the request field to 2. */ + length = 2; + + /* Determine if the next byte has the additional bytes + bit set (BIT 7). */ + if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) + { + + /* The specified request length is less than 128 and is actually in this byte! */ + *request_length = (UINT) byte; + + /* Return the actual length of the ANS1 request string. */ + return(length); + } + + /* Otherwise, we have a more complicated request length that we must loop through + to calculate the actual length. */ + + /* Pickup the number of bytes required to represent the request length. */ + total = (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); + + if ((INT)(length + total) > buffer_length) + { + /* Error, invalid request, return a NULL. */ + *request_type = 0; + *request_length = 0; + return(0); + } + + /* Initialize working request length. */ + value = 0; + + /* Loop through the remaining request length bytes. */ + for (i = 0; i < total; i++) + { + + /* Pickup next byte. */ + byte = *buffer_ptr++; + + /* Compute the request length based on the next value. */ + value = (value << 8) | ((UINT) byte); + + /* Increment the length. */ + length++; + } + + /* Return the calculated request length. */ + *request_length = value; + + /* Return the length of the request string. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_request_type_set_1byte PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the request type into the ASN.1 buffer. It is */ +/* intended for small requests whose size value can fit into one byte. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* request_type Request type */ +/* request_length Request length */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_request_type_set_1byte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end) +{ + + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 2) + return(0); + + /* First, set the request type byte. */ + *buffer_ptr++ = (UCHAR) request_type; + + /* Store the request_length. */ + *buffer_ptr = (UCHAR) (request_length & 0xFF); + + return 2; + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_request_type_set_multibyte PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the request type into the ASN.1 buffer. It is */ +/* intended for large requests whose size value requires more than one */ +/* byte, e.g. A2 82 xx yy. For get, getnext requests, and report and */ +/* trap responses, use _nx_snmp_utility_request_type_set_1byte. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* request_type Request type */ +/* request_length Request length */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_request_type_set_multibyte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end) +{ + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 4) + return(0); + + /* First, set the request type byte. */ + *buffer_ptr++ = (UCHAR) request_type; + + /* Set the continue bit to force two additional bytes for length. */ + *buffer_ptr++ = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; + + /* Store the MSB. */ + *buffer_ptr++ = (UCHAR) ((request_length >> 8) & 0xFF); + + /* Store the LSB. */ + *buffer_ptr = (UCHAR) (request_length & 0xFF); + + return 4; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_version_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the SNMP version from the supplied */ +/* ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* snmp_version Pointer to destination for */ +/* the snmp_version */ +/* buffer_length Size of buffer data */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_thread_entry SNMP Agent's thread entry */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_version_get(UCHAR *buffer_ptr, UINT *snmp_version, INT buffer_length) +{ + + if (buffer_length < 3) + { + + /* Clear the version. */ + *snmp_version = 0; + + /* Return a zero length. */ + return(0); + } + + /* Determine if the version string is correct. */ + if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) && + (buffer_ptr[1] == 1) && + ((buffer_ptr[2] == NX_SNMP_VERSION_1) || (buffer_ptr[2] == NX_SNMP_VERSION_2) || + (buffer_ptr[2] == NX_SNMP_VERSION_2C) || (buffer_ptr[2] == NX_SNMP_VERSION_3))) + { + + /* Yes, the SNMP version string is correct. */ + + /* Return the version. */ + *snmp_version = (UINT) buffer_ptr[2]; + + /* Return the length of the version string. */ + return(3); + } + else + { + + /* No, the SNMP version string is invalid. */ + + /* Clear the version. */ + *snmp_version = 0; + + /* Return a zero length. */ + return(0); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_utility_version_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the SNMP version into the ASN.1 buffer. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to ASN.1 buffer */ +/* snmp_version SNMP version number */ +/* buffer_end End of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* ASN.1 length Length of ASN.1 sequence, a */ +/* value of zero implies error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ +/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ +/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ +/* _nx_snmp_version_1_process Process SNMP v1 request */ +/* _nx_snmp_version_2_process Process SNMP v2 request */ +/* _nx_snmp_version_3_report_send Send SNMP v3 report */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_version_set(UCHAR *buffer_ptr, UINT snmp_version, UCHAR *buffer_end) +{ + + /* Check for the end of the buffer. */ + if ((UINT)(buffer_end - buffer_ptr) < 3) + return(0); + + /* First, set the INTEGER byte. */ + *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; + + /* Next set the length byte. */ + *buffer_ptr++ = (UCHAR) 1; + + /* Store the SNMP version. */ + *buffer_ptr = (UCHAR) (snmp_version & 0xFF); + + /* Return the length of the sequence string. */ + return(3); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_version_error_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the error information into the SNMP Manager's */ +/* request packet and returns it to the manager. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* packet_ptr Pointer to packet containing */ +/* the original SNMP request */ +/* request_type_ptr Pointer to place in ASN.1 */ +/* buffer for the request type */ +/* error_string_ptr Pointer to place in ASN.1 */ +/* buffer to place error info */ +/* error_code Error code */ +/* error_index Error index */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release the packet */ +/* nx_udp_socket_send Send the UDP packet */ +/* _nx_snmp_utility_error_info_set Set the error information */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_1_process SNMP v1 message processing */ +/* _nx_snmp_version_2_process SNMP v2 message processing */ +/* _nx_snmp_version_3_process SNMP v3 message processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, + UCHAR *error_string_ptr, UINT error_code, UINT error_index) +{ + +UINT status; +#ifndef NX_SNMP_DISABLE_V3 +ULONG temp; +#endif + + /* Increment the error counter. */ + agent_ptr -> nx_snmp_agent_request_errors++; + + /* Determine which specific error counter to increment. */ + switch(error_code) + { + case NX_SNMP_ERROR_TOOBIG: + agent_ptr -> nx_snmp_agent_too_big_errors++; + break; + case NX_SNMP_ERROR_BADVALUE: + case NX_SNMP_ERROR_WRONGVALUE: + case NX_SNMP_ERROR_WRONGENCODING: + case NX_SNMP_ERROR_WRONGTYPE: + case NX_SNMP_ERROR_WRONGLENGTH: + case NX_SNMP_ERROR_INCONSISTENTVALUE: + agent_ptr -> nx_snmp_agent_bad_value_errors++; + break; + case NX_SNMP_ERROR_NOSUCHNAME: + case NX_SNMP_ERROR_NOACCESS: + case NX_SNMP_ERROR_NOTWRITABLE: + case NX_SNMP_ERROR_NOCREATION: + case NX_SNMP_ERROR_INCONSISTENTNAME: + case NX_SNMP_ERROR_AUTHORIZATION: + agent_ptr -> nx_snmp_agent_no_such_name_errors++; + break; + case NX_SNMP_ERROR_GENERAL: + case NX_SNMP_ERROR_RESOURCEUNAVAILABLE: + case NX_SNMP_ERROR_COMMITFAILED: + case NX_SNMP_ERROR_UNDOFAILED: + agent_ptr -> nx_snmp_agent_general_errors++; + break; + } + + /* Set the request type to get/response. */ + *request_type_ptr = (UCHAR) NX_SNMP_ANS1_GET_RESPONSE; + + /* Update the error string with the error code and the object index. */ + _nx_snmp_utility_error_info_set(error_string_ptr, error_code, error_index, packet_ptr -> nx_packet_data_end); + +#ifndef NX_SNMP_DISABLE_V3 + /* Is the security set to encryption? */ + temp = (ULONG)agent_ptr -> nx_snmp_agent_v3_message_security_options; + if (temp & NX_SNMP_SECURITY_PRIVACY) + { + + /* Encrypt the PDU and setup the response to have an encryption header. This + will also compute our privacy parameter. */ + _nx_snmp_agent_encrypt_pdu(agent_ptr, NX_NULL, NX_NULL, + NX_NULL, NX_NULL, + NX_NULL, NX_NULL, pdu_privacy_ptr); + } + + /* Is the security set to authentication? */ + if (temp & NX_SNMP_SECURITY_AUTHORIZE) + { + + /* Compute our authentication parameter. */ + status = _nx_snmp_agent_add_auth_parameter(agent_ptr, packet_ptr, pdu_auth_parm_ptr); + } +#endif + + /* Increment the sent packet counter. */ + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Increment the get responses sent counter. */ + agent_ptr -> nx_snmp_agent_getresponse_sent++; + + /* Send the response packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), packet_ptr, + &(agent_ptr -> nx_snmp_agent_current_manager_ip), + agent_ptr -> nx_snmp_agent_current_manager_port); + + /* Check for successful call. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Return to caller. */ + return; +} + +#ifndef NX_SNMP_DISABLE_V1 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_version_1_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the SNMP v1 request from the manager. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* packet_ptr Pointer to packet containing */ +/* the SNMP request */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate response packet */ +/* nx_packet_release Release the packet */ +/* nx_udp_socket_send Send the UDP packet */ +/* _nx_snmp_utility_community_get Get the community name */ +/* _nx_snmp_utility_community_set Set the community name */ +/* _nx_snmp_utility_error_info_get Get the error information */ +/* _nx_snmp_utility_error_info_set Set the error information */ +/* _nx_snmp_utility_object_data_get Get the object data */ +/* _nx_snmp_utility_object_data_set Set the object data */ +/* _nx_snmp_utility_object_id_get Get the object ID */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_request_id_get Get the request ID */ +/* _nx_snmp_utility_request_id_set Set the request ID */ +/* _nx_snmp_utility_request_type_get Get the request type */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ +/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ +/* _nx_snmp_utility_version_get Get the SNMP version */ +/* _nx_snmp_utility_version_set Set the SNMP version */ +/* _nx_snmp_version_error_response Send SNMP Manager error */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_thread_entry SNMP Agent thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) +{ + +UINT sequence_length, version, request_type, request_length; +UINT error_code, error_index; +UINT variable_list_length, variable_length; +ULONG request_id; +UINT status, length, objects; +UCHAR *buffer_ptr; +UCHAR *variable_start_ptr = NX_NULL; +UCHAR *error_ptr, *request_type_ptr; +UINT response_length; +UINT total_variable_length = 0; +NX_PACKET *response_packet_ptr; +UCHAR *response_buffer_ptr; +UINT response_sequence_length, response_type_length; +UINT response_variable_list_length, response_variable_length; +UCHAR *response_sequence_ptr, *response_type_ptr; +UCHAR *response_variable_list_ptr, *response_variable_ptr; +UINT packet_type; +INT buffer_length; + + + buffer_length = (INT)(packet_ptr -> nx_packet_length); + + /* Setup a pointer to the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the SEQUENCE field. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP VERSION field. */ + length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP Community String field. */ + length = _nx_snmp_utility_community_get(buffer_ptr, + agent_ptr -> nx_snmp_agent_current_community_string, + buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Save the request type pointer. */ + request_type_ptr = buffer_ptr; + + /* Pickup the SNMP Request type. */ + length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; + if ((request_type == NX_SNMP_GET_REQUEST) || + (request_type == NX_SNMP_GET_NEXT_REQUEST) || + (request_type == NX_SNMP_GET_BULK_REQUEST)) + { + agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; + } + + /* Pickup the SNMP Request ID. */ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Save a pointer to the error string. */ + error_ptr = buffer_ptr; + + + /* Pickup the SNMP Error information. */ + length = _nx_snmp_utility_error_info_get(buffer_ptr, &error_code, &error_index, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Determine if the received packet size is too big. */ + if (packet_ptr -> nx_packet_next) + { + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); + + /* Done, return to caller. */ + return; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + if (agent_ptr -> nx_snmp_agent_username_process) + { + + status = agent_ptr -> nx_snmp_agent_username_process(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string); + + /* Determine if the callback routine generated an error. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of community/username errors. */ + agent_ptr -> nx_snmp_agent_username_errors++; + +#ifdef NX_SNMP_V1_AUTHORIZATION_ERROR_RESPONSE + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, 0); +#else + /* Authorization error response is not supported by version 1. */ + /* Release the packet. */ + nx_packet_release(packet_ptr); +#endif + + /* Done, return to caller. */ + return; + } + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP Variable list length. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* At this point we have parsed the incoming SNMP request up to the first + variable. */ + + /* Now prepare response message so we can process the variables one by one. */ + + /* Determine which packet type we allocate based on the destination address type. */ + if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif /* FEATURE_NX_IPV6 */ + } + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Allocate the packet for the SNMP response. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a response packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the response packet. */ + response_sequence_length = 0; + response_type_length = 0; + response_variable_list_length = 0; + + /* Setup a pointer to the response packet's buffer area. */ + response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the response sequence pointer. Remember it since we are going to have to + update it later with the actual length of the response. */ + response_sequence_ptr = response_buffer_ptr; + + /* First, write the sequence in the response packet. A zero is written for now. This will be + updated later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Now set the SNMP version in the response. */ + response_length = _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_1, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Set the SNMP community in the response message. */ + response_length = _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Remember the request type pointer, since it will need to be updated later. */ + response_type_ptr = response_buffer_ptr; + + /* Now set the request type in the response message. */ + response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Now set the request ID in the response message. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Set the response error information. Assume everything is okay at this point. */ + response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Remember the start of the response's variable list field. */ + response_variable_list_ptr = response_buffer_ptr; + + /* Setup the variable list response. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* At this point the response buffer is setup to exactly the same position the + SNMP Manager's input buffer is - right before the first variable. We can + now walk through the variable list to process each request and place the + result in the response buffer. */ + objects = 0; + do + { + + /* Remember the start of the variable. */ + variable_start_ptr = buffer_ptr; + + /* Pickup the first SNMP Variable length. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); + + /* Calculate the total variable size. */ + total_variable_length = variable_length + length; + + /* Determine if this variable will fit in the remaining length of the + variable list. */ + if ((length == 0) || (total_variable_length > variable_list_length)) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Send an SNMP version error response. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* Update the size of the remaining buffer. */ + buffer_length -= (INT)length; + + /* Now pickup the object ID. */ + length = _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length); + + /* Determine if the object retrieval was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* Update the size of the remaining buffer. */ + buffer_length -= (INT)length; + + /* Default the value to NULL. */ + agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; + + /* Determine if a value is present. */ + if (length != variable_length) + { + + /* Pickup the value associated with this variable. */ + length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); + + /* Determine if the object value was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Send an SNMP version error response. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + } + + /* At this point, we are ready to call the appropriate application request handling routine. + It is responsible for extracting or placing information in the object data structure. */ + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GET routine. */ + status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GETNEXT routine. */ + status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + { + + /* Increment the total number of set variables. */ + agent_ptr -> nx_snmp_agent_total_set_variables++; + + /* Call the application's SET routine. */ + status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Check for an error status from the agent's request processing callback routine. */ + if (status) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Per RFC2576 4.3 */ + switch(status) + { + case NX_SNMP_SUCCESS: + case NX_SNMP_ERROR_TOOBIG: + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects+1); + break; + case NX_SNMP_ERROR_BADVALUE: + case NX_SNMP_ERROR_WRONGVALUE: + case NX_SNMP_ERROR_WRONGENCODING: + case NX_SNMP_ERROR_WRONGTYPE: + case NX_SNMP_ERROR_WRONGLENGTH: + case NX_SNMP_ERROR_INCONSISTENTVALUE: + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); + break; + case NX_SNMP_ERROR_NOSUCHNAME: + case NX_SNMP_ERROR_NOACCESS: + case NX_SNMP_ERROR_NOTWRITABLE: + case NX_SNMP_ERROR_NOCREATION: + case NX_SNMP_ERROR_INCONSISTENTNAME: + case NX_SNMP_ERROR_AUTHORIZATION: + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects+1); + break; + case NX_SNMP_ERROR_GENERAL: + case NX_SNMP_ERROR_RESOURCEUNAVAILABLE: + case NX_SNMP_ERROR_COMMITFAILED: + case NX_SNMP_ERROR_UNDOFAILED: + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_GENERAL, objects+1); + break; + default: + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Done, return to caller. */ + return; + } + + /* Determine if the returning object is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Now ensure the returning object type is supported in V1. */ + if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && +#ifdef FEATURE_NX_IPV6 + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && +#endif + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID)) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Everything is okay, place the object and object data into the response buffer. */ + + /* Remember the start of the variable response sequence. */ + response_variable_ptr = response_buffer_ptr; + + /* Clear the response variable size. */ + response_variable_length = 0; + + /* Determine if there is enough room in the destination for the variable sequence. */ + if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); + + /* Done, return to caller. */ + return; + } + + /* Setup the variable response sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Place the object into the response buffer. */ + response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Insert the object's data into the response buffer. */ + response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Now update the response variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); + + /* Adjust the pointer to the next variable. */ + buffer_ptr = variable_start_ptr + total_variable_length; + + /* Decrement the size of the variable list. */ + variable_list_length = variable_list_length - total_variable_length; + + /* Increment the object counter. */ + objects++; + + } while (variable_list_length); + + /* At this point, several response fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); + + /* Now the response packet's pointers must be setup so it can be sent. */ + response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); + response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; + + /* Release the original request packet. */ + nx_packet_release(packet_ptr); + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; + agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + agent_ptr -> nx_snmp_agent_get_requests++; + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + agent_ptr -> nx_snmp_agent_getnext_requests++; + else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) + agent_ptr -> nx_snmp_agent_getbulk_requests++; + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + agent_ptr -> nx_snmp_agent_set_requests++; + + /* Increment the sent packet counter. */ + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Increment the get responses sent counter. */ + agent_ptr -> nx_snmp_agent_getresponse_sent++; + + /* Send the response packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, + &(agent_ptr -> nx_snmp_agent_current_manager_ip), + agent_ptr -> nx_snmp_agent_current_manager_port); + + /* Check for successful call. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + } +} +#endif /* NX_SNMP_DISABLE_V1 */ + + +#ifndef NX_SNMP_DISABLE_V2 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_version_2_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the SNMP v2 request from the manager. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* packet_ptr Pointer to packet containing */ +/* the SNMP request */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate response packet */ +/* nx_packet_release Release the packet */ +/* nx_udp_socket_send Send the UDP packet */ +/* _nx_snmp_utility_community_get Get the community name */ +/* _nx_snmp_utility_community_set Set the community name */ +/* _nx_snmp_utility_error_info_get Get the error information */ +/* _nx_snmp_utility_error_info_set Set the error information */ +/* _nx_snmp_utility_object_data_get Get the object data */ +/* _nx_snmp_utility_object_data_set Set the object data */ +/* _nx_snmp_utility_object_id_get Get the object ID */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_request_id_get Get the request ID */ +/* _nx_snmp_utility_request_id_set Set the request ID */ +/* _nx_snmp_utility_request_type_get Get the request type */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ +/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ +/* _nx_snmp_utility_version_get Get the SNMP version */ +/* _nx_snmp_utility_version_set Set the SNMP version */ +/* _nx_snmp_version_error_response Send SNMP Manager error */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_thread_entry SNMP Agent thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_version_2_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) +{ + +UINT sequence_length, version, request_type, request_length; +UINT non_repeaters, max_repetitions, current_repetitions, next_object; +UINT variable_list_length, variable_length; +ULONG request_id; +UINT status, length, objects; +UCHAR *buffer_ptr; +UCHAR *variable_start_ptr = NX_NULL; +UCHAR *error_ptr, *request_type_ptr; +UINT response_length; +UINT total_variable_length = 0; +NX_PACKET *response_packet_ptr; +UCHAR *response_buffer_ptr; +UINT response_sequence_length, response_type_length; +UINT response_variable_list_length, response_variable_length; +UCHAR *response_sequence_ptr, *response_type_ptr; +UCHAR *response_variable_list_ptr, *response_variable_ptr; +UINT packet_type; +INT buffer_length; + + buffer_length = (INT)(packet_ptr -> nx_packet_length); + + /* Setup a pointer to the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the SEQUENCE field. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP VERSION field. */ + length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP Community String field. */ + length = _nx_snmp_utility_community_get(buffer_ptr, + agent_ptr -> nx_snmp_agent_current_community_string, + buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Save the request type pointer. */ + request_type_ptr = buffer_ptr; + + /* Pick up the SNMP Request type. */ + length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; + if ((request_type == NX_SNMP_GET_REQUEST) || + (request_type == NX_SNMP_GET_NEXT_REQUEST) || + (request_type == NX_SNMP_GET_BULK_REQUEST)) + { + agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; + } + + /* Pickup the SNMP Request ID. */ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Save a pointer to the error string. */ + error_ptr = buffer_ptr; + + /* Pickup the SNMP Error information. This is actually used to derive the GETBULK + information in SNMP V2 and above. */ + length = _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Determine if the received packet size is too big. */ + if (packet_ptr -> nx_packet_next) + { + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); + + /* Done, return to caller. */ + return; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + + + /* Check to see if there is a username processing routine. */ + if (agent_ptr -> nx_snmp_agent_username_process) + { + + /* Yes, there is a callback routine to process the community/username. */ + status = (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string); + + /* Determine if the callback routine generated an error. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of community/username errors. */ + agent_ptr -> nx_snmp_agent_username_errors++; + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_AUTHORIZATION, 0); + + /* Done, return to caller. */ + return; + } + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP Variable list length. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* At this point we have parsed the incoming SNMP request up to the first + variable. */ + + /* Now prepare response message so we can process the variables one by one. */ + + /* Determine which packet type we allocate based on the destination address type. */ + if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif /* FEATURE_NX_IPV6 */ + + } + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Allocate the packet for the SNMP response. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a response packet was allocated. */ + if (status) + { + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the response packet. */ + response_sequence_length = 0; + response_type_length = 0; + response_variable_list_length = 0; + + /* Setup a pointer to the response packet's buffer area. */ + response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the response sequence pointer. Remember it since we are going to have to + update it later with the actual length of the response. */ + response_sequence_ptr = response_buffer_ptr; + + /* First, write the sequence in the response packet. A zero is written for now. This will be + updated later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Now set the SNMP version in the response. */ + response_length = _nx_snmp_utility_version_set(response_buffer_ptr, version, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Set the SNMP community in the response message. */ + response_length = _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Remember the request type pointer, since it will need to be updated later. */ + response_type_ptr = response_buffer_ptr; + + /* Now set the request type in the response message. */ + response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Now set the request ID in the response message. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Set the response error information. Assume everything is okay at this point. */ + response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Remember the start of the response's variable list field. */ + response_variable_list_ptr = response_buffer_ptr; + + /* Setup the variable list response. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* At this point the response buffer is setup to exactly the same position the + SNMP Manager's input buffer is - right before the first variable. We can + now walk through the variable list to process each request and place the + result in the response buffer. */ + objects = 0; + next_object = NX_TRUE; + current_repetitions = max_repetitions; + do + { + + /* Determine if the next object should be retrieved. */ + if (next_object) + { + + /* Remember the start of the variable. */ + variable_start_ptr = buffer_ptr; + + /* Pickup the first SNMP Variable length. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); + + /* Calculate the total variable size. */ + total_variable_length = variable_length + length; + + /* Determine if this variable will fit in the remaining length of the + variable list. */ + if ((length == 0) || (total_variable_length > variable_list_length)) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Now pickup the object ID. */ + length = _nx_snmp_utility_object_id_get(buffer_ptr, + agent_ptr -> nx_snmp_agent_current_octet_string, + buffer_length); + + /* Determine if the object retrieval was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Default the value to NULL. */ + agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; + + /* Determine if a value is present. */ + if (length != variable_length) + { + + /* Pickup the value associated with this variable. */ + length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); + + /* Determine if the object value was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Send an SNMP version error response. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + } + } + + /* At this point, we are ready to call the appropriate application request handling routine. + It is responsible for extracting or placing information in the object data structure. */ + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GET routine. */ + status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GETNEXT routine. */ + status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Clear the next object flag. */ + next_object = NX_FALSE; + + /* Call the application's GETNEXT routine. */ + status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); + + /* Decrement the number of non-repeaters. */ + if (non_repeaters) + { + + /* Decrement the number of non-repeaters. */ + non_repeaters--; + + /* Set the next object flag to move to the next entry of the request. */ + next_object = NX_TRUE; + } + else + { + + /* Decrement the repetitions. */ + if (current_repetitions) + current_repetitions--; + + /* Determine if there are more repetitions or if the end of MIB was detected. */ + if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + + /* Reset the current repetition. */ + current_repetitions = max_repetitions; + + /* Set the next object flag to true. */ + next_object = NX_TRUE; + } + } + } + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + { + + /* Increment the total number of set variables. */ + agent_ptr -> nx_snmp_agent_total_set_variables++; + + /* Call the application's SET routine. */ + status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Check for an error status from the agent's request processing callback routine. */ + if (status) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects); + + /* Done, return to caller. */ + return; + } + + /* Determine if the returning object is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Now ensure the returning object type is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && +#ifdef FEATURE_NX_IPV6 + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && +#endif + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Everything is okay, place the object and object data into the response buffer. */ + + /* Remember the start of the variable response sequence. */ + response_variable_ptr = response_buffer_ptr; + + /* Clear the response variable size. */ + response_variable_length = 0; + + /* Determine if there is enough room in the destination for the variable sequence. */ + if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Setup the variable response sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Place the object into the response buffer. */ + response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Insert the object's data into the response buffer. */ + response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Now update the response variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); + + /* Only update the source object information if the next object flag is set. */ + if (next_object) + { + + /* Adjust the pointer to the next variable. */ + buffer_ptr = variable_start_ptr + total_variable_length; + + /* Decrement the size of the variable list. */ + variable_list_length = variable_list_length - total_variable_length; + + /* Increment the object counter. */ + objects++; + } + + } while ((variable_list_length) || (next_object == NX_FALSE)); + + /* At this point, several response fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); + + /* Now the response packet's pointers must be setup so it can be sent. */ + response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); + response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; + + /* Release the original request packet. */ + nx_packet_release(packet_ptr); + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; + agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + agent_ptr -> nx_snmp_agent_get_requests++; + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + agent_ptr -> nx_snmp_agent_getnext_requests++; + else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) + agent_ptr -> nx_snmp_agent_getbulk_requests++; + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + agent_ptr -> nx_snmp_agent_set_requests++; + + /* Increment the sent packet counter. */ + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Increment the get responses sent counter. */ + agent_ptr -> nx_snmp_agent_getresponse_sent++; + + /* Send the response packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, + &(agent_ptr -> nx_snmp_agent_current_manager_ip), + agent_ptr -> nx_snmp_agent_current_manager_port); + + /* Check for successful call. */ + if (status) + { + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + } +} +#endif + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_version_3_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the SNMP v3 request from the manager. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* packet_ptr Pointer to packet containing */ +/* the SNMP request */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_des_encrypt Encrypt bytes */ +/* _nx_des_decrypt Decrypt bytes */ +/* _nx_des_key_set Set the DES key */ +/* _nx_md5_digest_calculate Finalize MD5 calculation */ +/* _nx_md5_initialize Initialize MD5 calculation */ +/* _nx_md5_update Update MD5 calculation */ +/* nx_packet_allocate Allocate response packet */ +/* nx_packet_release Release the packet */ +/* nx_udp_socket_send Send the UDP packet */ +/* _nx_snmp_utility_error_info_get Get the error information */ +/* _nx_snmp_utility_error_info_set Set the error information */ +/* _nx_snmp_utility_object_data_get Get the object data */ +/* _nx_snmp_utility_object_data_set Set the object data */ +/* _nx_snmp_utility_object_id_get Get the object ID */ +/* _nx_snmp_utility_object_id_set Set the object ID */ +/* _nx_snmp_utility_octet_get Get octet string */ +/* _nx_snmp_utility_octet_set Set octet string */ +/* _nx_snmp_utility_request_id_get Get the request ID */ +/* _nx_snmp_utility_request_id_set Set the request ID */ +/* _nx_snmp_utility_request_type_get Get the request type */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ +/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ +/* _nx_snmp_utility_version_get Get the SNMP version */ +/* _nx_snmp_utility_version_set Set the SNMP version */ +/* _nx_snmp_version_error_response Send SNMP Manager error */ +/* _nx_snmp_version_3_discovery_respond Send discovery response */ +/* _nx_sha1_digest_calculate Finalize SHA calculation */ +/* _nx_sha1_initialize Initialize SHA calculation */ +/* _nx_sha1_update Update SHA calculation */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_agent_thread_entry SNMP Agent thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_version_3_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) +{ + +UINT i, sequence_length, version, request_type, request_length; +UINT header_sequence_length, security_sequence_length, pdu_sequence_length; +UINT non_repeaters, max_repetitions, current_repetitions, next_object; +UINT variable_list_length, variable_length; +ULONG request_id; +UINT status, length, objects; +UCHAR *buffer_ptr; +UCHAR *variable_start_ptr = NX_NULL; +UCHAR *error_ptr, *request_type_ptr, *temp_ptr; +UINT response_length; +UINT total_variable_length = 0; +NX_PACKET *response_packet_ptr; +UINT context_engine_size, context_name_size; +UCHAR *response_buffer_ptr; +UINT response_sequence_length, response_header_length, response_security_length, response_pdu_length, response_type_length; +UINT response_variable_list_length, response_variable_length; +UCHAR *response_sequence_ptr, *response_header_ptr, *response_security_ptr, *response_pdu_ptr, *response_type_ptr; +UCHAR *response_variable_list_ptr, *response_variable_ptr; +UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; +UINT packet_type; +UCHAR *response_encryption_size_ptr = NX_NULL; +UCHAR *response_authentication_ptr = NX_NULL, *response_privacy_ptr = NX_NULL; +UCHAR *request_authentication_ptr = NX_NULL; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; +UINT authenticate_message = NX_FALSE; +UINT encrypt_message = NX_FALSE; +UCHAR message_sec_level; +UINT mask; +INT buffer_length; + + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("\nReceived a SNMPv3 request\n\r"); +#endif + + buffer_length = (INT)(packet_ptr -> nx_packet_length); + + /* Setup a pointer to the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the SEQUENCE field. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Pickup the SNMP VERSION field. */ + length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /***** Now we are positioned in front of the global header. *****/ + + /* Pickup the sequence for the header data, which includes the message ID, maximum reply size, + flags, and the security model. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &header_sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the message ID */ + /********************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_id), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the message size */ + /********************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_size), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the security options */ + /********************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_options), + sizeof(agent_ptr -> nx_snmp_agent_v3_message_security_options), &status, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Extracted security options: 0x%x\n\r", agent_ptr -> nx_snmp_agent_v3_message_security_options); +#endif + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + mask = NX_SNMP_SECURITY_AUTHORIZE | NX_SNMP_SECURITY_PRIVACY ; + + /* We want to mask out the reportable bit. */ + agent_ptr -> nx_snmp_agent_v3_message_security_options = (UCHAR)(agent_ptr -> nx_snmp_agent_v3_message_security_options & mask); + + /********************************************************/ + /* Get the security type */ + /********************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_type), buffer_length); + + /* Check for a valid packet. */ + if ((length == 0) || (agent_ptr -> nx_snmp_agent_v3_message_security_type != NX_SNMP_USM_SECURITY_MODEL)) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /**** Now we are positioned in front of the security parameters field. ****/ + + /* Determine if there are security parameters. */ + if ((buffer_ptr[0] == NX_SNMP_ANS1_OCTET_STRING) && (buffer_ptr[1])) + { + + /* Position the buffer pointer past the octet string. */ + buffer_ptr = buffer_ptr + 2; + + /* Pickup the sequence for the security data. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &security_sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the authoritative engine ID */ + /********************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_context_engine, + sizeof(agent_ptr -> nx_snmp_agent_v3_security_context_engine), + &(agent_ptr -> nx_snmp_agent_v3_security_context_engine_size), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the number of engine reboots */ + /********************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boots), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the engine boot time */ + /********************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the security username */ + /********************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, + sizeof(agent_ptr -> nx_snmp_agent_v3_security_user_name), &(agent_ptr -> nx_snmp_agent_v3_security_user_name_size), buffer_length); + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Security name parsed: %s Size: %d\n\r", &agent_ptr -> nx_snmp_agent_v3_security_user_name[0], agent_ptr -> nx_snmp_agent_v3_security_user_name_size); + +#endif + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Null terminate the User Name. */ + agent_ptr -> nx_snmp_agent_v3_security_user_name[agent_ptr -> nx_snmp_agent_v3_security_user_name_size] = 0; + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /********************************************************/ + /* Get the security authentication parameter */ + /********************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_authentication, + sizeof(agent_ptr -> nx_snmp_agent_v3_security_authentication), &(agent_ptr -> nx_snmp_agent_v3_security_authentication_size), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } +#ifndef NX_SNMP_NO_SECURITY + /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter. */ + + request_authentication_ptr = buffer_ptr + 2; +#endif + + /* Position to the next field. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + pdu_privacy_ptr = buffer_ptr + 2; + + /********************************************************/ + /* Get the security privacy parameter */ + /********************************************************/ + + /* This is effectively the salt which will be used to unencrypt the PDU. */ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_privacy, + sizeof(agent_ptr -> nx_snmp_agent_v3_security_privacy), &(agent_ptr -> nx_snmp_agent_v3_security_privacy_size), buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + } + else + { + + /* Position past the empty security parameter field. */ + length = 2; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Save the location where the request type is located (after context engine ID and name). */ + temp_ptr = buffer_ptr; + + /********************************************************/ + /* Determine if we send a report vs response */ + /********************************************************/ + + /* Check if Engine ID is missing AND the security user name is blank. */ + if ((agent_ptr -> nx_snmp_agent_v3_security_context_engine_size == 0) && + (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0)) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("No Engine ID, no user name, this is a discovery request. \n\r"); +#endif + agent_ptr -> nx_snmp_agent_unknown_engineid_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length); + + /* We're done ! Release the received SNMP packet. */ + nx_packet_release(packet_ptr); + + return; + } + /* Check for a mismatched Engine ID. */ + else if ((memcmp(&agent_ptr -> nx_snmp_agent_v3_context_engine[0], + &agent_ptr -> nx_snmp_agent_v3_security_context_engine[0], + agent_ptr -> nx_snmp_agent_v3_security_context_engine_size) != 0)) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Detect a mismatched (non null) engine ID\n\r"); +#endif + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_unknown_engineid_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* We will wait for the browser to make a discovery request (blank engine ID). */ + return; + } + /* Check for missing username in the securities header. */ + else if (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0) + { + + /* Missing user name in the securities field. */ + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Request is missing a securities username\n\r"); +#endif + + /* Update the unknown or missing user name at least. */ + agent_ptr -> nx_snmp_agent_unknown_username_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; + } + /* Check for valid username in the security parameters. */ + else if (agent_ptr -> nx_snmp_agent_username_process) + { + + status = (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name); + + if (status != NX_SUCCESS) + { + /* Unknown user name in the securities field. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Error in username callback: 0x%x\n\r", status); +#endif + + agent_ptr -> nx_snmp_agent_unknown_username_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Engine ID and username appear acceptable, Not a disco request. Check the boot time. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Request has a valid Engine ID and user name. Check the boot and boot time\n\r"); +#endif + + /* Check if both sides have authentication enabled. */ + if (((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) && + (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL)) + { + /* They do. So now we must check for mismatched boot data. */ + if (agent_ptr -> nx_snmp_agent_v3_context_engine_boots != agent_ptr -> nx_snmp_agent_v3_security_engine_boots) + { + + /* Boot count does not match. */ + agent_ptr -> nx_snmp_agent_mismatched_time_count++; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Detect a %d'th mismatch in the boot count. Agent boot count: %d; Browser boot count %d\n\r", + agent_ptr -> nx_snmp_agent_mismatched_time_count, + agent_ptr -> nx_snmp_agent_v3_context_engine_boots, + agent_ptr -> nx_snmp_agent_v3_security_engine_boots); +#endif + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + /* Determine if the browser boot time exceeds ours by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */ + else if ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) && + ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) > NX_SNMP_TIME_WINDOW)) + { + + agent_ptr -> nx_snmp_agent_mismatched_time_count++; + + /* Outside acceptable limits. Do not reply to this request. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is less than Browser boot time %d\n\r", + agent_ptr -> nx_snmp_agent_mismatched_time_count, + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, + agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time); +#endif + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + /* Determine if the our boot time exceeds the browser boot time by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */ + else if ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) && + ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) > NX_SNMP_TIME_WINDOW)) + { + + agent_ptr -> nx_snmp_agent_mismatched_time_count++; + + /* Outside acceptable limits. Do not reply to this request. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is greater than Browser boot time %d\n\r", + agent_ptr -> nx_snmp_agent_mismatched_time_count, + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, + agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time); +#endif + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + } + } + + + authenticate_message = NX_FALSE; + + /* Check again if the incoming request specifies authentication. */ + if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) + { + + /* Check if our key is not set up or authentication is not enabled (in which + case the authentication key is NULL anyway). */ + if (agent_ptr -> nx_snmp_agent_v3_authentication_key == NX_NULL) + { + + /* The request has an unsupported (as in none) authentication level requested. This is an error. */ + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__); +#endif + agent_ptr -> nx_snmp_agent_unsupported_sec_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); + + /* We're done ! Release the received SNMP packet. */ + nx_packet_release(packet_ptr); + + return; + } + else + { + /* Otherwise Ok to process authentication parameter. */ + authenticate_message = NX_TRUE; + } + } + /* Check if the incoming message is not requesting authentication. */ + else + { + + if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL) + { + + /* The request has an unsupported (as in none) authentication level requested. This + is an error. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__); +#endif + agent_ptr -> nx_snmp_agent_unsupported_sec_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); + + /* We're done ! Release the received SNMP packet. */ + nx_packet_release(packet_ptr); + + return; + } + } + + /********************************************************/ + /* Check Authentication Parameter */ + /********************************************************/ + + /* Are we processing the authentication parameter? */ + if (authenticate_message == NX_TRUE) + { + + /* Yes, authentication is required. */ + + /* Mark the location in the request buffer. */ + pdu_auth_parm_ptr = request_authentication_ptr; + + /* Clear the authentication field in the message. To calculate the + digest this must be cleared. Also position past the string and length. */ + for (i = 0; i < agent_ptr -> nx_snmp_agent_v3_security_authentication_size; i++) + { + + /* Clear the byte. */ + *request_authentication_ptr++ = 0; + } + /* Now determine which authentication is required. */ + if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) + { + + /* Copy the base MD5 key into key1. */ + for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base MD5 key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Calculate prepend Key1. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Prepend Key2 to the result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); + } + else if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) + { + + /* Copy the base SHA key into key1. */ + for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base SHA key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Calculate prepend Key1. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Prepend Key2 to the result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); + } + else + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Authentication error. Drop the request. Line %d \n\r", __LINE__); +#endif + /* Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* At this point, key2 contains the computed digest of the message. If this doesn't match, + then the message is invalid. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + { + + /* Check for a mismatch. */ + if (key2[i] != agent_ptr -> nx_snmp_agent_v3_security_authentication[i]) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Authentication mismatch. Drop the request. Line %d \n\r", __LINE__); +#endif + /* We are not. Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + } + } + + /* Now prepare response message so we can process the variables one by one. */ + + /* Determine which packet type we allocate based on the destination address type. */ + if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Device not enabled for IPv6\n\r"); +#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE*/ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif /* FEATURE_NX_IPV6 */ + + } + else + { + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Allocate the packet for the SNMP response. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a response packet was allocated. */ + if (status) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Response packet allocate error. Status: 0x%x\n\r", status); +#endif + + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the response packet. */ + response_sequence_length = 0; + response_header_length = 0; + response_security_length = 0; + response_pdu_length = 0; + response_type_length = 0; + response_variable_list_length = 0; + + /* Setup a pointer to the response packet's buffer area. */ + response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; + + /* This is also the response sequence pointer. Remember it since we are going to have to + update it later with the actual length of the response. */ + response_sequence_ptr = response_buffer_ptr; + + /* First, write the sequence in the response packet. A zero is written for now. This will be + updated later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /********************************************************/ + /* Set the Version ID */ + /********************************************************/ + response_length = _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_3, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Save the pointer to the global header. */ + response_header_ptr = response_buffer_ptr; + + /* Write the sequence for the global header in the response packet. A zero is written for now. + This will be updated later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /********************************************************/ + /* Set the request ID */ + /********************************************************/ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the header sequence length. */ + response_header_length = response_header_length + response_length; + + /********************************************************/ + /* Set the maximum message size */ + /********************************************************/ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the header sequence length. */ + response_header_length = response_header_length + response_length; + + /********************************************************/ + /* Set the message security options */ + /********************************************************/ + message_sec_level = agent_ptr -> nx_snmp_agent_v3_message_security_options; + + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, (UCHAR *)&message_sec_level, 1, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the header sequence length. */ + response_header_length = response_header_length + response_length; + + /****************************************************/ + /* Set the security type */ + /****************************************************/ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the header sequence length. */ + response_header_length = response_header_length + response_length; + + /* At this point, we have successfully built the security header. Now, we need to build + the security parameters field. */ + + /* First setup the octet string field. */ + response_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + response_buffer_ptr[1] = 0; + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + 2; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + 2; + + /* Remember the security header length pointer. */ + response_security_ptr = response_buffer_ptr; + + /* Now set the sequence of the USM security parameters. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /****************************************************/ + /* Set the Context Engine */ + /****************************************************/ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + /****************************************************/ + /* Set the Boot Count */ + /****************************************************/ + if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0) + { + /* No security, no time synching, so set boot data to zero. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + } + else + { + /* Set the actual boot count. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, response_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + /****************************************************/ + /* Set the Boot Time */ + /****************************************************/ + + if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0) + { + /* No security, no time synching, so set boot data to zero. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + } + else + { + + /* Get the tick count since last boot up. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + + /* Set the actual boot count. */ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, response_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + /****************************************************/ + /* Set the security user name */ + /****************************************************/ + + /* (Use the security name in the request message) */ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + /* Initialize the temporary string to zero. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + temp_string[i] = 0; + + /****************************************************/ + /* Set the security Authentication parameter */ + /****************************************************/ + + /* Now setup the authentication parameter if authentication is enabled, and only if called for. */ + if (authenticate_message == NX_TRUE) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Authenticating: initialize auth parameter to zero in response packet. (Line %d) \n\r", __LINE__); +#endif + + /* All set to add an authentication parameter. For now, set to all zeroes. */ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, response_packet_ptr -> nx_packet_data_end); + + /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter. */ + response_authentication_ptr = response_buffer_ptr + 2; + } + else + { +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Not Authenticating: set auth parameter to null in response packet. (Line %d) \n\r", __LINE__); +#endif + /* No security enabled so set this as an empty parameter. */ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end); + + } + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + encrypt_message = NX_FALSE; + + /* Check if the incoming request specifies authentication. A discovery request should not have + the authentication (or encxryption) flags set. */ + if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY) >= 2) + { + + /* Check if our key is not set up or privacy is not enabled (in which + case the privacy key is NULL anyway). */ + if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) + { + + /* The request has an unsupported (as in none) privacy level requested. This is an error. */ + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__); +#endif + agent_ptr -> nx_snmp_agent_unsupported_sec_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* We're done ! Release the received SNMP packet. */ + nx_packet_release(packet_ptr); + + return; + } + else + { + /* Otherwise Ok to process encrypt/decrypt SNMPv3 data. */ + encrypt_message = NX_TRUE; + } + } + + /* Check if the incoming message is not requesting privacy. */ + else + { + + if (agent_ptr -> nx_snmp_agent_v3_privacy_key != NX_NULL) + { + + /* The request has an unsupported (as in none) privacy level requested. This + is an error. */ +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__); +#endif + agent_ptr -> nx_snmp_agent_unsupported_sec_count++; + + _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* We're done ! Release the received SNMP packet. */ + nx_packet_release(packet_ptr); + + return; + } + } + + /****************************************************/ + /* Set the security Privacy parameter */ + /****************************************************/ + + /* Are we applying encryption to our response? */ + if (encrypt_message == NX_FALSE) + { + + /* No, so set the privacy field as an empty parameter. */ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end); + } + else + { + + /* Initialize the 8 character privacy parameter (salt) to all zeros field initially. */ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, 8, response_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + if (encrypt_message == NX_TRUE) + { + + /* Remember the pointer to the actual 8 byte privacy parameter. */ + response_privacy_ptr = response_buffer_ptr + 2; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Adjust the security sequence length. */ + response_security_length = response_security_length + response_length; + + /****************************************************/ + /* Decrypt the privacy data */ + /****************************************************/ + + /* Check if encryption is required */ + if (encrypt_message == NX_TRUE) + { + + response_encryption_size_ptr = 0x0; + + /* Save the location if we need to return an error message. */ + pdu_buffer_ptr = buffer_ptr; + + status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, response_buffer_ptr, &response_encryption_size_ptr, &response_length, buffer_length); + + if (status != NX_SUCCESS) + { + + /* Increment the privacy error counter. */ + agent_ptr -> nx_snmp_agent_privacy_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + return; + } + + /* This is typically coded as 0x30 0x29 [or whatever length] 0x04 0x82 or [length] without + the multi byte coding. This will also handle 0x81 "multi byte" coding. */ + if (buffer_ptr[3] & NX_SNMP_ANS1_MULTI_BYTES) + { + + /* Get the type of length of the string */ + UINT temp = (UINT)(buffer_ptr[3] & 0x7F); + + if (temp == 2) + { + + pdu_length = (UINT) (*(buffer_ptr+ 4) << 8) | ((UINT) *(buffer_ptr+5)); + pdu_buffer_ptr = buffer_ptr; + } + + else if (temp == 1) + { + pdu_length = *(buffer_ptr + 4); + pdu_buffer_ptr = buffer_ptr; + } + else + { + + /* String is either null or too big, return a zero length to indicate an error. */ + return; + } + } + else /* Assume one byte */ + { + pdu_length = *(buffer_ptr + 3); + pdu_buffer_ptr = buffer_ptr; + } + + response_length = 4; + + } + + /* Now we can process the request type pointer */ + while (temp_ptr < packet_ptr -> nx_packet_append_ptr) + { + temp_ptr++; + + /* Check for Get request type. */ + if ((*temp_ptr == NX_SNMP_ANS1_GET_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_GET_BULK_REQUEST)|| + (*temp_ptr == NX_SNMP_ANS1_GET_NEXT_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_SET_REQUEST)) + { + break; + } + } + + /* Check for invalid packet. */ + if (temp_ptr == packet_ptr -> nx_packet_append_ptr) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Save the request type pointer. */ + request_type_ptr = temp_ptr; + + /* Save the response pdu sequence pointer. */ + response_pdu_ptr = response_buffer_ptr; + + /* Move the response buffer pointer. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Increment the number of response sequence bytes. */ + response_sequence_length = response_sequence_length + response_length; + + /****************************************************/ + /* Get the PDU sequence length */ + /****************************************************/ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &pdu_sequence_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /****************************************************/ + /* Get the PDU engine ID */ + /****************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_engine_size, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + + /******************************************************************************/ + /* SET the PDU Sequence Header if the response is encrypted. */ + /******************************************************************************/ + + /* If the message is encrypted we have to insert an PDU "inner" sequence header. Because + we will use the multibyte sequence 0x30 82 xx yy format, we have to update the enclosing + sequences (total response length and pdu length and their respective pointers accordingly. + */ + if (encrypt_message) + { + + /* Move the response buffer pointer. */ + response_buffer_ptr = response_buffer_ptr + 4; + + /* Increment the number of response sequence bytes. */ + response_sequence_length = response_sequence_length + 4; + + /* Increment the response pdu sequence pointer. */ + response_pdu_ptr = response_pdu_ptr + 4; + + /* Increment the pdu length for this sequence header. */ + response_pdu_length = response_pdu_length + 4; + + } + + /****************************************************/ + /* SET the PDU engine ID */ + /****************************************************/ + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (response_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response pointer forward. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Increment the sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /****************************************************/ + /* Get the PDU engine name */ + /****************************************************/ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_name_size, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + + /* The browser uses the context name from the SNMP Agent to confirm + the response is coming from the SNMP Agent it sent the request to. They must match. + The request ID only matches the request with response. A user may have multiple + requests. There may be circumstances where the SNMP Agent only responds with + one context name. Don't know what that would be. */ + + /* Check if the SNMP agent has set a PDU engine name yet. */ + if (agent_ptr -> nx_snmp_agent_v3_context_name_size == 0) + { + + /* No it has not, so let's set it here. */ + + /* First verify that this is a legal length to copy. */ + if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING) + { + + /* Invalid length, this will overrun the buffer. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + memcpy(agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_current_octet_string, context_name_size); + + agent_ptr -> nx_snmp_agent_v3_context_name_size = context_name_size; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /****************************************************/ + /* SET the PDU engine name */ + /****************************************************/ + + response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid packet. */ + if (response_length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response pointer forward. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Save the pointer to the response type. */ + response_type_ptr = response_buffer_ptr; + + /* Increment the sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /****************************************************/ + /* Get the PDU request type */ + /****************************************************/ + length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; + if ((request_type == NX_SNMP_GET_REQUEST) || + (request_type == NX_SNMP_GET_NEXT_REQUEST) || + (request_type == NX_SNMP_GET_BULK_REQUEST)) + { + agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; + } + + + /****************************************************/ + /* SET the PDU request type */ + /****************************************************/ + response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /****************************************************/ + /* Get the PDU request ID */ + /****************************************************/ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /****************************************************/ + /* SET the PDU request ID */ + /****************************************************/ + response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Save a pointer to the error string. */ + error_ptr = buffer_ptr; + + /****************************************************/ + /* Get the PDU error information */ + /****************************************************/ + /* This is actually used to derive the GETBULK information in SNMP V3 and above. */ + length = _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Determine if the received packet size is too big. */ + if (packet_ptr -> nx_packet_next) + { + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Done, return to caller. */ + return; + } + +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /****************************************************/ + /* SET the PDU error information */ + /****************************************************/ + response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /****************************************************/ + /* Get the PDU variable list length */ + /****************************************************/ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); + + /* Check for a valid packet. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* At this point we have parsed the incoming SNMP request up to the first + variable. */ + + /* Remember the start of the response's variable list field. */ + response_variable_list_ptr = response_buffer_ptr; + + /* Setup the variable list response. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Process the variable binding list, line %d \n\r", __LINE__); +#endif + + /* At this point the response buffer is setup to exactly the same position the + SNMP Manager's input buffer is - right before the first variable. We can + now walk through the variable list to process each request and place the + result in the response buffer. */ + objects = 0; + next_object = NX_TRUE; + current_repetitions = max_repetitions; + do + { + + /* Determine if the next object should be retrieved. */ + if (next_object) + { + + /* Remember the start of the variable. */ + variable_start_ptr = buffer_ptr; + + /* Pickup the first SNMP Variable length. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); + + /* Calculate the total variable size. */ + total_variable_length = variable_length + length; + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Now pickup the object ID. */ + length = _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length); + + /* Determine if the object retrieval was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the buffer pointer up. */ + buffer_ptr = buffer_ptr + length; + + /* The buffer pointer is moved by the length. Update buffer size */ + buffer_length -= (INT)length; + + /* Default the value to NULL. */ + agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; + + /* Determine if a value is present. */ + if (length != variable_length) + { + + /* Pickup the value associated with this variable. */ + length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); + + /* Determine if the object value was successful. */ + if (length == 0) + { + + /* Increment the invalid packet error counter. */ + agent_ptr -> nx_snmp_agent_invalid_packets++; + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Send an SNMP version error response. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + } + } + + /* At this point, we are ready to call the appropriate application request handling routine. + It is responsible for extracting or placing information in the object data structure. */ + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GET routine. */ + status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Call the application's GETNEXT routine. */ + status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) + { + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Clear the next object flag. */ + next_object = NX_FALSE; + + /* Call the application's GETNEXT routine. */ + status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + + /* Decrement the number of non-repeaters. */ + if (non_repeaters) + { + + /* Decrement the number of non-repeaters. */ + non_repeaters--; + + /* Set the next object flag to move to the next entry of the request. */ + next_object = NX_TRUE; + } + else + { + + /* Decrement the repetitions. */ + if (current_repetitions) + current_repetitions--; + + /* Determine if there are more repetitions or if the end of MIB was detected. */ + if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + + /* Reset the current repetition. */ + current_repetitions = max_repetitions; + + /* Set the next object flag to true. */ + next_object = NX_TRUE; + } + } + } + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + { + + /* Increment the total number of set variables. */ + agent_ptr -> nx_snmp_agent_total_set_variables++; + + /* Call the application's SET routine. */ + status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + &(agent_ptr -> nx_snmp_agent_current_object_data)); + } + else + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Error processing variable binding items (invalid request type %d). Line %d \n\r", request_type, __LINE__); +#endif + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Check for an error status from the agent's request processing callback routine. */ + if (status) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Error processing variable binding get request callback. Line %d \n\r", __LINE__); +#endif + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects); + + /* Done, return to caller. */ + return; + } + + /* Determine if the returning object is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || + (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Error processing variable binding. Invalid object from get request callback. Line %d \n\r", __LINE__); +#endif + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Now ensure the returning object type is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && +#ifdef FEATURE_NX_IPV6 + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && +#endif + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Error processing variable binding (unknown object type). Line %d \n\r", __LINE__); +#endif + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + /* Everything is okay, place the object and object data into the response buffer. */ + + /* Remember the start of the variable response sequence. */ + response_variable_ptr = response_buffer_ptr; + + /* Clear the response variable size. */ + response_variable_length = 0; + + /* Determine if there is enough room in the destination for the variable sequence. */ + if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Setup the variable response sequence. For now, the length will be zero. We + will overwrite this with the actual length later. */ + response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the response packet too. */ + nx_packet_release(response_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Place the object into the response buffer. */ + response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Insert the object's data into the response buffer. */ + response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (response_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(response_packet_ptr); + + /* Call the error handling response routine. This will release the packet */ + _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + response_buffer_ptr = response_buffer_ptr + response_length; + + /* Adjust the response sequence length. */ + response_sequence_length = response_sequence_length + response_length; + + /* Increment the pdu length. */ + response_pdu_length = response_pdu_length + response_length; + + /* Adjust the response request type length. */ + response_type_length = response_type_length + response_length; + + /* Adjust the response variable list size. */ + response_variable_list_length = response_variable_list_length + response_length; + + /* Adjust the response variable size. */ + response_variable_length = response_variable_length + response_length; + + /* Now update the response variable sequence with the actual variable length. */ + _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); + + /* Only update the source object information if the next object flag is set. */ + if (next_object) + { + + /* Adjust the pointer to the next variable. */ + buffer_ptr = variable_start_ptr + total_variable_length; + + /* Decrement the size of the variable list. */ + variable_list_length = variable_list_length - total_variable_length; + + /* Increment the object counter. */ + objects++; + } + + } while ((variable_list_length) || (next_object == NX_FALSE)); + + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Variable binding processing completed\n\r"); +#endif + + /* At this point, several response fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(response_header_ptr, response_header_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(response_security_ptr, response_security_length, response_packet_ptr -> nx_packet_data_end); + if (encrypt_message == NX_FALSE) + { + _nx_snmp_utility_sequence_set_1byte(response_pdu_ptr, response_pdu_length, response_packet_ptr -> nx_packet_data_end); + } + _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); + + /* Setup the security OCTET string length. */ + + /* Backup to the OCTET string for the security size. */ + response_security_ptr = response_security_ptr - 2; + + /* Account for the 4 byte Security Sequence field. */ + response_security_length = response_security_length + 4; + + /* Store the security size. */ + response_security_ptr[1] = (UCHAR) (response_security_length & 0xFF); + + /* Determine if privacy is required. If so, encrypt the PDU and setup the response + to have an encryption header. */ + if (encrypt_message == NX_TRUE) + { + + _nx_snmp_agent_encrypt_pdu(agent_ptr, &response_pdu_length, &response_sequence_length, + response_encryption_size_ptr, &response_sequence_ptr, + response_packet_ptr -> nx_packet_data_end, + &response_buffer_ptr, response_privacy_ptr); + } + + /* Now the response packet's pointers must be setup so it can be sent. */ + response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); + response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; + + if (authenticate_message == NX_TRUE) + { + + /* Yes, authentication is required. */ + status = _nx_snmp_agent_add_auth_parameter(agent_ptr, response_packet_ptr, response_authentication_ptr); + + if (status != NX_SUCCESS) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r", __LINE__); +#endif + /* Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release the report packet too. */ + nx_packet_release(response_packet_ptr); + + /* Release the original request packet. */ + nx_packet_release(packet_ptr); + + return; + } + } + + /* Release the original request packet. */ + nx_packet_release(packet_ptr); + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; + agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; + if (request_type == NX_SNMP_ANS1_GET_REQUEST) + agent_ptr -> nx_snmp_agent_get_requests++; + else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) + agent_ptr -> nx_snmp_agent_getnext_requests++; + else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) + agent_ptr -> nx_snmp_agent_getbulk_requests++; + else if (request_type == NX_SNMP_ANS1_SET_REQUEST) + agent_ptr -> nx_snmp_agent_set_requests++; + + /* Increment the sent packet counter. */ + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Increment the get responses sent counter. */ + agent_ptr -> nx_snmp_agent_getresponse_sent++; + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Sending the response to SNMPv3 request on line %d.\n\r", __LINE__); +#endif + + /* Send the response packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, + &(agent_ptr -> nx_snmp_agent_current_manager_ip), + agent_ptr -> nx_snmp_agent_current_manager_port); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(response_packet_ptr); + } +} +#endif /* NX_SNMP_DISABLE_V3 */ + + +#ifndef NX_SNMP_DISABLE_V3 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_version_3_report_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends reports to the SNMP Manager in response to */ +/* received requests. These are usually discovery requests, but can */ +/* also be USM violations such as unknown username, unsupported */ +/* security level or invalid boot data. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* discovery_respond Reason for report */ +/* buffer_length Size of buffer data */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate response packet */ +/* nx_packet_release Release the packet */ +/* nx_udp_socket_send Send the UDP packet */ +/* _nx_snmp_utility_error_info_set Set the error information */ +/* _nx_snmp_utility_octet_set Set the octet string */ +/* _nx_snmp_utility_request_id_set Set the request ID */ +/* _nx_snmp_utility_request_type_set_multibyte */ +/* Set trap request type */ +/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ +/* _nx_snmp_utility_version_set Set the SNMP version */ +/* tx_time_get Get the time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_process Process SNMP v3 request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_version_3_report_send(NX_SNMP_AGENT *agent_ptr, UCHAR *buffer_ptr, UINT report_respond, INT buffer_length) +{ + +UINT status; +UINT report_length; +NX_PACKET *report_packet_ptr; +UCHAR *report_buffer_ptr, *report_sequence_ptr, *report_header_ptr, *report_security_ptr; +UCHAR *report_authentication_ptr = NX_NULL, *report_pdu_ptr, *report_type_ptr; +UINT report_sequence_length, report_header_length, report_security_length, report_pdu_length, report_type_length; +UCHAR *report_encryption_size_ptr = NX_NULL; +UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; +UINT packet_type; +UCHAR *report_variable_list_ptr = NX_NULL; +UINT report_variable_length = 0; +UINT report_variable_list_length = 0; +UCHAR *report_variable_ptr = NX_NULL; +ULONG request_id; +UINT temp, i; +UINT length; +UINT request_type; +UINT request_length; +UINT authenticate, encryption, send_reply; +UCHAR report_security_level; + + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Processing the report...\n\r"); +#endif + + /* Now prepare report message so we can process the report. */ + + /* Determine which packet type we allocate based on the destination address type. */ + if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) + { + packet_type = NX_IPv4_UDP_PACKET; + } + else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Report: IPv6 not enabled on this device.\n\r"); +#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE */ + + return; +#else + packet_type = NX_IPv6_UDP_PACKET; +#endif /* FEATURE_NX_IPV6 */ + } + else + { + return; + } + + /* Allocate the packet for the SNMP report. */ + status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &report_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); + + /* Determine if a report packet was allocated. */ + if (status) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Report: error allocating packet 0x%x.\n\r", status); +#endif + /* Increment the packet allocation error counter. */ + agent_ptr -> nx_snmp_agent_allocation_errors++; + + /* Return to caller. */ + return; + } + + memset(report_packet_ptr -> nx_packet_prepend_ptr, 0, + (UINT)(report_packet_ptr -> nx_packet_data_end - report_packet_ptr -> nx_packet_prepend_ptr)); + + /* Initialize the counters required for the length fields of the report packet. */ + report_sequence_length = 0; + report_header_length = 0; + report_security_length = 0; + report_pdu_length = 0; + report_type_length = 0; + + /* Setup a pointer to the report packet's buffer area. */ + report_buffer_ptr = report_packet_ptr -> nx_packet_prepend_ptr; + + _nx_snmp_agent_security_response_status(agent_ptr, &authenticate, &encryption, &send_reply); + + if (send_reply == NX_FALSE) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Report: received request with encryption set. Encryption not enabled on device; no report sent.\n\r"); +#endif + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + return; + } + + /* We need to set our own security level in case the report security settings differ from the incoming request. */ + report_security_level = (UCHAR)authenticate; + + /* Find out if we need to decrypt this message. */ + if (encryption == NX_TRUE) + { + + /* We do. Decrypt the data. We need to get the PDU data, request id and other data. */ + status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, NX_NULL, &report_encryption_size_ptr, &report_length, buffer_length); + + if (status != NX_SUCCESS) + { + + /* Release the report packet. */ + nx_packet_release(report_packet_ptr); + + return; + } + } + + /* Get the PDU sequence location. */ + length = _nx_snmp_utility_sequence_get(buffer_ptr, &temp, buffer_length); + + if (length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + buffer_ptr += length; + buffer_length -= (INT)length; + + /* Get the SNMP v3 PDU context engine field location. */ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length); + + if (length == 0) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + buffer_ptr += length; + buffer_length -= (INT)length; + + /* Get the SNMP v3 PDU context name field location. */ + length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, + sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length); + if (length == 0) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + buffer_ptr += length; + buffer_length -= (INT)length; + + /* Pick up the SNMP Request type and location. */ + length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); + if (length == 0) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + buffer_ptr += length; + buffer_length -= (INT)length; + + /* Get the SNMP Request ID. We need this for our report. */ + length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); + if (length == 0) + { + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* This is also the report sequence pointer. Remember it since we are going to have to + update it later with the actual length of the report. */ + report_sequence_ptr = report_buffer_ptr; + + /* First, write the sequence in the report packet. A zero is written for now. This will be + updated later. */ + report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /********************************************************/ + /* Set the version ID */ + /********************************************************/ + report_length = _nx_snmp_utility_version_set(report_buffer_ptr, NX_SNMP_VERSION_3, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Save the pointer to the global header. */ + report_header_ptr = report_buffer_ptr; + + /* Write the sequence for the global header in the report packet. A zero is written for now. + This will be updated later. */ + report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /********************************************************/ + /* Set the request ID */ + /********************************************************/ + + /* This must match the request specified by the discovery request. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the header sequence length. */ + report_header_length = report_header_length + report_length; + + /********************************************************/ + /* Set the maximum message size */ + /********************************************************/ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the header sequence length. */ + report_header_length = report_header_length + report_length; + + /********************************************************/ + /* Set the security options */ + /********************************************************/ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, (UCHAR *)&(report_security_level), 1, report_packet_ptr -> nx_packet_data_end); + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Setting report security level to 0x%x\n\r", report_security_level); +#endif + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the header sequence length. */ + report_header_length = report_header_length + report_length; + + /********************************************************/ + /* Set the security type */ + /********************************************************/ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the header sequence length. */ + report_header_length = report_header_length + report_length; + + /* At this point, we have successfully built the security header. Now, we need to build + the security parameters field. */ + + /* First setup the octet string field. */ + report_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + report_buffer_ptr[1] = 0; + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + 2; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + 2; + + /* Remember the security header pointer. */ + report_security_ptr = report_buffer_ptr; + + report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /********************************************************/ + /* Set the context engine */ + /********************************************************/ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /********************************************************/ + /* Set the boot count */ + /********************************************************/ + if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) + { + + /* Set boot count to zero for discovery requests. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + } + else + { + + /* Use the current SNMP boot count for all others. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, report_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /* Start the time (in ticks) since the previous reboot. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + + /********************************************************/ + /* Set the boot time */ + /********************************************************/ + if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) + { + + /* Set boot time to zero. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + } + else + { + + /* Start the time (in ticks) since the previous reboot. */ + agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); + /* Use the current SNMP boot time. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, report_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /********************************************************/ + /* Set the security user name */ + /********************************************************/ + + /* Set the security user name as specified in the request message. */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, report_packet_ptr -> nx_packet_data_end); + + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /* Initialize the temporary string to zero. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + temp_string[i] = 0; + /********************************************************/ + /* Set the security authentication parameter */ + /********************************************************/ + + if (authenticate == NX_TRUE) + { + + + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to zero in report. (Line %d) \n\r", __LINE__); +#endif + /* All set to add an authentication parameter. For now, set to all zeros. */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, report_packet_ptr -> nx_packet_data_end); + + /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE (12) byte authorization parameter. */ + report_authentication_ptr = report_buffer_ptr + 2; + } + else + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to empty. \n\r"); +#endif + /* No security enabled so set this as an empty parameter. */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); + } + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /* Set the Privacy Parameter field to empty (encryption/privacy not used in reports). */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the security sequence length. */ + report_security_length = report_security_length + report_length; + + /* Remember the PDU sequence pointer. */ + report_pdu_ptr = report_buffer_ptr; + + /* Now set the sequence of the PDU. We will replace this sequence type with 'opaque' + if encryption is required later. */ + report_length = _nx_snmp_utility_sequence_set(report_pdu_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /********************************************************/ + /* Set the Context Engine ID */ + /********************************************************/ + + /* The Context Engine ID should be the same as the msgAuthoritativeEngine ID since there is no proxy. */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, + agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Now setup the PDU context name field - it is a null field in the response. */ + report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Remember the type field's starting address. */ + report_type_ptr = report_buffer_ptr; + + /* Now setup the message type field. */ + report_length = _nx_snmp_utility_request_type_set_multibyte(report_buffer_ptr, NX_SNMP_ANS1_REPORT_REQUEST, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /********************************************************/ + /* Set PDU request ID */ + /********************************************************/ + /* Set the PDU request to zero instead of matching the request if the request is encrypted. + Otherwise the request ID must match the request specified by the browser request. */ + if (encryption) + { + request_id = 0; + } + + /* Set the PDU request ID. */ + report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, request_id, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the report type length. */ + report_type_length = report_type_length + report_length; + + /********************************************************/ + /* Set the error info */ + /********************************************************/ + report_length = _nx_snmp_utility_error_info_set(report_buffer_ptr, 0, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the report type length. */ + report_type_length = report_type_length + report_length; + + /* Mark the beginning of the variable list. */ + report_variable_list_ptr = report_buffer_ptr; + + /********************************************************/ + /* Set up the variable list */ + /********************************************************/ + + /* Now setup the sequence for the variable list. This is set to zero for now. */ + report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the report buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the report sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Adjust the PDU sequence length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the report type length. */ + report_type_length = report_type_length + report_length; + + /* Remember the start of the variable response sequence. */ + report_variable_ptr = report_buffer_ptr; + + /* Clear the response variable size. */ + report_variable_length = 0; + + /* Determine if there is enough room in the destination for the variable sequence. */ + if ((report_buffer_ptr + 4) >= report_packet_ptr -> nx_packet_data_end) + { + + /* Release the response packet. */ + nx_packet_release(report_packet_ptr); + + /* Done, return to caller. */ + return; + } + + /********************************************************/ + /* Initialize variable response sequence to zero */ + /********************************************************/ + + /* We will overwrite this with the actual length later. */ + report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the response sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Increment the pdu length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the response request type length. */ + report_type_length = report_type_length + report_length; + + /********************************************************/ + /* Adjust the response variable list size. */ + /********************************************************/ + + /* Adjust the response variable list size. */ + report_variable_list_length = report_variable_list_length + report_length; + + /********************************************************/ + /* Set the report OID object */ + /********************************************************/ + + if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) + { + /* This report is responding to a discovery request. */ + memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID, + sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID)); + + status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_engineid_count), + &agent_ptr -> nx_snmp_agent_current_object_data); + + } + else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM) + { + /* This report is responding to a mismatch ("unsupported") in security level. */ + memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC, + sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC)); + + status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unsupported_sec_count), + &agent_ptr -> nx_snmp_agent_current_object_data); + } + else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM) + { + + /* This report is responding to an unknown user name. */ + memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME, + sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME)); + + status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_username_count), + &agent_ptr -> nx_snmp_agent_current_object_data); + } + else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM) + { + + /* This report is responding to invalid boot time or boot count data received. */ + memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME, + sizeof(NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME)); + + status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_mismatched_time_count), + &agent_ptr -> nx_snmp_agent_current_object_data); + } + else + { + + /* Unknown report type. Abort! */ + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Unknown report parameter %d. Abort report processing. \n\r", report_respond); +#endif + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + return; + } + + /* Check for a valid operation. */ + if (status != NX_SUCCESS) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the response packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* Increment the total number of get variables. */ + agent_ptr -> nx_snmp_agent_total_get_variables++; + + /* Determine if the returning object is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || + (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Invalid object from application GET routine on line %d.\n\r", __LINE__); +#endif + /* Release the response packet. */ + nx_packet_release(report_packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Now ensure the returning object type is valid. */ + if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && +#ifdef FEATURE_NX_IPV6 + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && +#endif + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && + (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Invalid object type (%d) from application GET routine on line %d.\n\r", + agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type, __LINE__); +#endif + + /* Release the response packet. */ + nx_packet_release(report_packet_ptr); + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Done, return to caller. */ + return; + } + + /* Place the object into the response buffer. */ + report_length = _nx_snmp_utility_object_id_set_1byte(report_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(report_packet_ptr); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the response sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Increment the pdu length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the response request type length. */ + report_type_length = report_type_length + report_length; + + /* Adjust the response variable list size. */ + report_variable_list_length = report_variable_list_length + report_length; + + /* Adjust the response variable size. */ + report_variable_length = report_variable_length + report_length; + + /* Insert the object's data into the response buffer. */ + report_length = _nx_snmp_utility_object_data_set(report_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Release the response packet. */ + nx_packet_release(report_packet_ptr); + + /* Done, return to caller. */ + return; + } + + /* Move the response buffer pointer up. */ + report_buffer_ptr = report_buffer_ptr + report_length; + + /* Adjust the response sequence length. */ + report_sequence_length = report_sequence_length + report_length; + + /* Increment the pdu length. */ + report_pdu_length = report_pdu_length + report_length; + + /* Adjust the response request type length. */ + report_type_length = report_type_length + report_length; + + /* Adjust the response variable list size. */ + report_variable_list_length = report_variable_list_length + report_length; + + /* Adjust the response variable size. */ + report_variable_length = report_variable_length + report_length; + + /* Now update the response variable sequence with the actual variable length. */ + report_length = _nx_snmp_utility_sequence_set(report_variable_ptr, report_variable_length, report_packet_ptr -> nx_packet_data_end); + + /* Check for a valid operation. */ + if (report_length == 0) + { + + /* Increment the internal error counter. */ + agent_ptr -> nx_snmp_agent_internal_errors++; + + /* Release the report packet too. */ + nx_packet_release(report_packet_ptr); + + /* Return to caller. */ + return; + } + + /* At this point, several report fields need to be updated with actual lengths. */ + _nx_snmp_utility_sequence_set(report_sequence_ptr, report_sequence_length, report_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(report_header_ptr, report_header_length, report_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(report_security_ptr, report_security_length, report_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(report_pdu_ptr, report_pdu_length, report_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_sequence_set(report_variable_list_ptr, report_variable_list_length, report_packet_ptr -> nx_packet_data_end); + _nx_snmp_utility_request_type_set_multibyte(report_type_ptr, NX_SNMP_ANS1_REPORT_REQUEST, report_type_length, report_packet_ptr -> nx_packet_data_end); + + /* Now the report packet's pointers must be setup so it can be sent. */ + report_packet_ptr -> nx_packet_length = (ULONG)(report_buffer_ptr - report_packet_ptr -> nx_packet_prepend_ptr); + report_packet_ptr -> nx_packet_append_ptr = report_buffer_ptr; + + /********************************************************/ + /* Set the authorization parameter */ + /********************************************************/ + + /* Also adjust the length of the security parameters field. */ + report_security_ptr = report_security_ptr - 2; + + /* Adjust the report security length. */ + report_security_length = report_security_length + 4; + + /* Store the security string size. */ + report_security_ptr[1] = (UCHAR) (report_security_length & 0xFF); + + /* Update various statistics. */ + agent_ptr -> nx_snmp_agent_reports_sent++; + + /* Increment the sent packet counter. */ + agent_ptr -> nx_snmp_agent_packets_sent++; + + /* Set the authentication parameter if we have determined it needs to be set, and only if we + have a valid user name. (Otherwise there would be no shared key for the other side to check + our authentication.)*/ + if ((authenticate == NX_TRUE) && (report_respond != NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM)) + { + + /* Fill in the authentication parameter. */ + status = _nx_snmp_agent_add_auth_parameter(agent_ptr, report_packet_ptr, report_authentication_ptr); + + if (status != NX_SUCCESS) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r", __LINE__); +#endif + + /* Increment the authentication error counter. */ + agent_ptr -> nx_snmp_agent_authentication_errors++; + + /* Release the original request packet. */ + nx_packet_release(report_packet_ptr); + + return; + } + } + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Sending the report on line %d.\n\r", __LINE__); +#endif + + /* Send the report packet back to the requesting SNMP manager. */ + status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), report_packet_ptr, + &(agent_ptr -> nx_snmp_agent_current_manager_ip), + agent_ptr -> nx_snmp_agent_current_manager_port); + + /* Determine if the packet needs to be released. */ + if (status) + { + + /* Release packet. */ + nx_packet_release(report_packet_ptr); + } + + + /* Return to caller. */ + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_add_auth_parameter PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function updates the specified SNMPv3 response with an */ +/* authentication parameter. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* response_packet_ptr Pointer to reply message data */ +/* response_authentication_ptr Pointer to authentication */ +/* parameter in the reply */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successfully added */ +/* authentication parameter */ +/* */ +/* CALLS */ +/* */ +/* _nx_md5_update Calculate MD5 message digest */ +/* _nx_md5_digest_calculate MD5 digest calculated */ +/* _nx_md5_initialize Prepare data for MD5 calc */ +/* _nx_sha_update Calculate SHa message digest */ +/* _nx_sha__digest_calculate SHa digest calculated */ +/* _nx_sha__initialize Prepare data for SHa calc */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_process Process SNMP v3 request reply */ +/* _nx_snmp_version_3_report_send Process SNMP v3 report */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_agent_add_auth_parameter(NX_SNMP_AGENT *agent_ptr, NX_PACKET *response_packet_ptr, UCHAR *response_authentication_ptr) +{ + +UINT i; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; + + + /* Determine which authentication is required. */ + if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && + ((agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY)) + { + + /* Copy the base MD5 key into key1. */ + for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base MD5 key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Calculate prepend Key1. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); + + /* Prepend Key2 to the result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); + } + else if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && + (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY)) + { + + /* Copy the base SHA key into key1. */ + for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) + { + + /* Copy a byte of the base SHA key. */ + key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; + } + + /* Extend key1 to 64 bytes. */ + for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key1[i] = 0; + } + + /* Create key1 and key2. */ + for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) + { + key2[i] = key1[i] ^ 0x5C; + key1[i] = key1[i] ^ 0x36; + } + + /* Calculate the MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Calculate prepend Key1. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the message. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length); + + /* Final calculation of the first pass. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); + + /* Prepare to calculate the final MAC. */ + _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); + + /* Prepend Key2 to the result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); + + /* Calculate the previous result. */ + _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); + + /* Calculate the final MAC. */ + _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); + } + else + { + + /* Return to caller. */ + return NX_SNMP_UNSUPPORTED_AUTHENTICATION; + } + + /* At this point, key2 contains the computed digest of the message. This needs to be + placed in the outgoing message. */ + + /* Loop to setup the outgoing digest. */ + for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) + { + + /* Copy the next byte of digest into the response buffer. */ + response_authentication_ptr[i] = key2[i]; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_encrypt_pdu PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encrypts data pointed to by the response buffer pointer*/ +/* and updates the necessary SNMPv3 header size in the header sequence */ +/* data. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* [These pointers pertain to the encrypted data to send:] */ +/* response_pdu_length Size of the PDU data */ +/* response_sequence_length Size of the response sequence */ +/* response_encryption_size_ptr Size of encryption data */ +/* response_sequence_ptr Pointer to the SNMPv3 sequence*/ +/* response_buffer_ptr Pointer to the SNMPv3 response*/ +/* response_privacy_ptr Pointer to privacy parameter */ +/* response_length Updated size of response */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Data successfully decrypted */ +/* NX_SNMP_INVALID_PDU_ENCRYPTION Invalid encrypted data */ +/* NX_SNMP_INVALID_ENCRYPT_LENGTH Decryption processing error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_process Process SNMP v3 request reply */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_snmp_agent_encrypt_pdu(NX_SNMP_AGENT *agent_ptr, UINT *response_pdu_length, UINT *response_sequence_length, UCHAR *response_encryption_size_ptr, + UCHAR **response_sequence_ptr, UCHAR *response_sequence_buffer_end, UCHAR **response_buffer_ptr, UCHAR *response_privacy_ptr) +{ + +UINT i, j; +UINT padding = 0; +UCHAR *temp_ptr; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; +UINT pdu_sequence_length; +UINT adjusted_pdu_length; + + if (response_pdu_length != NX_NULL) + { + + /* Determine if any padding needs to be applied - account for the + four bytes of header information on the PDU. */ + padding = ((*response_pdu_length+7)/8)*8 - *response_pdu_length; + + /* Add the padding the response PDU length and the response sequence length. */ + *response_pdu_length = *response_pdu_length + padding; + *response_sequence_length = *response_sequence_length + padding; + + /* Use a work pointer to initialize the padding buffer. */ + temp_ptr = *response_buffer_ptr; + + /* Clear the end of the response message... just to be nice! */ + for (i = 0; i < padding; i++) + { + + /* Clear byte at the end of the response. */ + *temp_ptr++ = 0; + } + + adjusted_pdu_length = *response_pdu_length; + } + else + { + /* Set the temp ptr to where the PDU starts in the request packet. */ + temp_ptr = pdu_buffer_ptr; + adjusted_pdu_length = pdu_length; + } + + /* If this is not for our outgoing response e.g. we are re-encrypting the received packet as part + of an error message, use the length from that packet. */ + if ((response_encryption_size_ptr == NX_NULL) || (response_pdu_length == NX_NULL)) + { + + pdu_sequence_length = pdu_length; + } + else + { + + /* We need to set the PDU "inner" sequence length; it comes just after the main PDU sequence header. */ + pdu_sequence_length = *response_pdu_length - 4; + + /* Do not include padding in the inner pdu size! */ + pdu_sequence_length = pdu_sequence_length - padding; + } + + if ((response_encryption_size_ptr != NX_NULL) && (response_pdu_length != NX_NULL)) + { + + /* Now we set the PDU "inner" sequence header. Use the multibyte sequence 0x30 82 xx yy format. + Note that calling function has already set the pointer for writing encyrpted PDU data past this + inner header. */ + response_encryption_size_ptr[2] = 0x30; + response_encryption_size_ptr[3] = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; + response_encryption_size_ptr[4] = (UCHAR) ((pdu_sequence_length >> 8) & 0xFF); + response_encryption_size_ptr[5] = (UCHAR) (pdu_sequence_length & 0xFF); + + /* Update our response buffer pointer. */ + *response_buffer_ptr = temp_ptr; + + response_encryption_size_ptr[0] = (UCHAR) ((*response_pdu_length >> 8) & 0xFF); + response_encryption_size_ptr[1] = (UCHAR) (*response_pdu_length & 0xFF); + + /* Update the total response sequence length again. */ + _nx_snmp_utility_sequence_set(*response_sequence_ptr, *response_sequence_length, response_sequence_buffer_end); + } + + /* Increment the salt counter. */ + agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; + + /* Build the salt value for the encryption. */ + key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); + key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); + key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); + key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); + key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); + key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); + key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); + key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); + + + if (response_privacy_ptr != NX_NULL) + { + + /* Loop to store the salt in the privacy field. */ + for (i = 0; i < 8; i++) + { + + /* Store a byte of the salt. */ + response_privacy_ptr[i] = key1[i]; + } + } + + /* Setup pointer to the actual PDU. */ + if (response_encryption_size_ptr) + { + temp_ptr = response_encryption_size_ptr + 2; + } + + /* Make the Initialization Vector (IV). */ + for (i = 0; i < 8; i++) + { + + key2[i] = (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key[8+i] ^ key1[i]; + } + + /* Setup the DES. */ + _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key); + + /* Set up the first input block - use the IV for the first block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[i] ^ key2[i]; + } + + /* Encrypt the first 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); + + /* Loop to encrypt the rest of the PDU. */ + j = 8; + do + { + + /* Setup the next input block. */ + for (i = 0; i < 8; i++) + { + + key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; + } + + /* Encrypt the next 8 bytes. */ + _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); + + /* Move the major index forward. */ + j = j + 8; + + } while (j < adjusted_pdu_length); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_decrypt_pdu PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decrypts the data pointed to by the buffer pointer */ +/* input. If the input response buffer pointer is not null, it will set */ +/* up the initial sequence header for the encrypted data around the */ +/* msgData header */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* buffer_ptr Pointer to data to decrypt */ +/* response_buffer_ptr Pointer to response to send */ +/* [If response_buffer_ptr is null, these have no effect:] */ +/* response_encryption_size_ptr Pointer to encrypted data in */ +/* response */ +/* response_length Size of encrypted data so far */ +/* buffer_length Size of buffer data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Data successfully decrypted */ +/* NX_SNMP_INVALID_PDU_ENCRYPTION Invalid encrypted data */ +/* NX_SNMP_INVALID_ENCRYPT_LENGTH Decryption processing error */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_process Process SNMP v3 request reply */ +/* _nx_snmp_version_3_report_send PRocess SNMP v3 report */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_snmp_agent_decrypt_pdu(NX_SNMP_AGENT *agent_ptr, UCHAR **buffer_ptr, UCHAR *response_buffer_ptr, + UCHAR **response_encryption_size_ptr, UINT *response_length, INT buffer_length) +{ + +UINT i, j, encrypted_size; +UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; +UCHAR *temp_ptr; + + + *response_length = 0; + temp_ptr = *buffer_ptr; + + /* Decrypt the source PDU and setup the response to have an encryption header. */ + if (temp_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Encryption error (no privacy key in the request). Line %d \n\r", __LINE__); +#endif + /* Return to caller. */ + return NX_SNMP_INVALID_PDU_ENCRYPTION; + } + + /* Pickup the encrypted PDU size. */ + if (temp_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) + { + + UINT temp = temp_ptr[1] & 0x7F; + if (temp == 2) + { + + /* Two byte octet string. */ + encrypted_size = (((UINT) temp_ptr[2]) << 8) | ((UINT) temp_ptr[3]); + + /* Move the buffer pointer up to the actual encrypted PDU contents. */ + temp_ptr = temp_ptr + 4; + } + else if (temp == 1) + { + + /* One byte octet string e.g. 0x04 0x81 0xXY */ + encrypted_size = (UINT) temp_ptr[2]; + + /* Move the buffer pointer up to the actual encrypted PDU contents. */ + temp_ptr = temp_ptr + 3; + + } + else + { + /* Either null or too big. Invalid size type.*/ + return NX_SNMP_ERROR_WRONGENCODING; + } + } + else + { + + /* One byte octet string. */ + encrypted_size = (UINT) temp_ptr[1]; + + /* Move the buffer pointer up to the actual encrypted PDU contents. */ + temp_ptr = temp_ptr + 2; + + } + + /* Check for invalid buffer size. */ + if ((INT)encrypted_size > buffer_length) + { + + /* Invalid buffer size. */ + return NX_SNMP_INVALID_PDU_ENCRYPTION; + } + + /* Determine if the length is valid. */ + if (encrypted_size % 8) + { + +#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE + NX_SNMPV3_DBG_PRINTF("Encryption error (invalid length).Drop the request. Line %d \n\r", __LINE__); +#endif + /* Return to caller. */ + return NX_SNMP_INVALID_ENCRYPT_LENGTH; + } + + /* Create the Initialization Vector (IV). */ + for (i = 0; i < 8; i++) + { + + key2[i] = (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key[8+i] ^ agent_ptr -> nx_snmp_agent_v3_security_privacy[i]; + } + + /* Initialize the DES component. */ + _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key); + + /* Decrypt the first 8 bytes. */ + _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), temp_ptr, key1); + + /* XOR with the IV. */ + for (i = 0; i < 8; i++) + { + + /* XOR a byte of the IV. */ + key1[i] = key1[i] ^ key2[i]; + } + + /* Loop to decrypt the entire PDU. */ + j = 8; + do + { + + /* Decrypt the next 8-byte block. */ + _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &temp_ptr[j], key2); + + /* XOR with the previous encrypted 8-byte block. */ + for (i = 0; i < 8; i++) + { + + /* XOR result with previous block. */ + key2[i] = key2[i] ^ temp_ptr[(j-8)+i]; + + /* Copy a byte of the decrypted block over the source. */ + temp_ptr[(j-8)+i] = key1[i]; + + /* Save this byte of the new decrypted block. */ + key1[i] = key2[i]; + } + + /* Move j up to the next 8 octet sequence. */ + j = j + 8; + } while (j < encrypted_size); + + /* Flush the last block out to the buffer. */ + for (i = 0; i < 8; i++) + { + + /* Copy a byte of the decrypted block over the source. */ + temp_ptr[(j-8)+i] = key1[i]; + } + + *buffer_ptr = temp_ptr; + + /* If the caller is going to encrypt its response it will send a non null response buffer pointer. */ + if (response_buffer_ptr != NX_NULL) + { + + /* Now setup the response buffer to encapsulate the encrypted PDU. Note that + the actual encryption will be done after the complete response has been + formed. */ + response_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; + response_buffer_ptr[1] = 0x82; + response_buffer_ptr[2] = 0x00; + response_buffer_ptr[3] = 0x00; + + /* Save the response encryption size pointer. This will be filled in below + as we build the message. */ + *response_encryption_size_ptr = response_buffer_ptr + 2; + + *response_length = 4 ; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_agent_security_response_status PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines how to set authentication and privacy */ +/* parameters in the USM header. */ +/* */ +/* INPUT */ +/* */ +/* agent_ptr Pointer to SNMP agent */ +/* */ +/* OUTPUT */ +/* */ +/* *authenticate If true, authentication */ +/* parameter should be set */ +/* *encryption If true, privacy parameter */ +/* should be set */ +/* *send_reply If not true, no reply or */ +/* report should be sent */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_version_3_report_send PRocess SNMP v3 report */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_snmp_agent_security_response_status(NX_SNMP_AGENT *agent_ptr, UINT *authenticate, UINT *encryption, UINT *send_reply) +{ + + + /* Initialize the security parameters to off. */ + *encryption = NX_FALSE; + *authenticate = NX_FALSE; + + /* In all but one or two cases we always send a reply. Initialize to true. */ + *send_reply = NX_TRUE; + + /* Check if the incoming request specifies encryption (privacy). */ + if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY ) >= 2) + { + + /* It is. Check if the SNMP agent has created an encryption key. */ + if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) + { + + /* We cannot decrypt the incoming message, (need the request ID), so we cannot send a reply. */ + *send_reply = NX_FALSE; + + return; + } + + /* Ok to apply privacy security level. */ + *encryption = NX_TRUE; + } + else + { + + /* Incoming message does not specify privacy. */ + + /* Check if the SNMP agent has created an encryption key. */ + if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) + { + + /* It has not. The SNMP agent is not configured for privacy here. All good. */ + } + /* else + Same result, indicate no privacy applied to our response. */ + + } + + /* Now if the incoming message security level is set for authentication regardless + of matching privacy levels. */ + if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) + { + + /* It is. Check if the SNMP agent has created an authentication key. */ + if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL) + { + + /* Ok to authenticate (even if not going apply privacy). */ + *authenticate = NX_TRUE; + } + /*else + Cannot authenticate, but we will still send a reply. */ + } + + return; +} + +#endif /*NX_SNMP_DISABLE_V3 */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_snmp_asn1_tlv_block_parse PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function parses an ASN.1 type-length-value (TLV) block for use */ +/* by the SNMP Agent parsing data received from the browser. */ +/* */ +/* INPUT */ +/* */ +/* buffer Pointer to data to be parsed */ +/* buffer_length Size of input buffer */ +/* tlv_type Return block type */ +/* tlv_tag_class Return class of the tag */ +/* tlv_length Return parsed length */ +/* tlv_data Return pointer to block data */ +/* header_length Return length of block itself */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_snmp_utility_object_get Extract data from sender */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_snmp_utility_tlv_block_parse(UCHAR *buffer, INT buffer_length, USHORT *tlv_type, + USHORT *tlv_tag_class, ULONG *tlv_length, + UCHAR **tlv_data, ULONG *header_length) +{ +UINT current_index = 0; +USHORT current_tag; +ULONG length; +ULONG length_bytes; + + + /* Check the buffer length. */ + if ((INT)current_index >= buffer_length) + { + return(NX_SNMP_ERROR_WRONGLENGTH); + } + + current_tag = buffer[current_index]; + + /* Handle multi-byte encoded tags. */ + if ((current_tag & NX_SNMP_ASN_TAG_MULTIBYTE_MASK) == NX_SNMP_ASN_TAG_MULTIBYTE_MASK) + { + return(NX_SNMP_MULTIBYTE_TAG_UNSUPPORTED); + } + else + { + *header_length = 1; + } + + /* Get the class of the tag so we can return it. */ + *tlv_tag_class = (USHORT)((current_tag & NX_SNMP_ASN_TAG_CLASS_MASK) >> 6); + + /* Make sure we have a valid tag class. */ + if (*tlv_tag_class == NX_SNMP_ASN_TAG_CLASS_PRIVATE) + { + /* The tag class is invalid, return error. */ + return(NX_SNMP_INVALID_TAG_CLASS); + } + + /* The caller actually handles what happens based on the tag type. */ + if (current_tag & NX_SNMP_ASN_TAG_CONSTRUCTED_MASK) + { + current_tag = current_tag & (USHORT)(~NX_SNMP_ASN_TAG_CONSTRUCTED_MASK); + } + + /* Clear out the class and constructed bits before returning the tag value. */ + *tlv_type = current_tag & NX_SNMP_ASN_TAG_MASK; + current_index++; + + /* Check the buffer length. */ + if ((INT)current_index >= buffer_length) + { + return(NX_SNMP_ERROR_WRONGLENGTH); + } + + if (current_tag == NX_SNMP_ANS1_NULL) + { + /* If tag is NULL, there is no length byte, just a value of zero, */ + *tlv_length = 1; + + /* Set the data pointer and return. */ + *tlv_data = &buffer[current_index]; + + return(NX_SUCCESS); + } + + /* Handle the length. */ + length = buffer[current_index]; + current_index++; + *header_length = *header_length + 1; + + /* Check for multi-byte length by looking at the top bit of the length byte. */ + if (length & 0x80) + { + /* Multi-byte length: + > 127, high bit is set, and lower 7 bits becomes the number of following bytes of *length* + so 841 bytes of Value is encoded as 0x82, 0x03, 0x49 (0x82 = 2 bytes of length, 0x0349 = 841). + */ + + /* Mask off top bit to get the number of bytes in length. */ + length_bytes = length & 0x7F; + length = 0; + + /* Check for length too big to handle. */ + if (length_bytes > 4) + { + + return(NX_SNMP_ASN1_LENGTH_TOO_LONG); + } + + /* Update header length. */ + *header_length = *header_length + length_bytes; + + /* Check the buffer length. */ + if ((INT)(current_index + length_bytes) > buffer_length) + { + return(NX_SNMP_ERROR_WRONGLENGTH); + } + + while (length_bytes > 0) + { + /* Shift length one byte up and add in next byte. */ + length <<= 8; + length += buffer[current_index]; + + /* Advance our index by one byte. */ + current_index++; + length_bytes--; + } + } + else + { + /* Single-byte length: + <= 127 (7 bits), length is the number of bytes of Value */ + *tlv_length = length; + } + + /* Set the length to return to caller. */ + *tlv_length = length; + + /* Check the buffer length. */ + if ((INT)current_index >= buffer_length) + { + return(NX_SNMP_ERROR_WRONGLENGTH); + } + + /* Now, we can set the tld value */ + *tlv_data = &buffer[current_index]; + + return(NX_SUCCESS); +} + + diff --git a/addons/snmp/nxd_snmp.h b/addons/snmp/nxd_snmp.h new file mode 100644 index 00000000..2e604aa7 --- /dev/null +++ b/addons/snmp/nxd_snmp.h @@ -0,0 +1,888 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** Simple Network Management Protocol (SNMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_snmp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Simple Network Management Protocol */ +/* (SNMP) component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_SNMP_H +#define NXD_SNMP_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Include necessary digest and encryption files. */ + +#include "nx_api.h" +#ifndef NX_SNMP_DISABLE_V3 +#include "nx_md5.h" +#include "nx_sha1.h" +#include "nx_des.h" +#endif + + +/* Disable SNMP V1 message processing. +#define NX_SNMP_DISABLE_V1 +*/ + +/* Disable SNMP V2 message processing. +#define NX_SNMP_DISABLE_V2 +*/ + +/* Disable SNMP V3 message processing. +#define NX_SNMP_DISABLE_V3 +*/ + +/* Default support of SNMP V2 to only V2C. +#define NX_SNMP_V2C_ONLY +*/ + +/* By default support for security (authentication and encryption) is enabled. To disable + it define this option. +#define NX_SNMP_NO_SECURITY +*/ + + +/* Define the SNMP ID. */ + +#define NX_SNMP_ID 0x534E4D50UL + + +/* Define SNMP UDP socket create options. */ + +#ifndef NX_SNMP_TYPE_OF_SERVICE +#define NX_SNMP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_SNMP_FRAGMENT_OPTION +#define NX_SNMP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_SNMP_TIME_TO_LIVE +#define NX_SNMP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_SNMP_AGENT_PRIORITY +#define NX_SNMP_AGENT_PRIORITY 16 +#endif + +#ifndef NX_SNMP_AGENT_TIMEOUT +#define NX_SNMP_AGENT_TIMEOUT (1 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_SNMP_MAX_OCTET_STRING +#define NX_SNMP_MAX_OCTET_STRING 255 +#else +#if NX_SNMP_MAX_OCTET_STRING < 23 +#error "NX_SNMP_MAX_OCTET_STRING should not be smaller than 23." +#endif +#endif + +#ifndef NX_SNMP_MAX_CONTEXT_STRING +#define NX_SNMP_MAX_CONTEXT_STRING 32 +#endif + +#ifndef NX_SNMP_MAX_USER_NAME +#define NX_SNMP_MAX_USER_NAME 64 +#endif + +#ifndef NX_SNMP_MAX_TRAP_NAME +#define NX_SNMP_MAX_TRAP_NAME 64 +#endif + + +#ifndef NX_SNMP_MAX_SECURITY_KEY +#define NX_SNMP_MAX_SECURITY_KEY 64 +#else +#if NX_SNMP_MAX_SECURITY_KEY < 20 +#error "NX_SNMP_MAX_SECURITY_KEY should not be smaller than 20." +#endif +#endif + +#ifndef NX_SNMP_MAX_TRAP_KEY +#define NX_SNMP_MAX_TRAP_KEY 64 +#endif + +#ifndef NX_SNMP_PACKET_SIZE +#define NX_SNMP_PACKET_SIZE 560 +#endif + + +/* Define the maximum number of packets that can be queued on the SNMP Agent's UDP Port. */ + +#define NX_SNMP_QUEUE_DEPTH 5 + +/* Define a symbol for indicating trap contains proprietary data (instead of just standard cold start, warm start etc. */ +#define NX_SNMP_TRAP_CUSTOM 0xFFFFFFFF + + +/* Define the SNMP versions supported. */ + +#define NX_SNMP_VERSION_1 0 +#define NX_SNMP_VERSION_2C 1 +#define NX_SNMP_VERSION_2 2 +#define NX_SNMP_VERSION_3 3 + +/* Define constants for ASN1 BER encoding */ + +#define NX_SNMP_ASN_TAG_CONSTRUCTED_MASK 0x20 /* If bit 6 is set, it is a constructed type. */ +#define NX_SNMP_ASN_TAG_MULTIBYTE_MASK 0x1F /* Some ASN1 tags are multi-byte. */ +#define NX_SNMP_ASN_TAG_CLASS_MASK 0xC0 /* Top 2 bits of tag are the "class". */ +#define NX_SNMP_ASN_TAG_MASK 0x1F /* Bottom 6 bits are the tag itself. */ + +/* Tag classes. Bits refer to bit locations in the tag octet. + * Note that "Application" and "Private" are not recommended for use and + * should probably never be encountered in SNMP. + * Class | Bit 7 | Bit 8 | + * --------------------------------------------- + * Universal | 0 | 0 | + * Application | 0 | 1 | + * Context-specific | 1 | 0 | + * Private | 1 | 1 | + */ +#define NX_SNMP_ASN_TAG_CLASS_UNIVERSAL 0x00 /* ASN.1 standard tag values. */ +#define NX_SNMP_ASN_TAG_CLASS_APPLICATION 0x01 /* (UNUSED) Application-specific tag values. */ +#define NX_SNMP_ASN_TAG_CLASS_CONTEXT 0x02 /* Context-specific tag values. */ +#define NX_SNMP_ASN_TAG_CLASS_PRIVATE 0x03 /* (UNUSED) Private tag values. */ + +/* Define the SNMP/ANS1 control characters. */ + +#define NX_SNMP_ANS1_SEQUENCE 0x30 /* ANS1 Code for SEQUENCE */ +#define NX_SNMP_ANS1_INTEGER 0x02 /* ANS1 Code for INTEGER */ +#define NX_SNMP_ANS1_BIT_STRING 0x03 /* ANS1 Code for BIT STRING */ +#define NX_SNMP_ANS1_OCTET_STRING 0x04 /* ANS1 Code for OCTET STRING */ +#define NX_SNMP_ANS1_NULL 0x05 /* ANS1 Code for NULL */ +#define NX_SNMP_ANS1_OBJECT_ID 0x06 /* ANS1 Code for OBJECT ID */ +#define NX_SNMP_ANS1_IP_ADDRESS 0x40 /* ANS1 Code for IP ADDRESS */ +#define NX_SNMP_ANS1_COUNTER 0x41 /* ANS1 Code for COUNTER */ +#define NX_SNMP_ANS1_GAUGE 0x42 /* ANS1 Code for GAUGE */ +#define NX_SNMP_ANS1_TIME_TICS 0x43 /* ANS1 Code for TIME TICS */ +#define NX_SNMP_ANS1_OPAQUE 0x44 /* ANS1 Code for OPAQUE */ +#define NX_SNMP_ANS1_NSAP_ADDRESS 0x45 /* ANS1 Code for NSAP ADDRESS */ +#define NX_SNMP_ANS1_COUNTER64 0x46 /* ANS1 Code for COUNTER64 */ +#define NX_SNMP_ANS1_UINTEGER32 0x47 /* ANS1 Code for UINTEGER32 */ +#define NX_SNMP_ANS1_NO_SUCH_OBJECT 0x80 /* ANS1 Code for No Such Object */ +#define NX_SNMP_ANS1_NO_SUCH_INSTANCE 0x81 /* ANS1 Code for No Such Instance */ +#define NX_SNMP_ANS1_END_OF_MIB_VIEW 0x82 /* ANS1 Code for End of MIB view */ +#define NX_SNMP_ANS1_GET_REQUEST 0xA0 /* ANS1 Code for SNMP GET */ +#define NX_SNMP_ANS1_GET_NEXT_REQUEST 0xA1 /* ANS1 Code for SNMP GET NEXT */ +#define NX_SNMP_ANS1_GET_RESPONSE 0xA2 /* ANS1 Code for SNMP GET RESPONSE */ +#define NX_SNMP_ANS1_SET_REQUEST 0xA3 /* ANS1 Code for SNMP SET */ +#define NX_SNMP_ANS1_TRAP_REQUEST 0xA4 /* ANS1 Code for SNMP TRAP */ +#define NX_SNMP_ANS1_GET_BULK_REQUEST 0xA5 /* ANS1 Code for SNMP GET BULK (v2) */ +#define NX_SNMP_ANS1_INFORM_REQUEST 0xA6 /* ANS1 Code for SNMP INFORM (v2) */ +#define NX_SNMP_ANS1_TRAP2_REQUEST 0xA7 /* ANS1 Code for SNMP TRAP (v2) */ +#define NX_SNMP_ANS1_REPORT_REQUEST 0xA8 /* ANS1 Code for SNMP REPORT (v3) */ +#define NX_SNMP_ANS1_MULTI_BYTES 0x80 /* ANS1 Bit for Multiple Bytes */ +#ifdef FEATURE_NX_IPV6 +#define NX_SNMP_ANS1_IPV6_ADDRESS NX_SNMP_ANS1_OCTET_STRING /* ANS1 Code for OCTET string */ +#endif +/* Define the SNMP application GET/GETNEXT/SET callback return error codes. */ + +#define NX_SNMP_SUCCESS 0 /* Everything is okay */ +#define NX_SNMP_ERROR_TOOBIG 1 /* Can't fit reply in outgoing message */ +#define NX_SNMP_ERROR_NOSUCHNAME 2 /* Object could not be found */ +#define NX_SNMP_ERROR_BADVALUE 3 /* Invalid value of set operation */ +#define NX_SNMP_ERROR_READONLY 4 /* Object is read only and cannot be set*/ +#define NX_SNMP_ERROR_GENERAL 5 /* General error */ +#define NX_SNMP_ERROR_NOACCESS 6 +#define NX_SNMP_ERROR_WRONGTYPE 7 +#define NX_SNMP_ERROR_WRONGLENGTH 8 +#define NX_SNMP_ERROR_WRONGENCODING 9 +#define NX_SNMP_ERROR_WRONGVALUE 10 +#define NX_SNMP_ERROR_NOCREATION 11 +#define NX_SNMP_ERROR_INCONSISTENTVALUE 12 +#define NX_SNMP_ERROR_RESOURCEUNAVAILABLE 13 +#define NX_SNMP_ERROR_COMMITFAILED 14 +#define NX_SNMP_ERROR_UNDOFAILED 15 +#define NX_SNMP_ERROR_AUTHORIZATION 16 +#define NX_SNMP_ERROR_NOTWRITABLE 17 +#define NX_SNMP_ERROR_INCONSISTENTNAME 18 +#define NX_SNMP_UNKNOWN_USERNAME 19 +#define NX_SNMP_UNSUPPORTED_AUTHENTICATION 20 +#define NX_SNMP_INVALID_PDU_ENCRYPTION 21 +#define NX_SNMP_INVALID_ENCRYPT_LENGTH 22 +#define NX_SNMP_MULTIBYTE_TAG_UNSUPPORTED 23 +#define NX_SNMP_INVALID_TAG_CLASS 24 +#define NX_SNMP_ASN1_LENGTH_TOO_LONG 25 + +/* Define SNMP Traps. */ + +#define NX_SNMP_TRAP_COLDSTART 0 +#define NX_SNMP_TRAP_WARMSTART 1 +#define NX_SNMP_TRAP_LINKDOWN 2 +#define NX_SNMP_TRAP_LINKUP 3 +#define NX_SNMP_TRAP_AUTHENTICATE_FAILURE 4 +#define NX_SNMP_TRAP_EGPNEIGHBORLOSS 5 +#define NX_SNMP_TRAP_ENTERPRISESPECIFIC 6 + + +/* Define SNMP requests for use by the agent request processing callback routine. */ + +#define NX_SNMP_GET_REQUEST NX_SNMP_ANS1_GET_REQUEST +#define NX_SNMP_GET_NEXT_REQUEST NX_SNMP_ANS1_GET_NEXT_REQUEST +#define NX_SNMP_SET_REQUEST NX_SNMP_ANS1_SET_REQUEST +#define NX_SNMP_GET_BULK_REQUEST NX_SNMP_ANS1_GET_BULK_REQUEST + + +/* Define SNMP object type definitions. These will be mapped to the internal ANS1 equivalents. */ + +#define NX_SNMP_INTEGER NX_SNMP_ANS1_INTEGER +#define NX_SNMP_BIT_STRING NX_SNMP_ANS1_BIT_STRING +#define NX_SNMP_OCTET_STRING NX_SNMP_ANS1_OCTET_STRING +#define NX_SNMP_NULL NX_SNMP_ANS1_NULL +#define NX_SNMP_OBJECT_ID NX_SNMP_ANS1_OBJECT_ID +#define NX_SNMP_IP_ADDRESS NX_SNMP_ANS1_IP_ADDRESS +#define NX_SNMP_COUNTER NX_SNMP_ANS1_COUNTER +#define NX_SNMP_GAUGE NX_SNMP_ANS1_GAUGE +#define NX_SNMP_TIME_TICS NX_SNMP_ANS1_TIME_TICS +#define NX_SNMP_OPAQUE NX_SNMP_ANS1_OPAQUE +#define NX_SNMP_NSAP_ADDRESS NX_SNMP_ANS1_NSAP_ADDRESS +#define NX_SNMP_COUNTER64 NX_SNMP_ANS1_COUNTER64 +#define NX_SNMP_UINTEGER32 NX_SNMP_ANS1_UINTEGER32 +#define NX_SNMP_NO_SUCH_OBJECT NX_SNMP_ANS1_NO_SUCH_OBJECT +#define NX_SNMP_NO_SUCH_INSTANCE NX_SNMP_ANS1_NO_SUCH_INSTANCE +#define NX_SNMP_END_OF_MIB_VIEW NX_SNMP_ANS1_END_OF_MIB_VIEW + + +/* Define return code constants. */ + +#define NX_SNMP_ERROR 0x100 /* SNMP internal error */ +#define NX_SNMP_NEXT_ENTRY 0x101 /* SNMP found next entry */ +#define NX_SNMP_ENTRY_END 0x102 /* SNMP end of entry */ +#define NX_SNMP_TIMEOUT 0x101 /* SNMP timeout occurred */ +#define NX_SNMP_FAILED 0x102 /* SNMP error */ +#define NX_SNMP_POOL_ERROR 0x103 /* SNMP packet pool size error */ +#define NX_SNMP_INVALID_IP_PROTOCOL_ERROR 0x104 /* Invalid packet IP version */ + +/* Define the SNMP Agent UDP port number */ + +#ifndef NX_SNMP_AGENT_PORT +#define NX_SNMP_AGENT_PORT 161 /* Port for SNMP Agent */ +#endif + +#ifndef NX_SNMP_MANAGER_TRAP_PORT +#define NX_SNMP_MANAGER_TRAP_PORT 162 /* Trap Port for SNMP Manager */ +#endif + + +/* Define SNMP v3 constants. */ + +#define NX_SNMP_USM_SECURITY_MODEL 3 /* Value for USM Security model */ +#define NX_SNMP_SECURITY_AUTHORIZE 0x1 /* Authorization required bit */ +#define NX_SNMP_SECURITY_PRIVACY 0x2 /* Privacy (encryption) required bit */ +#define NX_SNMP_SECURITY_REPORTABLE 0x4 /* Reportable bit */ + + +/* Define SNMP authentication/encryption key types. */ + +#define NX_SNMP_MD5_KEY 1 +#define NX_SNMP_SHA_KEY 2 +#define NX_SNMP_DES_DEY 3 +#define NX_SNMP_AES_KEY 4 /* Future expansion */ + + +/* Define SNMP USM digest size. */ + +#define NX_SNMP_DIGEST_SIZE 12 /* Size of SNMP authentication digest */ +#define NX_SNMP_MD5_DIGEST_SIZE 16 /* Size of pure MD5 digest */ +#define NX_SNMP_SHA_DIGEST_SIZE 20 /* Size of pure SHA digest */ +#define NX_SNMP_DIGEST_WORKING_SIZE 64 /* Size of keys for the digest routines */ + +#define NX_SNMP_TCP_TIMER_RATE NX_IP_PERIODIC_RATE/NX_TCP_TRANSMIT_TIMER_RATE + + +/* Define the key data types that will be used by the digest and/or encryption routines. */ + +typedef struct NX_SNMP_SECURITY_KEY_STRUCT +{ + + UINT nx_snmp_security_key_size; + UINT nx_snmp_security_key_type; + UCHAR nx_snmp_security_key[NX_SNMP_MAX_SECURITY_KEY]; + +} NX_SNMP_SECURITY_KEY; + + + +/* Define the SNMP Agent object data structure. This structure is used for holding a single + variable's value. It is passed between the SNMP Agent and the application callback functions + in order to get/set variables. */ + +typedef struct NX_SNMP_OBJECT_DATA_STRUCT +{ + + UINT nx_snmp_object_data_type; /* Type of SNMP data contained */ + LONG nx_snmp_object_data_msw; /* Most significant 32 bits */ + LONG nx_snmp_object_data_lsw; /* Least significant 32 bits */ + UINT nx_snmp_object_octet_string_size; /* Size of OCTET string */ + UCHAR nx_snmp_object_octet_string[NX_SNMP_MAX_OCTET_STRING + 1]; + +} NX_SNMP_OBJECT_DATA; + + +/* Define the SNMP Agent object list type that defines application objects to be included in the + trap calls. */ + +typedef struct NX_SNMP_TRAP_OBJECT_STRUCT +{ + + UCHAR *nx_snmp_object_string_ptr; + NX_SNMP_OBJECT_DATA *nx_snmp_object_data; +} NX_SNMP_TRAP_OBJECT; + + +/* Define the SNMP Agent data structure. */ + +typedef struct NX_SNMP_AGENT_STRUCT +{ + ULONG nx_snmp_agent_id; /* SNMP Agent ID */ + CHAR *nx_snmp_agent_name; /* Name of this SNMP Agent */ + NX_IP *nx_snmp_agent_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_snmp_agent_packet_pool_ptr; /* Pointer to SNMP agent packet pool */ + UINT nx_snmp_agent_current_version; /* Current SNMP Version */ + UINT nx_snmp_agent_request_get_type; /* Indicate if last request received is Get or Set type*/ + UINT nx_snmp_agent_interface_index; /* SNMP network interface index */ + UINT nx_snmp_agent_v1_enabled; /* SNMP agent enabled for V1 status */ + UINT nx_snmp_agent_v2_enabled; /* SNMP agent enabled for V2/V2C status */ + UINT nx_snmp_agent_v3_enabled; /* SNMP agent enabled for V3 status */ +#ifndef NX_SNMP_DISABLE_V3 + ULONG nx_snmp_agent_v3_message_id; /* SNMP v3 message id */ + ULONG nx_snmp_agent_v3_message_size; /* SNMP v3 message size */ + ULONG nx_snmp_agent_v3_message_security_type; /* SNMP v3 message security type */ + UCHAR nx_snmp_agent_v3_message_security_options; /* SNMP v3 message security flags */ + UCHAR nx_snmp_agent_v3_security_context_engine[NX_SNMP_MAX_CONTEXT_STRING]; /* Context engine */ + UINT nx_snmp_agent_v3_security_context_engine_size; /* SNMP v3 security context engine size */ + ULONG nx_snmp_agent_v3_security_engine_boots; /* SNMP v3 security engine boot count */ + ULONG nx_snmp_agent_v3_security_engine_boot_time; /* SNMP v3 security engine boot time */ + UCHAR nx_snmp_agent_v3_security_user_name[NX_SNMP_MAX_USER_NAME]; /* SNMPv3 security username */ + UINT nx_snmp_agent_v3_security_user_name_size; /* SNMP v3 security user name size */ + UCHAR nx_snmp_agent_v3_security_trap_name[NX_SNMP_MAX_TRAP_NAME]; /* SNMPv3 username to send trap messages */ + UINT nx_snmp_agent_v3_security_trap_name_size; /* SNMP v3 security username size for trap messages */ + UINT nx_snmp_agent_unsupported_sec_count; /* Count of reports with no security */ + UINT nx_snmp_agent_unknown_engineid_count; /* Count of unknown engine ID reports */ + UINT nx_snmp_agent_unknown_username_count; /* Count of no username reports */ + UINT nx_snmp_agent_mismatched_time_count; /* Count of time out of synch reports */ + UCHAR nx_snmp_agent_v3_security_authentication[NX_SNMP_MAX_SECURITY_KEY]; /* security authentication */ + UINT nx_snmp_agent_v3_security_authentication_size; /* SNMP v3 security authentication size */ + UCHAR nx_snmp_agent_v3_security_privacy[NX_SNMP_MAX_SECURITY_KEY];/* SNMP v3 security privacy */ + UINT nx_snmp_agent_v3_security_privacy_size; /* SNMP v3 security privacy size */ + UCHAR nx_snmp_agent_v3_trap_authentication[NX_SNMP_MAX_TRAP_KEY]; /* security authentication */ + UINT nx_snmp_agent_v3_trap_authentication_size; /* SNMPv3 trap message authentication size */ + UCHAR nx_snmp_agent_v3_trap_privacy[NX_SNMP_MAX_TRAP_KEY];/* SNMP v3 trap message privacy */ + UINT nx_snmp_agent_v3_trap_privacy_size; /* SNMP v3 trap message privacy size */ + UCHAR nx_snmp_agent_v3_context_engine[NX_SNMP_MAX_CONTEXT_STRING]; /* SNMP v3 context name */ + UINT nx_snmp_agent_v3_context_engine_size; /* SNMP v3 context engine size */ + UCHAR nx_snmp_agent_v3_context_name[NX_SNMP_MAX_CONTEXT_STRING]; /* SNMPv3 context name */ + UINT nx_snmp_agent_v3_context_name_size; /* SNMP v3 context engine size */ + UINT nx_snmp_agent_v3_context_engine_boots; /* SNMP v3 context engine boots */ + UINT nx_snmp_agent_v3_context_engine_boot_time; /* SNMP v3 context engine boot time */ + UINT nx_snmp_agent_v3_context_salt_counter; /* SNMP v3 context salt counter */ + NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_authentication_key; /* SNMP v3 authentication key */ + NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_auth_trap_key; /* SNMP v3 authentication key for traps */ + NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_privacy_key; /* SNMP v3 privacy key */ + NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_priv_trap_key; /* SNMP v3 privacy key for traps */ + NX_MD5 nx_snmp_agent_v3_md5_data; /* SNMP v3 MD5 authentication data */ + NX_SHA1 nx_snmp_agent_v3_sha_data; /* SNMP v3 SHA authentication data */ + NX_DES nx_snmp_agent_v3_des_data; /* SNMP v3 DES encryption data */ +#endif /* NX_SNMP_DISABLE_V3 */ + UCHAR nx_snmp_agent_current_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Received Community string */ + UCHAR nx_snmp_agent_private_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Agent's private community string */ + UCHAR nx_snmp_agent_public_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Agent's public community string */ + UCHAR nx_snmp_agent_current_octet_string[NX_SNMP_MAX_OCTET_STRING + 1]; /* Current SNMP Object ID*/ + NX_SNMP_OBJECT_DATA nx_snmp_agent_current_object_data; /* Current SNMP Object information */ + NXD_ADDRESS nx_snmp_agent_current_manager_ip; /* Current SNMP Manager IPv6/IPv4 address*/ + UINT nx_snmp_agent_current_manager_port; /* Current SNMP Manager UDP port */ + ULONG nx_snmp_agent_packets_received; /* Number of SNMP packets received */ + ULONG nx_snmp_agent_packets_sent; /* Number of SNMP packets sent */ + ULONG nx_snmp_agent_invalid_version; /* Number of invalid SNMP versions */ + ULONG nx_snmp_agent_total_get_variables; /* Number of variables to get */ + ULONG nx_snmp_agent_total_set_variables; /* Number of variables to set */ + ULONG nx_snmp_agent_too_big_errors; /* Number of too big errors sent */ + ULONG nx_snmp_agent_no_such_name_errors; /* Number of no such name errors sent */ + ULONG nx_snmp_agent_bad_value_errors; /* Number of bad value errors sent */ + ULONG nx_snmp_agent_general_errors; /* Number of general errors sent */ + ULONG nx_snmp_agent_request_errors; /* Number of errors on SNMP requests */ + ULONG nx_snmp_agent_get_requests; /* Number of GET requests */ + ULONG nx_snmp_agent_getnext_requests; /* Number of GETNEXT requests */ + ULONG nx_snmp_agent_getbulk_requests; /* Number of GETBULK requests */ + ULONG nx_snmp_agent_set_requests; /* Number of SET requests */ + ULONG nx_snmp_agent_reports_sent; /* Number of DISCOVERY requests */ + ULONG nx_snmp_agent_internal_errors; /* Number of internal errors detected */ + ULONG nx_snmp_agent_traps_sent; /* Number of traps sent */ + ULONG nx_snmp_agent_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_snmp_agent_total_bytes_received; /* Number of total bytes received */ + ULONG nx_snmp_agent_unknown_requests; /* Number of unknown commands received */ + ULONG nx_snmp_agent_invalid_packets; /* Number of invalid SNMP packets */ + ULONG nx_snmp_agent_allocation_errors; /* Number of allocation errors */ + ULONG nx_snmp_agent_username_errors; /* Number of community/username errors */ + ULONG nx_snmp_agent_authentication_errors; /* Number of authentication errors */ + ULONG nx_snmp_agent_privacy_errors; /* Number of privacy errors */ + ULONG nx_snmp_agent_getresponse_sent; /* Number of getresponse sent */ + NX_UDP_SOCKET nx_snmp_agent_socket; /* SNMP Server UDP socket */ + TX_THREAD nx_snmp_agent_thread; /* SNMP agent thread */ + UINT (*nx_snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); + UINT (*nx_snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); + UINT (*nx_snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); + UINT (*nx_snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username); + +} NX_SNMP_AGENT; + + + +#ifndef NX_SNMP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_snmp_agent_authenticate_key_use _nx_snmp_agent_authenticate_key_use +#define nx_snmp_agent_auth_trap_key_use _nx_snmp_agent_auth_trap_key_use +#define nx_snmp_agent_community_get _nx_snmp_agent_community_get +#define nx_snmp_agent_context_engine_set _nx_snmp_agent_context_engine_set +#define nx_snmp_agent_context_name_set _nx_snmp_agent_context_name_set +#define nx_snmp_agent_v3_context_boots_set _nx_snmp_agent_v3_context_boots_set +#define nx_snmp_agent_create _nx_snmp_agent_create +#define nx_snmp_agent_delete _nx_snmp_agent_delete +#define nx_snmp_agent_request_get_type_test _nx_snmp_agent_request_get_type_test +#define nx_snmp_agent_current_version_get _nx_snmp_agent_current_version_get +#define nx_snmp_agent_version_set _nx_snmp_agent_version_set +#define nx_snmp_agent_set_interface _nx_snmp_agent_set_interface +#ifndef NX_SNMP_DISABLE_V3 +#define nx_snmp_agent_md5_key_create _nx_snmp_agent_md5_key_create +#define nx_snmp_agent_md5_key_create_extended _nx_snmp_agent_md5_key_create_extended +#define nx_snmp_agent_privacy_key_use _nx_snmp_agent_privacy_key_use +#define nx_snmp_agent_sha_key_create _nx_snmp_agent_sha_key_create +#define nx_snmp_agent_sha_key_create_extended _nx_snmp_agent_sha_key_create_extended +#endif +#define nx_snmp_agent_priv_trap_key_use _nx_snmp_agent_priv_trap_key_use +#define nx_snmp_agent_private_string_set _nx_snmp_agent_private_string_set +#define nx_snmp_agent_public_string_set _nx_snmp_agent_public_string_set +#define nx_snmp_agent_public_string_test _nx_snmp_agent_public_string_test +#define nx_snmp_agent_private_string_test _nx_snmp_agent_private_string_test +#define nx_snmp_agent_start _nx_snmp_agent_start +#define nx_snmp_agent_stop _nx_snmp_agent_stop +#define nx_snmp_agent_trap_send _nx_snmp_agent_trap_send +#define nx_snmp_agent_trapv2_send _nx_snmp_agent_trapv2_send +#define nx_snmp_agent_trapv3_send _nx_snmp_agent_trapv3_send +#define nxd_snmp_agent_trap_send _nxd_snmp_agent_trap_send +#define nxd_snmp_agent_trapv2_send _nxd_snmp_agent_trapv2_send +#define nxd_snmp_agent_trapv3_send _nxd_snmp_agent_trapv3_send +#define nx_snmp_object_compare _nx_snmp_object_compare +#define nx_snmp_object_compare_extended _nx_snmp_object_compare_extended +#define nx_snmp_object_copy _nx_snmp_object_copy +#define nx_snmp_object_copy_extended _nx_snmp_object_copy_extended +#define nx_snmp_object_counter_get _nx_snmp_object_counter_get +#define nx_snmp_object_counter_set _nx_snmp_object_counter_set +#define nx_snmp_object_counter64_get _nx_snmp_object_counter64_get +#define nx_snmp_object_counter64_set _nx_snmp_object_counter64_set +#define nx_snmp_object_end_of_mib _nx_snmp_object_end_of_mib +#define nx_snmp_object_gauge_get _nx_snmp_object_gauge_get +#define nx_snmp_object_gauge_set _nx_snmp_object_gauge_set +#define nx_snmp_object_id_get _nx_snmp_object_id_get +#define nx_snmp_object_id_set _nx_snmp_object_id_set +#define nx_snmp_object_integer_get _nx_snmp_object_integer_get +#define nx_snmp_object_integer_set _nx_snmp_object_integer_set +#define nx_snmp_object_ip_address_get _nx_snmp_object_ip_address_get +#define nx_snmp_object_ip_address_set _nx_snmp_object_ip_address_set +#ifdef FEATURE_NX_IPV6 +#define nx_snmp_object_ipv6_address_get _nx_snmp_object_ipv6_address_get +#define nx_snmp_object_ipv6_address_set _nx_snmp_object_ipv6_address_set +#endif +#define nx_snmp_object_no_instance _nx_snmp_object_no_instance +#define nx_snmp_object_not_found _nx_snmp_object_not_found +#define nx_snmp_object_octet_string_get _nx_snmp_object_octet_string_get +#define nx_snmp_object_octet_string_set _nx_snmp_object_octet_string_set +#define nx_snmp_object_string_get _nx_snmp_object_string_get +#define nx_snmp_object_string_set _nx_snmp_object_string_set +#define nx_snmp_object_timetics_get _nx_snmp_object_timetics_get +#define nx_snmp_object_timetics_set _nx_snmp_object_timetics_set +#define nx_snmp_agent_trapv2_oid_send _nx_snmp_agent_trapv2_oid_send +#define nx_snmp_agent_trapv3_oid_send _nx_snmp_agent_trapv3_oid_send + + +#else + +/* Services with error checking. */ + +#define nx_snmp_agent_authenticate_key_use _nxe_snmp_agent_authenticate_key_use +#define nx_snmp_agent_auth_trap_key_use _nxe_snmp_agent_auth_trap_key_use +#define nx_snmp_agent_community_get _nxe_snmp_agent_community_get +#define nx_snmp_agent_context_engine_set _nxe_snmp_agent_context_engine_set +#define nx_snmp_agent_context_name_set _nxe_snmp_agent_context_name_set +#define nx_snmp_agent_v3_context_boots_set _nxe_snmp_agent_v3_context_boots_set +#define nx_snmp_agent_create _nxe_snmp_agent_create +#define nx_snmp_agent_delete _nxe_snmp_agent_delete +#define nx_snmp_agent_request_get_type_test _nxe_snmp_agent_request_get_type_test +#define nx_snmp_agent_current_version_get _nxe_snmp_agent_current_version_get +#define nx_snmp_agent_version_set _nxe_snmp_agent_version_set +#define nx_snmp_agent_set_interface _nxe_snmp_agent_set_interface +#ifndef NX_SNMP_DISABLE_V3 +#define nx_snmp_agent_md5_key_create _nxe_snmp_agent_md5_key_create +#define nx_snmp_agent_md5_key_create_extended _nxe_snmp_agent_md5_key_create_extended +#define nx_snmp_agent_sha_key_create _nxe_snmp_agent_sha_key_create +#define nx_snmp_agent_sha_key_create_extended _nxe_snmp_agent_sha_key_create_extended +#define nx_snmp_agent_privacy_key_use _nxe_snmp_agent_privacy_key_use +#define nx_snmp_agent_priv_trap_key_use _nxe_snmp_agent_priv_trap_key_use +#endif +#define nx_snmp_agent_private_string_set _nxe_snmp_agent_private_string_set +#define nx_snmp_agent_public_string_set _nxe_snmp_agent_public_string_set +#define nx_snmp_agent_private_string_test _nxe_snmp_agent_private_string_test +#define nx_snmp_agent_public_string_test _nxe_snmp_agent_public_string_test +#define nx_snmp_agent_start _nxe_snmp_agent_start +#define nx_snmp_agent_stop _nxe_snmp_agent_stop +#define nx_snmp_agent_trap_send _nxe_snmp_agent_trap_send +#define nx_snmp_agent_trapv2_send _nxe_snmp_agent_trapv2_send +#define nx_snmp_agent_trapv3_send _nxe_snmp_agent_trapv3_send +#define nxd_snmp_agent_trap_send _nxde_snmp_agent_trap_send +#define nxd_snmp_agent_trapv2_send _nxde_snmp_agent_trapv2_send +#define nxd_snmp_agent_trapv3_send _nxde_snmp_agent_trapv3_send +#define nx_snmp_object_compare _nxe_snmp_object_compare +#define nx_snmp_object_compare_extended _nxe_snmp_object_compare_extended +#define nx_snmp_object_copy _nxe_snmp_object_copy +#define nx_snmp_object_copy_extended _nxe_snmp_object_copy_extended +#define nx_snmp_object_counter_get _nxe_snmp_object_counter_get +#define nx_snmp_object_counter_set _nxe_snmp_object_counter_set +#define nx_snmp_object_counter64_get _nxe_snmp_object_counter64_get +#define nx_snmp_object_counter64_set _nxe_snmp_object_counter64_set +#define nx_snmp_object_end_of_mib _nxe_snmp_object_end_of_mib +#define nx_snmp_object_gauge_get _nxe_snmp_object_gauge_get +#define nx_snmp_object_gauge_set _nxe_snmp_object_gauge_set +#define nx_snmp_object_id_get _nxe_snmp_object_id_get +#define nx_snmp_object_id_set _nxe_snmp_object_id_set +#define nx_snmp_object_integer_get _nxe_snmp_object_integer_get +#define nx_snmp_object_integer_set _nxe_snmp_object_integer_set +#define nx_snmp_object_ip_address_get _nxe_snmp_object_ip_address_get +#define nx_snmp_object_ip_address_set _nxe_snmp_object_ip_address_set +#ifdef FEATURE_NX_IPV6 +#define nx_snmp_object_ipv6_address_get _nxe_snmp_object_ipv6_address_get +#define nx_snmp_object_ipv6_address_set _nxe_snmp_object_ipv6_address_set +#endif +#define nx_snmp_object_no_instance _nxe_snmp_object_no_instance +#define nx_snmp_object_not_found _nxe_snmp_object_not_found +#define nx_snmp_object_octet_string_get _nxe_snmp_object_octet_string_get +#define nx_snmp_object_octet_string_set _nxe_snmp_object_octet_string_set +#define nx_snmp_object_string_get _nxe_snmp_object_string_get +#define nx_snmp_object_string_set _nxe_snmp_object_string_set +#define nx_snmp_object_timetics_get _nxe_snmp_object_timetics_get +#define nx_snmp_object_timetics_set _nxe_snmp_object_timetics_set +#define nx_snmp_agent_trapv2_oid_send _nxe_snmp_agent_trapv2_oid_send +#define nx_snmp_agent_trapv3_oid_send _nxe_snmp_agent_trapv3_oid_send + + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +UINT nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +UINT nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); +UINT nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); +UINT nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); +UINT nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); +UINT nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), + UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); +UINT nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); +UINT nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); +UINT nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); +UINT nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); +UINT nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); +UINT nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); +UINT nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); +UINT nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); +UINT nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); +UINT nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); +UINT nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); +UINT nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT nx_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); +UINT nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); +UINT nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); +UINT nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); +UINT nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +#ifdef FEATURE_NX_IPV6 +UINT nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +#endif +UINT nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); +UINT nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); + + + +#else + +/* SNMP source code is being compiled, do not perform any API mapping. */ + +UINT _nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nxe_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nxe_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +#ifndef NX_SNMP_DISABLE_V3 +UINT _nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nxe_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nxe_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nxe_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nxe_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); +UINT _nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nxe_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +UINT _nxe_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); +#endif +UINT _nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); +UINT _nxe_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); +UINT _nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); +UINT _nxe_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); +UINT _nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); +UINT _nxe_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); +UINT _nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); +UINT _nxe_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); +UINT _nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), + UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); +UINT _nxe_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), + UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), + UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); +UINT _nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); +UINT _nxe_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); +UINT _nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); +UINT _nxe_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); +UINT _nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); +UINT _nxe_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); +UINT _nxe_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); +UINT _nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); +UINT _nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); +UINT _nxe_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); +UINT _nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); +UINT _nxe_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); +UINT _nxe_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); +UINT _nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); +UINT _nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); +UINT _nxe_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); +UINT _nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); +UINT _nxe_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); +UINT _nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); +UINT _nxe_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); +UINT _nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); +UINT _nxe_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); +UINT _nxe_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxe_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxe_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxe_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxe_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxde_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxde_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxde_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxde_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nxde_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); +UINT _nx_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); +UINT _nxe_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); +UINT _nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); +UINT _nxe_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); +UINT _nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); +UINT _nxe_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); +UINT _nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); +UINT _nxe_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); +UINT _nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +#ifdef FEATURE_NX_IPV6 +UINT _nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +#endif +UINT _nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); +UINT _nxe_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); +UINT _nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); +UINT _nxe_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); + + +/* Define internal SNMP routines. */ + +VOID _nx_snmp_agent_thread_entry(ULONG snmp_agent_address); +UINT _nx_snmp_utility_community_get(UCHAR *buffer_ptr, UCHAR *community_string, INT buffer_length); +UINT _nx_snmp_utility_community_set(UCHAR *buffer_ptr, UCHAR *community_string, UCHAR *buffer_end); +UINT _nx_snmp_utility_error_info_get(UCHAR *buffer_ptr, UINT *error_code, UINT *error_index, INT buffer_length); +UINT _nx_snmp_utility_error_info_set(UCHAR *buffer_ptr, UINT error_code, UINT error_index, UCHAR *buffer_end); +UINT _nx_snmp_utility_object_id_get(UCHAR *buffer_ptr, UCHAR *object_string, INT buffer_length); +UINT _nx_snmp_utility_object_id_set(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end); +UINT _nx_snmp_utility_object_id_set_1byte(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end); +UINT _nx_snmp_utility_object_data_get(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, INT buffer_length); +UINT _nx_snmp_utility_object_data_set(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, UCHAR *buffer_end); +UINT _nx_snmp_utility_octet_get(UCHAR *buffer_ptr, UCHAR *octet_string, UINT max_octet_length, UINT *octet_length, INT buffer_length); +UINT _nx_snmp_utility_octet_set(UCHAR *buffer_ptr, UCHAR *octet_string, UINT octet_length, UCHAR *buffer_end); +UINT _nx_snmp_utility_sequence_get(UCHAR *buffer_ptr, UINT *sequence_value, INT buffer_length); +UINT _nx_snmp_utility_sequence_set(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end); +UINT _nx_snmp_utility_sequence_set_1byte(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end); +UINT _nx_snmp_utility_request_id_get(UCHAR *buffer_ptr, ULONG *request_id, INT buffer_length); +UINT _nx_snmp_utility_request_id_set(UCHAR *buffer_ptr, ULONG request_id, UCHAR *buffer_end); +UINT _nx_snmp_utility_request_type_get(UCHAR *buffer_ptr, UINT *request_type, UINT *request_length, INT buffer_length); +UINT _nx_snmp_utility_request_type_set_1byte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end); +UINT _nx_snmp_utility_request_type_set_multibyte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end); +UINT _nx_snmp_utility_version_get(UCHAR *buffer_ptr, UINT *snmp_version, INT buffer_length); +UINT _nx_snmp_utility_version_set(UCHAR *buffer_ptr, UINT snmp_version, UCHAR *buffer_end); +UINT _nx_snmp_utility_tlv_block_parse(UCHAR *buffer, INT buffer_length, USHORT *tlv_type, USHORT *tlv_tag_class, ULONG *tlv_length, UCHAR **tlv_data, ULONG *header_length); +VOID _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, UCHAR *error_string_ptr, UINT status, UINT objects); +VOID _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); +VOID _nx_snmp_version_2_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); +VOID _nx_snmp_version_3_report_send(NX_SNMP_AGENT *agent_ptr, UCHAR *buffer_ptr, UINT discovery_response, INT buffer_length); +VOID _nx_snmp_version_3_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); +UINT _nx_snmp_agent_encrypt_pdu(NX_SNMP_AGENT *agent_ptr, UINT *response_pdu_length, UINT *response_sequence_length, UCHAR *response_encryption_size_ptr, + UCHAR **response_sequence_ptr, UCHAR *response_sequence_buffer_end, UCHAR **response_buffer_ptr,UCHAR *response_privacy_ptr); +UINT _nx_snmp_agent_add_auth_parameter(NX_SNMP_AGENT *agent_ptr, NX_PACKET *response_packet_ptr, UCHAR *response_authentication_ptr); +UINT _nx_snmp_agent_decrypt_pdu(NX_SNMP_AGENT *agent_ptr, UCHAR **buffer_ptr, UCHAR *response_buffer_ptr, UCHAR **response_encryption_size_ptr, UINT *response_length, INT buffer_length); +VOID _nx_snmp_agent_security_response_status(NX_SNMP_AGENT *agent_ptr, UINT *authenticate, UINT *encryption, UINT *send_reply); + + +#endif /* NX_SNMP_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_SNMP_H */ + diff --git a/addons/sntp/nxd_sntp_client.c b/addons/sntp/nxd_sntp_client.c new file mode 100644 index 00000000..ccaf4967 --- /dev/null +++ b/addons/sntp/nxd_sntp_client.c @@ -0,0 +1,6362 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX SNTP Client Component */ +/** */ +/** Simple Network Time Protocol (SNTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_sntp_client.c PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Simple Network Time Protocol (SNTP) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#define NX_SNTP_SOURCE_CODE + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +#include "nx_api.h" +#include "nx_udp.h" + +#include "nx_ipv4.h" +#include "nxd_sntp_client.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_ipv6.h" +#endif + + +#include + +extern TX_THREAD *_tx_thread_current_ptr; +extern TX_THREAD _tx_timer_thread; +extern volatile ULONG _tx_thread_system_state; + +TX_EVENT_FLAGS_GROUP nx_sntp_client_events; + +static UINT _nx_sntp_client_number_to_ascii(CHAR *buffer_ptr, UINT buffer_size, UINT number); + +/* Define internal time variables for offsets between + receipt of SNTP packet and application to + SNTP Client local time. */ +static ULONG send_timerticks = 0; +static ULONG receive_timerticks = 0; +static ULONG process_timerticks = 0; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the SNTP client create */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* ip_ptr Pointer to client IP instance */ +/* iface_index Index of SNTP network interface */ +/* packet_pool_ptr Pointer to client packet pool */ +/* socket_ptr Pointer to client UDP socket */ +/* leap_second_handler Pointer to leap second handler */ +/* random_number_generator Random number generator callback */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* NX_INVALID_INTERFACE Invalid network interface */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_create Actual SNTP client create service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, + UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), + UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), + VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + /* Check for invalid network interface input. */ + if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + + return NX_INVALID_INTERFACE; + } + + /* Call the actual client create service. */ + status = _nx_sntp_client_create(client_ptr, ip_ptr, iface_index, packet_pool_ptr, + leap_second_handler, kiss_of_death_handler, random_number_generator); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a SNTP client with the input NetX and SNTP */ +/* parameters. Note the host application must initialize and start the */ +/* SNTP client using the nx_sntp_broadcast/unicast_initialize and */ +/* nx_sntp_run_broadcast/unicast services to receive SNTP time updates.*/ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to client struct */ +/* ip_ptr Pointer to client IP instance */ +/* iface_index Index of SNTP network interface */ +/* packet_pool_ptr Pointer to client packet pool */ +/* socket_ptr Pointer to client UDP socket */ +/* leap_second_handler Pointer to leap second handler */ +/* random_number_generator Random number generator callback */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD */ +/* Invalid packet pool payload */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_create Create ThreadX timer service */ +/* tx_timer_delete Delete ThreadX timer service */ +/* tx_mutex_create Create ThreadX mutex service */ +/* tx_mutex_delete Delete ThreadX mutex service */ +/* nx_udp_socket_create Create the SNTP Client socket */ +/* nx_udp_socket_delete Delete the SNTP Client socket */ +/* nx_udp_socket_bind Bind the SNTP Client to SNTP port */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, + UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), + UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), + VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)) +{ + +UINT status; + + + /* Null the members of NX_SNTP_CLIENT. */ + memset(client_ptr, 0, sizeof(NX_SNTP_CLIENT)); + + /* Set the Client ID to indicate the SNTP client thread is ready. */ + client_ptr -> nx_sntp_client_id = NXD_SNTP_ID; + + /* Set the IP instance. */ + client_ptr -> nx_sntp_client_ip_ptr = ip_ptr; + + /* Set the SNTP network interface. */ + client_ptr -> nx_sntp_client_interface_index = iface_index; + + /* Check for minimal packet size requirement. */ +#ifndef NX_DISABLE_IPV4 + if (packet_pool_ptr -> nx_packet_pool_payload_size < + (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) + { + + return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; + } +#endif /* NX_DISABLE_IPV4 */ + + + /* This only assures IPv4 packets will work. We do not know yet if the Client expects to receive + SNTP packets over ipv6 networks. When sending packets, the SNTP Client will have set its + SNTP server from which the IP type will be determined. However, for receiving packets, + it is up to the host to ensure its packet payload will be large enough for IPv6 packets: + + sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE) + 40 bytes 8 bytes 48 bytes + */ + + client_ptr -> nx_sntp_client_packet_pool_ptr = packet_pool_ptr; + + /* Create a udp socket to receive SNTP time data. */ + status = nx_udp_socket_create(client_ptr -> nx_sntp_client_ip_ptr, &(client_ptr -> nx_sntp_client_udp_socket), + NX_SNTP_CLIENT_UDP_SOCKET_NAME, NX_IP_NORMAL, + NX_FRAGMENT_OKAY, NX_SNTP_CLIENT_TIME_TO_LIVE, + NX_SNTP_CLIENT_MAX_QUEUE_DEPTH); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Register a receive notify callback. */ + status = nx_udp_socket_receive_notify(&(client_ptr -> nx_sntp_client_udp_socket), _nx_sntp_client_receive_notify); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + return status; + } + + /* Set callback for leap second handler (optional). */ + client_ptr -> leap_second_handler = leap_second_handler; + + /* Set callback for kiss of death server packet handler (optional). */ + client_ptr -> kiss_of_death_handler = kiss_of_death_handler; + + /* Set callback for random number generator (Only applicable for unicast clients + configured for random wait on startup). */ + client_ptr -> random_number_generator = random_number_generator; + + /* Create the SNTP update timeout timer. */ + status = tx_timer_create(&client_ptr -> nx_sntp_update_timer, "SNTP Client Update Timer", + _nx_sntp_client_update_timeout_entry, (ULONG)client_ptr, + (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL), + (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL), TX_NO_ACTIVATE); + + /* Check for error. */ + if (status != TX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Return error status. */ + return(status); + } + + /* Create the SNTP mutex. */ + status = tx_mutex_create(&(client_ptr -> nx_sntp_client_mutex), "NetX SNTP Client Mutex", TX_NO_INHERIT); + + /* Determine if the semaphore creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Delete the timer. */ + tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); + + /* No, return error status. */ + return(status); + } + + /* Create the SNTP event flag group. */ + status = tx_event_flags_create(&nx_sntp_client_events, "NetX SNTP Client Events"); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Delete the timer. */ + tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); + + /* Delete the Client mutex. */ + tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex); + + /* Error present, return error code. */ + return(status); + } + + /* Create the SNTP Client processing thread. */ + status = tx_thread_create(&(client_ptr -> nx_sntp_client_thread), "NetX SNTP Client", _nx_sntp_client_thread_entry, (ULONG)client_ptr, + client_ptr -> nx_sntp_client_thread_stack, NX_SNTP_CLIENT_THREAD_STACK_SIZE, + NX_SNTP_CLIENT_THREAD_PRIORITY, NX_SNTP_CLIENT_PREEMPTION_THRESHOLD, 1, TX_DONT_START); + + /* Determine if the thread creation was successful. */ + if (status != NX_SUCCESS) + { + + /* Delete the mutex. */ + tx_mutex_delete(&(client_ptr -> nx_sntp_client_mutex)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Delete the timer. */ + tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&nx_sntp_client_events); + + /* No, return error status. */ + return(status); + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors on the client delete service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer parameter */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_delete Actual SNTP client delete service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_delete(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for the validity of input parameter. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_sntp_client_id != NXD_SNTP_ID)) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual client create service. */ + status = _nx_sntp_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created SNTP Client and releases */ +/* ThreadX and NetX resources held by the Client. */ +/* */ +/* Note that it is the application's responsibility to delete/release */ +/* the Client packet pool. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_delete Delete ThreadX timer service */ +/* tx_mutex_delete Delete ThreadX mutex service */ +/* tx_timer_deactivate Deschedule ThreadX timer */ +/* nx_udp_socket_unbind Release NetX UDP socket port */ +/* nx_udp_socket_delete Delete NetX UDP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_delete(NX_SNTP_CLIENT *client_ptr) +{ + + /* Suspend the SNTP Client thread. */ + tx_thread_suspend(&client_ptr -> nx_sntp_client_thread); + + /* Terminate SNTP Client thread. */ + tx_thread_terminate(&client_ptr -> nx_sntp_client_thread); + + /* Delete SNTP Client thread. */ + tx_thread_delete(&client_ptr -> nx_sntp_client_thread); + + /* Delete the Client mutex. */ + tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex); + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + /* Delete the update timer. */ + tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); + + /* Make sure the socket is in an unbound state. */ + nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Ok to delete the UDP socket. */ + nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Delete the Client event flags group. */ + tx_event_flags_delete(&nx_sntp_client_events); + + /* Return success status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_update_timeout_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decrements the Client's time remaining since it last */ +/* received a time update. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX ThreadX timer callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_update_timeout_entry(ULONG info) +{ + +NX_SNTP_CLIENT *client_ptr; + + + client_ptr = (NX_SNTP_CLIENT *)info; + + /* Is the Client's time remaining large enough to decrement by the timeout interval? */ + if (client_ptr -> nx_sntp_update_time_remaining >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL)) + { + + /* Yes; ok to decrement time remaining. */ + client_ptr -> nx_sntp_update_time_remaining -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL); + } + else + { + /* No, set the time remaining to NULL. */ + client_ptr -> nx_sntp_update_time_remaining = 0; + } + + /* Update time elapsed. */ + client_ptr -> nx_sntp_client_local_ntp_time_elapsed += NX_SNTP_UPDATE_TIMEOUT_INTERVAL; + + /* Is the client operating in unicast? */ + if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) + { + + /* Yes; Update the time remaining till it is time to poll the SNTP server. */ + if (client_ptr -> nx_sntp_client_unicast_poll_interval >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL)) + { + client_ptr -> nx_sntp_client_unicast_poll_interval -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL); + } + else + { + + /* Time is up. Client should send out another update request. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = 0; + } + } + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_create_time_request_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts NTP time data from the input buffer into a */ +/* unicast time data and copies into the supplied packet buffer. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* packet_ptr Pointer to time update packet */ +/* time_message_ptr Pointer to time request */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_send_unicast_request Send unicast request to server */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, + NX_SNTP_TIME_MESSAGE *time_message_ptr) +{ + NX_PARAMETER_NOT_USED(client_ptr); + + if (40u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) + { + return(NX_SIZE_ERROR); + } + + /* Clear packet data. */ + memset(packet_ptr -> nx_packet_append_ptr, 0, 40); + + *(packet_ptr -> nx_packet_append_ptr) = (UCHAR)(time_message_ptr -> flags); + + /* Skip to transmit time; all other fields are not used for a client unicast request. */ + packet_ptr -> nx_packet_append_ptr += 40; + packet_ptr -> nx_packet_length += 40; + + /* Copy the transmit time stamp from time request into the packet buffer. */ + time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0]; + time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1]; + + /* Now copy the data to the buffer. */ + *((ULONG*)(packet_ptr -> nx_packet_append_ptr)) = (ULONG)(time_message_ptr -> transmit_time.seconds); + *((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4)) = (ULONG)(time_message_ptr -> transmit_time.fraction); + + /* Change endian to network order. */ + NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr))); + NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4))); + + packet_ptr -> nx_packet_append_ptr += 8; + packet_ptr -> nx_packet_length += 8; + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_sntp_client_initialize_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the service that */ +/* initializes the Client for unicast service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* unicast_time_server Pointer to unicast server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server) +{ + +UINT status; + + + /* Check pointer input. */ + if ((client_ptr == NX_NULL) || (unicast_time_server == NX_NULL)) + { + + /* Return error status. */ + return NX_PTR_ERROR; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual Client for initialize unicast service. */ + status = _nxd_sntp_client_initialize_unicast(client_ptr, unicast_time_server); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_sntp_client_initialize_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the Client to operate in unicast mode with the*/ +/* supplied IPv4 or IPv6 SNTP server as the primary (current) server. */ +/* */ +/* For adding IPv4 and IPv6 SNTP servers to the unicast server list, */ +/* use the nxd_sntp_client_duo_add_unicast_server_to_list service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* unicast_poll_interval Interval between update requests */ +/* unicast_time_server Pointer to unicast server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_PARAM_ERROR Invalid server list input */ +/* */ +/* CALLS */ +/* */ +/* memset Copy data to area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server) +{ + + + /* Set the Client polling interval. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE); + + /* Initialize the number of times we've increased the backoff rate to zero. */ + client_ptr -> nx_sntp_client_backoff_count = 0; + + /* Clear the Client's current server IP. */ + memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS)); + +#ifdef FEATURE_NX_IPV6 + /* Set as the Client's unicast server. */ + COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_unicast_time_server); + + /* Set as the Client's current SNTP server. */ + COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_server_ip_address); +#else + /* Set as the Client's unicast server. */ + client_ptr -> nx_sntp_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_unicast_time_server.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4; + + /* Set as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4; + +#endif /* FEATURE_NX_IPV6 */ + + + /* Set the Client operational mode to unicast mode. */ + client_ptr -> nx_sntp_client_protocol_mode = UNICAST_MODE; + + /* Indicate the Client task is ready to run! */ + client_ptr -> nx_sntp_client_unicast_initialized = NX_TRUE; + + /* Initialize the server status as good (receiving updates). */ + client_ptr -> nx_sntp_valid_server_status = NX_TRUE; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_initialize_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors on the initialize Client for unicast*/ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* unicast_time_server SNTP unicast server to use */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + /* Check input parameters. */ + if (client_ptr == NX_NULL) + { + + /* Return error status. */ + return NX_PTR_ERROR; + } + + if (unicast_time_server == 0x0) + { + return NX_INVALID_PARAMETERS; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + + /* Call the actual Client for initialize unicast service. */ + status = _nx_sntp_client_initialize_unicast(client_ptr, unicast_time_server); + + /* Return completion status. */ + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(unicast_time_server); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_initialize_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the input address to the NetX Duo address */ +/* format and calls the 'duo' equivalent service, nxd_sntp_client_ */ +/* _initialize_unicast. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* unicast_time_server SNTP unicast server to use */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* _nxd_sntp_client_initialize_unicast */ +/* Duo initialize unicast service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS duo_unicast_time_server; + + + + duo_unicast_time_server.nxd_ip_address.v4 = unicast_time_server; + duo_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4; + + status = _nxd_sntp_client_initialize_unicast(client_ptr, &duo_unicast_time_server); + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(unicast_time_server); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_run_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the run unicast service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* _nx_sntp_client_run_unicast Actual run unicast service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual run unicast service. */ + status = _nx_sntp_client_run_unicast(client_ptr); + + /* Return actual completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_run_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the SNTP Client for unicast SNTP processing */ +/* by activating the SNTP timer and main processing thread. The Client */ +/* is checked for being initialized for unicast SNTP and if it is */ +/* not, the function returns an error status. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */ +/* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_activate Start the ThreadX timer */ +/* tx_thread_resume Resume the specified thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; +ULONG startup_ticks; + + + status = tx_mutex_get(&client_ptr -> nx_sntp_client_mutex, TX_WAIT_FOREVER); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return status; + } + + /* Determine if SNTP has already been started. */ + if (client_ptr -> nx_sntp_client_started) + { + + /* Error SNTP has already been started. */ + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return completion status. */ + return(NX_SNTP_CLIENT_ALREADY_STARTED); + } + + /* Verify the client is ready to start receiving time data. */ + if (client_ptr -> nx_sntp_client_unicast_initialized == NX_FALSE) + { + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return the error condition. */ + return NX_SNTP_CLIENT_NOT_INITIALIZED; + } + + /* Should the first time request sleep for a random timeout? */ + if ((NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP == NX_TRUE) && (client_ptr -> random_number_generator)) + { + + /* Yes, generate a random number of ticks to sleep.*/ + (client_ptr -> random_number_generator)(client_ptr, &startup_ticks); + + /* Sleep for the random length. */ + tx_thread_sleep(startup_ticks); + } + + /* Set status that the first update is expected. */ + client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE; + + /* Initialize missed broadcasts and bad time updates from server. */ + client_ptr -> nx_sntp_client_invalid_time_updates = 0; + + + /* Set the maximum timeout to the full count. */ + client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); + + /* Activate SNTP update timer. */ + status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer)); + + /* Check for error. Ignore timer is already active error. */ + if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR) + { + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return the error condition. */ + return status; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + return status; + } + + status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread)); + + /* Start the SNTP Client thread. */ + if (status != NX_SUCCESS) + { + + /* Release the socket port. */ + nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + return status; + } + + /* The client thread is successfully started, so set the started flag to true. */ + client_ptr -> nx_sntp_client_started = NX_TRUE; + + /* Clear the sleep flag. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; + + /* Set poll interval to 0 to send request immediately. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = 0; + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_run_unicast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if the SNTP client has received a packet, and if*/ +/* so processes it for valid SNTP data and resets the timeouts */ +/* for sending (polling) and receiving updates. If no packet received it*/ +/* checks if the timeout to receive an update has expired. If so, it */ +/* sends out another SNTP request. */ +/* */ +/* When a timeout expires, the poll interval is increased as per */ +/* RFC guidelines until it exceeds the maximum time without an update. */ +/* An error flag is set, and it is up to the host application to */ +/* change its unicast SNTP server. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_reset_current_time_message */ +/* Save time update before next update */ +/* _nx_sntp_client_receive_time_update */ +/* Receive server update packets */ +/* _nx_sntp_client_process_time_data */ +/* Process time data in server update */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_process_unicast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; +ULONG sntp_events; + + + /* Check for a receive event. */ + status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT); + + if (status == NX_SUCCESS) + { + + /* Listen for a server update packet. */ + status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT); + + if (status == NX_SUCCESS) + { + + /* Process the server update packet and apply to local time if valid. */ + status = _nx_sntp_client_process_update_packet(client_ptr); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Reset the Client poll timeout to the original poll interval. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE); + + /* Reset the Client timeout for maximum time lapse without a valid update. */ + client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); + + /* Indicate the client has received at least one valid time update with the current server. */ + client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE; + + client_ptr -> nx_sntp_client_backoff_count = 0; + /* Set the server status as good (receiving updates). */ + client_ptr -> nx_sntp_valid_server_status = NX_TRUE; + + return; + } + } + + /* Has the timeout expired on the maximum lapse without a valid update? */ + if (client_ptr -> nx_sntp_update_time_remaining == 0) + { + + /* Yes, it has. Set the server status as no longer valid. */ + client_ptr -> nx_sntp_valid_server_status = NX_FALSE; + } + + /* Is it time to send another SNTP request? */ + if (client_ptr -> nx_sntp_client_unicast_poll_interval == 0) + { + + + /* Save the last server message before the next update. We need this for comparing time data. */ + _nx_sntp_client_reset_current_time_message(client_ptr); + + /* Create and send a unicast request . */ + _nx_sntp_client_send_unicast_request(client_ptr); + + + /* Check if we have received an update since the previous unicast poll. */ + if ((NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE - client_ptr -> nx_sntp_update_time_remaining) > + (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE)) + { + + /* No we have not. Increase the count of times we've increased the back off rate. */ + client_ptr -> nx_sntp_client_backoff_count++; + + client_ptr -> nx_sntp_client_unicast_poll_interval = + NX_IP_PERIODIC_RATE * NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_SNTP_CLIENT_EXP_BACKOFF_RATE * client_ptr -> nx_sntp_client_backoff_count; + } + else + { + + /* Reset the polling interval to it's normal value. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE; + } + + /* Check that the poll interval does not exceed the maximum lapse without a valid update. */ + if (client_ptr -> nx_sntp_client_unicast_poll_interval > (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE)) + { + + /* Set the poll interval equal to that lapse. */ + client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); + } + } + + /* Nothing to do but wait...*/ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_sntp_client_initialize_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the initialize Client for */ +/* IPv4 broadcast time updates service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* multicast_server_address Multicast server address */ +/* broadcast_time_server Broadcast server address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_SNTP_PARAM_ERROR Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* _nxd_sntp_client_initialize_duo_broadcast */ +/* Initialize broadcast Client service*/ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check for missing broadcast server input. */ + if ((multicast_server_address == NX_NULL) && (broadcast_server_address == NX_NULL)) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check for illegal broadcast address in IPv6. */ + if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V6)) + { + + return NX_SNTP_PARAM_ERROR; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual initialize client for broadcast time update service. */ + status = _nxd_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address); + + /* Return completion status. */ + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_sntp_client_initialize_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the Client to operate in broadcast mode with */ +/* either an IPv6 or an IPv4 broadcast server. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* multicast_server_address Multicast server address */ +/* broadcast_time_server Broadcast server address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address) +{ + + + /* Clear Client's current server IP. */ + memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS)); + + /* Was a multicast IP was supplied? */ + if (multicast_server_address != NX_NULL) + { + +#ifdef FEATURE_NX_IPV6 + /* Set the Client multicast server. */ + COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_multicast_server_address); + + /* Set this as the Client's current SNTP server. */ + COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_server_ip_address); +#else + /* Set the Client multicast server. */ + client_ptr -> nx_sntp_multicast_server_address.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_multicast_server_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4; + + /* Set this as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4; + +#endif /* FEATURE_NX_IPV6 */ + } + + /* No multicast address supplied, so was a broadcast address specified? This must be an IPv4 address + since IPv6 does not support broadcast. */ + else if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V4)) + { + + +#ifdef FEATURE_NX_IPV6 + /* Set the Client broadcast server. */ + COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_broadcast_time_server); + + /* Set this as the Client's current SNTP server. */ + COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_server_ip_address); +#else + /* Set the Client broadcast server. */ + client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4; + + /* Set this as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4; + +#endif /* FEATURE_NX_IPV6 */ + } + + /* Set client to work in broadcast (non unicast) mode. */ + client_ptr -> nx_sntp_client_protocol_mode = BROADCAST_MODE; + + /* Indicate the client task is ready to run! */ + client_ptr -> nx_sntp_client_broadcast_initialized = NX_TRUE; + + /* Initialize the server status as good (receiving updates) even though it has + not received one with the current server. */ + client_ptr -> nx_sntp_valid_server_status = NX_TRUE; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_initialize_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the initialize Client for */ +/* broadcast time updates service. Note that broadcast and multicast */ +/* services are only available for IPv4 SNTP communcations. For */ +/* multicast service, the host IP instance must be enabled for IGMP. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* multicast_server_address Server multicast address */ +/* broadcast_server_aaddres Broadcast server address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* _nx_sntp_client_initialize_broadcast */ +/* Actual initialize broadcast service*/ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + if ((multicast_server_address == 0x0) && (broadcast_server_address == 0x0)) + { + + return NX_INVALID_PARAMETERS; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual initialize client for broadcast time update service. */ + status = _nx_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address); + + /* Return completion status. */ + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(multicast_server_address); + NX_PARAMETER_NOT_USED(broadcast_server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_initialize_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the IPv4 addresses to the NetX Duo address */ +/* format and calls the 'duo' equivalent service, nxd_sntp_client_ */ +/* _initialize_broadcast. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* multicast_server_address Server multicast address */ +/* broadcast_server_address Broadcast server address */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxd_sntp_client_initialize_broadcast */ +/* Duo initialize broadcast service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; +NXD_ADDRESS server_address; + + + /* Was a multicast IP was supplied? */ + if (multicast_server_address != 0x0) + { + + server_address.nxd_ip_address.v4 = multicast_server_address; + server_address.nxd_ip_version = NX_IP_VERSION_V4; + status = _nxd_sntp_client_initialize_broadcast(client_ptr, &server_address, NX_NULL); + } + + /* Was a broadcast SNTP server specified? */ + else if (broadcast_server_address != 0x0) + { + + server_address.nxd_ip_address.v4 = broadcast_server_address; + server_address.nxd_ip_version = NX_IP_VERSION_V4; + status = _nxd_sntp_client_initialize_broadcast(client_ptr, NX_NULL, &server_address); + } + else + return NX_INVALID_PARAMETERS; + + return status; +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(multicast_server_address); + NX_PARAMETER_NOT_USED(broadcast_server_address); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the SNTP client thread stop*/ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_sntp_client_sto Actual stop SNTP service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_stop(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + status = _nx_sntp_client_stop(client_ptr); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function halts the SNTP Client thread and returns the SNTP */ +/* Client to an initial state. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client instance*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind the SNTP UDP socket */ +/* tx_thread_preemption_change Change the thread preemption */ +/* tx_thread_suspend Suspend SNTP processing */ +/* tx_thread_wait_abort Remove any thread suspension */ +/* tx_mutex_get Get the SNTP mutex */ +/* tx_mutex_put Release the SNTP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr) +{ + +UINT current_preemption; + + + /* Get the SNTP mutex. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + /* Determine if the SNTP client is started. */ + if (client_ptr -> nx_sntp_client_started == NX_FALSE) + { + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* SNTP client is not started so it can't be stopped. */ + return(NX_SNTP_CLIENT_NOT_STARTED); + } + + /* Clear the started flag here to ensure other threads can't issue a stop while + this stop is in progress. */ + client_ptr -> nx_sntp_client_started = NX_FALSE; + + /* Indicate the client needs to be re-initialized to run again. */ + client_ptr -> nx_sntp_client_unicast_initialized = NX_FALSE; + client_ptr -> nx_sntp_client_broadcast_initialized = NX_FALSE; + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Loop to wait for the SNTP Client thread to be in a position to be stopped. */ + while (client_ptr -> nx_sntp_client_sleep_flag != NX_TRUE) + { + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Sleep temporarily. */ + tx_thread_sleep(1); + + /* Get the SNTP mutex. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + } + + /* Clear the sleep flag. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; + + /* Get rid of any previous server message. */ + memset(&(client_ptr -> nx_sntp_previous_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Get rid of the current server message if there is one. */ + memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + /* Suspend the SNTP Client thread. */ + tx_thread_suspend(&(client_ptr -> nx_sntp_client_thread)); + + /* Abort the wait on the SNTP Client thread. */ + tx_thread_wait_abort(&(client_ptr -> nx_sntp_client_thread)); + + /* Unbind the port. */ + nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Restore preemption. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_run_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the run broadcast service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_run_broadcast Actual run broadcast service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for pointer error. */ + if (client_ptr == NX_NULL) + { + + /* Return error status. */ + return NX_PTR_ERROR; + } + + /* Verify this is called from thread context only. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual run broadcast service. */ + status = _nx_sntp_client_run_broadcast(client_ptr); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_run_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts the SNTP Client for broadcast SNTP processing */ +/* by activating the SNTP timer and main processing thread. The Client */ +/* is checked for being initialized for broadcast SNTP and if it is */ +/* not, the function returns an error status. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */ +/* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_activate Start the ThreadX timer */ +/* tx_thread_resume Resume the specified thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Get the SNTP mutex. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + /* Determine if SNTP has already been started. */ + if (client_ptr -> nx_sntp_client_started) + { + + /* Error SNTP has already been started. */ + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return completion status. */ + return(NX_SNTP_CLIENT_ALREADY_STARTED); + } + + /* Verify the client is ready to start receiving time data. */ + if (client_ptr -> nx_sntp_client_broadcast_initialized == NX_FALSE) + { + + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + /* Return error condition. */ + return NX_SNTP_CLIENT_NOT_INITIALIZED; + } + + + /* Set the maximum timeout to the full count. */ + client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); + + /* Activate the SNTP update timer. */ + status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer)); + + /* Check for error. Ignore timer is already active error. */ + if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR) + { + + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + /* Return the error condition. */ + return status; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + return status; + } + + /* Set status that the first update is expected. */ + client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE; + + status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread)); + + if (status != NX_SUCCESS) + { + + /* Release the socket port. */ + nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); + + /* Deactivate SNTP update timer. */ + tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); + + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return status; + } + + /* Clear the sleep flag. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; + + client_ptr -> nx_sntp_client_started = NX_TRUE; + + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_process_broadcast PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if the SNTP client has received a packet, and if*/ +/* so processes it for valid SNTP data and resets the timeouts */ +/* for receiving the next update. */ +/* */ +/* If the invalid packet update count exceeds the maximum allowed */ +/* updates, or no valid packet is received within the maximum interval, */ +/* an error flag is set, and it is up to the host application to change */ +/* its broadcast SNTP server. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_reset_current_time_message */ +/* Save time update before next update */ +/* _nx_sntp_client_receive_time_update */ +/* Receive server update packets */ +/* _nx_sntp_client_process_time_data */ +/* Process time data in server update */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_process_broadcast(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; +ULONG sntp_events; + + + /* Check for a receive event. */ + status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT); + + if (status == NX_SUCCESS) + { + + /* Save this server time update before receiving the next server time update. */ + _nx_sntp_client_reset_current_time_message(client_ptr); + + /* Listen for a server update packet. */ + status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT); + + if (status == NX_SUCCESS) + { + + /* Process the server update packet and apply to local time if valid. */ + status = _nx_sntp_client_process_update_packet(client_ptr); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Have we exceeded the max number of invalid or missed updates from this server? */ + if (client_ptr -> nx_sntp_client_invalid_time_updates > NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT) + { + + /* Yes, set the server status as no longer valid. */ + client_ptr -> nx_sntp_valid_server_status = NX_FALSE; + } + + return; + } + + /* Reset the Client timeout for receiving broadcast updates, zero out invalid update count. */ + client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); + + client_ptr -> nx_sntp_client_invalid_time_updates = 0; + + /* Set the server status as good (receiving updates). */ + client_ptr -> nx_sntp_valid_server_status = NX_TRUE; + + /* Indicate the client has received at least one valid time update with the current server. */ + client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE; + + return; + } + } + + /* Has the timeout for receiving the next time update expired? */ + if (client_ptr -> nx_sntp_update_time_remaining == 0) + { + + /* Yes, set the server status as no longer valid. */ + client_ptr -> nx_sntp_valid_server_status = NX_FALSE; + } + + /* Nothing to do but wait...*/ + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_send_unicast_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a packet from the Client packet pool,creates*/ +/* a time request time message, transfers the request message into the */ +/* packet buffer, and sends the packet via the Client UDP socket. It */ +/* then releases the packet back to the packet pool. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* nx_packet_allocate Allocate packet from packet pool */ +/* nx_packet_release Release packet back to packet pool */ +/* nx_udp_socket_send Transmit packet via UDP socket */ +/* _nx_sntp_client_utility_convert_time_to_UCHAR */ +/* Copy NX_SNTP_TIME data into a */ +/* UCHAR[4] time stamp field */ +/* _nx_sntp_client_create_time_request_packet */ +/* Create packet with time request data*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_run_unicast Send and receive unicast time data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT *client_ptr) +{ + +NX_PACKET *packet_ptr; +UINT status; +NX_SNTP_TIME_MESSAGE *unicast_request; +NX_SNTP_TIME local_time; + + + /* Lock access to the SNTP Client while we create a unicast request. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + unicast_request = &(client_ptr -> nx_sntp_current_time_message_request); + + /* Clear the time request. */ + memset(unicast_request, 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Add client version to the time request flags. */ + unicast_request -> flags = NX_SNTP_CLIENT_NTP_VERSION << 3; + + /* Set the Client association (mode) in the last three bits of the flag field. */ + unicast_request -> flags |= PROTOCOL_MODE_CLIENT; + + /* Release the mutex before a potentially blocking call. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + /* Allocate a packet from the Client pool. */ + status = nx_packet_allocate(client_ptr -> nx_sntp_client_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_SNTP_CLIENT_PACKET_TIMEOUT); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Reacquire the lock to SNTP Client while we process request. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + /* Check for minimal packet size requirement. */ + + + /* IPv6 packets require more space for the IPv6 header. */ + if (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + nx_packet_release(packet_ptr); + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return NX_SNTP_INVALID_IP_ADDRESS; +#else + + if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size < + (sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) + { + + nx_packet_release(packet_ptr); + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; + } +#endif /* FEATURE_NX_IPV6 */ + } + else /* IPv4 */ + { + +#ifdef NX_DISABLE_IPV4 + nx_packet_release(packet_ptr); + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return NX_SNTP_INVALID_IP_ADDRESS; +#else + + if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size < + (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) + { + + nx_packet_release(packet_ptr); + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; + } +#endif /* NX_DISABLE_IPV4 */ + } + + + /* Convert the local time into the request's transmit time stamp field. */ + local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds + + client_ptr -> nx_sntp_client_local_ntp_time_elapsed; + local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; + _nx_sntp_client_utility_convert_time_to_UCHAR(&local_time, unicast_request, TRANSMIT_TIME); + + /* Create the request packet with the unicast request message. */ + status = _nx_sntp_client_create_time_request_packet(client_ptr, packet_ptr, unicast_request); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + /* Return error status. */ + return status; + } + + /* Release the lock. we're done with the SNTP Client data. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + /* Send the time request packet. */ + status = nxd_udp_socket_send(&(client_ptr -> nx_sntp_client_udp_socket), packet_ptr, &client_ptr -> nx_sntp_server_ip_address, NX_SNTP_SERVER_UDP_PORT); + + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return status; + } + + send_timerticks = tx_time_get(); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_receive_time_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives UDP data on the Client socket with specified */ +/* wait (timeout option). Received packets are checked for valid */ +/* and sender IP and port. Packet data is then extracted and stored */ +/* in the specified time message. The packet is released regardless of */ +/* validity of packet received. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* timeout Wait option to receive packet */ +/* */ +/* OUTPUT */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_receive Listen for packets on UDP socket */ +/* nx_packet_release Release packet back to packet pool*/ +/* tx_mutex_get Obtain exclusive lock on list */ +/* memset Clear specified area of memory */ +/* _nx_sntp_client_add_server_ULONG_to_list */ +/* Add sender address to Client list */ +/* _nx_sntp_client_utility_convert_LONG_to_IP */ +/* Convert IP to string for display */ +/* _nx_sntp_client_extract_time_message_from_packet */ +/* Extract packet data to time message*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_run_unicast Send and receive server time updates*/ +/* _nx_sntp_client_run_broadcast Listen for server update broadcasts */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout) +{ + +UINT status; +UINT length; +NX_PACKET *receive_packet; +UINT sender_port; +NX_UDP_HEADER *udp_header_ptr; +NXD_ADDRESS source_ip_address, destination_ip_address; + + /* Loop to receive packets. */ + for(;;) + { + + /* Indicate the SNTP Client can be stopped while the SNTP client waits for a packet. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE; + + /* Wait to receive packets on the Client UDP socket. */ + status = nx_udp_socket_receive(&(client_ptr -> nx_sntp_client_udp_socket), &receive_packet, timeout * NX_IP_PERIODIC_RATE); + + /* Indicate the SNTP Client can not be stopped. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + /* Check the sender port in the UDP packet header. */ + udp_header_ptr = (NX_UDP_HEADER *)(receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER)); + sender_port = (UINT)udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16; + + /* Check if this is the server port the Client expects. */ + if (sender_port != NX_SNTP_CLIENT_UDP_PORT) + { + + /* No, reject the packet. */ + nx_packet_release(receive_packet); + + continue; + } + + + /* If this an IPv6 packet? An SNTP client with an IPv6 SNTP server will only accept IPv6 packets. */ + if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V6) && + (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6)) + { + +#ifndef FEATURE_NX_IPV6 + nx_packet_release(receive_packet); + continue; +#else + NX_IPV6_HEADER *ipv6_header_ptr; + + /* Pick up the IPv6 header from the packet. */ + ipv6_header_ptr = (NX_IPV6_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV6_HEADER)); + + /* Copy sender address into a local variable. */ + COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_source_ip, &(source_ip_address.nxd_ip_address.v6[0])); + source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + /* Copy destination address into a local variable. */ + COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_destination_ip, &(destination_ip_address.nxd_ip_address.v6[0])); + destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; + + if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) + { + + /* Does the source address match the expected server address? */ + if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0])) + { + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + /* Set update time to null. */ + memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); + + continue; + } + } + else /* Multicast mode */ + { + + /* Define the all hosts multicast address. */ + NXD_ADDRESS All_Hosts_Multicast; + All_Hosts_Multicast.nxd_ip_version = NX_IP_VERSION_V6; + All_Hosts_Multicast.nxd_ip_address.v6[0] = 0xff020000; + All_Hosts_Multicast.nxd_ip_address.v6[1] = 0x00000000; + All_Hosts_Multicast.nxd_ip_address.v6[2] = 0x00000000; + All_Hosts_Multicast.nxd_ip_address.v6[3] = 0x00000001; + + /* Does the source address match the expected server address )? */ + if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0])) + { + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + /* Set update time to null. */ + memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); + + continue; + } + + /* Does the destination address match the expected server address (all hosts address FF02::1)? */ + if (!CHECK_IPV6_ADDRESSES_SAME(&destination_ip_address.nxd_ip_address.v6[0], &All_Hosts_Multicast.nxd_ip_address.v6[0])) + { + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + /* Set update time to null. */ + memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); + + continue; + } + + } +#endif /* FEATURE_NX_IPV6 */ + + } + /* Otherwise is this an IPv4 packet and is the SNTP client set for IPv4? */ + else if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V4) && + (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V4)) + { +#ifdef NX_DISABLE_IPV4 + nx_packet_release(receive_packet); + continue; +#else + + NX_IPV4_HEADER *ipv4_header_ptr; + + ipv4_header_ptr = (NX_IPV4_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); + + /* Copy into a local variable. */ + source_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_source_ip; + source_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + + /* Copy into a local variable. */ + destination_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_destination_ip; + destination_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + + if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) + { + /* Compare the sender address with the Client's current sntp server. */ + if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4) + { + /* This is an untrusted server or the client had a broadcast server already, + reject this packet and return an error condition. */ + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + continue; + } + } + else /* BROADCAST_MODE */ + { + + ULONG network_mask; + UINT iface_index; + + /* Compare the sender address with the Client's current sntp server. */ + if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4) + { + + /* This is an untrusted server or the client had a broadcast server already, + reject this packet and return an error condition. */ + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + continue; + } + + /* Set a local variable on the SNTP network index. */ + iface_index = client_ptr -> nx_sntp_client_interface_index; + + /* Set a local variable to the network mask. */ + network_mask = client_ptr -> nx_sntp_client_ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask; + + /* Now verify this is a broadcast packet. */ + if ((destination_ip_address.nxd_ip_address.v4 & ~network_mask) != ~network_mask) + { + /* This is not a broadcast packet on the local network. */ + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + continue; + } + } +#endif /* NX_DISABLE_IPV4 */ + } + else + { + /* Not interested, discard the packet. */ + nx_packet_release(receive_packet); + + continue; + } + + /* Check that the packet has the proper length for an NTP message. */ + length = receive_packet -> nx_packet_length; + + /* Verify the packet data contains at least the minimum time update data, + but no more than the max size with authentication data appended. */ + + if ((length < NX_SNTP_TIME_MESSAGE_MIN_SIZE) || (length > NX_SNTP_TIME_MESSAGE_MAX_SIZE)) + { + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + continue; + } + + memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Extract time message data from packet data into time message. */ + _nx_sntp_client_extract_time_message_from_packet(client_ptr, receive_packet); + + /* No further need for the receive packet. Release back to the client pool. */ + nx_packet_release(receive_packet); + + return NX_SUCCESS; + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_extract_time_message_from_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts time data from an SNTP server packet and */ +/* copies the information into the specified time message buffer. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* packet_ptr Pointer to server packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Copy data to area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_receive_time_update Process SNTP server packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ + +ULONG *ntp_word_0; +NX_SNTP_TIME_MESSAGE *time_message_ptr; + + + time_message_ptr = &(client_ptr -> nx_sntp_current_server_time_message); + + process_timerticks = tx_time_get(); + + memset(time_message_ptr, 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Pickup the pointer to the head of the UDP packet. */ + ntp_word_0 = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + + /* Extract fields from the first 32 bits of the time message. */ + time_message_ptr -> flags = (*ntp_word_0 & 0xFF000000UL) >> 24; + + time_message_ptr -> peer_clock_stratum = (*ntp_word_0 & 0x00FF0000UL) >> 16; + + time_message_ptr -> peer_poll_interval = (*ntp_word_0 & 0x0000FF00UL) >> 8; + + time_message_ptr -> peer_clock_precision = (*ntp_word_0 & 0x00000000FFUL); + + /* Advance to the next 32 bit field and extract the root delay field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + + time_message_ptr -> root_delay = (ULONG)(*ntp_word_0); + + /* Advance to the next 32 bit field and extract the clock dispersion field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + + time_message_ptr -> clock_dispersion= *ntp_word_0; + + /* Advance to the next 32 bit field and extract the reference clock ID field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + memcpy(time_message_ptr -> reference_clock_id, ntp_word_0, 4); + + /* Advance to the next field (64 bit field) and extract the reference time stamp field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> reference_clock_update_time_stamp[0] = *ntp_word_0; + + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> reference_clock_update_time_stamp[1] = *ntp_word_0; + + /* If a non zero reference time was supplied, separate out seconds and fraction. */ + if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> reference_clock_update_time_stamp), 8) == NX_FALSE) + { + + time_message_ptr -> reference_clock_update_time.seconds = time_message_ptr -> reference_clock_update_time_stamp[0]; + + time_message_ptr -> reference_clock_update_time.fraction = time_message_ptr -> reference_clock_update_time_stamp[1]; + } + + /* Copy the first 32 bits into the originate time stamp seconds field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> originate_time_stamp[0] = *ntp_word_0; + + /* Copy the next 32 bits into the originate time stamp fraction field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> originate_time_stamp[1] = *ntp_word_0; + + /* If an originate time was supplied, separate out seconds and fraction. */ + if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> originate_time_stamp), 8) == NX_FALSE) + { + + time_message_ptr -> originate_time.seconds = time_message_ptr -> originate_time_stamp[0]; + + time_message_ptr -> originate_time.fraction = time_message_ptr -> originate_time_stamp[1]; + } + + + /* Copy the first 32 bits into the receive time stamp seconds field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> receive_time_stamp[0] = *ntp_word_0; + + /* Copy the next 32 bits into the receive time stamp fraction field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> receive_time_stamp[1] = *ntp_word_0; + + /* If an receive time was supplied, separate out seconds and fraction. */ + if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> receive_time_stamp), 8) == NX_FALSE) + { + + time_message_ptr -> receive_time.seconds = time_message_ptr -> receive_time_stamp[0]; + time_message_ptr -> receive_time.fraction = time_message_ptr -> receive_time_stamp[1]; + } + + /* Copy the first 32 bits into the transmit time stamp seconds field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> transmit_time_stamp[0] = *ntp_word_0; + + /* Copy the next 32 bits into the transmit time stamp fraction field. */ + ntp_word_0++; + NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); + time_message_ptr -> transmit_time_stamp[1] = *ntp_word_0; + + /* If an transmit time was supplied, separate out seconds and fraction. */ + if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> transmit_time_stamp), 8) == NX_FALSE) + { + + time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0]; + + time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1]; + + } + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_reset_current_time_message PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function saves the current time message from the server to */ +/* the previous time message field, and clears the current time message*/ +/* field. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_receive_time_update Process received update packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr) +{ + + /* Does the client have a non NULL current server time update? */ + if (client_ptr -> nx_sntp_current_server_time_message.flags) + { + + /* Yes, copy to the previous time update. */ + memcpy(&client_ptr -> nx_sntp_previous_server_time_message, &client_ptr -> nx_sntp_current_server_time_message, sizeof(NX_SNTP_TIME_MESSAGE)); + + /* Clear the current time update data. */ + memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + } + + /* Clear the current time update request. */ + memset(&(client_ptr -> nx_sntp_current_time_message_request), 0, sizeof(NX_SNTP_TIME_MESSAGE)); + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_process_update_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes SNTP time data received in a server update */ +/* packet, applies sanity checks, calculates round trip time, and */ +/* updates the Client time with the SNTP server time. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_BAD_SERVER_ROOT_DISPERSION Server dispersion too high */ +/* receive_status Actual packet receive status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Copy data to area of memory */ +/* _nx_sntp_client_apply_sanity_checks Apply sanity checks to update */ +/* _nx_sntp_client_check_server_clock_dispersion */ +/* Check server clock dispersion */ +/* _nx_sntp_client_calculate_roundtrip */ +/* Compute roundtrip time to server*/ +/* _nx_sntp_client_process_time_data Apply server time to local time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_process_unicast Process unicast SNTP data */ +/* _nx_sntp_client_process_broadcast Process broadcast SNTP data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; + + /* Apply client's set of sanity checks on the data. */ + status = _nx_sntp_client_apply_sanity_checks(client_ptr); + + /* Check for sanity check errors. */ + if (status != NX_SUCCESS) + { + + /* Count these as bad updates from the server. */ + client_ptr -> nx_sntp_client_invalid_time_updates++; + + /* Ok to continue Client task. */ + return status; + } + + /* Check server clock dispersion (if any reported) in first update + from current server for unicast clients. */ + if ((client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) + { + + status = _nx_sntp_client_check_server_clock_dispersion(client_ptr); + + /* Is the server clock variance acceptable? */ + if (status != NX_SUCCESS) + { + + /* Return the error status. */ + return status; + } + } + + /* At this point we have received a valid server response. */ + + /* Clear the count of (consecutive) bad time updates received from this server. */ + client_ptr -> nx_sntp_client_invalid_time_updates = 0; + + /* Apply server time to local device time. */ + status = _nx_sntp_client_process_time_data(client_ptr); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error condition*/ + return status; + } + + /* If the Client is configured with a time update callback, call it now. */ + if (client_ptr -> nx_sntp_client_time_update_notify) + { + + client_ptr -> nx_sntp_client_time_update_notify(&(client_ptr -> nx_sntp_current_server_time_message), + &(client_ptr -> nx_sntp_client_local_ntp_time)); + } + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_duplicate_update_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs a comparison of time values between two */ +/* time messages to verify they are not duplicates. Duplicate updates */ +/* can be a form of denial of service/clogging attack on a host. */ +/* */ +/* INPUT */ +/* */ +/* timeA_msg_ptr Pointer to first time update */ +/* timeB_msg_ptr Pointer to second time update */ +/* is_a_dupe Result of comparison */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Copy data to area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_apply_sanity_checks Verify received SNTP data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr, + NX_SNTP_TIME_MESSAGE *timeB_msg_ptr, + UINT *is_a_dupe) +{ + + *is_a_dupe = NX_FALSE; + + if ( (!memcmp(timeA_msg_ptr -> transmit_time_stamp, + timeB_msg_ptr -> transmit_time_stamp, 8)) && + (!memcmp(timeA_msg_ptr -> receive_time_stamp, + timeB_msg_ptr -> receive_time_stamp, 8)) && + (!memcmp(timeA_msg_ptr -> originate_time_stamp, + timeB_msg_ptr -> originate_time_stamp, 8)) && + (!memcmp(timeA_msg_ptr -> reference_clock_update_time_stamp, + timeB_msg_ptr -> reference_clock_update_time_stamp, 8)) && + (!memcmp(timeA_msg_ptr -> reference_clock_id, + timeB_msg_ptr -> reference_clock_id, 4)) && + (timeA_msg_ptr -> root_delay == timeB_msg_ptr -> root_delay) && + (timeA_msg_ptr -> clock_dispersion == timeB_msg_ptr -> clock_dispersion) + ) + { + + *is_a_dupe = NX_TRUE; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_apply_sanity_checks PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for invalid SNTP data received from server. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_DUPE_SERVER_PACKET Duplicate server packet received */ +/* NX_SNTP_INVALID_SERVER_MODE Server mode won't work with Client */ +/* NX_SNTP_INVALID_NTP_VERSION Server NTP version won't work with */ +/* Client NTP version. */ +/* NX_SNTP_SERVER_CLOCK_NOT_SYNC Server is not ready to send updates*/ +/* NX_SNTP_INVALID_SERVER_STRATUM Server stratum not acceptable */ +/* NX_SNTP_NULL_SERVER_TIMESTAMP Invalid or NULL timestamp in update*/ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Copy data into area of memory */ +/* _nx_sntp_client_duplicate_update_check */ +/* Check for duplicate updates service*/ +/* _nx_sntp_client_utility_get_msec_diff */ +/* Check for time difference in msecs */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_run_broadcast Receive broadcast SNTP updates */ +/* _nx_sntp_client_run_unicast Send and receive SNTP updates */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr) +{ + + +UINT status; +UINT mode; +UINT leap_second_indicator; +UINT server_ntp_version; +UINT is_a_dupe_check; +ULONG msecs; +NX_SNTP_TIME_MESSAGE *server_time_msg_ptr; + + server_time_msg_ptr = &(client_ptr -> nx_sntp_current_server_time_message); + + /* Was a previous response received from the server? */ + if (client_ptr -> nx_sntp_previous_server_time_message.flags) + { + + /* Yes; perform a duplicate packet check. */ + status = _nx_sntp_client_duplicate_update_check(&(client_ptr -> nx_sntp_current_server_time_message), + &(client_ptr -> nx_sntp_previous_server_time_message), + &is_a_dupe_check); + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return error status. */ + return status; + } + + /* Is this a duplicate packet (e.g. possible 'clogging' attack)? */ + if (is_a_dupe_check) + { + + return NX_SNTP_DUPE_SERVER_PACKET; + } + } + + /* Get the association type from the server. */ + mode = server_time_msg_ptr ->flags & 0x07; + + /* Is the server of the correct association for a unicast client? */ + if ((mode != PROTOCOL_MODE_SERVER_UNICAST) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) + { + + /* Return error status. */ + return NX_SNTP_INVALID_SERVER_MODE; + } + /* Is the server of the correct association for a broadcast client? */ + else if ((mode != PROTOCOL_MODE_SERVER_BROADCAST) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE)) + { + + /* Return error status. */ + return NX_SNTP_INVALID_SERVER_MODE; + } + + /* Extract server's NTP version from the flags field. */ + server_ntp_version = (server_time_msg_ptr -> flags & 0x38) >> 3; + + /* As per NTP protocol, check if the server reply has the same SNTP version that + the Client sent in its unicast request. */ + if ((server_ntp_version != NX_SNTP_CLIENT_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) + { + + /* Return the error condition. */ + return NX_SNTP_INVALID_NTP_VERSION; + } + /* If broadcast, verify the server SNTP version is compatible with the Client. */ + else if ((server_ntp_version < NX_SNTP_CLIENT_MIN_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE)) + { + + /* Return the error condition. */ + return NX_SNTP_INVALID_NTP_VERSION; + } + + /* Get the leap second indicator from the flags field. */ + leap_second_indicator = (server_time_msg_ptr -> flags & 0xC0) >> 6; + + /* Is the server clock not yet synchronized? */ + if (leap_second_indicator == 3) + { + /* Return the error condition. */ + return NX_SNTP_SERVER_CLOCK_NOT_SYNC; + } + + /* Has the server sent a 'kiss of death' (stratum = 0) packet? */ + if (server_time_msg_ptr -> peer_clock_stratum == 0) + { + + /* Does the Client have a kiss of death handler? */ + if (client_ptr -> kiss_of_death_handler) + { + UINT code_id; + + /* Convert the message to code.*/ + _nx_sntp_client_utility_convert_refID_KOD_code(server_time_msg_ptr -> reference_clock_id, &code_id); + + /* Yes, let the handler deal with this server response. */ + status = (client_ptr -> kiss_of_death_handler)(client_ptr, code_id); + + /* Is it ok to continue with this server? */ + if (status != NX_SUCCESS) + { + + /* No, it is not. Return the error condition. */ + return status; + } + } + else + { + /* It is not ok to continue. Return the error condition. */ + return NX_SNTP_KOD_SERVER_NOT_AVAILABLE; + } + } + + /* Is the server stratum a valid stratum ? */ + else if (server_time_msg_ptr -> peer_clock_stratum & STRATUM_RESERVED) + { + + /* Return error status. */ + return NX_SNTP_INVALID_SERVER_STRATUM; + + } + /* Does the server stratum acceptable to the Client? */ + else if (server_time_msg_ptr -> peer_clock_stratum > NX_SNTP_CLIENT_MIN_SERVER_STRATUM) + { + + /* Return error status. */ + return NX_SNTP_INVALID_SERVER_STRATUM; + } + + /* Is the Client operating in unicast mode? */ + if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) + { + UINT pos_diff = NX_TRUE; + + /* Yes; Are any server time stamps NULL? */ + + /* Special case: the client has not set its local time. Only check server's receive and transmit time. */ + if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0) + { + if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) || + (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)) + { + + /* Return error status. */ + return NX_SNTP_INVALID_TIMESTAMP; + } + + } + else + { + /* Check all server time stamps to be non null. */ + if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> originate_time_stamp), 8) == NX_TRUE) || + (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) || + (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)) + { + + /* Return error status. */ + return NX_SNTP_INVALID_TIMESTAMP; + } + + } + + /* Get the time difference server transmit time - server receive time. */ + status = _nx_sntp_client_utility_get_msec_diff(&(server_time_msg_ptr -> receive_time), + &(server_time_msg_ptr -> transmit_time), + &msecs, &pos_diff); + + /* Is the server transmit time <= server receive time [physically not possible]? */ + if (status != NX_SUCCESS) + { + + /* Yes; Return the error condition. */ + return status; + } + else if (pos_diff == NX_FALSE) + { + + /* treat as an error in this case. */ + return NX_SNTP_INVALID_TIMESTAMP; + } + } + /* Client is in broadcast mode. */ + else + { + + /* Is the broadcast server transmit time stamp is NULL? */ + if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE) + + { + + /* Return the error status. */ + return NX_SNTP_INVALID_TIMESTAMP; + } + } + + /* Is there an impending leap second adjustment? */ + if ((leap_second_indicator == 1) || (leap_second_indicator == 2)) + { + + /* Does the Client have a leap second handler?*/ + if (client_ptr -> leap_second_handler) + { + + /* Yes, invoke the leap second handler for impending leap second event. */ + (client_ptr -> leap_second_handler)(client_ptr, leap_second_indicator); + } + } + + /* Return successful completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_check_server_clock_dispersion PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks server clock dispersion extracted from server */ +/* time message in 32 bit representation: */ +/* sum of 1/(2 ^ bit) of bits 16-31 in the time message format */ +/* and compares it against the Client's dispersion tolerance. */ +/* */ +/* If NX_SNTP_CLIENT_MAX_ROOT_DISPERSION is set to zero, the function */ +/* simply returns a successful result but does no calculations. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS dispersion is acceptable */ +/* NX_SNTP_BAD_SERVER_ROOT_DISPERSION dispersion is too large */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_process_update_packet */ +/* Process time data in update packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr) +{ + +#if (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) +UINT mask = 0x8000; +UINT bit = 1; +ULONG divisor; +ULONG dispersion_usecs; + + /* Check for zero clock dispersion reported in server update. */ + if (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion == 0) + { + + /* Return successful status. */ + return NX_SUCCESS; + } + + /* Get the most significant 16 bits of dispersion field and convert to microseconds.*/ + dispersion_usecs = (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion >> 16) * 1000000; + + /* Compare seconds in the most significant 16 bits against the Client dispersion tolerance. */ + if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION) + { + + /* Yes, indicate that server clock dispersion exceeds tolerance. */ + return NX_SNTP_BAD_SERVER_ROOT_DISPERSION; + } + + /* Compare fraction from least significant 16 bits; sum of (1 / 2 ^ bit field) of lower 16 bits. */ + + /* Get the lower 16 bits. */ + client_ptr -> nx_sntp_current_server_time_message.clock_dispersion = + client_ptr -> nx_sntp_current_server_time_message.clock_dispersion & 0xFFFF; + + /* Compute the dispersion. */ + while(mask) + { + if (mask & client_ptr -> nx_sntp_current_server_time_message.clock_dispersion) + { + divisor = (ULONG)(1 << bit); + if ((divisor < 1000000) && (divisor > 0)) + { + dispersion_usecs += 1000000/divisor; + } + } + bit++; + mask >>= 1; + } + + /* Is the computed clock dispersion more than the max tolerance? */ + if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION) + { + /* Yes, indicate that server clock dispersion exceeds tolerance. */ + return NX_SNTP_BAD_SERVER_ROOT_DISPERSION; + } +#else + NX_PARAMETER_NOT_USED(client_ptr); +#endif /* (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) */ + + /* Return successful computation. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the processing thread for the SNTP Client. It */ +/* executes periodic SNTP tasks with SNTP Client mutex protection, then*/ +/* briefly sleeps to allow the host application to call SNTP Client */ +/* services. */ +/* */ +/* INPUT */ +/* */ +/* sntp_instance Pointer to SNTP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_process Main SNTP processing function */ +/* tx_thread_sleep Sleep for specified time */ +/* tx_mutex_get Get the SNTP mutex */ +/* tx_mutex_put Release the SNTP mutex */ +/* tx_thread_preemption_change Change thread preemption */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_thread_entry(ULONG sntp_instance) +{ + +NX_SNTP_CLIENT *client_ptr; +UINT status; +UINT current_preemption; + + + /* Setup the SNTP pointer. */ + client_ptr = (NX_SNTP_CLIENT *) sntp_instance; + + /* Enter while loop. */ + do + { + + /* Loop for obtaining the SNTP mutex. */ + do + { + + /* Get the SNTP mutex. */ + status = tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + } while (status != TX_SUCCESS); + + /* Perform periodic tasks for the SNTP Client. */ + _nx_sntp_client_process(client_ptr); + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Disable preemption for critical section. */ + tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); + + /* Indicate the SNTP Client process is idle. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE; + + /* Sleep for timer interval. */ + tx_thread_sleep(NX_SNTP_CLIENT_SLEEP_INTERVAL); + + /* Clear flag to indicate SNTP thread is not in a position to be stopped. */ + client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; + + /* Restore original preemption. */ + tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); + + + } while (1); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the socket receive callback for the SNTP Client */ +/* UDP socket. It sets a flag for the SNTP Client thread to know there*/ +/* is a packet waiting to be processed. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to Client UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Sets a receive event */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr) +{ + NX_PARAMETER_NOT_USED(socket_ptr); + + /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */ + tx_event_flags_set(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR); + + receive_timerticks = tx_time_get(); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called periodically by the SNTP client thread, and */ +/* depending on the CLient mode (unicast or broadcast) calls the */ +/* unicast or broadcast process function. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to the SNTP client */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_process_unicast Process unicast tasks */ +/* _nx_sntp_client_process_broadcast Process broadcast tasks */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr) +{ + + + /* Is the client using unicast or unicast to receive updates? */ + if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) + { + /* Call the unicast process function. */ + _nx_sntp_client_process_unicast(client_ptr); + } + else + { + + /* Call the broadcast process function. */ + _nx_sntp_client_process_broadcast(client_ptr); + } + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_process_time_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function applies the server time data to client local time taking*/ +/* into account the round trip time. Time updates are checked for a max */ +/* time offset set by the Client max_time_adjustment parameter. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_INVALID_SERVER_UPDATE_TIME No time of server update recorded*/ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* memcpy Copy data to area of memory */ +/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ +/* Add msec to NTP time fraction field*/ +/* _nx_sntp_client_utility_get_msec_diff */ +/* Compute time difference in msecs */ +/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ +/* Add time in msecs to an NTP time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_run_broadcast Listen and process broadcast updates*/ +/* _nx_sntp_client_process_update_packet */ +/* Process update SNTP packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr) +{ + +UINT status; +UINT ignore_max_adjustment_limit; +ULONG elapsed_msecs_difference; +UINT adjustment; +NX_SNTP_TIME local_time; + + + /* Copy the received time update to the update time just received from the server. */ + memcpy(&client_ptr -> nx_sntp_server_update_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); + + /* Check if the client is configured for round trip time calculation. */ + if (NX_SNTP_CLIENT_RTT_REQUIRED == NX_TRUE) + { + + /* Compute roundtrip delay. */ + _nx_sntp_client_calculate_roundtrip(&(client_ptr -> nx_sntp_client_roundtrip_time_msec)); + + /* Has the client computed a valid round trip time? */ + if (client_ptr -> nx_sntp_client_roundtrip_time_msec) + { + + /* Yes, Add 1/2 round trip to server's reported time. */ + status =_nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_current_server_time_message.transmit_time), + ((client_ptr -> nx_sntp_client_roundtrip_time_msec) / 2)); + + if (status != NX_SUCCESS) + { + + /* Cannot use this time update. */ + return status; + } + } + } + + /* Is this the first update? */ + if (client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) + { + /* Check Client configuration if we ignore max adjustment limit on first update. */ + ignore_max_adjustment_limit = NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP; + } + else + ignore_max_adjustment_limit = NX_FALSE; + + /* If not ignoring the max adjustment, deal with time difference between client and server. */ + if (ignore_max_adjustment_limit == NX_FALSE) + { + UINT pos_diff = NX_TRUE; + + /* Compute difference of server update packet minus the client's local time. It is reasonable + to assume that the Client time is 'behind' the server time because it is updated by the + server time. */ + local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds + + client_ptr -> nx_sntp_client_local_ntp_time_elapsed; + local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; + status = _nx_sntp_client_utility_get_msec_diff(&local_time, + &(client_ptr -> nx_sntp_server_update_time), + &elapsed_msecs_difference, &pos_diff); + + + /* Note that a positive difference vs negative difference is not an error. */ + if (status != NX_SUCCESS) + { + + /* Cannot use this time update. */ + return status; + } + + /* Is the difference less than the client's minimum adjustment? */ + if (elapsed_msecs_difference > NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT) + { + + /* The adjustment is larger than the Client's minimum adjustment. */ + + /* Set the local clock to the server time only if 1)we are ignoring the maximum adjustment on startup, + or 2) the difference is within the Client's max time adjustment. */ + if (elapsed_msecs_difference > NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT) + { + /* Cannot use this time update. */ + return NX_SNTP_INVALID_TIME; + } + } + } + + /* Ok to update client local time. */ + memcpy(&client_ptr -> nx_sntp_client_local_ntp_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); + client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0; + + /* Apply a correction to server's time for internal SNTP Client delays e.g. periodic task intervals. */ + adjustment = ((process_timerticks - receive_timerticks) * 1000) / NX_IP_PERIODIC_RATE; + + status = _nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_client_local_ntp_time), (LONG)adjustment); + + /* Done processing time update. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_calculate_roundtrip PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes roundtrip based on the elapsed time from */ +/* sending the unicast request to receiving the SNTP response. */ +/* */ +/* INPUT */ +/* */ +/* roundtrip_time round trip time computation */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Valid time computations result */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_process_update_packet */ +/* Process server update packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time) +{ + +ULONG x; + + + /* Initialize invalid results. */ + *roundtrip_time = 0; + + /* Compute the roundtrip as the time the packet left the SNTP Client + to the time it received a response from the SNTP server. */ + + /* Check for wrapped timer value. */ + if (send_timerticks > receive_timerticks) + { + /* The time has wrapped. */ + x = 0xFFFFFFFF - send_timerticks; + *roundtrip_time = (LONG)(receive_timerticks + x); + } + else + { + *roundtrip_time = (LONG)(receive_timerticks - send_timerticks); + } + + /* Convert to milliseconds. */ + *roundtrip_time = (LONG)((ULONG)(*roundtrip_time) * NX_SNTP_MILLISECONDS_PER_TICK); + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_get_local_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get local time service.*/ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Pointer to SNTP seconds */ +/* fraction Local time fraction component */ +/* buffer Pointer for time in string format */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_get_local_time Get local time service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer) +{ + +UINT status; + + + /* Check input pointer parameters. */ + if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL)) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_sntp_client_get_local_time(client_ptr, seconds, fraction, buffer); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_get_local_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the current SNTP Client local time and */ +/* returns the data in seconds and fractions, and if a non zero */ +/* buffer pointer is supplied, a string containing the data in ASCII. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Pointer to SNTP seconds */ +/* fraction Local time fraction component */ +/* buffer Pointer for time in string format */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* _nx_sntp_client_get_local_time_extended */ +/* Get local time service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer) +{ + +UINT status; + + status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, NX_MAX_STRING_LENGTH); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_get_local_time_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get extended local */ +/* time service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Pointer to SNTP seconds */ +/* fraction Local time fraction component */ +/* buffer Pointer for time in string format */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_get_local_time_extended */ +/* Get extended local time service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size) +{ + +UINT status; + + + /* Check input pointer parameters. */ + if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL)) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check if this function is called from the appropriate thread. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, buffer_size); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_get_local_time_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the current SNTP Client local time and */ +/* returns the data in seconds and fractions, and if a non zero */ +/* buffer pointer is supplied, a string containing the data in ASCII. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Pointer to SNTP seconds */ +/* fraction Local time fraction component */ +/* buffer Pointer for time in string format */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_fraction_to_usecs */ +/* Convert NTP fraction to usecs */ +/* _nx_sntp_client_number_to_ascii Converts number to ascii text */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size) +{ + +ULONG usecs; +UINT offset = 0; +UINT length = 0; + + *seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds; + *fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; + + if (buffer != NX_NULL) + { + + /* Convert SNTP fraction component into microseconds. */ + _nx_sntp_client_utility_fraction_to_usecs(client_ptr -> nx_sntp_client_local_ntp_time.fraction, &usecs); + + /* Decrease length for terminal zero. */ + buffer_size--; + + /* Create a string with just the time. */ + /* Format: "Time: %lu.%06lu sec.\r\n" */ + if (buffer_size < 6) + { + return(NX_SIZE_ERROR); + } + buffer[offset++] = 'T'; + buffer[offset++] = 'i'; + buffer[offset++] = 'm'; + buffer[offset++] = 'e'; + buffer[offset++] = ':'; + buffer[offset++] = ' '; + length = _nx_sntp_client_number_to_ascii(&buffer[offset], buffer_size - offset, + client_ptr->nx_sntp_client_local_ntp_time.seconds); + if (length == 0) + { + return(NX_SIZE_ERROR); + } + offset += length; + if ((buffer_size - offset) < 14) + { + return(NX_SIZE_ERROR); + } + buffer[offset++] = '.'; + length = _nx_sntp_client_number_to_ascii(&buffer[offset], 6, usecs); + if (length == 0) + { + return(NX_SIZE_ERROR); + } + + if (length < 6) + { + + /* Append zeroes. */ + memmove(&buffer[offset + (6 - length)], &buffer[offset], length); + memset(&buffer[offset], '0', (6 - length)); + } + buffer[offset++] = ' '; + buffer[offset++] = 's'; + buffer[offset++] = 'e'; + buffer[offset++] = 'c'; + buffer[offset++] = '.'; + buffer[offset++] = '\r'; + buffer[offset++] = '\n'; + buffer[offset] = '\0'; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_convert_time_to_UCHAR PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts time from the ULONG seconds and msecs in the */ +/* NX_SNTP_TIME data to the 32 bit UCHAR seconds and fraction fields in*/ +/* the NTP time message. The caller specifies which time stamp in the */ +/* NTP time message (transmit,receive, origination, or reference clock)*/ +/* and that field is converted over. */ +/* */ +/* INPUT */ +/* */ +/* time_ptr Pointer to NX_SNTP_TIME time */ +/* time_message_ptr Pointer to NTP (UCHAR) time */ +/* which_stamp Which time stamp to convert */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_PARAM_ERROR Invalid time stamp requested */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memset Clear specified area of memory */ +/* memcpy Copy data to specified area of memory*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_send_unicast_request */ +/* Create a time request and transmit it*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time_ptr, + NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp) +{ + +ULONG *buffer; + + /* Copy the buffer to the requested time stamp field. */ + switch (which_stamp) + { + + case REFERENCE_TIME: + buffer = time_message_ptr -> reference_clock_update_time_stamp; + break; + + case ORIGINATE_TIME: + buffer = time_message_ptr -> originate_time_stamp; + break; + + case RECEIVE_TIME: + buffer = time_message_ptr -> receive_time_stamp; + break; + + case TRANSMIT_TIME: + buffer = time_message_ptr -> transmit_time_stamp; + break; + + default: + /* Invalid time stamp. Return as error. */ + return NX_SNTP_PARAM_ERROR; + } + + /* Copy NX_SNTP_TIME seconds and fraction to the buffer. */ + *(buffer) = time_ptr -> seconds; + *(buffer + 1) = time_ptr -> fraction; + + /* Return successful completion. */ + return NX_SUCCESS; +} + +/* The conventional civil timescale used in most parts of the world is based on Coordinated Universal Time (UTC), + which replaced Greenwich Mean Time (GMT) many years ago. UTC is based on International Atomic Time (TAI), + which is derived from hundreds of cesium oscillators in the national standards laboratories of many regions. + Deviations of UTC from TAI are implemented in the form of leap seconds, which occur at intervals from a + few months to serveral years. */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_convert_seconds_to_date PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the month, day, and time in an NTP time based */ +/* on the known number of seconds at 1/1/1999 since 1/1/1900 (the NTP */ +/* time epoch) and the current NTP time. The caller must indicated the */ +/* year of the NTP time to convert to simplify the computation. The data*/ +/* is written to an NX_SNTP_DATE_TIME object from which the call can */ +/* extract date and time data, or call the NetX SNTP API to display the */ +/* data/time string. */ +/* */ +/* INPUT */ +/* */ +/* current_NTP_time_ptr Pointer to NTP time */ +/* current_year Year in the NTP time data */ +/* current_date_time_ptr Pointer to date time object */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting time */ +/* NX_SNTP_UNABLE_TO_CONVERT_DATETIME Insufficient data for converting */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_convert_fraction_to_msecs */ +/* Converts the 32 bit fraction field*/ +/* in an NTP time to milliseconds */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year, + NX_SNTP_DATE_TIME *current_date_time_ptr) +{ + + /* Check if there is a base number of seconds set. */ +#if (NTP_SECONDS_AT_01011999 == 0) + + /* No, so we cannot convert time into months and years. */ + return NX_SNTP_UNABLE_TO_CONVERT_DATETIME; +#else + +UINT seconds_diff; +UINT years_diff; +UINT leapyears_diff; +UINT leaps; +UINT seconds_into_currentyear; +UINT seconds_into_currentmonth; +UINT seconds_into_currentday; +UINT seconds_into_currenthour; + + memset(current_date_time_ptr, 0, sizeof(NX_SNTP_DATE_TIME)); + + do + { + + current_date_time_ptr -> year = current_year; + + seconds_diff = current_NTP_time_ptr -> seconds - NTP_SECONDS_AT_01011999; + + years_diff = current_year - 1999; + + /* Figure out number of leap years since 1999 not including the current year. */ + leapyears_diff = (current_year - 1 - 1996) >> 2; + + /* Determine if this is a leap year. */ + leaps = (current_year - 1996) & 3; + + /* Check if this is a leap year. */ + if (leaps == 0 ) + { + /* It is! */ + current_date_time_ptr -> leap_year = NX_TRUE; + } + else + { + + /* Not a leap year. Clear the leap year flag. */ + current_date_time_ptr -> leap_year = NX_FALSE; + } + + /* Compute number of seconds into the current year e.g. as of 01/01 at midnite by subtracting + the total number of seconds since 1/1/1999 up to the end of the previous year. Remember to compute + the leapyear seconds at a different rate. */ + seconds_into_currentyear = seconds_diff - ((years_diff - leapyears_diff) * SECONDS_PER_NONLEAPYEAR) + - (leapyears_diff * SECONDS_PER_LEAPYEAR); + + current_year++; + + }while(seconds_into_currentyear > SECONDS_PER_NONLEAPYEAR); + + /* Initialize month to January till we find out what the month is. */ + current_date_time_ptr -> month = JANUARY; + + while (1) + { + + /* Does the number of seconds goes past January? */ + if (seconds_into_currentyear >= SEC_IN_JAN) + { + + /* Yes, reset month to Feb and subtract seconds in January. */ + current_date_time_ptr -> month = FEBRUARY; + seconds_into_currentyear -= SEC_IN_JAN; + } + /* No, we're done going month to month. */ + else break; + + /* Handle February differently because it is a leap month. */ + if (current_date_time_ptr -> leap_year) + { + + /* This is a leap year so Feb has 29 days. */ + if (seconds_into_currentyear >= SEC_IN_LEAPFEB) + { + current_date_time_ptr -> month = MARCH; + seconds_into_currentyear -= SEC_IN_LEAPFEB; + } + else break; + + } + else + { + /* Not a leap year, Feb has the usual 28 days. */ + if (seconds_into_currentyear >= SEC_IN_NONLEAPFEB) + { + current_date_time_ptr -> month = MARCH; + seconds_into_currentyear -= SEC_IN_NONLEAPFEB; + } + else break; + + } + + /* Repeat for each month for the rest of the year. */ + + if (seconds_into_currentyear >= SEC_IN_MAR) + { + current_date_time_ptr -> month = APRIL; + seconds_into_currentyear -= SEC_IN_MAR; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_APR) + { + current_date_time_ptr -> month = MAY; + seconds_into_currentyear -= SEC_IN_APR; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_MAY) + { + current_date_time_ptr -> month = JUNE; + seconds_into_currentyear -= SEC_IN_MAY; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_JUN) + { + current_date_time_ptr -> month = JULY; + seconds_into_currentyear -= SEC_IN_JUN; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_JUL) + { + current_date_time_ptr -> month = AUGUST; + seconds_into_currentyear -= SEC_IN_JUL; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_AUG) + { + current_date_time_ptr -> month = SEPTEMBER; + seconds_into_currentyear -= SEC_IN_AUG; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_SEP) + { + current_date_time_ptr -> month = OCTOBER; + seconds_into_currentyear -= SEC_IN_SEP; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_OCT) + { + current_date_time_ptr -> month = NOVEMBER; + seconds_into_currentyear -= SEC_IN_OCT; + } + else break; + + if (seconds_into_currentyear >= SEC_IN_NOV) + { + current_date_time_ptr -> month = DECEMBER; + seconds_into_currentyear -= SEC_IN_NOV; + } + else break; + + /* We should not have more than the seconds in december or there is an error. */ + if (seconds_into_currentyear > SEC_IN_DEC) + { + + /* Return the error status. */ + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + else break; + } + + /* Time is now in the current month. */ + seconds_into_currentmonth = seconds_into_currentyear; + + /* Compute how many complete days the time goes into the current month and + add one for the current day. */ + current_date_time_ptr -> day = seconds_into_currentmonth/SECONDS_PER_DAY + 1; + + /* Compute the number of seconds into the current day. */ + seconds_into_currentday = seconds_into_currentmonth % SECONDS_PER_DAY; + + /* Compute the number of complete hours into the current day we are. */ + current_date_time_ptr -> hour = seconds_into_currentday/SECONDS_PER_HOUR; + + /* Compute the number of seconds into the current hour. */ + seconds_into_currenthour = seconds_into_currentday % SECONDS_PER_HOUR; + + /* Break this down into minutes. */ + current_date_time_ptr -> minute = seconds_into_currenthour/SECONDS_PER_MINUTE; + + /* Finally the remainder is the seconds. */ + current_date_time_ptr -> second = seconds_into_currenthour % SECONDS_PER_MINUTE; + + /* Convert time fraction field into milliseconds. */ + _nx_sntp_client_utility_convert_fraction_to_msecs((ULONG *)(&(current_date_time_ptr -> millisecond)), current_NTP_time_ptr); + + return NX_SUCCESS; +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_utility_display_date_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking services on the display date */ +/* time service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* buffer Pointer to string buffer */ +/* length Size of the string buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_SNTP_PARAM_ERROR Invalid non pointer input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_display_date_time */ +/* Actual display date/time service */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length) +{ + +UINT status; + + + /* Check for invalid pointer input. */ + if ((client_ptr == NX_NULL) || (buffer == NX_NULL)) + { + + /* Return pointer error. */ + return NX_PTR_ERROR; + } + + /* Check for invalid parameter input. */ + if (length == 0) + { + + /* Return parameter error. */ + return NX_SNTP_PARAM_ERROR; + } + + /* Call the actual display time service. */ + status = _nx_sntp_client_utility_display_date_time(client_ptr, buffer, length); + + /* Return completion status. */ + return status; +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_request_unicast_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the service that */ +/* forwards a unicast request from the SNTP Client application. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* wait_option Time to wait for response (ticks) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if (client_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + status = _nx_sntp_client_request_unicast_time(client_ptr, wait_option); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_request_unicast_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a unicast request regardless if the SNTP Client */ +/* is configured for unicast or broadcast mode. After sending the */ +/* request, the function waits for the specified time for a response. */ +/* */ +/* If received, the SNTP Server response is processed as it normally is*/ +/* for valid SNTP data, and applied to the SNTP Client's notion of time*/ +/* "local time". */ +/* */ +/* This will not interfere with subsequent unicast requests in unicast */ +/* mode, or the processing of periodic updates in broadcast mode. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* wait_option Time to wait for response (ticks) */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Actual completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option) +{ + +UINT status; + + + /* Make sure the client is started. */ + if (!client_ptr -> nx_sntp_client_started) + { + return NX_SNTP_CLIENT_NOT_STARTED; + } + + /* Create and send a unicast request. */ + status = _nx_sntp_client_send_unicast_request(client_ptr); + + if (status != NX_SUCCESS) + { + return status; + } + + /* Wait to receive a response. */ + status = _nx_sntp_client_receive_time_update(client_ptr, wait_option); + + /* If we got a valid SNTP packet, process the data. */ + if (status == NX_SUCCESS) + { + + /* Process the server update packet and apply to local time if valid. */ + status = _nx_sntp_client_process_update_packet(client_ptr); + } + + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + /* Return completion status. */ + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_display_date_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts an NTP time data into a month-date-year time, */ +/* including seconds and second fraction string. It is intended as a */ +/* human readable representation of NTP time. The caller must supply a */ +/* pointer to a buffer large enough (40 chars is enough) to hold the */ +/* string and define the NX_SNTP_CURRENT_YEAR parameter, usually as the */ +/* current year. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* buffer Pointer to string buffer */ +/* length Size of the string buffer */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_INVALID_DATETIME_BUFFER Buffer not large enough */ +/* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting NTP time*/ +/* status Convert seconds completion status */ +/* */ +/* CALLS */ +/* _nx_sntp_client_utility_convert_seconds_to_date */ +/* Converts seconds to year, month */ +/* _nx_sntp_client_number_to_ascii Converts number to ascii text */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length) +{ + +UINT status; +UINT offset; +UINT return_length; +NX_SNTP_DATE_TIME DisplayTime; +const CHAR *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aud", "Sep", "Oct", "Nov", "Dec"}; + + +#ifndef NX_SNTP_CURRENT_YEAR + return NX_SNTP_ERROR_CONVERTING_DATETIME; +#else + + /* Verify the client has set a local time. */ + if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + + status = _nx_sntp_client_utility_convert_seconds_to_date(&(client_ptr -> nx_sntp_client_local_ntp_time), NX_SNTP_CURRENT_YEAR, &DisplayTime); + if (status != NX_SUCCESS) + { + return status; + } + + /* Check if we have a long enough buffer. */ + if (length < 5) + { + + /* Return the error status. */ + return NX_SNTP_INVALID_DATETIME_BUFFER; + } + + /* Decrease length for terminal zero. */ + length--; + + /* Substitute numeric month to name of the month. */ + if ((DisplayTime.month < JANUARY) || (DisplayTime.month > DECEMBER)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + buffer[0] = months[DisplayTime.month - JANUARY][0]; + buffer[1] = months[DisplayTime.month - JANUARY][1]; + buffer[2] = months[DisplayTime.month - JANUARY][2]; + buffer[3] = ' '; + offset = 4; + + /* Write in the rest of the data as numeric from the Date Time objext. */ + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.day); + if ((return_length == 0) || ((length - offset) < 2)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = ','; + buffer[offset++] = ' '; + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.year); + if ((return_length == 0) || ((length - offset) < 1)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = ' '; + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.hour); + if ((return_length == 0) || ((length - offset) < 1)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = ':'; + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.minute); + if ((return_length == 0) || ((length - offset) < 1)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = ':'; + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.second); + if ((return_length == 0) || ((length - offset) < 1)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = '.'; + return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.millisecond); + if ((return_length == 0) || ((length - offset) < 5)) + { + return NX_SNTP_ERROR_CONVERTING_DATETIME; + } + offset += return_length; + buffer[offset++] = ' '; + buffer[offset++] = 'U'; + buffer[offset++] = 'T'; + buffer[offset++] = 'C'; + buffer[offset++] = ' '; + buffer[offset] = '\0'; + +#endif + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_add_msecs_to_ntp_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds msecs (not necessarily a positive value and not */ +/* limited to less than a second) to an NTP time value. Msecs cannot be */ +/* added directly to the fraction field in the NTP time field because */ +/* this field is represented in fixed point notation. Arithmetic */ +/* overflow and loss of sign errors as a result of adding numbers are */ +/* handled as errors. */ +/* */ +/* INPUT */ +/* */ +/* timeA_ptr Pointer to NTP time operand */ +/* msecs_to_add Time (msecs) to add */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_OVERFLOW_ERROR Overflow result adding numbers */ +/* NX_SNTP_INVALID_TIME An invalid result (e.g. negative */ +/* time) from adding numbers */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_process_time_data Apply server time to local time */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add) +{ + +UINT status; +ULONG timeA_usec; +LONG seconds; +LONG usecs; + + + /* Separate msecs_to_add into seconds and milliseconds. */ + seconds = msecs_to_add / 1000; + usecs = (msecs_to_add % 1000) * 1000; + + /* Are we adding a positive number? */ + if (msecs_to_add > 0) + { + /* Yes; check for overflow before trying to add seconds to the TimeA operand. */ + status = _nx_sntp_client_utility_addition_overflow_check(timeA_ptr -> seconds, (ULONG)seconds); + + /* Check for error (overflow). */ + if (status != NX_SUCCESS) + { + + /* Return the error condition. */ + return status; + } + } + /* Check if a negative number larger than the timeA operand is being added (creates negative time!)*/ + else if (timeA_ptr -> seconds < (ULONG)abs(seconds)) + { + + /* Yes; return the error condition. */ + return NX_SNTP_INVALID_TIME; + } + + /* Ok to add seconds to the NTP time seconds. */ + timeA_ptr -> seconds += (ULONG)seconds; + + /* Next get the usecs from the timeA operand (always positive and < 1000000). */ + _nx_sntp_client_utility_fraction_to_usecs(timeA_ptr -> fraction, &timeA_usec); + + /* In case usecs is < 0, we might have to perform a carry. */ + if ((usecs + (LONG)timeA_usec) < 0) + { + /* Perform a carry by subtracting a second from timeA seconds...*/ + timeA_ptr -> seconds--; + + /* And adding it to the usecs of timeA. */ + timeA_usec += 1000000; + } + + /* OK to add the usecs up. */ + usecs += (LONG)timeA_usec; + + /* Check for a positive carry over into seconds. */ + if (usecs >= 1000000) + { + /* Yes there's a carry; check for possibility of overflow + before adding carry (unlikely for another 30 years). */ + if (timeA_ptr -> seconds == 0xFFFFFFFF) + { + + return NX_SNTP_OVERFLOW_ERROR; + } + + /* OK to increment the seconds. */ + timeA_ptr -> seconds++; + + /* Set milliseconds to remainder. */ + usecs = usecs % 1000000; + } + + /* Convert usecs to the fixed point notation fraction and store in TimeA fraction. */ + status = _nx_sntp_client_utility_usecs_to_fraction((ULONG)usecs, &(timeA_ptr ->fraction)); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_receiving_updates PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the get SNTP get receive */ +/* status service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP client instance */ +/* receive_status Pointer to server status */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid input status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_receiving_updates */ +/* Actual get server status service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status) +{ + +UINT status; + + /* Check for the validity of input parameter. */ + if ((client_ptr == NX_NULL) || (receive_status == NX_NULL)) + { + + /* Return error status. */ + return(NX_PTR_ERROR); + } + + status = _nx_sntp_client_receiving_updates(client_ptr, receive_status); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_receiving_updates PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the status of the Client SNTP server. If the */ +/* client has not received a valid update within the NX_SNTP_CLIENT_MAX_*/ +/* _TIME_LAPSE interval or if the number of invalid updates received by */ +/* the client exceeds the NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT limit, */ +/* the status is set to NX_FALSE. If the Client has not yet received */ +/* its first valid update from the current SNTP server, status is set to*/ +/* false. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP client instance */ +/* receive_status Pointer to receive_status */ +/* NX_FALSE: not receiving updates */ +/* NX_TRUE: receiving valid updates */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid input status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get the SNTP mutex */ +/* tx_mutex_put Release the SNTP mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status) +{ + + + /* Get the SNTP mutex. */ + tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); + + /* Verify the client's SNTP server is valid, and the Client has received at least one valid udpate from it. */ + *receive_status = ((client_ptr -> nx_sntp_valid_server_status == NX_TRUE) && (client_ptr -> nx_sntp_client_first_update_pending == NX_FALSE)); + + /* Release the SNTP mutex. */ + tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); + + /* Return completion status. */ + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_set_local_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the set client local time */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Local time seconds component */ +/* fraction Local time fraction component */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_set_local_time Actual set client local time service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction) +{ + +UINT status; + + + /* Check for invalid input. */ + if (client_ptr == NX_NULL) + { + return NX_PTR_ERROR; + } + + /* Call the actual service. */ + status = _nx_sntp_client_set_local_time(client_ptr, seconds, fraction); + + /* Return completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_set_local_time PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function takes the seconds and fraction input from the caller */ +/* (or more accurately the independent time clock source, and applies it*/ +/* to the SNTP client local time. */ +/* */ +/* In between SNTP server updates, it is expected that the SNTP Client */ +/* host application will update the SNTP client local time from the */ +/* independent time source (e.g. real time clock on board) and then */ +/* use the SNTP Server time updates to correct the local time for drifts*/ +/* from the correct time. */ +/* */ +/* It can also set the SNTP Client's base time before starting up the */ +/* SNTP Client. If the host application cannot obtain a base time, the */ +/* SNTP Client will take the first SNTP update as the absolute time. If */ +/* the host application does have a real time clock or independent time */ +/* keeper, the SNTP client can set a large enough max adjustment that */ +/* any Server time udpate will be accepted to the SNTP Client. This */ +/* leaves the SNTP Client completely dependent on the network and SNTP */ +/* Server, plus it is vulnerable to rogue SNTP packets. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to SNTP Client */ +/* seconds Local time seconds component */ +/* fraction Local time fraction component */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction) +{ + + + client_ptr -> nx_sntp_client_local_ntp_time.seconds = seconds; + client_ptr -> nx_sntp_client_local_ntp_time.fraction = fraction; + client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0; + + /* Return completion status. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_set_time_update_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the set time update */ +/* callback service. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* time_update_cb Pointer to callback when Client */ +/* receives an SNTP update */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_set_time_update_notify */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, + VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)) +{ + +UINT status; + + + /* Check for valid input. */ + if ((client_ptr == NX_NULL) || (time_update_cb == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_sntp_client_set_time_update_notify(client_ptr, time_update_cb); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_set_time_update_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the application of a valid SNTP time update. */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to Client struct */ +/* time_update_cb Pointer to callback when Client */ +/* receives an SNTP update */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, + VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)) +{ + + + client_ptr -> nx_sntp_client_time_update_notify = time_update_cb; + + return NX_SUCCESS; +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_get_msec_diff PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the difference in milliseconds between two */ +/* NTP times, receiving an NTP packet, and transmitting it back. */ +/* The logic calculates the difference in the seconds component and */ +/* converts it to milliseconds. It converts the fraction to useconds */ +/* and calculates that difference. Useconds are rounded to the nearest */ +/* millisecond. This logic assumes the transmit time occurs after */ +/* receive time. */ +/* */ +/* The net difference is the difference in milliseconds from the */ +/* fractions added to (or subtracted from) the difference in */ +/* milliseconds from the seconds component. */ +/* */ +/* Note that the conversion of useconds to milliseconds may result */ +/* in the two times' difference to be zero, when they are actually */ +/* different by useconds. */ +/* */ +/* INPUT */ +/* */ +/* timeReceived_ptr NTP time of received message */ +/* timeTransmit_ptr NTP time of transmitted message */ +/* total_difference_msecs Millseconds of difference in time */ +/* pos_diff True if Transmit Time >= */ +/* Receive Time */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Valid transmit/receive times */ +/* NX_SNTP_OVERFLOW_ERROR Overflow result */ +/* NX_SNTP_INVALID_TIME Transmit time seconds > timeTransmit_ptr -> seconds) + { + + /* Use a temporary variable to store the difference in the seconds. */ + temp = timeReceived_ptr -> seconds - timeTransmit_ptr -> seconds; + *pos_diff = NX_FALSE; + } + else + { + + /* Reverse the operand to get the absolute difference in the seconds. */ + temp = timeTransmit_ptr -> seconds -timeReceived_ptr -> seconds; + *pos_diff = NX_TRUE; + } + + /* Check for overflow when converting seconds to milliseconds + (0x3E8 = 1000). */ + if (temp > (0xFFFFFFFF / 0x3E8)) + { + + /* Return error status. */ + return NX_SNTP_OVERFLOW_ERROR; + } + + /* Convert to msecs. */ + seconds_difference_in_msecs = temp * 1000; + + /* Convert the Received time fraction to usecs and msecs. */ + _nx_sntp_client_utility_fraction_to_usecs(timeReceived_ptr -> fraction, &usecsReceived); + + msecsReceived = usecsReceived / 1000; + + if (usecsReceived % 1000 >= 500) + msecsReceived++; + + /* Convert the Transmit Time fraction to usecs and msecs. */ + _nx_sntp_client_utility_fraction_to_usecs(timeTransmit_ptr -> fraction, &usecsTransmit); + + msecsTransmit = usecsTransmit / 1000; + + if (usecsTransmit % 1000 >= 500) + msecsTransmit++; + + /* Get the difference of the two time stamps' fraction in milliseconds. */ + if (timeReceived_ptr -> seconds == timeTransmit_ptr -> seconds) + { + + /* Determine the absolute difference in the millisecond component. */ + if (usecsTransmit >= usecsReceived) + { + + *total_difference_msecs = msecsTransmit - msecsReceived; + } + else + { + + /* Transmit time usecs < Received time usecs. */ + *pos_diff = NX_FALSE; + *total_difference_msecs = msecsReceived - msecsTransmit; + } + } + else + { + + /* Consider the case where the transmit time seconds is greater. */ + if (timeTransmit_ptr -> seconds > timeReceived_ptr -> seconds) + { + + if ( usecsTransmit >= usecsReceived) + { + + /* This will add to the total milliseconds' difference. */ + *total_difference_msecs = seconds_difference_in_msecs + (msecsTransmit - msecsReceived); + } + else /* (usecsReceived > usecsTransmit) */ + { + + /* This will subtract from the total milliseconds' difference . */ + *total_difference_msecs = seconds_difference_in_msecs - (msecsReceived - msecsTransmit); + } + } + + /* Consider the case where the transmit time seconds is less. */ + else + { + + if (usecsReceived >= usecsTransmit) + { + + /* This will add to the total milliseconds' difference. */ + *total_difference_msecs = seconds_difference_in_msecs + (msecsReceived - msecsTransmit); + } + else /* (usecsTransmit > usecsReceived) */ + { + + /* This will subtract from the total milliseconds' difference . */ + *total_difference_msecs = seconds_difference_in_msecs - (msecsTransmit - msecsReceived); + } + } + } + + /* Return successful completion status. */ + return NX_SUCCESS; + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_is_zero_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function tests each byte (UCHAR) of data to be non zero. The */ +/* return value indicates if the entire data is zero. */ +/* */ +/* INPUT */ +/* */ +/* data Pointer to first byte of data */ +/* size Number of bytes in data */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE Each byte of data is zero */ +/* NX_FALSE At least one byte is non zero */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_apply_sanity_checks Checks SNTP server reply validity*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size) +{ + +UINT i; +UINT is_zero; + + + /* Initialize local variables. */ + i = 0; + is_zero = NX_TRUE; + + while(i < size) + { + + if (*data != 0x0) + { + + is_zero = NX_FALSE; + break; + } + + data += sizeof(UCHAR); + i++; + } + + return is_zero; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_convert_fraction_to_msecs PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the fraction in an NTP time to milliseconds. */ +/* */ +/* INPUT */ +/* */ +/* milliseconds Pointer to milliseconds converted */ +/* time_ptr Pointer to an NTP time */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_fraction_to_usecs */ +/* Convert fraction to usecs */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_utility_display_NTP_time */ +/* Display NTP time in seconds */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr) +{ + +ULONG usecs; + + + /* Convert to usecs first. */ + _nx_sntp_client_utility_fraction_to_usecs(time_ptr ->fraction, &usecs); + + /* Then convert to milliseconds. */ + *milliseconds = usecs / 1000; + + /* Round up if greater than 500 usecs left over*/ + if (usecs % 1000 >= 500) + { + + (*milliseconds)++; + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_utility_usecs_to_fraction PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the utility to convert */ +/* microseconds to fraction. */ +/* */ +/* INPUT */ +/* */ +/* usecs Microseconds to convert */ +/* fraction Pointer to converted fraction */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_INVALID_TIME Invalid SNTP data input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_usecs_to_fraction */ +/* Actual usecs conversion service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction) +{ + +UINT status; + + + if ((usecs == 0) || (fraction == NX_NULL)) + { + + return NX_SNTP_INVALID_TIME; + } + + status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_usecs_to_fraction PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts microseconds to a time stamp fraction. It is */ +/* primarily an intermediary function used in the process of converting */ +/* millliseconds to fixed point time fraction data. */ +/* */ +/* This conversion scheme is limited to microseconds less than 1000000. */ +/* */ +/* INPUT */ +/* */ +/* usecs Microseconds to convert */ +/* fraction Fraction to converted fraction */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_OVERFLOW_ERROR Overflow error status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_utility_msecs_to_fraction */ +/* Convert milliseconds to fixed point*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction) +{ + +ULONG _frac = usecs * 3962; + + + *fraction = (usecs * 4294) + (_frac >> 12); + + if((_frac & 4095) >= 2048) + *fraction = *fraction + 1; + + /* Successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_utility_msecs_to_fraction PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the utility to convert */ +/* milliseconds to fraction. */ +/* */ +/* INPUT */ +/* */ +/* msecs Milliseconds to convert */ +/* fraction Pointer to converted fraction */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_INVALID_TIME Invalid SNTP data input */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_msecs_to_fraction */ +/* Actual msecs conversion service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction) +{ + +UINT status; + + + if ((msecs == 0) || (fraction == NX_NULL)) + { + + return NX_SNTP_INVALID_TIME; + } + + status = _nx_sntp_client_utility_msecs_to_fraction(msecs, fraction); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_msecs_to_fraction PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts milliseconds to fixed point notation used in */ +/* the NTP time fraction field. This will not accept msecs >= 1000 */ +/* because that number cannot be represented in an NTP time fraction. */ +/* */ +/* INPUT */ +/* */ +/* msecs Milliseconds to convert */ +/* fraction Pointer to converted fraction */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_SNTP_OVERFLOW_ERROR Overflow result */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_usecs_to_fraction */ +/* Convert usecs to fixed point */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ +/* Add msecs to an NTP time data */ +/* _nx_sntp_client_utility_add_NTPtime */ +/* Add two NTP time fields */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction) +{ + +UINT status; +ULONG usecs; + + + /* Check for possible overflow. */ + if (msecs > 1000) + { + + /* Return error condition. */ + return NX_SNTP_OVERFLOW_ERROR; + } + + /* Convert msecs to usecs first. */ + usecs = msecs * 1000; + + /* Convert usecs to fraction. */ + status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Return the error status. */ + return status; + } + + /* Successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_sntp_client_utility_fraction_to_usecs PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking on the utility to convert */ +/* fraction to microseconds. */ +/* */ +/* INPUT */ +/* */ +/* fraction Fraction to convert */ +/* usecs Pointer to converted microseconds */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_sntp_client_utility_fraction_to_usecs */ +/* Actual usecs conversion service */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs) +{ + +UINT status; + + + if (usecs == NX_NULL) + { + return NX_SNTP_INVALID_TIME; + } + + status = _nx_sntp_client_utility_fraction_to_usecs(fraction, usecs); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_fraction_to_usecs PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a time stamp fraction to microseconds. It is */ +/* primarily an intermediary function used in the process of converting */ +/* fixed point time fraction data to msecs. */ +/* */ +/* INPUT */ +/* */ +/* fraction Fraction to convert to usecs */ +/* usecs Pointer to ucsecs from fraction */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_get_local_time_extended */ +/* Get extended local time */ +/* _nx_sntp_client_utility_convert_fraction_to_msecs */ +/* Convert time fraction to msecs */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs) +{ + +ULONG value, segment; +int i; + + value = 0; + + for(i = 2; i < 32; i+=6) + { + segment = (fraction >> i) & 0x3F; + + if((value & 0x3F) >= 32) + value = (value >> 6) + segment * 15625 + 1; + else + value = (value >> 6) + segment * 15625; + } + *usecs = value; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_convert_refID_KOD_code PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the reference ID field in a NTP time message */ +/* data to a known Kiss of Death reference_id. */ +/* */ +/* Note the Kiss of Death reference_id list is subject to change. This */ +/* is current as of 4/01/2007. */ +/* */ +/* INPUT */ +/* */ +/* reference_id Pointer to the reference ID to convert */ +/* code_id Pointer to converted code */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Copy data to specified area of memory */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code (e.g. the Client kiss of death handler callback) */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id) +{ + +/* This is the internal list of Kiss of Death codes and their meaning. */ + + + /* Compare the reference_id to each known reference_id and if it matches return the reference_id ID. */ + if (!memcmp(reference_id, ANYCAST, 4)) + { + *code_id = NX_SNTP_KOD_ANYCAST; + } + else if (!memcmp(reference_id, AUTH_FAIL, 4)) + { + *code_id = NX_SNTP_KOD_AUTH_FAIL; + } + else if (!memcmp(reference_id, AUTOKEY_FAIL, 4)) + { + *code_id = NX_SNTP_KOD_AUTOKEY_FAIL; + } + else if (!memcmp(reference_id, BROADCAST, 4)) + { + *code_id = NX_SNTP_KOD_BROADCAST; + } + else if (!memcmp(reference_id, CRYP_FAIL, 4)) + { + *code_id = NX_SNTP_KOD_CRYP_FAIL; + } + else if (!memcmp(reference_id, DENY, 4)) + { + *code_id = NX_SNTP_KOD_DENY; + } + else if (!memcmp(reference_id, DROP, 4)) + { + *code_id = NX_SNTP_KOD_DROP; + } + else if (!memcmp(reference_id, DENY_POLICY, 4)) + { + *code_id = NX_SNTP_KOD_DENY_POLICY; + } + else if (!memcmp(reference_id, NOT_INIT, 4)) + { + *code_id = NX_SNTP_KOD_NOT_INIT; + } + else if (!memcmp(reference_id, MANYCAST, 4)) + { + *code_id = NX_SNTP_KOD_MANYCAST; + } + else if (!memcmp(reference_id, NO_KEY, 4)) + { + *code_id = NX_SNTP_KOD_NO_KEY; + } + else if (!memcmp(reference_id, RATE, 4)) + { + *code_id = NX_SNTP_KOD_RATE; + } + else if (!memcmp(reference_id, RMOT, 4)) + { + *code_id = NX_SNTP_KOD_RMOT; + } + else if (!memcmp(reference_id, STEP, 4)) + { + *code_id = NX_SNTP_KOD_STEP; + } + else + { + /* Set reference_id ID to generic KOD 'other' reference_id. */ + *code_id = NX_SNTP_KISS_OF_DEATH_PACKET; + } + + /* Return successful completion. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_utility_addition_overflow_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs a simple platform independent check for */ +/* overflow when adding two operands. */ +/* */ +/* INPUT */ +/* */ +/* temp1 First addition operand */ +/* temp2 Second addition operand */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SNTP_OVERFLOW_ERROR Overflow result adding time */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ +/* Add msecs to an NTP time */ +/* _nx_sntp_client_utility_add_NTPtime */ +/* Add two NTP times */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2) +{ + +ULONG sum_lower_16, sum_upper_16; +UINT carry; + + + carry = 0; + + /* Add the lower 16 bits. */ + sum_lower_16 = (temp1 & NX_LOWER_16_MASK) + (temp2 & NX_LOWER_16_MASK); + + /* Check for carry. */ + if (sum_lower_16 & NX_CARRY_BIT) + { + + /* Use variable to add the carry to the upper 16 bits.*/ + carry = 1; + } + + /* Add the upper 16 bits. */ + sum_upper_16 = (temp1 >> NX_SHIFT_BY_16) + (temp2 >> NX_SHIFT_BY_16) + carry; + + /* Check for carry. */ + if (sum_upper_16 & NX_CARRY_BIT) + { + + /* This indicates an overflow. Return as an error. */ + return NX_SNTP_OVERFLOW_ERROR; + } + + /* Ok to add operands!*/ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_sntp_client_number_to_ascii PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number to ascii text. */ +/* */ +/* INPUT */ +/* */ +/* buffer_ptr Pointer to output string buffer */ +/* buffer_size Size of output buffer */ +/* number Number to convert to ASCII */ +/* */ +/* OUTPUT */ +/* */ +/* size Size of converted string */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_sntp_client_utility_display_date_time */ +/* Convert an NTP time */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_sntp_client_number_to_ascii(CHAR *buffer_ptr, UINT buffer_size, UINT number) +{ + +UINT i; +UINT digit; +UINT size; + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < buffer_size) + { + + /* Shift the current digits over one. */ + for (i = size; i != 0; i--) + { + + /* Move each digit over one place. */ + buffer_ptr[i] = buffer_ptr[i - 1]; + } + + /* Compute the next decimal digit. */ + digit = (number % 10); + + /* Update the input number. */ + number = (number / 10); + + /* Store the new digit in ASCII form. */ + if (digit < 10) + { + buffer_ptr[0] = (CHAR)(digit + '0'); + } + else + { + buffer_ptr[0] = (CHAR)((digit - 10) + 'a'); + } + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + return(0); + } + + /* Return size to caller. */ + return(size); +} \ No newline at end of file diff --git a/addons/sntp/nxd_sntp_client.h b/addons/sntp/nxd_sntp_client.h new file mode 100644 index 00000000..64612a65 --- /dev/null +++ b/addons/sntp/nxd_sntp_client.h @@ -0,0 +1,781 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX SNTP Client Component */ +/** */ +/** Simple Network Time Protocol (SNTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_sntp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Simple Network Time Protocol (SNTP) */ +/* Client component, including all data types and external references. */ +/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ +/* have already been included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_SNTP_CLIENT_H +#define NXD_SNTP_CLIENT_H + +#include "nx_ip.h" + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + + +#define NXD_SNTP_ID 0x534E5460UL + + +/* Conversion between seconds and timer ticks. This must equal the + NetX timer tick to seconds ratio. */ + +#define NX_SNTP_MILLISECONDS_PER_TICK (1000 / NX_IP_PERIODIC_RATE) + +/* Set minimum and maximum Client unicast poll period (in seconds) for requesting + time data. RFC 4330 polling range is from 16 - 131072 seconds. + Note that the RFC 4330 strongly recommends polling intervals of at least + one minute to unnecessary reduce demand on public time servers. */ + +#define NX_SNTP_CLIENT_MIN_UNICAST_POLL_INTERVAL 64 +#define NX_SNTP_CLIENT_MAX_UNICAST_POLL_INTERVAL 131072 + +/* Define Client request types. Note that this does not limit the + NetX SNTP Client from using MANYCAST or MULTICAST discovery options. */ + +#define BROADCAST_MODE 1 +#define UNICAST_MODE 2 + +#define NX_SNTP_CLIENT_RECEIVE_EVENT ((ULONG) 0x00000001) /* Event flag to signal a receive packet event */ + +/* Define the minimum size of the packet NTP/SNTP time message + (e.g. without authentication data). */ + +#define NX_SNTP_TIME_MESSAGE_MIN_SIZE 48 + + +/* Define the maximum size of the packet NTP/SNTP time message (includes 20 bytes for + optional authentication data). */ + +#define NX_SNTP_TIME_MESSAGE_MAX_SIZE 68 + +/* Define the largest IP4 size for ip address e.g. xxx.xxx.xxx.xxx */ + +#define NX_SNTP_CLIENT_MAX_IP_ADDRESS_SIZE 15 + + + +/* Define fields in the NTP message format. */ + +#define REFERENCE_TIME 0 +#define ORIGINATE_TIME 1 +#define RECEIVE_TIME 2 +#define TRANSMIT_TIME 3 + +/* Define masks for stratum levels. */ + +#define STRATUM_KISS_OF_DEATH 0x00 +#define STRATUM_PRIMARY 0x01 +#define STRATUM_SECONDARY 0x0E /* 2 - 15 */ +#define STRATUM_RESERVED 0xF0 /* 16 - 255*/ + + +/* Kiss of death strings (see Codes below). Applicable when stratum = 0 + + Code Meaning + -------------------------------------------------------------- */ + + +#define ANYCAST "ACST" /* The association belongs to an anycast server. */ +#define AUTH_FAIL "AUTH" /* Server authentication failed. */ +#define AUTOKEY_FAIL "AUTO" /* Autokey sequence failed. */ +#define BROADCAST "BCST" /* The association belongs to a broadcast server. */ +#define CRYP_FAIL "CRYP" /* Cryptographic authentication or identification failed. */ +#define DENY "DENY" /* Access denied by remote server. */ +#define DROP "DROP" /* Lost peer in symmetric mode. */ +#define DENY_POLICY "RSTR" /* Access denied due to local policy. */ +#define NOT_INIT "INIT" /* The association has not yet synchronized for the first time. */ +#define MANYCAST "MCST" /* The association belongs to a manycast server. */ +#define NO_KEY "NKEY" /* No key found. Either the key was never installed or is not trusted. */ +#define RATE "RATE" /* Rate exceeded. The server temporarily denied access; client exceeded rate threshold. */ +#define RMOT "RMOT" /* Somebody is tinkering with association from remote host running ntpdc. OK unless they've stolen your keys. */ +#define STEP "STEP" /* A step change in system time has occurred, but association has not yet resynchronized. */ + +/* Define Kiss of Death error codes. Note: there should be a 1 : 1 correspondence of + KOD strings to KOD error codes! */ + +#define NX_SNTP_KISS_OF_DEATH_PACKET 0xF00 + +#define NX_SNTP_KOD_ANYCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x01) +#define NX_SNTP_KOD_AUTH_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x02) +#define NX_SNTP_KOD_AUTOKEY_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x03) +#define NX_SNTP_KOD_BROADCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x04) +#define NX_SNTP_KOD_CRYP_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x05) +#define NX_SNTP_KOD_DENY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x06) +#define NX_SNTP_KOD_DROP (NX_SNTP_KISS_OF_DEATH_PACKET | 0x07) +#define NX_SNTP_KOD_DENY_POLICY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x08) +#define NX_SNTP_KOD_NOT_INIT (NX_SNTP_KISS_OF_DEATH_PACKET | 0x09) +#define NX_SNTP_KOD_MANYCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0A) +#define NX_SNTP_KOD_NO_KEY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0B) +#define NX_SNTP_KOD_RATE (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0C) +#define NX_SNTP_KOD_RMOT (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0D) +#define NX_SNTP_KOD_STEP (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0E) + +/* Define SNTP protocol modes. SNTP is limited to primarily Client, server and broadcast modes. */ + +#define PROTOCOL_MODE_RESERVED 0 +#define PROTOCOL_MODE_SYMM_ACTIVE 1 +#define PROTOCOL_MODE_SYMM_PASSIVE 2 +#define PROTOCOL_MODE_CLIENT 3 +#define PROTOCOL_MODE_SERVER_UNICAST 4 +#define PROTOCOL_MODE_SERVER_BROADCAST 5 +#define PROTOCOL_MODE_NTP_CNTL_MSG 6 +#define PROTOCOL_MODE_PRIVATE 7 + + +/* NX SNTP Client configurable options. */ + + + +/* Set the NetX SNTP client thread stack size . */ + +#ifndef NX_SNTP_CLIENT_THREAD_STACK_SIZE +#define NX_SNTP_CLIENT_THREAD_STACK_SIZE 2048 +#endif + + +/* Set the client thread time slice. */ + +#ifndef NX_SNTP_CLIENT_THREAD_TIME_SLICE +#define NX_SNTP_CLIENT_THREAD_TIME_SLICE TX_NO_TIME_SLICE +#endif + + + +#ifndef NX_SNTP_CLIENT_THREAD_PRIORITY +#define NX_SNTP_CLIENT_THREAD_PRIORITY 2 +#endif + + +/* Set NetX SNTP client thread preemption threshold. */ + +#ifndef NX_SNTP_CLIENT_PREEMPTION_THRESHOLD +#define NX_SNTP_CLIENT_PREEMPTION_THRESHOLD NX_SNTP_CLIENT_THREAD_PRIORITY +#endif + + + +/* Configure the NetX SNTP client network parameters */ + +/* Set Client UDP socket name. */ + +#ifndef NX_SNTP_CLIENT_UDP_SOCKET_NAME +#define NX_SNTP_CLIENT_UDP_SOCKET_NAME "SNTP Client socket" +#endif + + +/* Set port for client to bind UDP socket. */ + +#ifndef NX_SNTP_CLIENT_UDP_PORT +#define NX_SNTP_CLIENT_UDP_PORT 123 +#endif + +/* Set port for client to connect to SNTP server. */ + +#ifndef NX_SNTP_SERVER_UDP_PORT +#define NX_SNTP_SERVER_UDP_PORT 123 +#endif + +/* Set Time to Live (TTL) value for transmitted UDP packets, including manycast and + multicast transmissions. The default TTL for windows operating system time + server is used. */ + +#ifndef NX_SNTP_CLIENT_TIME_TO_LIVE +#define NX_SNTP_CLIENT_TIME_TO_LIVE NX_IP_TIME_TO_LIVE +#endif + + +/* Set maximum queue depth for client socket.*/ + +#ifndef NX_SNTP_CLIENT_MAX_QUEUE_DEPTH +#define NX_SNTP_CLIENT_MAX_QUEUE_DEPTH 5 +#endif + + +/* Set the time out (timer ticks) for packet allocation from the client packet pool. */ + +#ifndef NX_SNTP_CLIENT_PACKET_TIMEOUT +#define NX_SNTP_CLIENT_PACKET_TIMEOUT (1 * NX_IP_PERIODIC_RATE) +#endif + + +/* Set the NTP/SNTP version of this NTP Client. */ + +#ifndef NX_SNTP_CLIENT_NTP_VERSION +#define NX_SNTP_CLIENT_NTP_VERSION 3 +#endif + + +/* Set minimum NTP/SNTP version the Client will accept from its time server. */ + +#ifndef NX_SNTP_CLIENT_MIN_NTP_VERSION +#define NX_SNTP_CLIENT_MIN_NTP_VERSION 3 +#endif + + + +/* Define the minimum (numerically highest) stratum the Client will + accept for a time server. Valid range is 1 - 15. */ + +#ifndef NX_SNTP_CLIENT_MIN_SERVER_STRATUM +#define NX_SNTP_CLIENT_MIN_SERVER_STRATUM 2 +#endif + + +/* Define minimum time difference (msec) between server and client time + the Client requires to change its local time. */ + +#ifndef NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT +#define NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT 10 +#endif + + +/* Define maximum time update (msec) the Client will make to its local time + per update. */ + +#ifndef NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT +#define NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT 180000 +#endif + + +/* Determine if the Client should ignore the maximum time adjustment on startup. If the + host application has a pretty accurate notion of time, this can be set to false. If not + the SNTP Client may be unable to apply the first (any) updates. */ + +#ifndef NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP +#define NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP NX_TRUE +#endif + + +/* Determine if the Client should create a random delay before starting SNTP polling. */ + +#ifndef NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP +#define NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP NX_FALSE +#endif + + +/* Set the maximum time lapse (in seconds) without a time update that can be tolerated by + the Client (application). This should be determined by application time sensitivity. + For unicast operation, the max lapse could be set to three successive poll requests + without an update. Here we set it to 2 hour based on the RFC recommendation to limit + traffic congestion. */ + +#ifndef NX_SNTP_CLIENT_MAX_TIME_LAPSE +#define NX_SNTP_CLIENT_MAX_TIME_LAPSE 7200 +#endif + + +/* Define a time out (seconds) for the SNTP Client timer. */ + +#ifndef NX_SNTP_UPDATE_TIMEOUT_INTERVAL +#define NX_SNTP_UPDATE_TIMEOUT_INTERVAL 1 +#endif + +/* Define the SNTP Client task sleep interval in timer ticks when + the SNTP CLient thread is idle. */ + +#ifndef NX_SNTP_CLIENT_SLEEP_INTERVAL +#define NX_SNTP_CLIENT_SLEEP_INTERVAL 1 +#endif + + +/* Set the unicast poll interval (in seconds) for Client time update requests. RFC 4330 + recommends a minimum polling interval of once per hour to minimize traffic congestion. */ + +#ifndef NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL +#define NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL 3600 +#endif + + +/* Set the Client exponential back off rate for extending Client poll interval. + To effectively disable, set to 1. */ + +#ifndef NX_SNTP_CLIENT_EXP_BACKOFF_RATE +#define NX_SNTP_CLIENT_EXP_BACKOFF_RATE 2 +#endif + +/* Determine if the Client requires round trip calculation of SNTP messages. */ + +#ifndef NX_SNTP_CLIENT_RTT_REQUIRED +#define NX_SNTP_CLIENT_RTT_REQUIRED NX_FALSE +#endif + + +/* Define the upper limit of server clock dispersion (usec) the Client + will accept. To disable this check, set this parameter to 0x0. */ + +#ifndef NX_SNTP_CLIENT_MAX_ROOT_DISPERSION +#define NX_SNTP_CLIENT_MAX_ROOT_DISPERSION 50000 +#endif + + +/* Set the limit on consecutive bad updates from server before Client + switches to alternate server. */ + +#ifndef NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT +#define NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT 3 +#endif + +/* Set size of SNTP data in bytes, not including IP and UDP header fields or authentication. */ +#define NX_SNTP_CLIENT_PACKET_DATA_SIZE 48 + +/* To display date in year/month/date format, set the current year (same year as in NTP time being evaluated) e.g 2015. + Otherwise set to zero. */ +#ifndef NX_SNTP_CURRENT_YEAR +#define NX_SNTP_CURRENT_YEAR 2015 +#endif /* NX_SNTP_CURRENT_YEAR */ + + +/* Define status levels for SNTP update processing */ + +#define UPDATE_STATUS_CONTINUE 1 +#define UPDATE_STATUS_BREAK 2 +#define UPDATE_STATUS_ERROR 3 +#define UPDATE_STATUS_SUCCESS 4 + + +/* Define the number of seconds from 01-01-1990 00:00:00 to 01-01-1999 00:00:00 (last occurrance + of a leap second) to be able to define time in year, month, date. If zero, + no date time is displayed. */ +#ifndef NTP_SECONDS_AT_01011999 +#define NTP_SECONDS_AT_01011999 0xBA368E80 +#endif /* NTP_SECONDS_AT_01011999 */ + +/* Define which epoch time is relative on the host system. */ + +#define UNIX_EPOCH 1 +#define NTP_EPOCH 2 + + + +/* Enumerate months*/ + +#define JANUARY 1 +#define FEBRUARY 2 +#define MARCH 3 +#define APRIL 4 +#define MAY 5 +#define JUNE 6 +#define JULY 7 +#define AUGUST 8 +#define SEPTEMBER 9 +#define OCTOBER 10 +#define NOVEMBER 11 +#define DECEMBER 12 + + +/* Compute seconds per month for convenience computating date and time. */ + +#define SEC_IN_JAN (31 * SECONDS_PER_DAY) +#define SEC_IN_LEAPFEB (29 * SECONDS_PER_DAY) +#define SEC_IN_NONLEAPFEB (28 * SECONDS_PER_DAY) +#define SEC_IN_MAR (31 * SECONDS_PER_DAY) +#define SEC_IN_APR (30 * SECONDS_PER_DAY) +#define SEC_IN_MAY (31 * SECONDS_PER_DAY) +#define SEC_IN_JUN (30 * SECONDS_PER_DAY) +#define SEC_IN_JUL (31 * SECONDS_PER_DAY) +#define SEC_IN_AUG (31 * SECONDS_PER_DAY) +#define SEC_IN_SEP (30 * SECONDS_PER_DAY) +#define SEC_IN_OCT (31 * SECONDS_PER_DAY) +#define SEC_IN_NOV (30 * SECONDS_PER_DAY) +#define SEC_IN_DEC (31 * SECONDS_PER_DAY) + +/* Compute seconds per year, month,day for convenience computating date and time. */ + +#define SECONDS_PER_LEAPYEAR (86400 * 366) +#define SECONDS_PER_NONLEAPYEAR (86400 * 365) +#define SECONDS_PER_DAY 86400 +#define SECONDS_PER_HOUR 3600 +#define SECONDS_PER_MINUTE 60 + + +/* Internal SNTP error processing codes. */ + +#define NX_SNTP_ERROR_CONSTANT 0xD00 + + +/* Client side errors. */ +#define NX_SNTP_CLIENT_NOT_INITIALIZED (NX_SNTP_ERROR_CONSTANT | 0x01) /* Client not properly initialized to receive time data. */ +#define NX_SNTP_OVER_LIMIT_ON_SERVERS (NX_SNTP_ERROR_CONSTANT | 0x02) /* Cannot accept server because client list has reached max # servers. */ +#define NX_SNTP_INVALID_DOMAIN (NX_SNTP_ERROR_CONSTANT | 0x03) /* Invalid domain such as bad IP format or empty string. Applicable to broadcast mode. */ +#define NX_SNTP_NO_AVAILABLE_SERVERS (NX_SNTP_ERROR_CONSTANT | 0x04) /* Client has no available time servers to contact. */ +#define NX_SNTP_INVALID_LOCAL_TIME (NX_SNTP_ERROR_CONSTANT | 0x05) /* Client local time has not been set or is invalid. */ +#define NX_SNTP_OUT_OF_DOMAIN_SERVER (NX_SNTP_ERROR_CONSTANT | 0x06) /* Broadcast server does not belong to client broadcast domain. */ +#define NX_SNTP_INVALID_DATETIME_BUFFER (NX_SNTP_ERROR_CONSTANT | 0x07) /* Insufficient or invalid buffer for writing human readable time date string. */ +#define NX_SNTP_ERROR_CONVERTING_DATETIME (NX_SNTP_ERROR_CONSTANT | 0x08) /* An internal error has occurred converting NTP time to mm-dd-yy time format. */ +#define NX_SNTP_UNABLE_TO_CONVERT_DATETIME (NX_SNTP_ERROR_CONSTANT | 0x09) /* An internal error has occurred converting NTP time to mm-dd-yy time format. */ +#define NX_SNTP_INVALID_SERVER_ADDRESS (NX_SNTP_ERROR_CONSTANT | 0x0A) /* Invalid server type e.g. IPv4 or IPv6 incompatible. */ +#define NX_SNTP_CLIENT_NOT_STARTED (NX_SNTP_ERROR_CONSTANT | 0x0B) /* SNTP Client task is not running */ +#define NX_SNTP_CLIENT_ALREADY_STARTED (NX_SNTP_ERROR_CONSTANT | 0x0C) /* SNTP Client task is already running */ +#define NX_SNTP_PARAM_ERROR (NX_SNTP_ERROR_CONSTANT | 0x0D) /* Invalid non pointer parameter. */ + + /* Server side errors */ +#define NX_SNTP_SERVER_NOT_AVAILABLE (NX_SNTP_ERROR_CONSTANT | 0x10) /* Client will not get any time update service from current server. */ +#define NX_SNTP_NO_UNICAST_FROM_SERVER (NX_SNTP_ERROR_CONSTANT | 0x11) /* Client did not receive a valid unicast response from server. */ +#define NX_SNTP_SERVER_CLOCK_NOT_SYNC (NX_SNTP_ERROR_CONSTANT | 0x12) /* Server clock not synchronized. */ +#define NX_SNTP_KOD_SERVER_NOT_AVAILABLE (NX_SNTP_ERROR_CONSTANT | 0x13) /* Server sent a KOD packet indicating service temporarily not available. */ +#define NX_SNTP_KOD_REMOVE_SERVER (NX_SNTP_ERROR_CONSTANT | 0x14) /* Server sent a KOD packet indicating service is not available to client (ever). */ +#define NX_SNTP_SERVER_AUTH_FAIL (NX_SNTP_ERROR_CONSTANT | 0x15) /* Server rejects Client packet on basis of missing or invalid authorization data. */ + +/* Bad packet and time update errors */ +#define NX_SNTP_INVALID_TIME_PACKET (NX_SNTP_ERROR_CONSTANT | 0x20) /* Invalid packet (length or data incorrect). */ +#define NX_SNTP_INVALID_NTP_VERSION (NX_SNTP_ERROR_CONSTANT | 0x21) /* Server NTP/SNTP version not incompatible with client. */ +#define NX_SNTP_INVALID_SERVER_MODE (NX_SNTP_ERROR_CONSTANT | 0x22) /* Server association invalid (out of protocol with client). */ +#define NX_SNTP_INVALID_SERVER_PORT (NX_SNTP_ERROR_CONSTANT | 0x23) /* Server port does not match what the client expects. */ +#define NX_SNTP_INVALID_IP_ADDRESS (NX_SNTP_ERROR_CONSTANT | 0x24) /* Server IP address does not match what the client expects. */ +#define NX_SNTP_INVALID_SERVER_STRATUM (NX_SNTP_ERROR_CONSTANT | 0x25) /* Server stratum is invalid or below client stratum. */ +#define NX_SNTP_BAD_SERVER_ROOT_DISPERSION (NX_SNTP_ERROR_CONSTANT | 0x26) /* Server root dispersion (clock precision) is too high or invalid value (0) reported. */ +#define NX_SNTP_OVER_INVALID_LIMIT (NX_SNTP_ERROR_CONSTANT | 0x27) /* Client over the limit on consecutive server updates with bad data received. */ +#define NX_SNTP_DUPE_SERVER_PACKET (NX_SNTP_ERROR_CONSTANT | 0x28) /* Client has received duplicate packets from server. */ +#define NX_SNTP_INVALID_TIMESTAMP (NX_SNTP_ERROR_CONSTANT | 0x29) /* Server time packet has one or more invalid time stamps in update message. */ +#define NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD (NX_SNTP_ERROR_CONSTANT | 0x2A) /* Packet payload not large enough for SNTP message. */ +#define NX_SNTP_INVALID_SNTP_PACKET (NX_SNTP_ERROR_CONSTANT | 0x2B) /* Server IP version does not match what the client expects. */ + +/* Arithmetic errors or invalid results */ +#define NX_SNTP_INVALID_TIME (NX_SNTP_ERROR_CONSTANT | 0x30) /* Invalid time resulting from arithmetic operation. */ +#define NX_SNTP_INVALID_RTT_TIME (NX_SNTP_ERROR_CONSTANT | 0x31) /* Round trip time correction to server time yields invalid time (e.g. <0). */ +#define NX_SNTP_OVERFLOW_ERROR (NX_SNTP_ERROR_CONSTANT | 0x32) /* Overflow error resulting from multiplying/adding two 32 bit (timestamp) numbers. */ +#define NX_SNTP_SIGN_ERROR (NX_SNTP_ERROR_CONSTANT | 0x33) /* Loss of sign error resulting from multiplying/adding two 32 bit (timestamp) numbers. */ + +/* Time out errors */ +#define NX_SNTP_TIMED_OUT_ON_SERVER (NX_SNTP_ERROR_CONSTANT | 0x44) /* Client did not receive update from the current server within specified timeout. */ +#define NX_SNTP_MAX_TIME_LAPSE_EXCEEDED (NX_SNTP_ERROR_CONSTANT | 0x45) /* Client has not received update from any server within the max allowed time lapse. */ + + + +/* Define the Netx Date Time structure. */ + + typedef struct NX_SNTP_DATE_TIME_STRUCT + { + UINT year; + UINT month; + UINT day; + UINT hour; + UINT minute; + UINT second; + UINT millisecond; /* This is the fraction part of the NTP time data. */ + UINT time_zone; /* NTP time is represented in Coordinated Universal Time (UTC). */ + UINT leap_year; /* Indicates if current time is in a leap year. */ + + } NX_SNTP_DATE_TIME; + + +/* Define the Netx SNTP Time structure. */ + + typedef struct NX_SNTP_TIME_STRUCT + { + ULONG seconds; /* Seconds, in the 32 bit field of an NTP time data. */ + ULONG fraction; /* Fraction of a second, in the 32 bit fraction field of an NTP time data. */ + + } NX_SNTP_TIME; + + +/* Define the NetX SNTP Time Message structure. The Client only uses the flags field and the transmit_time_stamp field + in time requests it sends to its time server. */ + + typedef struct NX_SNTP_TIME_MESSAGE_STRUCT + { + /* These are represented as 8 bit data fields in the time message format. */ + UINT flags; /* Flag containing host's NTP version, mode and leap indicator. */ + UINT peer_clock_stratum; /* Level of precision in the NTP network. Applicable only in server NTP messages. */ + UINT peer_poll_interval; /* Frequency at which an NTP host polls its NTP peer. Applicable only in server NTP messages. */ + UINT peer_clock_precision; /* Precision of the NTP server clock. Applicable only in server NTP messages. */ + + /* These are represented as 32 bit data fields in the time message format*/ + ULONG root_delay; /* Round trip time from NTP Server to primary reference source. Applicable only in server NTP messages. */ + ULONG clock_dispersion; /* Server reference clock type (but if stratum is zero, indicates server status when not able to send time updates. */ + UCHAR reference_clock_id[4]; /* Maximum error in server clock based to the clock frequency tolerance. Applicable only in server NTP messages. */ + + /* These are represented as 64 bit data fields in the time message format*/ + ULONG reference_clock_update_time_stamp[2]; /* Time at which the server clock was last set or corrected in a server time message. */ + ULONG originate_time_stamp[2]; /* Time at which the Client update request left the Client in a server time message. */ + ULONG receive_time_stamp[2]; /* Time at which the server received the Client request in a server time message. */ + ULONG transmit_time_stamp[2]; /* Time at which the server transmitted its reply to the Client in a server time message (or the time client request was sent in the client request message). */ + + /* Optional authenticator fields. */ + UCHAR KeyIdentifier[4]; /* Key Identifier and Message Digest fields contain the... */ + UCHAR MessageDigest[16]; /* ...message authentication code (MAC) information defined. */ + + /* These fields are used internally for 'convert' UCHAR data in NX_SNTP_TIME data e.g. seconds and fractions. */ + NX_SNTP_TIME reference_clock_update_time; /* Time at which the server clock was last set or corrected in a server time message. */ + NX_SNTP_TIME originate_time; /* Time at which the Client update request left the Client in a server time message. */ + NX_SNTP_TIME receive_time; /* Time at which the server received the Client request in a server time message. */ + NX_SNTP_TIME transmit_time; /* Time at which the server transmitted its reply to the Client in a server time message (or the time client request was sent in the client request message). */ + + } NX_SNTP_TIME_MESSAGE; + + +/* Define the SNTP client structure. */ + + typedef struct NX_SNTP_CLIENT_STRUCT + { + ULONG nx_sntp_client_id; /* SNTP ID for identifying the client service task. */ + NX_IP *nx_sntp_client_ip_ptr; /* Pointer to the Client IP instance. */ + UINT nx_sntp_client_interface_index; /* Index to SNTP network interface */ + NX_PACKET_POOL *nx_sntp_client_packet_pool_ptr; /* Pointer to the Client packet pool. */ + UINT nx_sntp_client_sleep_flag; /* The flag indicating the SNTP Client thread is sleeping */ + UINT nx_sntp_client_started; /* Flag indicating the SNTP Client task is running */ + TX_THREAD nx_sntp_client_thread; /* The SNTP Client processing thread */ + TX_MUTEX nx_sntp_client_mutex; /* The SNTP Client mutex for protecting access */ + UCHAR nx_sntp_client_thread_stack[NX_SNTP_CLIENT_THREAD_STACK_SIZE]; /* Stack size for SNTP client thread */ + NXD_ADDRESS nx_sntp_server_ip_address; /* Client's current time server IP address. */ + NX_UDP_SOCKET nx_sntp_client_udp_socket; /* Client UDP socket for sending and receiving time updates. */ + UINT nx_sntp_client_first_update_pending; /* First SNTP update not yet received with current server */ + UINT nx_sntp_client_time_start_wait; /* Initial time at start of receiving broadcast SNTP updates */ + UINT nx_sntp_client_sent_initial_unicast; /* Status on initial unicast transmittal for clients in broadcast mode */ + UINT nx_sntp_client_invalid_time_updates; /* Number of invalid SNTP messages received */ + UINT nx_sntp_valid_server_status; /* Server status; if receiving valid updates, status is TRUE */ + UINT nx_sntp_client_protocol_mode; /* Mode of operation, either unicast or broadcast */ + UINT nx_sntp_client_broadcast_initialized; /* Client task is ready to receive broadcast time data. */ + NXD_ADDRESS nx_sntp_broadcast_time_server; /* Client's broadcast SNTP server */ + NXD_ADDRESS nx_sntp_multicast_server_address; /* IP address Client should listen on to receive broadcasts from a multicast server. */ + UINT nx_sntp_client_unicast_initialized; /* Client task is ready to receive unicast time data. */ + NXD_ADDRESS nx_sntp_unicast_time_server; /* Client's unicast time server. */ + ULONG nx_sntp_client_unicast_poll_interval; /* Unicast interval at which client is polling the time server. */ + UINT nx_sntp_client_backoff_count; /* Count of times the back off rate has been applied to the poll interval */ + TX_TIMER nx_sntp_update_timer; /* SNTP update timer; expires when no data received for specified time lapse. */ + ULONG nx_sntp_update_time_remaining; /* Time (in seconds) remaining that the Client task can continue running without receiving a valid update. */ + LONG nx_sntp_client_roundtrip_time_msec; /* Round trip time (msec) for a packet to travel to server and back to client. Does not include server processing time. */ + ULONG nx_sntp_client_local_ntp_time_elapsed; /* Seconds elapsed since local time is updated last time. */ + NX_SNTP_TIME_MESSAGE nx_sntp_current_server_time_message; /* Time update which the Client has just received from its server. */ + NX_SNTP_TIME_MESSAGE nx_sntp_current_time_message_request; /* Client request to send to its time server. */ + NX_SNTP_TIME_MESSAGE nx_sntp_previous_server_time_message; /* Previous valid time update received from the Client time server. */ + NX_SNTP_TIME nx_sntp_client_local_ntp_time; /* Client's notion of local time. */ + NX_SNTP_TIME nx_sntp_server_update_time; /* Time (based on client local time) when the server update was received in response to the current request. */ + UINT (*apply_custom_sanity_checks)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, NX_SNTP_TIME_MESSAGE *client_time_msg_ptr, NX_SNTP_TIME_MESSAGE *server_time_msg_ptr); + /* Pointer to callback service for performing additional sanity checks on received time data. */ + UINT (*leap_second_handler)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, UINT indicator); + /* Pointer to callback service for handling an impending leap second. */ + UINT (*kiss_of_death_handler)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, UINT code); + /* Pointer to callback service for handling kiss of death packets received from server. */ + VOID (*random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand); + /* Pointer to callback service for random number generator. */ + + VOID (*nx_sntp_client_time_update_notify)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time); + + } NX_SNTP_CLIENT; + + +#ifndef NX_SNTP_SOURCE_CODE + +/* Define the system API mappings based on the error checking selected by the user. */ + + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + + +#ifdef NX_SNTP_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_sntp_client_create _nx_sntp_client_create +#define nx_sntp_client_delete _nx_sntp_client_delete +#define nx_sntp_client_get_local_time _nx_sntp_client_get_local_time +#define nx_sntp_client_get_local_time_extended _nx_sntp_client_get_local_time_extended +#define nxd_sntp_client_initialize_broadcast _nxd_sntp_client_initialize_broadcast +#define nxd_sntp_client_initialize_unicast _nxd_sntp_client_initialize_unicast +#define nx_sntp_client_initialize_broadcast _nx_sntp_client_initialize_broadcast +#define nx_sntp_client_initialize_unicast _nx_sntp_client_initialize_unicast +#define nx_sntp_client_receiving_updates _nx_sntp_client_receiving_updates +#define nx_sntp_client_run_broadcast _nx_sntp_client_run_broadcast +#define nx_sntp_client_run_unicast _nx_sntp_client_run_unicast +#define nx_sntp_client_set_local_time _nx_sntp_client_set_local_time +#define nx_sntp_client_stop _nx_sntp_client_stop +#define nx_sntp_client_utility_msecs_to_fraction _nx_sntp_client_utility_msecs_to_fraction +#define nx_sntp_client_utility_usecs_to_fraction _nx_sntp_client_utility_usecs_to_fraction +#define nx_sntp_client_utility_fraction_to_usecs _nx_sntp_client_utility_fraction_to_usecs +#define nx_sntp_client_utility_display_date_time _nx_sntp_client_utility_display_date_time +#define nx_sntp_client_request_unicast_time _nx_sntp_client_request_unicast_time +#define nx_sntp_client_set_time_update_notify _nx_sntp_client_set_time_update_notify + +#else + +/* Services with error checking. */ + +#define nx_sntp_client_create _nxe_sntp_client_create +#define nx_sntp_client_delete _nxe_sntp_client_delete +#define nx_sntp_client_get_local_time _nxe_sntp_client_get_local_time +#define nx_sntp_client_get_local_time_extended _nxe_sntp_client_get_local_time_extended +#define nxd_sntp_client_initialize_broadcast _nxde_sntp_client_initialize_broadcast +#define nxd_sntp_client_initialize_unicast _nxde_sntp_client_initialize_unicast +#define nx_sntp_client_initialize_broadcast _nxe_sntp_client_initialize_broadcast +#define nx_sntp_client_initialize_unicast _nxe_sntp_client_initialize_unicast +#define nx_sntp_client_receiving_updates _nxe_sntp_client_receiving_updates +#define nx_sntp_client_run_broadcast _nxe_sntp_client_run_broadcast +#define nx_sntp_client_run_unicast _nxe_sntp_client_run_unicast +#define nx_sntp_client_set_local_time _nxe_sntp_client_set_local_time +#define nx_sntp_client_stop _nxe_sntp_client_stop +#define nx_sntp_client_utility_msecs_to_fraction _nxe_sntp_client_utility_msecs_to_fraction +#define nx_sntp_client_utility_usecs_to_fraction _nxe_sntp_client_utility_usecs_to_fraction +#define nx_sntp_client_utility_fraction_to_usecs _nxe_sntp_client_utility_fraction_to_usecs +#define nx_sntp_client_utility_display_date_time _nxe_sntp_client_utility_display_date_time +#define nx_sntp_client_request_unicast_time _nxe_sntp_client_request_unicast_time +#define nx_sntp_client_set_time_update_notify _nxe_sntp_client_set_time_update_notify + +#endif /* NX_SNTP_DISABLE_ERROR_CHECKING */ + + +/* Define the prototypes accessible to the application software. */ + +UINT nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, + UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), + UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), + VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); +UINT nx_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); +UINT nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); +UINT nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); +UINT nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); +UINT nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); +UINT nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); +UINT nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); +UINT nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); +UINT nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); +UINT nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); +UINT nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); +UINT nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); +UINT nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); +UINT nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); +UINT nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); +UINT nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); +UINT nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); +UINT nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); + +#else /* NX_SNTP_SOURCE_CODE */ + + +/* SNTP source code is being compiled, do not perform any API mapping. */ + +UINT _nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, + UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), + UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), + VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); +UINT _nxe_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, + UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), + UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), + VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); +UINT _nx_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); +UINT _nxe_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); +UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); +UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); +UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); +UINT _nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); +UINT _nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); +UINT _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); +UINT _nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); +UINT _nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); +UINT _nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); +UINT _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); +UINT _nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); +UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); +UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); +UINT _nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); +UINT _nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); +UINT _nxe_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); +UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); +UINT _nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); +UINT _nxe_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); +UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); +UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); +UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); +UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); +UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); +UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); +UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); +UINT _nxe_sntp_client_utility_display_NTP_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer); +UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); +UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); +UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); +UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); + +/* Define internal SNTP Client functions. */ + +UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time); +UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_SNTP_TIME_MESSAGE *time_message_ptr); +UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr, NX_SNTP_TIME_MESSAGE *timeB_msg_ptr, UINT *is_a_dupe); +UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); +VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr); +VOID _nx_sntp_client_process_broadcast(NX_SNTP_CLIENT *client_ptr); +VOID _nx_sntp_client_process_unicast(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr); +VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr); +UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout); +UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr); +UINT _nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT *client_ptr); +VOID _nx_sntp_client_thread_entry(ULONG sntp_instance); +VOID _nx_sntp_client_update_timeout_entry(ULONG info); +UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add); +UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr); +UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year, NX_SNTP_DATE_TIME *current_date_time_ptr); +UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id); +UINT _nx_sntp_client_utility_get_msec_diff(NX_SNTP_TIME *timeA_ptr, NX_SNTP_TIME *timeB_ptr, ULONG *total_difference_msecs, UINT *pos_diff); +UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2); +UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time, NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp); +UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size); + + + +#endif /* NX_SNTP_SOURCE_CODE */ + +/* If a C++ compiler is being used....*/ +#ifdef __cplusplus +} +#endif + + +#endif /* NXD_SNTP_CLIENT_H */ diff --git a/addons/telnet/nxd_telnet_client.c b/addons/telnet/nxd_telnet_client.c new file mode 100644 index 00000000..c85a76c2 --- /dev/null +++ b/addons/telnet/nxd_telnet_client.c @@ -0,0 +1,961 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** TELNET Client Protocol */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_TELNET_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_telnet_client.h" + + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_telnet_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client connect call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* server_ip TELNET server IPv6 address */ +/* server_port Server TCP port (usually 23) */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxde_telnet_client_connect Actual client connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, + UINT server_port, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (!server_ip_address)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid non pointer input. */ + if (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) + { + return NX_TELNET_INVALID_PARAMETER; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client connect function. */ + status = _nxd_telnet_client_connect(client_ptr, server_ip_address, server_port, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_telnet_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a previously created TELNET instance with */ +/* the TCP port at the specified address. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* server_ip_address TELNET server address */ +/* server_port Server TCP port (usually 23) */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nxd_tcp_client_socket_connect Connect to TELNET server */ +/* nx_tcp_client_socket_bind Bind client socket to port */ +/* nx_tcp_client_socket_unbind Unbind client socket from port*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, + UINT server_port, ULONG wait_option) + +{ + +UINT status; + + + /* Determine if the client is still in a not connected state. */ + if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Already connected, return an error. */ + return(NX_TELNET_NOT_DISCONNECTED); + } + + /* Bind the client control socket. */ + status = nx_tcp_client_socket_bind(&(client_ptr -> nx_telnet_client_socket), NX_ANY_PORT, wait_option); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Unable to bind socket to port. */ + return(status); + } + + /* Connect the socket to the TELNET server using the 'duo' (support IPv4 and IPv6 addresses types) + tcp connect service. */ + status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_telnet_client_socket), + server_ip_address, server_port, wait_option); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Unbind the socket. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_telnet_client_socket)); + + /* Unable to connect socket to server TELNET control port. */ + return(status); + } + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client connect call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* server_ip TELNET server IP address */ +/* server_port Server TCP port (usually 23) */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_telnet_client_connect Actual client connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip, UINT server_port, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid server IP address. */ + if (server_ip == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client connect function. */ + status = _nx_telnet_client_connect(client_ptr, server_ip, server_port, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(server_ip); + NX_PARAMETER_NOT_USED(server_port); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts the IPv4 address to a NetX Duo NXD_ADDRESS */ +/* data and forwarded to the NetX Duo Telnet connect function, */ +/* nxd_telnet_client_connect to connect a previously created TELNET */ +/* instance with the TCP port at the specified IPv4 address. */ +/* */ +/* This serves primarily as a wrapper function for backward */ +/* compatibility with NetX Telnet applications. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* server_ip_address TELNET server IPv4 address */ +/* server_port Server TCP port (usually 23) */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nxd_tcp_client_socket_connect Connect to TELNET server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, + UINT server_port, ULONG wait_option) +{ +#ifndef NX_DISABLE_IPV4 +NXD_ADDRESS server_ipduo_address; + + /* Construct an IP address structure, and fill in IPv4 address information. */ + server_ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; + server_ipduo_address.nxd_ip_address.v4 = server_ip_address; + + /* Invoke the real connection call. */ + return (_nxd_telnet_client_connect(client_ptr, &server_ipduo_address, server_port, wait_option)); +#else + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(server_ip_address); + NX_PARAMETER_NOT_USED(server_port); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* client_name Name of this TELNET client */ +/* ip_ptr Pointer to IP instance */ +/* window_size Size of TCP receive window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id == NX_TELNET_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Call actual client create function. */ + status = _nx_telnet_client_create(client_ptr, client_name, ip_ptr, window_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an TELNET client instance. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* client_name Name of this TELNET client */ +/* ip_ptr Pointer to IP instance */ +/* window_size Size of TCP receive window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size) +{ + +UINT status; + + + /* Clear the client TELNET control block. */ + memset((void *) client_ptr, 0, sizeof(NX_TELNET_CLIENT)); + + /* Create the TCP control socket. */ + status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_telnet_client_socket), client_name, + NX_TELNET_TOS, NX_TELNET_FRAGMENT_OPTION, NX_TELNET_TIME_TO_LIVE, window_size, + NX_NULL, NX_NULL); + + /* Check for an error. */ + if (status) + { + + /* Return an error. */ + return(NX_TELNET_ERROR); + } + + /* Save off the remaining information. */ + + /* Save the client name. */ + client_ptr -> nx_telnet_client_name = client_name; + + /* Save the IP pointer. */ + client_ptr -> nx_telnet_client_ip_ptr = ip_ptr; + + /* Set the TELNET client id. */ + client_ptr -> nx_telnet_client_id = NX_TELNET_CLIENT_ID; + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_client_delete Actual client delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_delete(NX_TELNET_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nx_telnet_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created TELNET client instance. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_delete Delete TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr) +{ + + /* Determine if the client is still in an established state. */ + if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Still connected, return an error. */ + return(NX_TELNET_NOT_DISCONNECTED); + } + + /* Delete the socket. */ + nx_tcp_socket_delete(&(client_ptr -> nx_telnet_client_socket)); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client disconnect. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_client_disconnect Actual client disconnect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client disconnect function. */ + status = _nx_telnet_client_disconnect(client_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disconnects a previously established TELNET */ +/* connection. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_unbind Unbind a socket */ +/* nx_tcp_socket_disconnect Disconnect a socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option) +{ + + + /* Determine if the client is still in an established state. */ + if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state != NX_TCP_ESTABLISHED) + { + + /* Not connected, return an error. */ + return(NX_TELNET_NOT_CONNECTED); + } + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_telnet_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_telnet_client_socket)); + + /* Return success to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client packet */ +/* receive call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* packet_ptr Destination for packet ptr */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_client_packet_receive Actual client packet receive */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client packet receive function. */ + status = _nx_telnet_client_packet_receive(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client packet */ +/* receive call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* packet_ptr Destination for packet ptr */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_receive Receive TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + /* Attempt to receive a packet from the TCP socket. */ + status = nx_tcp_socket_receive(&(client_ptr -> nx_telnet_client_socket), packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_client_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client packet */ +/* send call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* packet_ptr Pointer to packet to send */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_client_packet_send Actual client packet send */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client packet send function. */ + status = _nx_telnet_client_packet_send(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_client_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET client packet */ +/* send call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to TELNET client */ +/* packet_ptr Pointer to packet to send */ +/* wait_option Specifies how long to wait */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_send Send TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + /* Attempt to send a packet on the TCP socket. */ + status = nx_tcp_socket_send(&(client_ptr -> nx_telnet_client_socket), packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} diff --git a/addons/telnet/nxd_telnet_client.h b/addons/telnet/nxd_telnet_client.h new file mode 100644 index 00000000..6a4390bd --- /dev/null +++ b/addons/telnet/nxd_telnet_client.h @@ -0,0 +1,184 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** TELNET Client Protocol */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_telnet_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Duo TELNET Protocol for Clients, */ +/* including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_TELNET_CLIENT_H +#define NXD_TELNET_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the TELNET ID. */ + +#define NX_TELNET_CLIENT_ID 0x54454C4DUL + + + +/* Define TELNET TCP socket create options. */ + +#ifndef NX_TELNET_TOS +#define NX_TELNET_TOS NX_IP_NORMAL +#endif + +#ifndef NX_TELNET_FRAGMENT_OPTION +#define NX_TELNET_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + + +#ifndef NX_TELNET_TIME_TO_LIVE +#define NX_TELNET_TIME_TO_LIVE 0x80 +#endif + + +/* Define the TELNET Server TCP port number. */ +#ifndef NX_TELNET_SERVER_PORT +#define NX_TELNET_SERVER_PORT 23 /* Default Port for TELNET server */ +#endif + +/* Define return code constants. */ + +#define NX_TELNET_ERROR 0xF0 /* TELNET internal error */ +#define NX_TELNET_TIMEOUT 0xF1 /* TELNET timeout occurred */ +#define NX_TELNET_FAILED 0xF2 /* TELNET error */ +#define NX_TELNET_NOT_CONNECTED 0xF3 /* TELNET not connected error */ +#define NX_TELNET_NOT_DISCONNECTED 0xF4 /* TELNET not disconnected error */ +#define NX_TELNET_INVALID_PARAMETER 0xF5 /* Invalid non pointer input to Telnet function */ + + +/* Define the TELNET Client structure. */ + +typedef struct NX_TELNET_CLIENT_STRUCT +{ + ULONG nx_telnet_client_id; /* TELNET Client ID */ + CHAR *nx_telnet_client_name; /* Name of this TELNET client */ + NX_IP *nx_telnet_client_ip_ptr; /* Pointer to associated IP structure */ + NX_TCP_SOCKET nx_telnet_client_socket; /* Client TELNET socket */ +} NX_TELNET_CLIENT; + + +#ifndef NX_TELNET_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nxd_telnet_client_connect _nxd_telnet_client_connect +#define nx_telnet_client_connect _nx_telnet_client_connect +#define nx_telnet_client_create _nx_telnet_client_create +#define nx_telnet_client_delete _nx_telnet_client_delete +#define nx_telnet_client_disconnect _nx_telnet_client_disconnect +#define nx_telnet_client_packet_receive _nx_telnet_client_packet_receive +#define nx_telnet_client_packet_send _nx_telnet_client_packet_send + +#else + +/* Services with error checking. */ + +#define nxd_telnet_client_connect _nxde_telnet_client_connect +#define nx_telnet_client_connect _nxe_telnet_client_connect +#define nx_telnet_client_create _nxe_telnet_client_create +#define nx_telnet_client_delete _nxe_telnet_client_delete +#define nx_telnet_client_disconnect _nxe_telnet_client_disconnect +#define nx_telnet_client_packet_receive _nxe_telnet_client_packet_receive +#define nx_telnet_client_packet_send _nxe_telnet_client_packet_send +#define nx_telnet_server_create _nxe_telnet_server_create + +#endif + +/* Define the prototypes accessible to the application software. */ +UINT nxd_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); +UINT nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); +UINT nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); +UINT nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); +UINT nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); +UINT nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); + + +#else + +/* TELNET source code is being compiled, do not perform any API mapping. */ +UINT _nxde_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); +UINT _nxd_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); + +UINT _nxe_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); +UINT _nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); +UINT _nxe_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); +UINT _nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); +UINT _nxe_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); +UINT _nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); +UINT _nxe_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); +UINT _nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); +UINT _nxe_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); + + +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_TELNET_CLIENT_H */ diff --git a/addons/telnet/nxd_telnet_server.c b/addons/telnet/nxd_telnet_server.c new file mode 100644 index 00000000..22cc65f4 --- /dev/null +++ b/addons/telnet/nxd_telnet_server.c @@ -0,0 +1,2565 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** TELNET Protocol (TELNET) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_TELNET_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_telnet_server.h" +#include "stdio.h" +#include "string.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* server_name Name of TELNET server */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* new_connection Pointer to user's new */ +/* connection function */ +/* receive_data Pointer to user's receive */ +/* data function */ +/* connection_end Pointer to user's end of */ +/* connection function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), + void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), + void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id == NX_TELNET_SERVER_ID) || + (stack_ptr == NX_NULL) || (new_connection == NX_NULL) || (receive_data == NX_NULL) || (connection_end == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server create function. */ + status = _nx_telnet_server_create(server_ptr, server_name, ip_ptr, stack_ptr, stack_size, new_connection, receive_data, connection_end); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a TELNET server on the specified IP. In doing */ +/* so this function creates a TCP socket for subsequent TELNET */ +/* transfers and a thread for the TELNET server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* server_name Name of TELNET server */ +/* ip_ptr Pointer to IP instance */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* new_connection Pointer to user's new */ +/* connection function */ +/* receive_data Pointer to user's receive */ +/* data function */ +/* connection_end Pointer to user's end of */ +/* connection function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create sockets */ +/* nx_tcp_socket_delete Delete sockets */ +/* nx_tcp_socket_receive_notify Register receive notify */ +/* callback */ +/* tx_event_flags_create Create event flags */ +/* tx_event_flags_delete Delete event flags */ +/* tx_thread_create Create TELNET server thread */ +/* tx_thread_delete Delete TELNET server thread */ +/* tx_timer_create Create TELNET server timer */ +/* tx_timer_delete Delete TELNET server timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), + void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), + void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)) +{ + +UINT i; +UINT status; + + /* Clear the TELNET server structure. */ + memset((void *) server_ptr, 0, sizeof(NX_TELNET_SERVER)); + + /* Create the TELNET Server thread. */ + status = tx_thread_create(&(server_ptr -> nx_telnet_server_thread), "TELNET Server Thread", + _nx_telnet_server_thread_entry, (ULONG) server_ptr, stack_ptr, + stack_size, NX_TELNET_SERVER_PRIORITY, NX_TELNET_SERVER_PRIORITY, + TX_NO_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred creating the thread. */ + if (status != TX_SUCCESS) + { + + /* Error creating the server thread. */ + return(status); + } + + /* Create the ThreadX event flags. These will be used to driver the TELNET server thread. */ + status = tx_event_flags_create(&(server_ptr -> nx_telnet_server_event_flags), "TELNET Server Thread Events"); + + /* Determine if an error occurred creating the event flags. */ + if (status != TX_SUCCESS) + { + + /* Delete the server thread. */ + tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); + + /* Error creating the server event flags. */ + return(status); + } + + /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if + a client connection has gone silent and needs to be terminated. */ + status = tx_timer_create(&(server_ptr -> nx_telnet_server_timer), "TELNET Server Timer", + _nx_telnet_server_timeout, (ULONG) server_ptr, + (NX_IP_PERIODIC_RATE * NX_TELNET_TIMEOUT_PERIOD), + (NX_IP_PERIODIC_RATE * NX_TELNET_TIMEOUT_PERIOD), TX_NO_ACTIVATE); + + /* Determine if an error occurred creating the timer. */ + if (status != TX_SUCCESS) + { + + /* Delete the server thread. */ + tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); + + /* Delete the server event flags. */ + tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); + + /* Error creating the server timer. */ + return(status); + } + + /* Loop to create all the TELNET client sockets. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Setup the logical index for this client request structure. */ + server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_connection = i; + + /* Create an TELNET client socket. */ + status += nx_tcp_socket_create(ip_ptr, &(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket), "TELNET Server Control Socket", + NX_TELNET_TOS, NX_TELNET_FRAGMENT_OPTION, NX_TELNET_TIME_TO_LIVE, NX_TELNET_SERVER_WINDOW_SIZE, NX_NULL, _nx_telnet_server_disconnect_present); + + /* If no error is present, register the receive notify function. */ + if (status == NX_SUCCESS) + { + + /* Register the receive function. */ + nx_tcp_socket_receive_notify(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket), + _nx_telnet_server_data_present); + } + + /* Make sure each socket points to the TELNET server. */ + server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket.nx_tcp_socket_reserved_ptr = server_ptr; + } + + /* Determine if an error has occurred. */ + if (status != NX_SUCCESS) + { + + /* Loop to delete any created sockets. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Delete the TELNET socket. */ + nx_tcp_socket_delete(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket)); + } + + /* Delete the server thread. */ + tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); + + /* Delete the timer. */ + tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); + + /* Return the NetX error. */ + return(status); + } + + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + +#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL + + /* Create the packet pool for negotiating telnet options, and check the status */ + status = nx_packet_pool_create(&(server_ptr -> nx_telnet_server_packet_pool), "Telnet Server Options", + NX_TELNET_SERVER_PACKET_PAYLOAD, &server_ptr -> nx_telnet_server_pool_area, + NX_TELNET_SERVER_PACKET_POOL_SIZE); + + /* Determine if it was successful. */ + if (status != NX_SUCCESS) + { + /* Loop to delete any created sockets. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Delete the TELNET socket. */ + nx_tcp_socket_delete(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket)); + } + + /* Delete the server thread. */ + tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); + + /* Delete the timer. */ + tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); + + /* No, return error status. */ + return(status); + } + + server_ptr -> nx_telnet_server_packet_pool_ptr = &(server_ptr -> nx_telnet_server_packet_pool); +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + + /* Save the Server name. */ + server_ptr -> nx_telnet_server_name = server_name; + + /* Save the IP pointer address. */ + server_ptr -> nx_telnet_server_ip_ptr = ip_ptr; + + /* Save the user-supplied new connection and receive data functions. */ + server_ptr -> nx_telnet_new_connection = new_connection; + server_ptr -> nx_telnet_receive_data = receive_data; + server_ptr -> nx_telnet_connection_end = connection_end; + + /* Set the server ID to indicate the TELNET server thread is ready. */ + server_ptr -> nx_telnet_server_id = NX_TELNET_SERVER_ID; + + server_ptr -> nx_telnet_server_open_connections = 0; + + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_delete Actual server delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_delete(NX_TELNET_SERVER *server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_telnet_server_delete(server_ptr); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created TELNET server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_unaccept Unaccept server socket */ +/* nx_tcp_server_socket_unlisten Unlisten on server */ +/* nx_tcp_socket_delete Delete socket */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* tx_event_flags_delete Delete event flags */ +/* tx_thread_delete Delete thread */ +/* tx_thread_suspend Suspend thread */ +/* tx_thread_terminate Terminate thread */ +/* tx_timer_deactivate Deactivate timer */ +/* tx_timer_delete Delete timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr) +{ + +UINT i; +NX_TELNET_CLIENT_REQUEST *client_request_ptr; + + + /* Clear the server ID to indicate the TELNET server is no longer ready. */ + server_ptr -> nx_telnet_server_id = 0; + + /* Suspend the TELNET server thread. */ + tx_thread_suspend(&(server_ptr -> nx_telnet_server_thread)); + + /* Terminate server thread. */ + tx_thread_terminate(&(server_ptr -> nx_telnet_server_thread)); + + /* Delete server thread. */ + tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); + + /* Delete the event flag group. */ + tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); + + /* Deactivate and delete timer. */ + tx_timer_deactivate(&(server_ptr -> nx_telnet_server_timer)); + tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); + + /* If the Telnet Server is configured to send options and the packet + pool is created by the internally (by the Telnet server task) + we need to delete it. */ +#ifndef NX_TELNET_SERVER_OPTION_DISABLE +#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL + nx_packet_pool_delete(&server_ptr -> nx_telnet_server_packet_pool); +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + + /* Walk through the server structure to close and delete any open sockets. */ + i = 0; + client_request_ptr = &(server_ptr -> nx_telnet_server_client_list[0]); + while (i < NX_TELNET_MAX_CLIENTS) + { + + /* Disconnect the socket. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); + + /* Unaccept the socket. */ + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_telnet_client_request_socket)); + + /* Delete the socket. */ + nx_tcp_socket_delete(&(client_request_ptr -> nx_telnet_client_request_socket)); + + /* Increment the pointer into the client request list. */ + client_request_ptr++; + i++; + } + + /* Unlisten on the TELNET port. */ + nx_tcp_server_socket_unlisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server disconnect */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* logical_connection Logical connection entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_disconnect Actual server disconnect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for a valid logical connection. */ + if (logical_connection >= NX_TELNET_MAX_CLIENTS) + return(NX_OPTION_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server disconnect function. */ + status = _nx_telnet_server_disconnect(server_ptr, logical_connection); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes server disconnect requests made by the */ +/* application receive data callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* logical_connection Logical connection entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_relisten Relisten on Telnet port */ +/* nx_tcp_server_socket_unaccept Socket unaccept */ +/* nx_tcp_socket_disconnect Socket disconnect */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection) +{ + +UINT i; +UINT status; +NX_TELNET_CLIENT_REQUEST *client_ptr; + + /* Set a pointer to the indicated client connection. */ + client_ptr = &(server_ptr -> nx_telnet_server_client_list[logical_connection]); + + /* Determine if the connection is alive. */ + if (client_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state >= NX_TCP_ESTABLISHED) + { + + /* Disconnect the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); + + /* Call the application's end connection callback routine. */ + if (server_ptr -> nx_telnet_connection_end) + { + + /* Yes, there is a connection end callback routine - call it! */ + (server_ptr -> nx_telnet_connection_end)(server_ptr, client_ptr -> nx_telnet_client_request_connection); + } + + /* Unaccept this socket. */ + nx_tcp_server_socket_unaccept(&(client_ptr -> nx_telnet_client_request_socket)); + + /* Update number of current open connections. */ + if (server_ptr -> nx_telnet_server_open_connections > 0) + server_ptr -> nx_telnet_server_open_connections--; + + /* Clear the client request activity timeout. */ + client_ptr -> nx_telnet_client_request_activity_timeout = 0; + } + else + { + + /* Error, disconnecting an unconnected socket. */ + return(NX_TELNET_NOT_CONNECTED); + } + + /* Now look for a socket that is closed to relisten on. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Set a pointer to client request structure. */ + client_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket is closed. */ + if (client_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + /* Relisten on this socket. */ + status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, + &(client_ptr -> nx_telnet_client_request_socket)); + /* Check for bad status. */ + if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + + /* Increment the error count and keep trying. */ + server_ptr -> nx_telnet_server_relisten_errors++; + continue; + } + + /* Break out of loop. */ + break; + } + } + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server packet send */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* logical_connection Logical connection entry */ +/* packet_ptr Packet pointer to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_packet_send Actual server packet send call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for a valid logical connection. */ + if (logical_connection >= NX_TELNET_MAX_CLIENTS) + return(NX_OPTION_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server packet send function. */ + status = _nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packet send requests made from the */ +/* application's receive data callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* logical_connection Logical connection entry */ +/* packet_ptr Packet pointer to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_send Send packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; +NX_TELNET_CLIENT_REQUEST *client_ptr; + + + /* Derive the pointer to the appropriate client connection. */ + client_ptr = &(server_ptr -> nx_telnet_server_client_list[logical_connection]); + + /* Send the packet to the client. */ + status = nx_tcp_socket_send(&(client_ptr -> nx_telnet_client_request_socket), packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status) + { + + /* Map to a generic error. */ + status = NX_TELNET_FAILED; + } + + /* Return to caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_start Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_start(NX_TELNET_SERVER *server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nx_telnet_server_start(server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts a previously created TELNET server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_TELNET_NO_PACKET_POOL Telnet server packet pool not */ +/* set yet */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_listen Listen of TELNET clients */ +/* tx_thread_resume Resume TELNET server thread */ +/* tx_timer_activate Activate TELNET server timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_start(NX_TELNET_SERVER *server_ptr) +{ + +UINT status; +ULONG events; + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + + /* Check for Telnet server packet pool we'll need to send options. */ + if (server_ptr -> nx_telnet_server_packet_pool_ptr == NX_NULL) + { + + /* The Telnet server packet pool is not set. */ + return NX_TELNET_NO_PACKET_POOL; + } +#endif + + /* Start listening on the TELNET socket. */ + status = nx_tcp_server_socket_listen(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, + &(server_ptr -> nx_telnet_server_client_list[0].nx_telnet_client_request_socket), + NX_TELNET_MAX_CLIENTS, _nx_telnet_server_connection_present); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(status); + } + + /* Activate TELNET server timer. */ + tx_timer_activate(&(server_ptr -> nx_telnet_server_timer)); + + /* Clear stop event. */ + tx_event_flags_get(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_STOP_EVENT, TX_OR_CLEAR, &events, TX_NO_WAIT); + + /* Start the TELNET server thread. */ + tx_thread_resume(&(server_ptr -> nx_telnet_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_stop Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_stop(NX_TELNET_SERVER *server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_telnet_server_stop(server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops a previously started TELNET server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* tx_timer_deactivate Deactivate TELNET server timer*/ +/* nx_tcp_server_socket_unaccept Unaccept server socket */ +/* nx_tcp_server_socket_unlisten Unlisten on server */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr) +{ +UINT i; +NX_TELNET_CLIENT_REQUEST *client_request_ptr; + + /* Deactivate TELNET server timer. */ + tx_timer_deactivate(&(server_ptr -> nx_telnet_server_timer)); + + /* Suspend the TELNET server thread. */ + tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_STOP_EVENT, TX_OR); + + /* Walk through the server structure to close and delete any open sockets. */ + i = 0; + client_request_ptr = &(server_ptr -> nx_telnet_server_client_list[0]); + while (i < NX_TELNET_MAX_CLIENTS) + { + + /* Disconnect the socket. */ + nx_tcp_socket_disconnect(&(client_request_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); + + /* Unaccept the socket. */ + nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_telnet_client_request_socket)); + + /* Reset client request. */ + client_request_ptr -> nx_telnet_client_request_activity_timeout = 0; + + /* Increment the pointer into the client request list. */ + client_request_ptr++; + i++; + } + + /* Unlisten on the TELNET port. */ + nx_tcp_server_socket_unlisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_get_open_connection_count PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server get open */ +/* connection count service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* current_connections Pointer to # open connections */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_get_open_connection_count */ +/* Actual server get count call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (current_connections == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_telnet_server_get_open_connection_count(server_ptr, current_connections); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_get_open_connection_count PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the number of currently open connections. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* current_connections Pointer to # open connections */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections) +{ + + /* Retrieve server's record of open connections. */ + *current_connections = server_ptr -> nx_telnet_server_open_connections; + + /* Return completion status. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry of the TELNET server. All basic */ +/* processing is initiated by this function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* telnet_server Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_connect_process Process connection */ +/* _nx_telnet_server_data_process Process received data */ +/* _nx_telnet_server_disconnect_process Process disconnection */ +/* _nx_telnet_server_timeout_processing Process activity timeout */ +/* tx_event_flags_get Get TELNET event(s) */ +/* tx_thread_suspend Suspend TELNET thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_thread_entry(ULONG telnet_server) +{ + +NX_TELNET_SERVER *server_ptr; +UINT status; +ULONG events; + + + /* Setup the server pointer. */ + server_ptr = (NX_TELNET_SERVER *) telnet_server; + + /* Loop to process TELNET Server requests. */ + while(1) + { + + /* Wait for an TELNET client activity. */ + status = tx_event_flags_get(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_ANY_EVENT, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Check the return status. */ + if (status) + { + + /* If an error occurs, simply continue the loop. */ + continue; + } + + /* Check whether service is started. */ + if (events & NX_TELNET_STOP_EVENT) + { + + /* Suspend thread here. */ + tx_thread_suspend(&server_ptr -> nx_telnet_server_thread); + continue; + } + + /* Otherwise, an event is present. Process according to the event. */ + + /* Check for a client connection event. */ + if (events & NX_TELNET_SERVER_CONNECT) + { + + /* Call the connect processing. */ + _nx_telnet_server_connect_process(server_ptr); + } + + /* Check for a TELNET client write data event. */ + if (events & NX_TELNET_SERVER_DATA) + { + + /* Call processing to handle server data. */ + _nx_telnet_server_data_process(server_ptr); + } + + /* Check for a client disconnect event. */ + if (events & NX_TELNET_SERVER_DISCONNECT) + { + + /* Call the disconnect processing. */ + _nx_telnet_server_disconnect_process(server_ptr); + } + + /* Check for a client activity timeout event. */ + if (events & NX_TELNET_SERVER_ACTIVITY_TIMEOUT) + { + + /* Call the activity timeout processing. */ + _nx_telnet_server_timeout_processing(server_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_connect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all TELNET client connections received. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_accept Accept connection on socket */ +/* nx_tcp_server_socket_relisten Relisten for connection */ +/* nx_tcp_server_socket_unaccept Unaccept connection */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_thread_entry TELNET server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_connect_process(NX_TELNET_SERVER *server_ptr) +{ + +UINT i; +UINT status; +NX_TELNET_CLIENT_REQUEST *client_req_ptr; + + + /* One of the client request sockets is in the process of connection. */ + + /* Search the connections to see which one. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket was the one that is in being connected. */ + if ((client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state > NX_TCP_CLOSED) && + (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state < NX_TCP_ESTABLISHED) && + (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_connect_port)) + { + + /* Yes, we have found the socket being connected. */ + + /* Increment the number of connection requests. */ + server_ptr -> nx_telnet_server_connection_requests++; + + /* Attempt to accept on this socket. */ + status = nx_tcp_server_socket_accept(&(client_req_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); + + /* Determine if it is successful. */ + if (status) + { + + /* Not successful, simply unaccept on this socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); + } + else + { + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_telnet_client_request_activity_timeout = NX_TELNET_ACTIVITY_TIMEOUT; + + /* Update number of current open connections. */ + server_ptr -> nx_telnet_server_open_connections++; + + /* Call the application's new connection callback routine. */ + if (server_ptr -> nx_telnet_new_connection) + { + /* Yes, there is a new connection callback routine - call it! */ + (server_ptr -> nx_telnet_new_connection)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); + } + + /* Disable remote echo by default. */ + if(server_ptr -> nx_telnet_set_echo) + server_ptr -> nx_telnet_set_echo(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, NX_FALSE); + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + + /* Yes, send out server echo option requests. */ + status = _nx_telnet_server_send_option_requests(server_ptr, client_req_ptr); + if(status != NX_SUCCESS) + return; +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + + } + } + } + + /* Now look for a socket that is closed to relisten on. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Set a pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket is closed. */ + if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + /* Relisten on this socket. */ + status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, + &(client_req_ptr -> nx_telnet_client_request_socket)); + /* Check for bad status. */ + if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + + /* Increment the error count and keep trying. */ + server_ptr -> nx_telnet_server_relisten_errors++; + continue; + } + + /* Break out of loop. */ + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_connection_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all TELNET client connections received on */ +/* the socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Socket event occurred */ +/* port Port the connection occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port) +{ + +NX_TELNET_SERVER *server_ptr; + + NX_PARAMETER_NOT_USED(port); + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the connect event flag. */ + tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_CONNECT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_disconnect_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles all TELNET client disconnections received on */ +/* the socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_disconnect_present(NX_TCP_SOCKET *socket_ptr) +{ + +NX_TELNET_SERVER *server_ptr; + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the disconnect event flag. */ + tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_DISCONNECT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_disconnect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes all TELNET client disconnections received */ +/* on the socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_relisten Relisten on Telnet port */ +/* nx_tcp_server_socket_unaccept Unaccept connection */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_thread_entry TELNET server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_disconnect_process(NX_TELNET_SERVER *server_ptr) +{ + +UINT i; +UINT status; +NX_TELNET_CLIENT_REQUEST *client_req_ptr; +UINT reset_client_request; + + + /* Now look for a socket that has a disconnect state. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + reset_client_request = NX_FALSE; + + /* Setup pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Has the socket received a RST packet? If so NetX will put it in a CLOSED or LISTEN state + and the socket activity timeout has not been reset yet. */ + if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state < NX_TCP_SYN_SENT) + { + + if (client_req_ptr -> nx_telnet_client_request_activity_timeout > 0) + { + + reset_client_request = NX_TRUE; + } + } + else + { + + /* Now see if this socket has entered a disconnect state. */ + while (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) + { + + /* Yes, a disconnect is present, which signals an end of session for TELNET request. */ + + /* First, cleanup this socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); + + reset_client_request = NX_TRUE; + } + } + + /* If this connection is closed, update the telnet data and notify the application of a disconnect. */ + if (reset_client_request == NX_TRUE) + { + + /* Unaccept this socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_telnet_client_request_activity_timeout = 0; + + /* Update number of current open connections. */ + if (server_ptr -> nx_telnet_server_open_connections > 0) + server_ptr -> nx_telnet_server_open_connections--; + + /* Call the application's end connection callback routine. */ + if (server_ptr -> nx_telnet_connection_end) + { + + /* Yes, there is a connection end callback routine - call it! */ + (server_ptr -> nx_telnet_connection_end)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); + } + } + } + + /* Now look for a socket that is closed to relisten on. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket is closed. */ + if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + /* Relisten on this socket. */ + status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, + &(client_req_ptr -> nx_telnet_client_request_socket)); + /* Check for bad status. */ + if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + + /* Increment the error count and keep trying. */ + server_ptr -> nx_telnet_server_relisten_errors++; + continue; + } + + /* Break out of loop. */ + break; + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_data_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function notifies the TELNET server thread of data received */ +/* from a client on the socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Socket event occurred */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_data_present(NX_TCP_SOCKET *socket_ptr) +{ + +NX_TELNET_SERVER *server_ptr; + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_DATA, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_data_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes all TELNET client data packets received on */ +/* the request socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive from socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_thread_entry TELNET server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_data_process(NX_TELNET_SERVER *server_ptr) +{ + +UINT i; +UINT status; +NX_PACKET *packet_ptr; +NX_TELNET_CLIENT_REQUEST *client_req_ptr; +#ifndef NX_TELNET_SERVER_OPTION_DISABLE +UCHAR data_char; +UINT offset; +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + + /* Now look for a socket that has receive data. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Setup pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket has data. If so, process all of it now! */ + while (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_receive_queue_count) + { + + /* Reset the client request activity timeout. */ + client_req_ptr -> nx_telnet_client_request_activity_timeout = NX_TELNET_ACTIVITY_TIMEOUT; + + /* Attempt to read a packet from this socket. */ + status = nx_tcp_socket_receive(&(client_req_ptr -> nx_telnet_client_request_socket), &packet_ptr, NX_NO_WAIT); + + /* Check for not data present. */ + if (status != NX_SUCCESS) + { + + /* Break to look at the next socket. */ + break; + } + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + + /* If the first byte of the packet data is the telnet "IAC" code, + this is a telnet option packet. */ + if (*packet_ptr -> nx_packet_prepend_ptr == NX_TELNET_IAC) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + if (packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(packet_ptr); + break; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* We will use an offset to mark the beginning of each telnet option, if there is more + than one, in the packet payload. */ + offset = 0; + + /* Validate the packet length. */ + if (packet_ptr -> nx_packet_length == 1) + { + nx_packet_release(packet_ptr); + break; + } + + /* Set the work pointer to just past the telnet IAC tag. */ + data_char = *(packet_ptr -> nx_packet_prepend_ptr + 1); + + /* Verify the next byte is a valid Telnet option code. */ + if ((data_char >= NX_TELNET_WILL) && (data_char <= NX_TELNET_DONT)) + { + + /* Process the entire packet for telnet options, ensuring we don't go off the end of the payload. */ + while((offset < packet_ptr -> nx_packet_length) && (*(packet_ptr -> nx_packet_prepend_ptr + offset) == NX_TELNET_IAC)) + { + + /* Process this telnet option. The offset will be updated to the location + of the next option (if there is one) on return of this function. */ + _nx_telnet_server_process_option(server_ptr, packet_ptr, &offset, client_req_ptr); + } + } + + /* Are there any data left? */ + if ((offset < packet_ptr -> nx_packet_length) && (server_ptr -> nx_telnet_receive_data)) + { + + /* Yes. Adjust packet. */ + packet_ptr -> nx_packet_prepend_ptr += offset; + packet_ptr -> nx_packet_length -= offset; + + /* Yes, there is a process data callback routine - call it! */ + (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); + } + else + { + + /* We're done with this packet. */ + nx_packet_release(packet_ptr); + } + + /* Check if the echo negotiation is successful. */ + if((client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success == NX_TRUE) && + (client_req_ptr -> nx_telnet_client_agree_server_will_echo_success == NX_TRUE)) + { + + /* Enable remote echo. */ + if(server_ptr -> nx_telnet_set_echo) + server_ptr -> nx_telnet_set_echo(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, NX_TRUE); + } + } + + /* It's not an option packet. */ + else + { + + /* Check server receive callback. */ + if (server_ptr -> nx_telnet_receive_data) + { + + /* Yes, there is a process data callback routine - call it! */ + (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); + } + else + { + + /* Error, no application callback routine. */ + + /* Release the packet and continue the loop. */ + nx_packet_release(packet_ptr); + } + } +#else + if (*packet_ptr -> nx_packet_prepend_ptr == NX_TELNET_IAC) + { + nx_packet_release(packet_ptr); + } + /* Call the server receive callback. */ + else if (server_ptr -> nx_telnet_receive_data) + { + + /* Yes, there is a process data callback routine - call it! */ + (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); + } + else + { + + /* Error, no application callback routine. */ + + /* Release the packet and continue the loop. */ + nx_packet_release(packet_ptr); + } + +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the periodic timer for this TELNET server. Its */ +/* duty is to inform the TELNET server that it is time to check for */ +/* activity timeouts. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* telnet_server_address TELNET server's address */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX ThreadX timer callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_timeout(ULONG telnet_server_address) +{ + +NX_TELNET_SERVER *server_ptr; + + /* Pickup server pointer. */ + server_ptr = (NX_TELNET_SERVER *) telnet_server_address; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_ACTIVITY_TIMEOUT, TX_OR); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_timeout_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reviews all the active TELNET client connections and */ +/* looks for an activity timeout. If a connection has not had any */ +/* activity within NX_TELNET_ACTIVITY_TIMEOUT seconds, the connection */ +/* is deleted and its resources are made available to a new connection.*/ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_relisten Relisten for another connect */ +/* nx_tcp_server_socket_unaccept Unaccept server connection */ +/* nx_tcp_socket_disconnect Disconnect socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_thread_entry TELNET server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_timeout_processing(NX_TELNET_SERVER *server_ptr) +{ + +UINT i; +NX_TELNET_CLIENT_REQUEST *client_req_ptr; + + + /* Now look through all the sockets. */ + for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) + { + + /* Set a pointer to client request structure. */ + client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); + + /* Now see if this socket has an activity timeout active. */ + if (client_req_ptr -> nx_telnet_client_request_activity_timeout) + { + + /* Decrement the activity timeout for this client request. */ + if (client_req_ptr -> nx_telnet_client_request_activity_timeout > NX_TELNET_TIMEOUT_PERIOD) + client_req_ptr -> nx_telnet_client_request_activity_timeout = client_req_ptr -> nx_telnet_client_request_activity_timeout - NX_TELNET_TIMEOUT_PERIOD; + else + client_req_ptr -> nx_telnet_client_request_activity_timeout = 0; + + /* Determine if this entry has exceeded the activity timeout. */ + if (client_req_ptr -> nx_telnet_client_request_activity_timeout == 0) + { + + /* Yes, the activity timeout has been exceeded. Tear down and clean up the + entire client request structure. */ + + /* Increment the activity timeout counter. */ + server_ptr -> nx_telnet_server_activity_timeouts++; + + /* Now disconnect the command socket. */ + nx_tcp_socket_disconnect(&(client_req_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); + + /* Unaccept the server socket. */ + nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); + + /* Relisten on this socket. This will probably fail, but it is needed just in case all available + clients were in use at the time of the last relisten. */ + nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, + &(client_req_ptr -> nx_telnet_client_request_socket)); + + /* Update number of current open connections. */ + if (server_ptr -> nx_telnet_server_open_connections > 0) + server_ptr -> nx_telnet_server_open_connections--; + + /* Call the application's end connection callback routine. */ + if (server_ptr -> nx_telnet_connection_end) + { + + /* Yes, there is a connection end callback routine - call it! */ + (server_ptr -> nx_telnet_connection_end)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); + } + } + } + } +} + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + +#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TELNET server create packet */ +/* pool call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* pool_ptr Pointer to telnet packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_telnet_server_packet_pool_set Actual set packet pool call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr) +{ + +UINT status; + + /* Check for invalid pointer input. */ + if ((server_ptr == NX_NULL) || (pool_ptr == NX_NULL)) + { + return NX_PTR_ERROR; + } + + /* Actual set packet pool service. */ + status = _nx_telnet_server_packet_pool_set(server_ptr, pool_ptr); + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_telnet_server_packet_pool_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the Telnet Server packet pool to the packet pool */ +/* created outside the Telnet Server domain. This permits the packet */ +/* pool memory to be in a different location from the Telnet Server. */ +/* */ +/* The Telnet Server only uses this packet pool for sending Telnet */ +/* options (requires NX_TELNET_SERVER_OPTION_DISABLE not be defined). */ +/* */ +/* Note: This will overwrite an existing Telnet Server packet pool if */ +/* one was previously set. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* pool_ptr Pointer to telnet packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Telnet server packet pool */ +/* successfully set */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr) +{ + + + server_ptr -> nx_telnet_server_packet_pool_ptr = pool_ptr; + + return NX_SUCCESS; +} + +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_create_option_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates option packet for specified type and id. */ +/* */ +/* INPUT */ +/* */ +/* option_message_type Option type */ +/* option_id Option_id */ +/* stream Output buffer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_send_option_requests Send telnet option */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_telnet_server_create_option_packet(UCHAR option_message_type, UCHAR option_id, UCHAR *stream) +{ + + *(stream++) = NX_TELNET_IAC; + *(stream++) = option_message_type; + *stream = option_id; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_send_option_requests PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called if 1) the server is configured to send out */ +/* options without waiting to receive client option requests, or 2)after*/ +/* receiving a client's initial option requests. This will send out */ +/* those option requests the server did not receive from the client */ +/* based on the server session option list. */ +/* */ +/* This function obtains mutex protection on the client session record */ +/* to update the record with options sent out from the server. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to telnet server */ +/* client_req_ptr Pointer to client record */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet from pool */ +/* nx_packet_release Release packet back to pool */ +/* nx_packet_data_append Append data to packet payload */ +/* _nx_telnet_server_create_option_packet */ +/* Create telnet option message */ +/* _nx_telnet_server_packet_send Send telnet option to client */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_data_process Top level telnet packet handler*/ +/* _nx_telnet_server_connect_process Telnet connection handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_telnet_server_send_option_requests(NX_TELNET_SERVER *server_ptr, NX_TELNET_CLIENT_REQUEST *client_req_ptr) +{ +UINT status; +NX_PACKET *packet_ptr; +UINT option_length; +UINT packet_available; +UCHAR option_stream[9]; + + status = NX_SUCCESS; + + /* Indicate packet not available, nor needing to be released. */ + packet_available = NX_FALSE; + + /* Allocate a packet for replies to send to this telnet client. */ + status = nx_packet_allocate(server_ptr -> nx_telnet_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT); + + if (status != NX_SUCCESS) + return status; + + /* Now a packet is available, and if not used should be released. */ + packet_available = NX_TRUE; + + /* Initialize option data to zero bytes. */ + option_length = 0; + + client_req_ptr -> nx_telnet_client_agree_server_will_echo_success = NX_FALSE; + client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success = NX_FALSE; + + /* Yes, create will echo request (3 bytes). */ + _nx_telnet_server_create_option_packet(NX_TELNET_WILL, NX_TELNET_ECHO, &option_stream[0]); + + /* Yes, create dont echo request (3 bytes). */ + _nx_telnet_server_create_option_packet(NX_TELNET_DONT, NX_TELNET_ECHO, &option_stream[3]); + + /* Yes, create will SGA request (3 bytes). */ + _nx_telnet_server_create_option_packet(NX_TELNET_WILL, NX_TELNET_SGA, &option_stream[6]); + + /* Update the the packet payload for number of bytes for a telnet option request. */ + option_length = 9; + + /* Add to the packet payload. */ + status = nx_packet_data_append(packet_ptr, option_stream, 9, server_ptr -> nx_telnet_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if (status) + { + nx_packet_release(packet_ptr); + return(status); + } + + /* Check if we have a packet started, but not sent yet. */ + if (option_length > 0) + { + + /* Send the telnet packet out to the client. */ + status = _nx_telnet_server_packet_send(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr, 100); + + /* If errors sending, we need to release the packet. */ + if (status != NX_SUCCESS) + { + nx_packet_release(packet_ptr); + return status; + } + + /* Indicate we need another packet, just sent out the last one. */ + packet_available = NX_FALSE; + } + + /* Check for unused packet (needs to be released). */ + if (packet_available == NX_TRUE) + { + + /* Release the packet we did not use. */ + nx_packet_release(packet_ptr); + } + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_telnet_server_process_option PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function examines the telnet option in the current packet and */ +/* determines if it is a new client request, an option with */ +/* subnegotiation data for the server, or a response to a previously */ +/* sent server telnet option request to the client. It then forwards */ +/* the telnet option information to the appropriate telnet processor. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TELNET server */ +/* packet_ptr Packet with telnet option */ +/* offset Option offset in packet */ +/* client_req_ptr Telnet client sending packet */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TELNET_SESSION_OPTIONS_FULL Session option list is fill */ +/* NX_SUCCESS Option successfully processed */ +/* */ +/* CALLS */ +/* _nx_telnet_server_update_server_session_attributes */ +/* Updates server telnet features*/ +/* _nx_telnet_server_update_client_session_attributes */ +/* Updates client telnet features*/ +/* _nx_telnet_server_process_new_option Add new option to session list*/ +/* _nx_telnet_server_respond_to_pending_option */ +/* Send server reply to option */ +/* _nx_telnet_server_process_subnegotiation_data */ +/* Process received option specs */ +/* _nx_telnet_server_validate_option_change */ +/* Determine if option is dupe */ +/* Process received option specs */ +/* CALLED BY */ +/* */ +/* _nx_telnet_server_data_process Top level incoming telnet */ +/* packet handler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +VOID _nx_telnet_server_process_option(NX_TELNET_SERVER *server_ptr, NX_PACKET *packet_ptr, UINT *offset, + NX_TELNET_CLIENT_REQUEST *client_req_ptr) +{ +UCHAR data_char; +UCHAR *work_ptr; + + NX_PARAMETER_NOT_USED(server_ptr); + + /* Set the work pointer to see what option received. */ + work_ptr = (UCHAR *)(packet_ptr -> nx_packet_prepend_ptr + (*offset) + 2); + + /* This option isn't complete, just move to the end of the packet. */ + if (work_ptr >= packet_ptr -> nx_packet_append_ptr) + { + *offset = packet_ptr -> nx_packet_length; + return; + } + + data_char = *work_ptr; + + /* If it is a echo option. */ + if(data_char == NX_TELNET_ECHO) + { + + /* Check whether the client replies with echo negotiation of the local echo disabled. */ + work_ptr--; + data_char = *work_ptr; + if(data_char == NX_TELNET_DO) + { + + /* Server will echo what received from the telnet connection. */ + client_req_ptr -> nx_telnet_client_agree_server_will_echo_success = NX_TRUE; + + /* Move the offset to past the option. */ + (*offset)+=3; + } + else + { + + /* Move the offset to past the option. */ + (*offset)+=3; + } + } + + /* If it is a SGA option. */ + else if(data_char == NX_TELNET_SGA) + { + + /* Check whether the client replies with SGA negotiation. */ + work_ptr--; + data_char = *work_ptr; + if(data_char == NX_TELNET_DO) + { + + /* Server will enable SGA option. */ + client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success = NX_TRUE; + + /* Move the offset to past the option. */ + (*offset)+=3; + } + else + { + /* Move the offset to past the option. */ + (*offset)+=3; + return; + } + } + + /* We have not implemented this option, just return. */ + else + { + + /* See next three bytes. */ + (*offset)+=3; + return; + } +} +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ diff --git a/addons/telnet/nxd_telnet_server.h b/addons/telnet/nxd_telnet_server.h new file mode 100644 index 00000000..6b8723c7 --- /dev/null +++ b/addons/telnet/nxd_telnet_server.h @@ -0,0 +1,354 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** TELNET Server Protocol (TELNET Server) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_telnet_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Duo TELNET Protocol (TELNET) component, */ +/* including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_TELNET_SERVER_H +#define NXD_TELNET_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the Server TELNET ID. */ + +#define NX_TELNET_SERVER_ID 0x54454C4EUL + +/* Defined, option negotiation is disabled. +#define NX_TELNET_SERVER_OPTION_DISABLE +*/ + + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + +/* If NX_TELNET_SERVER_OPTION_DISABLE is not defined, and Telnet Server + needs a packet pool, this option lets the application create the packet + pool instead of the Telnet Server. +#define NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +*/ + +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + +/* Define the maximum number of clients the TELNET Server can accommodate. */ + +#ifndef NX_TELNET_MAX_CLIENTS +#define NX_TELNET_MAX_CLIENTS 4 +#endif + + +/* Define TELNET TCP socket create options. */ + +#ifndef NX_TELNET_TOS +#define NX_TELNET_TOS NX_IP_NORMAL +#endif + +#ifndef NX_TELNET_FRAGMENT_OPTION +#define NX_TELNET_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_TELNET_SERVER_WINDOW_SIZE +#define NX_TELNET_SERVER_WINDOW_SIZE 2048 +#endif + +#ifndef NX_TELNET_TIME_TO_LIVE +#define NX_TELNET_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_TELNET_SERVER_TIMEOUT +#define NX_TELNET_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_TELNET_SERVER_PRIORITY +#define NX_TELNET_SERVER_PRIORITY 16 +#endif + +#ifndef NX_TELNET_ACTIVITY_TIMEOUT +#define NX_TELNET_ACTIVITY_TIMEOUT 600 /* Seconds allowed with no activity */ +#endif + +#ifndef NX_TELNET_TIMEOUT_PERIOD +#define NX_TELNET_TIMEOUT_PERIOD 60 /* Number of seconds to check */ +#endif + + +/* Define TELNET commands that are optionally included in the TELNET data. The application is responsible for + recognizing and responding to the commands in accordance with the specification. The TELNET option command + requires three bytes, as follows: + + IAC, COMMAND, OPTION ID + +*/ + +/* Define byte indicating TELNET command follows. */ + +#define NX_TELNET_IAC 255 /* TELNET Command byte - two consecutive -> 255 data */ + +/* Define TELNET Negotiation Commands - Immediately follows IAC. */ + +#define NX_TELNET_WILL 251 /* TELNET WILL - Sender wants to enable the option */ +#define NX_TELNET_WONT 252 /* TELNET WONT - Sender wants to disable the option */ +#define NX_TELNET_DO 253 /* TELNET DO - Sender wants receiver to enable option */ +#define NX_TELNET_DONT 254 /* TELNET DONT - Sender wants receiver to disable option*/ + + +/* Define the Telnet Server packet payload. */ + +#ifndef NX_TELNET_SERVER_PACKET_PAYLOAD +#define NX_TELNET_SERVER_PACKET_PAYLOAD 300 +#endif + +/* Define the size of the Telnet Server packet pool. This will allow room for about + 5-6 packets of 300 byte payload. */ + +#ifndef NX_TELNET_SERVER_PACKET_POOL_SIZE +#define NX_TELNET_SERVER_PACKET_POOL_SIZE 2048 +#endif + + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + +/* Define TELNET Option IDs. */ +#define NX_TELNET_ECHO 1 /* TELNET ECHO Option */ +#define NX_TELNET_SGA 3 /* TELNET SGA Option */ +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + +/* Define Server thread events. */ + +#define NX_TELNET_SERVER_CONNECT 0x01 /* TELNET connection is present */ +#define NX_TELNET_SERVER_DISCONNECT 0x02 /* TELNET disconnection is present */ +#define NX_TELNET_SERVER_DATA 0x04 /* TELNET receive data is present */ +#define NX_TELNET_SERVER_ACTIVITY_TIMEOUT 0x08 /* TELNET activity timeout check */ +#define NX_TELNET_STOP_EVENT 0x10 /* TELNET stop service */ +#define NX_TELNET_ANY_EVENT 0xFF /* Any TELNET event */ + + +/* Define return code constants. */ + +#define NX_TELNET_ERROR 0xF0 /* TELNET internal error */ +#define NX_TELNET_TIMEOUT 0xF1 /* TELNET timeout occurred */ +#define NX_TELNET_FAILED 0xF2 /* TELNET error */ +#define NX_TELNET_NOT_CONNECTED 0xF3 /* TELNET not connected error */ +#define NX_TELNET_NOT_DISCONNECTED 0xF4 /* TELNET not disconnected error */ +#define NX_TELNET_INVALID_PARAMETER 0xF5 /* Invalid non pointer input to Telnet function */ +#define NX_TELNET_NO_PACKET_POOL 0xF6 /* Telnet server packet pool not set */ + +/* Define the TELNET Server TCP port numbers. */ + +#ifndef NX_TELNET_SERVER_PORT +#define NX_TELNET_SERVER_PORT 23 /* Default Port for TELNET server */ +#endif + + +/* Define the per client request structure for the TELNET Server data structure. */ + +typedef struct NX_TELNET_CLIENT_REQUEST_STRUCT +{ + UINT nx_telnet_client_request_connection; /* Logical connection number */ + ULONG nx_telnet_client_request_activity_timeout; /* Timeout for client activity */ + ULONG nx_telnet_client_request_total_bytes; /* Total bytes read or written */ + NX_TCP_SOCKET nx_telnet_client_request_socket; /* Client request socket */ +#ifndef NX_TELNET_SERVER_OPTION_DISABLE + USHORT nx_telnet_client_agree_server_will_echo_success; /* True if server will echo negotiation success */ + USHORT nx_telnet_client_agree_server_will_SGA_success; /* True if server will SGA negotiation success */ +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + +} NX_TELNET_CLIENT_REQUEST; + + +/* Define the TELNET Server data structure. */ + +typedef struct NX_TELNET_SERVER_STRUCT +{ + ULONG nx_telnet_server_id; /* TELNET Server ID */ + CHAR *nx_telnet_server_name; /* Name of this TELNET server */ + NX_IP *nx_telnet_server_ip_ptr; /* Pointer to associated IP structure */ + ULONG nx_telnet_server_connection_requests; /* Number of connection requests */ + ULONG nx_telnet_server_disconnection_requests; /* Number of disconnection requests */ + ULONG nx_telnet_server_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_telnet_server_total_bytes_received; /* Number of total bytes received */ + ULONG nx_telnet_server_relisten_errors; /* Number of relisten errors */ + ULONG nx_telnet_server_activity_timeouts; /* Number of activity timeouts */ + ULONG nx_telnet_server_open_connections; /* Number of currently open connections */ + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE +#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL + UCHAR nx_telnet_server_pool_area[NX_TELNET_SERVER_PACKET_POOL_SIZE]; + NX_PACKET_POOL nx_telnet_server_packet_pool; /* Server TCP packet pool + for telnet option messages */ +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ + NX_PACKET_POOL *nx_telnet_server_packet_pool_ptr; /* Pointer to packet pool */ +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ + NX_TELNET_CLIENT_REQUEST /* TELNET client request array */ + nx_telnet_server_client_list[NX_TELNET_MAX_CLIENTS]; + TX_EVENT_FLAGS_GROUP + nx_telnet_server_event_flags; /* TELNET server thread events */ + TX_TIMER nx_telnet_server_timer; /* TELNET server activity timeout timer */ + TX_THREAD nx_telnet_server_thread; /* TELNET server thread */ + void (*nx_telnet_new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection); + void (*nx_telnet_receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr); + void (*nx_telnet_connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection); + void (*nx_telnet_set_echo)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, UINT echo_flag); +} NX_TELNET_SERVER; + +#ifndef NX_TELNET_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_telnet_server_create _nx_telnet_server_create +#define nx_telnet_server_delete _nx_telnet_server_delete +#define nx_telnet_server_disconnect _nx_telnet_server_disconnect +#define nx_telnet_server_packet_send _nx_telnet_server_packet_send +#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +#define nx_telnet_server_packet_pool_set _nx_telnet_server_packet_pool_set +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +#define nx_telnet_server_start _nx_telnet_server_start +#define nx_telnet_server_stop _nx_telnet_server_stop +#define nx_telnet_server_get_open_connection_count _nx_telnet_server_get_open_connection_count + +#else + +/* Services with error checking. */ + +#define nx_telnet_server_create _nxe_telnet_server_create +#define nx_telnet_server_delete _nxe_telnet_server_delete +#define nx_telnet_server_disconnect _nxe_telnet_server_disconnect +#define nx_telnet_server_packet_send _nxe_telnet_server_packet_send +#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +#define nx_telnet_server_packet_pool_set _nxe_telnet_server_packet_pool_set +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +#define nx_telnet_server_start _nxe_telnet_server_start +#define nx_telnet_server_stop _nxe_telnet_server_stop +#define nx_telnet_server_get_open_connection_count _nxe_telnet_server_get_open_connection_count + +#endif + +/* Define the prototypes accessible to the application software. */ + +UINT nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), + void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), + void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); +UINT nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr); +UINT nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); +UINT nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); +#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +UINT nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +UINT nx_telnet_server_start(NX_TELNET_SERVER *server_ptr); +UINT nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr); +UINT nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); + + +#else + +/* TELNET source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), + void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), + void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); +UINT _nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, + void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), + void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), + void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); +UINT _nxe_telnet_server_delete(NX_TELNET_SERVER *server_ptr); +UINT _nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr); +UINT _nxe_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); +UINT _nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); +UINT _nxe_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); +#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL +UINT _nxe_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); +UINT _nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); +#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ +UINT _nxe_telnet_server_start(NX_TELNET_SERVER *server_ptr); +UINT _nx_telnet_server_start(NX_TELNET_SERVER *server_ptr); +UINT _nxe_telnet_server_stop(NX_TELNET_SERVER *server_ptr); +UINT _nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr); +UINT _nxe_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); +UINT _nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); + +/* Define internal TELNET functions. */ + +VOID _nx_telnet_server_thread_entry(ULONG telnet_server); +VOID _nx_telnet_server_connect_process(NX_TELNET_SERVER *server_ptr); +VOID _nx_telnet_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); +VOID _nx_telnet_server_disconnect_present(NX_TCP_SOCKET *socket_ptr); +VOID _nx_telnet_server_disconnect_process(NX_TELNET_SERVER *server_ptr); +VOID _nx_telnet_server_data_present(NX_TCP_SOCKET *socket_ptr); +VOID _nx_telnet_server_data_process(NX_TELNET_SERVER *server_ptr); +VOID _nx_telnet_server_timeout(ULONG telnet_server_address); +VOID _nx_telnet_server_timeout_processing(NX_TELNET_SERVER *server_ptr); + +#ifndef NX_TELNET_SERVER_OPTION_DISABLE +UINT _nx_telnet_server_send_option_requests(NX_TELNET_SERVER *server_ptr, NX_TELNET_CLIENT_REQUEST *client_req_ptr); +VOID _nx_telnet_server_process_option(NX_TELNET_SERVER *server_ptr, NX_PACKET *packet_ptr, UINT *offset, NX_TELNET_CLIENT_REQUEST *client_request_ptr); +VOID _nx_telnet_server_create_option_packet(UCHAR option_message_type, UCHAR option_id, UCHAR *stream); +#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_TELNET_SERVER_H */ diff --git a/addons/tftp/nxd_tftp_client.c b/addons/tftp/nxd_tftp_client.c new file mode 100644 index 00000000..c5a23a4c --- /dev/null +++ b/addons/tftp/nxd_tftp_client.c @@ -0,0 +1,2396 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Trivial File Transfer Protocol (TFTP) Client */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_TFTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_ipv6.h" +#include "nxd_tftp_client.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP client create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* tftp_client_name Name of TFTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id == NXD_TFTP_CLIENT_ID) || + (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Call actual client create function. */ + status = _nxd_tftp_client_create(tftp_client_ptr, tftp_client_name, ip_ptr, pool_ptr, ip_type); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a TFTP client on the specified IP. In doing */ +/* so this function creates an UDP socket for subsequent TFTP */ +/* transfers. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* tftp_client_name Name of TFTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to TFTP pool */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_bind Bind the UDP socket */ +/* nx_udp_socket_create Create a UDP socket */ +/* nx_udp_socket_delete Delete the UDP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type) +{ + +UINT status; + + + /* Clear the TFTP server structure. */ + memset((void *) tftp_client_ptr, 0, sizeof(NX_TFTP_CLIENT)); + + /* Setup the TFTP client data structure. */ + + /* Save the TFTP client name. */ + tftp_client_ptr -> nx_tftp_client_name = tftp_client_name; + + /* Save the TFTP IP pointer. */ + tftp_client_ptr -> nx_tftp_client_ip_ptr = ip_ptr; + + /* Save the TFTP packet pool pointer. */ + tftp_client_ptr -> nx_tftp_client_packet_pool_ptr = pool_ptr; + + /* Initialize the server port number. This can change after the open request. */ + tftp_client_ptr -> nx_tftp_client_server_port = NX_TFTP_SERVER_PORT; + + /* Setup the current state to not open. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_NOT_OPEN; + + /* Default the client network interface to the primary interface. */ + tftp_client_ptr -> nx_tftp_client_interface_index = 0; + + /* Create the UDP socket. */ + status = nx_udp_socket_create(ip_ptr, &(tftp_client_ptr -> nx_tftp_client_socket), tftp_client_name, + NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH); + + /* Determine if an error occurred. */ + if (status) + { + + /* Yes, return error code. */ + return(status); + } + + /* Now, bind the socket to a port number. */ + + /* Let NetX decide which port. */ + status = nx_udp_socket_bind(&(tftp_client_ptr -> nx_tftp_client_socket), NX_TFTP_SOURCE_PORT, NX_WAIT_FOREVER); + + /* Determine if an error occurred. */ + if (status) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_client_ptr -> nx_tftp_client_socket)); + + /* Yes, return error code. */ + return(status); + } + + /* Otherwise, all is okay. Set the TFTP ID to indicate success. */ + tftp_client_ptr -> nx_tftp_client_id = NXD_TFTP_CLIENT_ID; + + NX_PARAMETER_NOT_USED(ip_type); + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_delete Actual client delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nxd_tftp_client_delete(tftp_client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a TFTP client on the specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind the UDP socket */ +/* nx_udp_socket_delete Delete the UDP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr) +{ + + /* Unbind the TFTP client UDP socket. */ + nx_udp_socket_unbind(&(tftp_client_ptr -> nx_tftp_client_socket)); + + /* Delete the TFTP client UDP socket. */ + nx_udp_socket_delete(&(tftp_client_ptr -> nx_tftp_client_socket)); + + /* Clear the TFTP client ID. */ + tftp_client_ptr -> nx_tftp_client_id = 0; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP client set interface */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* if_index Interface for tftp messages */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_INTERFACE Invalid interface index input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_set_interface Actual set interface call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index) +{ + +UINT status; + + /* Check for invalid input pointer input. */ + if (tftp_client_ptr == NX_NULL) + return(NX_PTR_ERROR); + + /* Verify a valid index as been supplied. */ + if (if_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_TFTP_INVALID_INTERFACE; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nxd_tftp_client_set_interface(tftp_client_ptr, if_index); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_set_interface PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the physical interface which the TFTP client */ +/* sends and receives TFTP packets. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* if_index Interface for tftp messages */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_INVALID_INTERFACE Invalid interface index input */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_unbind Unbind the UDP socket */ +/* nx_udp_socket_delete Delete the UDP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index) +{ + + + /* Set the TFTP client interface index. */ + tftp_client_ptr -> nx_tftp_client_interface_index = if_index; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_error_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP error information */ +/* get call. */ +/* */ +/* Note: error_string pointer points to string generated by internal */ +/* logic and it is always NULL-terminated. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* error_code Pointer to destination for */ +/* error code */ +/* error_string Pointer to destination for */ +/* the error string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_error_info_get Actual get error info call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || + (error_code == NX_NULL) || (error_string == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client error information get function. */ + status = _nxd_tftp_client_error_info_get(tftp_client_ptr, error_code, error_string); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_error_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function picks up the error code and error string for the */ +/* specified TFTP client instance. */ +/* */ +/* Note: error_string pointer points to string generated by internal */ +/* logic and it is always NULL-terminated. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* error_code Pointer to destination for */ +/* error code */ +/* error_string Pointer to destination for */ +/* the error string */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string) +{ + + /* Return the error code and the error string. */ + *error_code = tftp_client_ptr -> nx_tftp_client_error_code; + *error_string = &(tftp_client_ptr -> nx_tftp_client_error_string[0]); + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_file_close PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP file close call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_file_close Actual client file close */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file close function. */ + status = _nxd_tftp_client_file_close(tftp_client_ptr, ip_type); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_file_close PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function closes the previously opened TFTP file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet for 0-length */ +/* data packet */ +/* nxd_udp_socket_send Send UDP data packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type) +{ + +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT status; + + + /* Determine if the file is still open for writing. */ + if (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_WRITE_OPEN) + { + + /* Allocate a new packet for the final data message. */ + if (ip_type == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); + } + else + { + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_NO_WAIT); + } + + /* Determine if an error occurred trying to allocate a packet. */ + if (status != NX_SUCCESS) + { + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Return error condition. */ + return(status); + } + + if (4u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) + { + /* Return the unsent packet to the packet pool. */ + nx_packet_release(packet_ptr); + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + return(NX_SIZE_ERROR); + } + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now, build the TFTP 0-data length message. */ + + /* Setup a pointer to the packet payload. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Initial byte is always zero. */ + *buffer_ptr++ = 0; + + /* Set the ACK code. */ + *buffer_ptr++ = NX_TFTP_CODE_DATA; + + /* Put the block number in. */ + *buffer_ptr++ = (UCHAR) ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8)); + *buffer_ptr = (UCHAR) ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF)); + + /* Adjust the packet pointers and length. */ + packet_ptr -> nx_packet_length = 4; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + 4; + + /* Send the 0-length data packet out. */ + status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, + &tftp_client_ptr -> nx_tftp_client_server_ip, + tftp_client_ptr -> nx_tftp_client_server_port); + + /* Determine if an error occurred trying to sending the packet. */ + if (status) + { + + /* Return the unsent packet to the packet pool. */ + nx_packet_release(packet_ptr); + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Return error condition. */ + return(status); + } + } + + /* Indicate the client is finished with the file. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_FINISHED; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP file open call. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* file_name Pointer to file name */ +/* server_ip_address IP address of TFTP server */ +/* open_type Open for read or write */ +/* wait_option Timeout for the open request */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_IP_ADDRESS_ERROR Invalid address supplied */ +/* NX_OPTION_ERROR Invalid TFTP option supplied */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_client_file_open Actual client file open */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option) +{ + +#ifndef NX_DISABLE_IPV4 +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid server IP address. */ + if (server_ip_address == 0) + return(NX_IP_ADDRESS_ERROR); + + /* Check for illegal open option type. */ + if ((open_type != NX_TFTP_OPEN_FOR_READ) && (open_type != NX_TFTP_OPEN_FOR_WRITE)) + return(NX_OPTION_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file open function. */ + status = _nx_tftp_client_file_open(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option); + + /* Return completion status. */ + return(status); +#else + NX_PARAMETER_NOT_USED(tftp_client_ptr); + NX_PARAMETER_NOT_USED(file_name); + NX_PARAMETER_NOT_USED(server_ip_address); + NX_PARAMETER_NOT_USED(open_type); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens a TFTP file. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* file_name Pointer to file name */ +/* tftp_server_address IP address of TFTP server */ +/* open_type Open for read or write */ +/* wait_option Timeout for the open request */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_client_file_open_internal Actual open service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option) +{ +#ifndef NX_DISABLE_IPV4 +UINT status; + + +NXD_ADDRESS server_address; + + /* Create the IPv4 address block. Set the version to IPv4. */ + server_address.nxd_ip_version = NX_IP_VERSION_V4; + server_address.nxd_ip_address.v4 = server_ip_address; + + /* Call the actual file open service. */ + status = _nx_tftp_client_file_open_internal(tftp_client_ptr, file_name, &server_address, open_type, wait_option, NX_IP_VERSION_V4); + + + /* Return the completion status. */ + return status; +#else + NX_PARAMETER_NOT_USED(tftp_client_ptr); + NX_PARAMETER_NOT_USED(file_name); + NX_PARAMETER_NOT_USED(server_ip_address); + NX_PARAMETER_NOT_USED(open_type); + NX_PARAMETER_NOT_USED(wait_option); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_IPV4 */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP file open call. */ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* file_name Pointer to file name */ +/* server_ip_address IP address of TFTP server */ +/* open_type Open for read or write */ +/* wait_option Timeout for the open request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* NX_IP_ADDRESS_ERROR Invalid address supplied */ +/* NX_OPTION_ERROR Invalid TFTP option supplied */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_file_open Actual client file open */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for an invalid server IP address. */ + if (!server_ip_address) + return(NX_IP_ADDRESS_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for illegal open option type. */ + if ((open_type != NX_TFTP_OPEN_FOR_READ) && (open_type != NX_TFTP_OPEN_FOR_WRITE)) + return(NX_OPTION_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file open function. */ + status = _nxd_tftp_client_file_open(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option, ip_type); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_file_open PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens a TFTP file received over IPv4 or IPv6 networks.*/ +/* */ +/* Note: The string length of file_name is limited by the packet */ +/* payload size. */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* file_name Pointer to file name */ +/* tftp_server_address IP address of TFTP server */ +/* open_type Open for read or write */ +/* wait_option Timeout for the open request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ +/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ +/* NX_TFTP_NOT_CLOSED TFTP client file already open */ +/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_client_file_open_internal Actual open service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Call the actual file open service. */ + status = _nx_tftp_client_file_open_internal(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option, ip_type); + + /* Return the completion status. */ + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_client_file_open_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens a TFTP file received. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* file_name Pointer to file name */ +/* tftp_server_address IP address of TFTP server */ +/* open_type Open for read or write */ +/* wait_option Timeout for the open request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ +/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ +/* NX_TFTP_NOT_CLOSED TFTP client file already open */ +/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet for TFTP */ +/* request or data */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_receive Receive UDP data packet */ +/* nxd_udp_socket_send Send UDP data packet */ +/* nxd_udp_source_extract Extract IP and port from msg */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tftp_client_file_open_internal(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) + +{ + +UINT status; +UINT i; +NXD_ADDRESS ip_address; + +UINT port; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; +UINT matching = NX_FALSE; + + + /* Determine if the TFTP instance is already open. */ + if ((tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_OPEN) || + (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_WRITE_OPEN)) + { + + /* This instance is already open, return an error. */ + return(NX_TFTP_NOT_CLOSED); + } + + /* Enter the open state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_OPEN; + + /* Save the server's IP address. */ + + if (ip_type == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + return NX_TFTP_INVALID_IP_VERSION; +#else + COPY_NXD_ADDRESS(server_ip_address, &tftp_client_ptr -> nx_tftp_client_server_ip); +#endif + } + else + { + +#ifndef NX_DISABLE_IPV4 + /* If not IPv6, assume the client IP request is using IPv4 if not explicitly specified. */ + tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_version = ip_type; + tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4 = server_ip_address -> nxd_ip_address.v4; +#else + return NX_TFTP_INVALID_IP_VERSION; +#endif /* NX_DISABLE_IPV4 */ + } + + /* Initialize the server port number. This can change after the open request. */ + tftp_client_ptr -> nx_tftp_client_server_port = NX_TFTP_SERVER_PORT; + + /* Clear the error code. */ + tftp_client_ptr -> nx_tftp_client_error_code = 0; + + /* Specify that the first block. */ + tftp_client_ptr -> nx_tftp_client_block_number = 1; + + /* Allocate a packet for initial open request message. Determine whether we are sending + IPv4 or IPv6 packets. */ + + if (ip_type == NX_IP_VERSION_V4) + { + + status = nx_packet_allocate((tftp_client_ptr -> nx_tftp_client_ip_ptr) -> nx_ip_default_packet_pool, + &packet_ptr, NX_IPv4_UDP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate((tftp_client_ptr -> nx_tftp_client_ip_ptr) -> nx_ip_default_packet_pool, + &packet_ptr, NX_IPv6_UDP_PACKET, wait_option); + } + + /* Determine if an error occurred trying to allocate a packet. */ + if (status != NX_SUCCESS) + { + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Return error condition. */ + return(status); + } + + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Now, build the TFTP open request. */ + + /* Setup a pointer to the packet payload. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Initial byte is always zero. */ + *buffer_ptr++ = 0; + + /* Determine the type of open requested. */ + if (open_type == NX_TFTP_OPEN_FOR_READ) + *buffer_ptr++ = NX_TFTP_CODE_READ; + else + *buffer_ptr++ = NX_TFTP_CODE_WRITE; + + /* Now place the file name in the buffer. */ + i = 0; + while (file_name[i] && (ULONG)(packet_ptr -> nx_packet_data_end - buffer_ptr) > 7u) + { + + /* Store character of file name into request. */ + *buffer_ptr++ = (UCHAR) file_name[i]; + i++; + } + + /* Place a NULL after the file name. */ + *buffer_ptr++ = NX_NULL; + + /* Now place the mode string. */ + *buffer_ptr++ = (UCHAR) 'O'; + *buffer_ptr++ = (UCHAR) 'C'; + *buffer_ptr++ = (UCHAR) 'T'; + *buffer_ptr++ = (UCHAR) 'E'; + *buffer_ptr++ = (UCHAR) 'T'; + + /* Place a NULL after the mode. */ + *buffer_ptr++ = NX_NULL; + + /* Adjust the packet length and the append pointer. */ + packet_ptr -> nx_packet_append_ptr = buffer_ptr; + packet_ptr -> nx_packet_length = (ULONG)(buffer_ptr - packet_ptr -> nx_packet_prepend_ptr); + + /* Now send the open request to the TFTP server. */ + status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, + server_ip_address, tftp_client_ptr -> nx_tftp_client_server_port); + + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + nx_packet_release(packet_ptr); + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Return error condition. */ + return(status); + } + + /* Determine if the TFTP file was open for writing. */ + if (open_type == NX_TFTP_OPEN_FOR_WRITE) + { + + /* Change to the open for writing state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_WRITE_OPEN; + + /* Open for write request is present. We now need to wait for the ACK of block number 0 + from the server. */ + status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), &packet_ptr, wait_option); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Return error condition. */ + return(status); + } + + /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ + if (packet_ptr -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } + + /* Extract the source IP and port numbers. */ + status = nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + + /* Check for an invalid server IP address. */ + +#ifndef NX_DISABLE_IPV4 + if ((ip_type == NX_IP_VERSION_V4)&& + (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4)) + { + + matching = NX_TRUE; + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (ip_type == NX_IP_VERSION_V6) + { + + if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) + { + + matching = NX_TRUE; + } + } + else +#endif + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_TFTP_INVALID_IP_VERSION; + } + + /* Do we have a match? */ + if (!matching) + { + /* No, invalid IP address! */ + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_INVALID_SERVER_ADDRESS); + } + + /* Save the source port since the server can change its port. */ + tftp_client_ptr -> nx_tftp_client_server_port = port; + + /* Check for valid server ACK. */ + + /* Setup a pointer to the packet payload. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Check for valid ACK message. */ + if ((buffer_ptr[0] != 0) || (buffer_ptr[1] != NX_TFTP_CODE_ACK) || + (buffer_ptr[2] != 0) || (buffer_ptr[3] != 0) || + (packet_ptr -> nx_packet_length != 4)) + { + + UINT code; + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Get the error status from the server message. */ + buffer_ptr++; + code = *(buffer_ptr); + + /* If this is a server error, save it to the TFTP client. */ + if (code == NX_TFTP_CODE_ERROR) + { + + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code = ((UINT) (*buffer_ptr)) << 8; + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); + buffer_ptr++; + + /* Loop to save error message to TFTP Client. */ + tftp_client_ptr -> nx_tftp_client_error_string[sizeof(tftp_client_ptr -> nx_tftp_client_error_string) - 1] = NX_NULL; + for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++) + { + + /* Store desired file name. */ + tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; + + /* Check for NULL character. */ + if (tftp_client_ptr -> nx_tftp_client_error_string[i] == NX_NULL) + { + break; + } + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_CODE_ERROR); + } + /* Unknown code, not an error or an ACK. */ + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_NO_ACK_RECEIVED); + } + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Otherwise, return success! */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_file_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP file read call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* packet_ptr Pointer to destination for */ +/* return packet pointer */ +/* wait_option Timeout for the read request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_file_read Actual client file read */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file read function. */ + status = _nxd_tftp_client_file_read(tftp_client_ptr, packet_ptr, wait_option, ip_type); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_file_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function reads a buffer from a previously opened TFTP file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* packet_ptr Pointer to destination for */ +/* return packet pointer */ +/* wait_option Timeout for the read request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_TFTP_CLIENT_NOT_OPEN Requested file not open */ +/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ +/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ +/* NX_TFTP_END_OF_FILE No more data in file */ +/* NX_TFTP_INVALID_BLOCK_NUMBER Mismatching block number in */ +/* received TFTP packet */ +/* NX_TFTP_CODE_ERROR Unknown TFTP code received */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet for ACK packet*/ +/* nx_packet_release Release packet */ +/* nx_udp_socket_receive Receive UDP data packet */ +/* nxd_udp_socket_send Send TFTP ACK packet */ +/* nxd_udp_source_extract Extract IP and port from msg */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UCHAR *buffer_ptr; +UINT status; +NXD_ADDRESS ip_address; +UINT port; +UINT i; +USHORT block_number; +UCHAR code; +NX_PACKET *ack_packet; +UINT matching = NX_FALSE; +UCHAR resend_ACK_packet = NX_FALSE; + + + /* Determine if we are still in an open state. */ + if (tftp_client_ptr -> nx_tftp_client_state != NX_TFTP_STATE_OPEN) + { + + /* This instance is not open, return an error. */ + if (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_END_OF_FILE) + return(NX_TFTP_END_OF_FILE); + else + return(NX_TFTP_NOT_OPEN); + } + + /* Read the next block of the file. */ + status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, wait_option); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Check for the type of error. */ + if (status != NX_NO_PACKET) + { + + /* Serious error, enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + } + + /* Return error condition. */ + return(status); + } + + /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ + if ((*packet_ptr) -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } + + /* At this point, we have a block of the file from the server. */ + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(*packet_ptr, &ip_address, &port); + + /* Check for an invalid server IP address. */ + +#ifndef NX_DISABLE_IPV4 + if (ip_type == NX_IP_VERSION_V4) + { + + if (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4) + { + matching = NX_TRUE; + } + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (ip_type == NX_IP_VERSION_V6) + { + if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) + { + + matching = NX_TRUE; + } + } + else +#endif + { + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + return NX_TFTP_INVALID_IP_VERSION; + } + + /* Do we have a match? */ + if (matching == NX_FALSE) + { + + /* No, Invalid IP address! */ + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Return error condition. */ + return(NX_TFTP_INVALID_SERVER_ADDRESS); + } + + /* Save the source port since the server can change its port. */ + tftp_client_ptr -> nx_tftp_client_server_port = port; + + /* Setup a pointer to the buffer. */ + buffer_ptr = (*packet_ptr) -> nx_packet_prepend_ptr; + + /* Pickup the type of packet. */ + buffer_ptr++; + code = *buffer_ptr; + + /* Is a data packet present? */ + if (code == NX_TFTP_CODE_DATA) + { + + /* Yes, a data packet is present. */ + + /* Pickup the block number. */ + buffer_ptr++; + block_number = (USHORT)((*buffer_ptr) << 8); + buffer_ptr++; + block_number = (USHORT)(block_number | (*buffer_ptr)); + + /* Check if the server didn't receive last TFTP ACK. */ + if ((USHORT)(tftp_client_ptr -> nx_tftp_client_block_number - 1) == block_number) + { + + /* The Server will resend previous packet till it times out. + set a flag to indicate we need to resend the ACK packet to + prevent this. */ + resend_ACK_packet = NX_TRUE; + } + /* Is there a block number match (greater than 1) ? */ + else if (tftp_client_ptr -> nx_tftp_client_block_number != block_number) + { + + /* Block numbers don't match. Invalid packet or old data packet. Discard it. */ + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Return error condition. */ + return(NX_TFTP_INVALID_BLOCK_NUMBER); + } + + /* Valid block number, end ACK back to server. */ + + /* Allocate a new packet for the ACK message. Determine whether we are sending + IPv4 or IPv6 packets. */ + + if (ip_type == NX_IP_VERSION_V4) + { + + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &ack_packet, NX_IPv4_UDP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &ack_packet, NX_IPv6_UDP_PACKET, wait_option); + } + + /* Determine if an error occurred trying to allocate a packet. */ + if (status != NX_SUCCESS) + { + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the data packet. */ + nx_packet_release(*packet_ptr); + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Return error condition. */ + return(status); + } + + if (4u > ((ULONG)(ack_packet -> nx_packet_data_end) - (ULONG)(ack_packet -> nx_packet_append_ptr))) + { + nx_packet_release(*packet_ptr); + + nx_packet_release(ack_packet); + return(NX_SIZE_ERROR); + } + + ack_packet -> nx_packet_append_ptr = ack_packet -> nx_packet_prepend_ptr; + + /* Valid block number, we need to send an ACK back to server. So now + build the TFTP ACK message. */ + + /* Setup a pointer to the packet payload. */ + buffer_ptr = ack_packet -> nx_packet_prepend_ptr; + + /* Initial byte is always zero. */ + *buffer_ptr++ = 0; + + /* Set the ACK code. */ + *buffer_ptr++ = NX_TFTP_CODE_ACK; + + /* Put the block number in. */ + *buffer_ptr++ = (UCHAR) (block_number >> 8); + *buffer_ptr = (UCHAR) (block_number & 0xFF); + + /* Adjust the ACK packet pointers and length. */ + ack_packet -> nx_packet_length = 4; + ack_packet -> nx_packet_append_ptr = ack_packet -> nx_packet_append_ptr + 4; + + /* Send the ACK packet out. */ + status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), ack_packet, + &tftp_client_ptr -> nx_tftp_client_server_ip, + tftp_client_ptr -> nx_tftp_client_server_port); + + /* Check error status. */ + if (status != NX_SUCCESS) + { + nx_packet_release(*packet_ptr); + + nx_packet_release(ack_packet); + return status; + } + + /* If we received a duplicate data packet, release it here. */ + if (resend_ACK_packet == NX_TRUE) + { + + /* ACK for previous packet sent, so we can release this duplicate packet. */ + nx_packet_release(*packet_ptr); + + /* Set packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Do not handle as an error. Indicate the TFTP Client is still downloading a file. */ + return NX_TFTP_INVALID_BLOCK_NUMBER; + } + + /* Adjust the packet to position past the TFTP header. */ + (*packet_ptr) -> nx_packet_length = (*packet_ptr) -> nx_packet_length - 4; + (*packet_ptr) -> nx_packet_prepend_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + 4; + + /* Check for end of file condition. Anything less than 512 bytes signals an end of file. */ + if ((*packet_ptr) -> nx_packet_length < NX_TFTP_FILE_TRANSFER_MAX) + { + + /* End of file is present. */ + + /* Mark the state as end of file. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_END_OF_FILE; + + + /* Return EOF condition. */ + return(NX_TFTP_END_OF_FILE); + + } + else + { + + /* More packets are still required. Increment the block number. */ + tftp_client_ptr -> nx_tftp_client_block_number++; + } + + /* Return a successful status. */ + return(NX_SUCCESS); + } + else if (code == NX_TFTP_CODE_ERROR) + { + + /* Error code received. */ + + /* Change the state to error. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Save the error code and message. */ + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code = (((UINT) (*buffer_ptr)) << 8); + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); + buffer_ptr++; + + /* Loop to save error message. */ + for (i = 0; (i < (sizeof(tftp_client_ptr -> nx_tftp_client_error_string) -1)) && (*buffer_ptr); i++) + { + + /* Store desired file name. */ + tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; + } + + /* Set NULL terminator. */ + tftp_client_ptr -> nx_tftp_client_error_string[i] = NX_NULL; + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + /* Return a failed status. */ + return(NX_TFTP_CODE_ERROR); + } + /* This could be an ack from the previous file write. Just ignore it. */ + else if (code == NX_TFTP_CODE_ACK) + { + + /* Release the data packet. */ + nx_packet_release(*packet_ptr); + + /* Not an error. */ + return NX_SUCCESS; + } + else + { + + /* Change the state to error. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the packet. */ + nx_packet_release(*packet_ptr); + + /* Return a failed status. */ + return(NX_TFTP_FAILED); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_file_write PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP file write call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* packet_ptr Pointer to packet */ +/* wait_option Timeout for the write request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_client_file_write Actual client file write */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file write function. */ + status = _nxd_tftp_client_file_write(tftp_client_ptr, packet_ptr, wait_option, ip_type); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_file_write PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function writes a buffer to a previously opened TFTP file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_client_ptr Pointer to TFTP client */ +/* packet_ptr Pointer to packet */ +/* wait_option Timeout for the write request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ +/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_receive Receive UDP data packet */ +/* nxd_udp_socket_send Send TFTP ACK packet */ +/* nxd_udp_source_extract Extract IP and port */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UCHAR *buffer_ptr; +UINT status; +ULONG length; +NXD_ADDRESS ip_address; +UINT port; +UINT matching = NX_FALSE; + + + /* Determine if we are still in an open state. */ + if (tftp_client_ptr -> nx_tftp_client_state != NX_TFTP_STATE_WRITE_OPEN) + { + + /* This instance is not open, return an error. */ + return(NX_TFTP_NOT_OPEN); + } + + /* Save the length of the TFTP write data. */ + length = packet_ptr -> nx_packet_length; + + /* Place the TFTP information in front of the data packet. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 4; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 4; + + /* Setup a pointer to the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Set the TFTP data code. */ + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_DATA; + + /* Set the block number. */ + *buffer_ptr++ = (UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8); + *buffer_ptr++ = (UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF); + + /* Send the data packet out. */ + status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, + &tftp_client_ptr -> nx_tftp_client_server_ip, tftp_client_ptr -> nx_tftp_client_server_port); + + /* Determine if an error occurred trying to send the packet. */ + if (status) + { + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the data packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(status); + } + + /* We now need to wait for the ACK for this write request. */ + status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), &packet_ptr, wait_option); + + /* Check the return status. */ + if (status) + { + + /* Return error code, the application may rebuild another packet and try again. */ + + /* Return error condition. */ + return(NX_TFTP_TIMEOUT); + } + + /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ + if (packet_ptr -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + /* Check for an invalid server IP address. */ + +#ifndef NX_DISABLE_IPV4 + if (ip_type == NX_IP_VERSION_V4) + { + + if (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4) + { + matching = NX_TRUE; + } + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (ip_type == NX_IP_VERSION_V6) + { + if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) + { + + matching = NX_TRUE; + } + } + else +#endif + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + + return NX_TFTP_INVALID_IP_VERSION; + } + + /* Do we have a match? */ + if (!matching) + { + + /* No, Invalid IP address! */ + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_INVALID_SERVER_ADDRESS); + } + + /* Setup a pointer to the buffer. */ + buffer_ptr = (packet_ptr) -> nx_packet_prepend_ptr; + + /* Check for valid ACK message. */ + if ((buffer_ptr[0] != 0) || (buffer_ptr[1] != NX_TFTP_CODE_ACK) || + (buffer_ptr[2] != ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8))) || + (buffer_ptr[3] != ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF))) || + (packet_ptr -> nx_packet_length != 4)) + { + + UINT code; + + /* Enter error state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; + + /* Get the error status from the server message. */ + buffer_ptr++; + code = *(buffer_ptr); + + /* Check if this is a error reported by the server. If so save it to + the TFTP Client. */ + if (code == NX_TFTP_CODE_ERROR) + { + UINT i; + + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code = ((UINT) (*buffer_ptr)) << 8; + buffer_ptr++; + tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); + buffer_ptr++; + + /* Loop to save error message. */ + for (i = 0; (i < (sizeof(tftp_client_ptr -> nx_tftp_client_error_string) -1)) && (*buffer_ptr); i++) + { + + /* Store desired file name. */ + tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; + } + + /* Set NULL terminator. */ + tftp_client_ptr -> nx_tftp_client_error_string[i] = NX_NULL; + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_CODE_ERROR); + } + /* Unknown code, not an error or an ACK. */ + else + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return error condition. */ + return(NX_TFTP_NO_ACK_RECEIVED); + } + } + + /* At this point, everything is okay. */ + + /* Release the ACK packet. */ + nx_packet_release(packet_ptr); + + /* Check the length to see if we have the end of the file. */ + if (length < NX_TFTP_FILE_TRANSFER_MAX) + { + + /* Yes, this is the last packet. */ + + /* Enter into the finished state. */ + tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_FINISHED; + } + else + { + + /* More blocks to transfer still, increment the block number. */ + tftp_client_ptr -> nx_tftp_client_block_number++; + } + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_client_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP packet allocate call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to packet pool */ +/* packet_ptr Pointer to destination for */ +/* pointer of newly allocated */ +/* packet */ +/* wait_option Timeout for the request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp _client_file_write Actual client file write */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) + { + return NX_INVALID_PARAMETERS; + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client packet allocate function. */ + status = _nxd_tftp_client_packet_allocate(pool_ptr, packet_ptr, wait_option, ip_type); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_client_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a packet with extra room for the TFTP */ +/* control information. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pointer to packet pool */ +/* packet_ptr Pointer to destination for */ +/* pointer of newly allocated */ +/* packet */ +/* wait_option Timeout for the request */ +/* ip_type IP type */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) +{ + +UINT status; + + + /* Allocate a new packet. Determine whether we are sending IPv4 or IPv6 packets. */ + if (ip_type == NX_IP_VERSION_V4) + { + + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv4_UDP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv6_UDP_PACKET, wait_option); + } + + /* Determine if an error is present. */ + if (status) + { + + /* Return the error code from the allocate routine. */ + return(status); + } + + (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr; + + /* Successful packet allocation. Adjust the prepend and append pointers forward to + accommodate the TFTP header. */ + (*packet_ptr) -> nx_packet_prepend_ptr += 4; + (*packet_ptr) -> nx_packet_append_ptr += 4; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/addons/tftp/nxd_tftp_client.h b/addons/tftp/nxd_tftp_client.h new file mode 100644 index 00000000..96e46b6c --- /dev/null +++ b/addons/tftp/nxd_tftp_client.h @@ -0,0 +1,313 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Trivial File Transfer Protocol (TFTP) Client */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_tftp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ +/* Client component, including all data types and external references */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_TFTP_CLIENT_H +#define NXD_TFTP_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the NetX TFTP CLIENT ID. */ + +#define NXD_TFTP_CLIENT_ID 0x54465460UL + + +/* Define TFTP maximum error string. */ + +#ifndef NX_TFTP_ERROR_STRING_MAX +#define NX_TFTP_ERROR_STRING_MAX 64 /* Maximum error sting size */ +#endif + +/* Define TFTP UDP socket create options. */ + +#ifndef NX_TFTP_TYPE_OF_SERVICE +#define NX_TFTP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_TFTP_FRAGMENT_OPTION +#define NX_TFTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_TFTP_TIME_TO_LIVE +#define NX_TFTP_TIME_TO_LIVE 0x80 +#endif + + +/* If the host application wishes to specify a source port, define it here. The default is to let + NetX choose the TFTP Client source port. */ +#ifndef NX_TFTP_SOURCE_PORT +#define NX_TFTP_SOURCE_PORT NX_ANY_PORT +#endif + +#define NX_TFTP_QUEUE_DEPTH 5 + +#define NX_TFTP_FILE_TRANSFER_MAX 512 /* 512 byte maximum file transfer */ + + +/* Define open types. */ + +#define NX_TFTP_OPEN_FOR_READ 0x01 /* TFTP open for reading */ +#define NX_TFTP_OPEN_FOR_WRITE 0x02 /* TFTP open for writing */ + + +/* Define TFTP message codes. */ + +#define NX_TFTP_CODE_READ 0x01 /* TFTP read file request */ +#define NX_TFTP_CODE_WRITE 0x02 /* TFTP write file request */ +#define NX_TFTP_CODE_DATA 0x03 /* TFTP data packet */ +#define NX_TFTP_CODE_ACK 0x04 /* TFTP command/data acknowledgement */ +#define NX_TFTP_CODE_ERROR 0x05 /* TFTP error message */ + + +/* Define TFTP error code constants. */ + +#define NX_TFTP_ERROR_NOT_DEFINED 0x00 /* TFTP not defined error code, see error string */ +#define NX_TFTP_ERROR_FILE_NOT_FOUND 0x01 /* TFTP file not found error code */ +#define NX_TFTP_ERROR_ACCESS_VIOLATION 0x02 /* TFTP file access violation error code */ +#define NX_TFTP_ERROR_DISK_FULL 0x03 /* TFTP disk full error code */ +#define NX_TFTP_ERROR_ILLEGAL_OPERATION 0x04 /* TFTP illegal operation error code */ +#define NX_TFTP_CODE_ERROR 0x05 /* TFTP client request received error code from server */ +#define NX_TFTP_ERROR_FILE_EXISTS 0x06 /* TFTP file already exists error code */ +#define NX_TFTP_ERROR_NO_SUCH_USER 0x07 /* TFTP no such user error code */ +#define NX_TFTP_INVALID_SERVER_ADDRESS 0x08 /* Invalid TFTP server IP extracted from received packet*/ +#define NX_TFTP_NO_ACK_RECEIVED 0x09 /* Did not receive TFTP server ACK response */ +#define NX_TFTP_INVALID_BLOCK_NUMBER 0x0A /* Invalid block number received from Server response */ +#define NX_TFTP_INVALID_INTERFACE 0x0B /* Invalid interface for TFTP Client */ + /* (or multihome not supported) */ +#define NX_TFTP_INVALID_IP_VERSION 0x0C /* Invalid or unsupported IP version specified */ + + +/* Define offsets into the TFTP message buffer. */ + +#define NX_TFTP_CODE_OFFSET 0 /* Offset to TFTP code in buffer */ +#define NX_TFTP_FILENAME_OFFSET 2 /* Offset to TFTP filename in message */ +#define NX_TFTP_BLOCK_NUMBER_OFFSET 2 /* Offset to TFTP block number in buffer */ +#define NX_TFTP_DATA_OFFSET 4 /* Offset to TFTP data in buffer */ +#define NX_TFTP_ERROR_CODE_OFFSET 2 /* Offset to TFTP error code */ +#define NX_TFTP_ERROR_STRING_OFFSET 4 /* Offset to TFPT error string */ + + +/* Define return code constants. */ + +#define NX_TFTP_ERROR 0xC0 /* TFTP internal error */ +#define NX_TFTP_TIMEOUT 0xC1 /* TFTP timeout occurred */ +#define NX_TFTP_FAILED 0xC2 /* TFTP error */ +#define NX_TFTP_NOT_OPEN 0xC3 /* TFTP not opened error */ +#define NX_TFTP_NOT_CLOSED 0xC4 /* TFTP not closed error */ +#define NX_TFTP_END_OF_FILE 0xC5 /* TFTP end of file error */ +#define NX_TFTP_POOL_ERROR 0xC6 /* TFTP packet pool size error - less than 560 bytes */ + + +/* Define TFTP connection states. */ + +#define NX_TFTP_STATE_NOT_OPEN 0 /* TFTP connection not open */ +#define NX_TFTP_STATE_OPEN 1 /* TFTP connection open */ +#define NX_TFTP_STATE_WRITE_OPEN 2 /* TFTP connection open for writing */ +#define NX_TFTP_STATE_END_OF_FILE 3 /* TFTP connection at end of file */ +#define NX_TFTP_STATE_ERROR 4 /* TFTP error condition */ +#define NX_TFTP_STATE_FINISHED 5 /* TFTP finished writing condition */ + + +/* Define the TFTP Server UDP port number */ + +#define NX_TFTP_SERVER_PORT 69 /* Port for TFTP server */ + + +/* Define the basic TFTP Client data structure. */ + +typedef struct NX_TFTP_CLIENT_STRUCT +{ + ULONG nx_tftp_client_id; /* TFTP Client ID */ + CHAR *nx_tftp_client_name; /* Name of this TFTP client */ + UINT nx_tftp_client_interface_index; /* Index specifying network interface */ + NX_IP *nx_tftp_client_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_tftp_client_packet_pool_ptr; /* Pointer to TFTP client packet pool */ + NXD_ADDRESS nx_tftp_client_server_ip; /* Server's IP address */ + UINT nx_tftp_client_server_port; /* Server's port number (69 originally) */ + UINT nx_tftp_client_state; /* State of TFTP client */ + USHORT nx_tftp_client_block_number; /* Block number in file transfer */ + USHORT nx_tftp_client_reserved; /* Reserved for future use */ + UINT nx_tftp_client_error_code; /* Error code received */ + CHAR nx_tftp_client_error_string[NX_TFTP_ERROR_STRING_MAX + 1]; + NX_UDP_SOCKET nx_tftp_client_socket; /* TFTP Socket */ + +} NX_TFTP_CLIENT; + + + +#ifndef NX_TFTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/******************* Services without error checking. ***********************/ + +/* NetX (IPv4 supported only) services */ +#define nx_tftp_client_file_open _nx_tftp_client_file_open + +/* For NetX applications, map the NetX TFTP service to the NetX Duo TFTP service. */ +#define nx_tftp_client_create(a,b,c,d) _nxd_tftp_client_create(a,b,c,d,NX_IP_VERSION_V4) +#define nx_tftp_client_packet_allocate(a,b,c) _nxd_tftp_client_packet_allocate(a,b,c, NX_IP_VERSION_V4) +#define nx_tftp_client_delete _nxd_tftp_client_delete +#define nx_tftp_client_error_info_get _nxd_tftp_client_error_info_get +#define nx_tftp_client_file_close(a) _nxd_tftp_client_file_close(a, NX_IP_VERSION_V4) +#define nx_tftp_client_file_read(a,b,c) _nxd_tftp_client_file_read(a,b,c,NX_IP_VERSION_V4) +#define nx_tftp_client_file_write(a,b,c) _nxd_tftp_client_file_write(a,b,c,NX_IP_VERSION_V4) +#define nx_tftp_client_set_interface _nxd_tftp_client_set_interface + +/* NetX Duo TFTP (IPv4 and IPv6 supported) services. */ +#define nxd_tftp_client_create _nxd_tftp_client_create +#define nxd_tftp_client_delete _nxd_tftp_client_delete +#define nxd_tftp_client_file_open _nxd_tftp_client_file_open +#define nxd_tftp_client_error_info_get _nxd_tftp_client_error_info_get +#define nxd_tftp_client_file_close _nxd_tftp_client_file_close +#define nxd_tftp_client_file_read _nxd_tftp_client_file_read +#define nxd_tftp_client_file_write _nxd_tftp_client_file_write +#define nxd_tftp_client_packet_allocate _nxd_tftp_client_packet_allocate +#define nxd_tftp_client_set_interface _nxd_tftp_client_set_interface + +#else + +/*************** Services with error checking. ******************/ + +/* NetX (IPv4 supported only) services */ +#define nx_tftp_client_file_open _nxe_tftp_client_file_open + +/* For NetX TFTP applications, map the NetX TFTP service to the equivalent NetX Duo TFTP service. */ +#define nx_tftp_client_create(a,b,c,d) _nxde_tftp_client_create(a,b,c,d,NX_IP_VERSION_V4) +#define nx_tftp_client_packet_allocate(a,b,c) _nxde_tftp_client_packet_allocate(a,b,c,NX_IP_VERSION_V4) +#define nx_tftp_client_delete _nxde_tftp_client_delete +#define nx_tftp_client_error_info_get _nxde_tftp_client_error_info_get +#define nx_tftp_client_file_close(a) _nxde_tftp_client_file_close(a, NX_IP_VERSION_V4) +#define nx_tftp_client_file_read(a,b,c) _nxde_tftp_client_file_read(a,b,c,NX_IP_VERSION_V4) +#define nx_tftp_client_file_write(a,b,c) _nxde_tftp_client_file_write(a,b,c,NX_IP_VERSION_V4) +#define nx_tftp_client_set_interface _nxde_tftp_client_set_interface + +/* NetX Duo (IPv4 and IPv6 supported) services. */ +#define nxd_tftp_client_create _nxde_tftp_client_create +#define nxd_tftp_client_delete _nxde_tftp_client_delete +#define nxd_tftp_client_file_open _nxde_tftp_client_file_open +#define nxd_tftp_client_error_info_get _nxde_tftp_client_error_info_get +#define nxd_tftp_client_file_close _nxde_tftp_client_file_close +#define nxd_tftp_client_file_read _nxde_tftp_client_file_read +#define nxd_tftp_client_file_write _nxde_tftp_client_file_write +#define nxd_tftp_client_packet_allocate _nxde_tftp_client_packet_allocate +#define nxd_tftp_client_set_interface _nxde_tftp_client_set_interface + + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); + +UINT nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); +UINT nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); +UINT nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); +UINT nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); +UINT nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftpv6_client_ptr, UINT if_index); + +#else + +/* TFTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); +UINT _nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); + +UINT _nxde_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); +UINT _nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); +UINT _nxde_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nxde_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT _nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT _nxde_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); +UINT _nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); +UINT _nxde_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); +UINT _nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); +UINT _nxde_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxde_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxde_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); +UINT _nxde_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index); +UINT _nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index); + + + +#endif /* NX_TFTP_SOURCE_CODE */ + +/* Internal functions. */ +UINT _nx_tftp_client_file_open_internal(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_TFTP_CLIENT_H */ diff --git a/addons/tftp/nxd_tftp_server.c b/addons/tftp/nxd_tftp_server.c new file mode 100644 index 00000000..ba066fee --- /dev/null +++ b/addons/tftp/nxd_tftp_server.c @@ -0,0 +1,2855 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** Trivial File Transfer Protocol (TFTP) Server */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_TFTP_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nxd_tftp_server.h" +#ifdef FEATURE_NX_IPV6 +#include "nx_ipv6.h" +#endif + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* tftp_server_name Name of TFTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_TFTP_POOL_ERROR Invalid packet size for TFTP */ +/* server packet pool */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, + FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id == NXD_TFTP_SERVER_ID) || + (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) + { + + return(NX_PTR_ERROR); + } + + /* Pickup a packet from the supplied packet pool. */ + packet_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Determine if the packet payload is large enough (must include 512 bytes plus packet headers). */ + if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_TFTP_PACKET_SIZE) + { + + return(NX_TFTP_POOL_ERROR); + } + + /* Call actual server create function. */ + status = _nxd_tftp_server_create(tftp_server_ptr, tftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a TFTP server on the specified IP. In doing */ +/* so this function creates an UDP socket for subsequent TFTP */ +/* transfers and a thread for the TFTP server. */ +/* */ +/* If NX_TFTP_SERVER_RETRANSMIT_ENABLE is enabled, it also creates */ +/* a timer for retransmitting TFTP server packets up to a maximum */ +/* number of retries before terminating the connection. */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* tftpvserver_name Name of TFTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual cmpletion status */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* nx_udp_socket_bind Bind the TFTP server socket */ +/* nx_udp_socket_create Create TFTP server socket */ +/* nx_udp_socket_delete Delete TFTP server socket */ +/* nx_udp_socket_unbind Unbind TFTP server socket */ +/* tx_thread_create Create TFTP server thread */ +/* tx_timer_create Create retransmit timer */ +/* nx_udp_socket_receive_notify Set a receive callback */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, + FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr) +{ + +UINT status; + + + /* Clear the TFTP server structure. */ + memset((void *) tftp_server_ptr, 0, sizeof(NX_TFTP_SERVER)); + + /* Create the server's UDP socket. */ + status = nx_udp_socket_create(ip_ptr, &(tftp_server_ptr -> nx_tftp_server_socket), tftp_server_name, + NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, return error code. */ + return(status); + } + + /* Register the receive function. */ + nx_udp_socket_receive_notify(&(tftp_server_ptr -> nx_tftp_server_socket), _nx_tftp_server_data_present); + + /* Make sure the socket points to the TFTP server. */ + tftp_server_ptr -> nx_tftp_server_socket.nx_udp_socket_reserved_ptr = tftp_server_ptr; + + /* Now, bind the socket to a the well known TFTP UDP port number. */ + status = nx_udp_socket_bind(&(tftp_server_ptr -> nx_tftp_server_socket), NX_TFTP_SERVER_PORT, NX_NO_WAIT); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Yes, return error code. */ + return(status); + } + + /* Now create the TFTP Server thread. */ + status = tx_thread_create(&(tftp_server_ptr -> nx_tftp_server_thread), "TFTP Server Thread", _nx_tftp_server_thread_entry, + (ULONG) tftp_server_ptr, stack_ptr, stack_size, NX_TFTP_SERVER_PRIORITY, NX_TFTP_SERVER_PRIORITY, + NX_TFTP_SERVER_TIME_SLICE, TX_DONT_START); + + /* Determine if an error occurred creating the thread. */ + if (status != NX_SUCCESS) + { + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Yes, return error code. */ + return(status); + } + + /* Create the ThreadX event flags. These will be used to drive the TFTP server thread. */ + status = tx_event_flags_create(&(tftp_server_ptr -> nx_tftp_server_event_flags), "TFTP Server Thread Events"); + + /* Determine if an error occurred creating the event flags. */ + if (status != TX_SUCCESS) + { + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the server thread. */ + tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Error creating the server event flags. */ + return(status); + } + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + /* Create the ThreadX retransmit timeout timer. This will be used to retransmit TFTP server + packets if the Client has not responded or sends a duplicate (old) ACK or data packet. */ + status = tx_timer_create(&(tftp_server_ptr -> nx_tftp_server_timer), "TFTP Server Timer", + _nx_tftp_server_timer_entry, (ULONG) tftp_server_ptr, + (NX_TFTP_SERVER_TIMEOUT_PERIOD), + (NX_TFTP_SERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE); + + if (status != NX_SUCCESS) + { + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the event flags. */ + tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags)); + + /* Delete the server thread. */ + tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Yes, return error code. */ + return(status); + } +#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ + + /* Save the Server name. */ + tftp_server_ptr -> nx_tftp_server_name = tftp_server_name; + + /* Save the IP pointer address. */ + tftp_server_ptr -> nx_tftp_server_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + tftp_server_ptr -> nx_tftp_server_packet_pool_ptr = pool_ptr; + + /* Save the media pointer address. */ + tftp_server_ptr -> nx_tftp_server_media_ptr = media_ptr; + + /* Clear the error code and error string. */ + tftp_server_ptr -> nx_tftp_server_error_code = 0; + tftp_server_ptr -> nx_tftp_server_error_string[0] = NX_NULL; + + /* Set the server ID to indicate the TFTP server thread is ready. */ + tftp_server_ptr -> nx_tftp_server_id = NXD_TFTP_SERVER_ID; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP server delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_server_delete Actual server delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nxd_tftp_server_delete(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created TFTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close File close */ +/* nx_udp_socket_delete Delete TFTP server socket */ +/* nx_udp_socket_unbind Unbind TFTP server socket */ +/* tx_thread_delete Delete TFTP server thread */ +/* tx_thread_suspend Suspend TFTP server thread */ +/* tx_thread_terminate Terminate TFTP server */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr) +{ + +UINT i; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + + /* Clear the server ID to indicate the TFTP server is no longer ready. */ + tftp_server_ptr -> nx_tftp_server_id = 0; + + /* Unbind the UDP socket. */ + nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Delete the UDP socket. */ + nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); + + /* Suspend the TFTP server thread. */ + tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Terminate server thread. */ + tx_thread_terminate(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Delete the server flag group. */ + tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags)); + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + tx_timer_delete(&(tftp_server_ptr -> nx_tftp_server_timer)); +#endif + + + /* Delete server thread. */ + tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Walk through the server structure to close any remaining open files. */ + i = 0; + + client_request_ptr = &(tftp_server_ptr -> nx_tftp_server_client_list[0]); + + while (i < NX_TFTP_MAX_CLIENTS) + { + + /* Is this entry in use? */ + + /* First determine which IP address type. */ + if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* This is an IPv4 client. Is this slot empty? */ + if ((client_request_ptr -> nx_tftp_client_request_port != 0) && + (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4) != 0) + { + + /* No, need to close the file on this client! */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + } +#endif /* NX_DISABLE_IPV4 */ + } + else if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifdef FEATURE_NX_IPV6 + /* This is an IPv6 Client. Is this slot empty? */ + if ((client_request_ptr -> nx_tftp_client_request_port != 0) && + (!CHECK_UNSPECIFIED_ADDRESS(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0]))) + { + + /* No, need to close the file on this client!*/ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + } +#endif /* FEATURE_NX_IPV6 */ + } + + /* Increment the pointer into the client request list. */ + client_request_ptr++; + i++; + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP server start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_server_start Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nxd_tftp_server_start(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts a previously created TFTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_resume Resume TFTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr) +{ + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + /* Activate TFTP server timer. */ + tx_timer_activate(&(tftp_server_ptr -> nx_tftp_server_timer)); +#endif + + /* Start the TFTP server thread. */ + tx_thread_resume(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxde_tftp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TFTP server stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nxd_tftp_server_stop Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxde_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nxd_tftp_server_stop(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxd_tftp_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops a previously started TFTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Suspend TFTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr) +{ + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + /* Deactivate TFTP server timer. */ + tx_timer_deactivate(&(tftp_server_ptr -> nx_tftp_server_timer)); +#endif + + /* Suspend the TFTP server thread. */ + tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_data_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is notified by NetX of receive events generated by */ +/* TFTP Clients connecting or sending data. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Socket receiving data */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX TCP socket callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr) +{ + +NX_TFTP_SERVER *server_ptr; + + /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ + server_ptr = (NX_TFTP_SERVER *)(socket_ptr -> nx_udp_socket_reserved_ptr); + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_RECEIVE_EVENT, TX_OR); +} + + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function captures timer events used to determine if the Client */ +/* retransmit timer has expired. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ULONG Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for server thread */ +/* */ +/* CALLED BY */ +/* */ +/* NetX NetX connect callback */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address) +{ + +NX_TFTP_SERVER *server_ptr; + + /* Pickup server pointer. */ + server_ptr = (NX_TFTP_SERVER *) tftp_server_address; + + /* Set the data event flag. */ + tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_TIMER_EVENT, TX_OR); + + return; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_timer_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks all the active TFTP client connections */ +/* for their retransmission timeout. If expired, the Server retransmits*/ +/* the data or ACK up to a maximum number of retries */ +/* (NX_TFTP_SERVER_MAX_RETRIES) and then terminates the connection and */ +/* closes any open files. The client request is cleared and available */ +/* for the next client request */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close session file. */ +/* fx_file_delete Delete the file */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP server task function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr) +{ + +UINT i; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + + /* Now look through all the sockets. */ + for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++) + { + + /* Set a pointer to client request structure. */ + client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]); + + /* Check if this request has a retransmit timeout pending. */ + if (client_request_ptr -> nx_tftp_client_retransmit_timeout ) + { + + /* Update reatransmit timeout. */ + if (client_request_ptr -> nx_tftp_client_retransmit_timeout >= NX_TFTP_SERVER_TIMEOUT_PERIOD) + { + + client_request_ptr -> nx_tftp_client_retransmit_timeout -= NX_TFTP_SERVER_TIMEOUT_PERIOD; + } + else + { + + client_request_ptr -> nx_tftp_client_retransmit_timeout = 0; + } + + /* Has the retransmit timeout expired? */ + if (client_request_ptr -> nx_tftp_client_retransmit_timeout == 0) + { + + /* Yes, retransmit unless we have hit the max retry limit. */ + if (client_request_ptr -> nx_tftp_client_retransmit_retries < NX_TFTP_SERVER_MAX_RETRIES) + { + + + /* Update the Client request retransmit timeout and number of retries. */ + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; + client_request_ptr -> nx_tftp_client_retransmit_retries++; + + /* Determine which type of request this is. */ + if (client_request_ptr -> nx_tftp_client_request_open_type == NX_TFTP_STATE_WRITE_OPEN) + { + + /* Retransmit the ACK. */ + _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_TRUE); + } + else + { + + /* Retransmit the file data. */ + _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_TRUE); + } + } + else + { + + /* The session has timed out. Send error and close. */ + _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address, + client_request_ptr -> nx_tftp_client_request_port, + NX_TFTP_SESSION_TIMED_OUT, "NetX TFTP Server: Session timed out"); + + /* Error, close the file and delete the client request. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + } + } + } + } +} +#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry of the TFTP server. All basic */ +/* processing is initiated by this function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tftp_server Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_get Get the TFTP events */ +/* _nx_tftp_server_process_received_data Process received packet */ +/* _nx_tftp_server_timer_process Process TFTP timer */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_thread_entry(ULONG tftp_server) +{ + +NX_TFTP_SERVER *server_ptr; +UINT status; +ULONG events; + + + /* Setup the server pointer. */ + server_ptr = (NX_TFTP_SERVER *) tftp_server; + + /* Loop to process TFTP Server requests. */ + while(1) + { + + /* Wait for TFTP events. */ + status = tx_event_flags_get(&(server_ptr -> nx_tftp_server_event_flags), NX_SERVER_TFTP_ANY_EVENT, + TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Check the return status. */ + if (status) + { + + /* If an error occurs, simply continue the loop. */ + continue; + } + + /* Otherwise, an event is present. Process according to the event. */ + + /* Check for a client receive event. */ + if (events & NX_TFTP_SERVER_RECEIVE_EVENT) + { + + /* Call the data received handler. */ + _nx_tftp_server_process_received_data(server_ptr); + } + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + /* Check for a timer event. */ + if (events & NX_TFTP_SERVER_TIMER_EVENT) + { + /* Call the timer timeout handler. */ + _nx_tftp_server_timer_process(server_ptr); + } +#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE*/ + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_process_received_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called when the TFTP server is notified of a */ +/* receive event. It parses the TFTP Client message and calls the */ +/* appropriate handler for read and write requests, client errors, or */ +/* ACKing data sent by the server. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_server_ack_process Process ACK from previous read*/ +/* _nx_tftp_server_data_process Write data packet to file */ +/* _nx_tftp_server_error_process Process error packet */ +/* _nx_tftp_server_open_for_read_process Open file for reading */ +/* _nx_tftp_server_open_for_write_process Open for writing */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_receive Receive next TFTP packet */ +/* */ +/* CALLED BY */ +/* */ +/* nx_tftp_server_thread_entry TFTP thread task function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UCHAR request_code; + + + /* Wait for a request on the TFTP UDP well known port 69. */ + status = nx_udp_socket_receive(&(server_ptr -> nx_tftp_server_socket), &packet_ptr, NX_NO_WAIT); + + /* Check the return status. */ + if (status) + { + + /* If an error occurs, simply return to caller. */ + return; + } + + /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ + if (packet_ptr -> nx_packet_length < 4) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } + + /* Otherwise, we have received a packet successfully. */ + + /* Setup a pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup up the request code. First one must be zero. */ + request_code = *buffer_ptr++; + + /* If not zero, abort. */ + if (request_code) + { + + nx_packet_release(packet_ptr); + + return; + } + + /* Now get the actual request code. */ + request_code = *buffer_ptr++; + + /* Process relative to the TFTP request code. */ + switch (request_code) + { + + case NX_TFTP_CODE_READ: + + /* Process an open for read request. */ + _nx_tftp_server_open_for_read_process(server_ptr, packet_ptr); + + /* Increment the number of open for read requests. */ + server_ptr -> nx_tftp_server_open_for_read_requests++; + break; + + case NX_TFTP_CODE_WRITE: + + /* Process an open for write request. */ + _nx_tftp_server_open_for_write_process(server_ptr, packet_ptr); + + /* Increment the number of open for write requests. */ + server_ptr -> nx_tftp_server_open_for_write_requests++; + break; + + case NX_TFTP_CODE_DATA: + + /* Process a data request. */ + _nx_tftp_server_data_process(server_ptr, packet_ptr); + + /* Increment the number of data block write requests. */ + server_ptr -> nx_tftp_server_data_blocks_received++; + break; + + case NX_TFTP_CODE_ACK: + + /* Process an ack response. */ + _nx_tftp_server_ack_process(server_ptr, packet_ptr); + + /* Increment the number of acks for previous data blocks sent. */ + server_ptr -> nx_tftp_server_acks_received++; + break; + + case NX_TFTP_CODE_ERROR: + + /* Process an error request. */ + _nx_tftp_server_error_process(server_ptr, packet_ptr); + + /* Increment the number of errors received. */ + server_ptr -> nx_tftp_server_errors_received++; + break; + + default: + + /* Increment the number of unknown codes received. */ + server_ptr -> nx_tftp_server_unknown_commands++; + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_open_for_read_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens the specified file for reading, and returns */ +/* the first block of the file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* packet_ptr Pointer to TFTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_directory_information_get Get information about file */ +/* fx_file_close Close file on EOF or error */ +/* fx_file_open Open file for reading */ +/* fx_file_read Read block from file */ +/* _nx_tftp_server_find_client_request Find client entry */ +/* _nx_tftp_server_send_error Send error message */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_send Send TFTP data packet */ +/* nx_udp_source_extract Extract IP and port */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP Server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ +NXD_ADDRESS ip_address; +ULONG file_size; +ULONG actual_size; +UINT port; +UCHAR *buffer_ptr; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; +NX_PACKET *new_packet = NX_NULL; +UINT status; + + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + /* First, try to find a matching exiting entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); + + /* See if we need to find a new entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Yes, find a free entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL); + } + else + { + + /* This is a dupe request. Ignore it. */ + nx_packet_release(packet_ptr); + return; + } + + /* Determine if there was a free entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Increment the maximum clients errors. */ + server_ptr -> nx_tftp_server_clients_exceeded_errors++; + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients"); + + /* No more clients can be serviced, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Initialize the client request structure. */ +#ifndef NX_DISABLE_IPV4 + if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + + client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4; + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) + { + COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address)); + } + else +#endif + { + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; + } + + + client_request_ptr -> nx_tftp_client_request_port = port; + client_request_ptr -> nx_tftp_client_request_block_number = 1; + client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_OPEN; + client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + /* Reset the retransmission timeout and retries for the client request. */ + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; + client_request_ptr -> nx_tftp_client_retransmit_retries = 0; +#else + + /* Clear the count of ACK retransmits from the other side. */ + client_request_ptr -> nx_tftp_client_request_retransmits = 0; + +#endif + + /* Setup a pointer to the file name. */ + buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); + + if (packet_ptr -> nx_packet_length < 4) + { + nx_packet_release(packet_ptr); + return; + } + + /* Check if the packet buffer ends with NULL. */ + if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1)) + { + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the file size. */ + status = fx_directory_information_get(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr, NX_NULL, &file_size, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL); + + /* Check the return status. */ + if (status != FX_SUCCESS) + { + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Not Found"); + + /* Unable to find the file size, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Attempt to open the file. */ + status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr ->nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_READ); + + /* Check the return status. */ + if (status != FX_SUCCESS) + { + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed"); + + /* Unable to open the file, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* The file has been opened successfully, now try to read up to 512 bytes. */ + + /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ + if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); + } + else if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); + } + else + status = NX_TFTP_INVALID_ADDRESS_TYPE; + /* Check for successful packet allocation. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Unable to allocate net packet, release the original. */ + nx_packet_release(packet_ptr); + return; + } + + if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) + { + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + nx_packet_release(new_packet); + return; + } + + client_request_ptr -> nx_tftp_client_file_size = file_size; + + /* Read data when length of file is larger then 0. */ + if(file_size) + { + + /* Attempt to read the requested file. */ + status = fx_file_read(&(client_request_ptr ->nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4, NX_TFTP_FILE_TRANSFER_MAX, &actual_size); + + /* Check for successful file read. */ + if ((status != NX_SUCCESS) || + ((file_size > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != NX_TFTP_FILE_TRANSFER_MAX)) || + ((file_size < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != file_size))) + { + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error"); + + /* Unable to read the file, close it and release the packet. */ + fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); + + nx_packet_release(packet_ptr); + return; + } + } + else + { + + actual_size = 0; + } + + /* Increment the number of total bytes sent. */ + server_ptr -> nx_tftp_server_total_bytes_sent += actual_size; + + /* Setup the client request structure. */ + client_request_ptr -> nx_tftp_client_request_remaining_bytes = file_size - actual_size; + + /* Determine if the file size is evenly divisible by our TFTP transfer size. */ + if (file_size % NX_TFTP_FILE_TRANSFER_MAX) + { + + /* Not an exact fit, ensure the exact fit flag is clear. */ + client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; + } + else if (file_size > 0) + { + + /* Yes, the file size happens to be evenly divisible by the TFTP transfer size. In this + case, we need to send a zero-length data packet at the end of file to let the other side + know we are at the end. */ + client_request_ptr -> nx_tftp_client_request_exact_fit = NX_TRUE; + } + + /* Move the TFTP data code and block number into the payload before sending it to the client. */ + buffer_ptr = new_packet -> nx_packet_prepend_ptr; + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_DATA; + *buffer_ptr++ = 0; + *buffer_ptr++ = 1; /* First block number of file. */ + + /* Setup the packet pointers appropriately. */ + new_packet -> nx_packet_length = actual_size + 4; + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length; + + /* Send the data packet out. */ + status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port); + + /* Release packet if send fails. */ + if (status) + { + nx_packet_release(new_packet); + } + + /* Release the original packet. */ + nx_packet_release(packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_open_for_write_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function opens the specified file for writing, and returns */ +/* an ACK for block 0 to let the client know everything is good. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* packet_ptr Pointer to TFTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_create Create file, if necessary */ +/* fx_file_close Close file on EOF or error */ +/* fx_file_open Open file for reading */ +/* fx_file_write Write block to file */ +/* _nx_tftp_server_find_client_request Find client entry */ +/* _nx_tftp_server_send_error Send error message */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_send Send TFTP data packet */ +/* nx_udp_source_extract Extract IP and port */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP Server thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ +NXD_ADDRESS ip_address; +UINT port; +UCHAR *buffer_ptr; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; +NX_PACKET *new_packet; +UINT status; + + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + /* First, try to find a matching exiting entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); + + /* See if we need to find a new entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Find a free entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL); + } + else + { + + /* This is a dupe request. Ignore it. */ + nx_packet_release(packet_ptr); + return; + } + + /* Determine if there was a free entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Increment the maximum clients errors. */ + server_ptr -> nx_tftp_server_clients_exceeded_errors++; + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients"); + + /* No more clients can be serviced, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Setup a pointer to the file name. */ + buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); + + if (packet_ptr -> nx_packet_length < 4) + { + nx_packet_release(packet_ptr); + return; + } + + /* Check if the packet buffer ends with NULL. */ + if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1)) + { + nx_packet_release(packet_ptr); + return; + } + + /* Perform a file create. This will fail if the file is already present, which we don't care about at this point. */ + fx_file_delete(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr); + fx_file_create(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr); + + /* Attempt to open the file. */ + status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr -> nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); + + /* Check for file is open errors. */ + if (status != NX_SUCCESS) + { + + /* This is an actual file open error. Send an error to the client. */ + if (status == FX_ACCESS_ERROR) + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ACCESS_VIOLATION, "NetX TFTP Server: File Access Error"); + else + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed"); + + /* Unable to open the file, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Now, attempt to build an ACK response to let the client know it can start writing. */ + + /* Allocate packet for the ACK packet. Determine whether we are sending IP packets. */ + if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); + } + else + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); + } + + /* Check for successful packet allocation. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Close the file. */ + fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); + + /* Unable to allocate net packet, release the original. */ + nx_packet_release(packet_ptr); + return; + } + + if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) + { + nx_packet_release(new_packet); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; + } + + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; + + /* Setup the client request structure. */ +#ifndef NX_DISABLE_IPV4 + if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + + client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4; + client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4; + } + else +#endif /* NX_DISABLE_IPV4 */ +#ifdef FEATURE_NX_IPV6 + if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) + { + COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address)); + } + else +#endif + { + + /* Close the file. */ + fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; + } + + + client_request_ptr -> nx_tftp_client_request_port = port; + client_request_ptr -> nx_tftp_client_request_block_number = 1; + client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_WRITE_OPEN; + client_request_ptr -> nx_tftp_client_request_remaining_bytes = 0; + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + /* Reset retransmission timeouts and retries on current client request. */ + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; + client_request_ptr -> nx_tftp_client_retransmit_retries = 0; + +#else + + /* Clear the count of data retransmits from the other side. */ + client_request_ptr -> nx_tftp_client_request_retransmits = 0; +#endif + + /* Create the ACK packet. */ + buffer_ptr = new_packet -> nx_packet_prepend_ptr; + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_ACK; + *buffer_ptr++ = 0; + *buffer_ptr++ = 0; /* 0, just to signal server is ready. */ + + /* Setup the packet pointers appropriately. */ + new_packet -> nx_packet_length = 4; + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4; + + /* Send the data packet out. */ + status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port); + + /* Release packet if send fails. */ + if (status) + { + nx_packet_release(new_packet); + } + + /* Release the original packet. */ + nx_packet_release(packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_data_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function takes the supplied data packet and writes it to the */ +/* previously opened file. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* packet_ptr Pointer to TFTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file on EOF or error */ +/* fx_file_write Write block to file */ +/* _nx_tftp_server_find_client_request Find client entry */ +/* _nx_tftp_server_send_error Send error message */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_copy Copy packet */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_send Send TFTP ACK packet */ +/* nx_udp_source_extract Extract IP and port */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP Server thread loop */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +NXD_ADDRESS ip_address; +UINT port; +USHORT block_number; +UCHAR *buffer_ptr; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; +UINT status; + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + /* Find the matching entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); + + + /* Determine if there was a matching entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Increment the unknown clients errors. */ + server_ptr -> nx_tftp_server_unknown_clients_errors++; + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection"); + + /* No more clients can be serviced, release the packet. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Setup a pointer to the block number. */ + buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); + + if (packet_ptr -> nx_packet_length < 4) + { + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the block number. */ + block_number = (USHORT)(*buffer_ptr++); + block_number = (USHORT)((block_number << 8) | (*buffer_ptr)); + + /* Determine if this block number matches the current client block number. */ + if (client_request_ptr -> nx_tftp_client_request_block_number != block_number) + { + + /* No, it does not. */ + + /* Check if it matches our previous ACK e.g. it could be a retransmit from the other side. */ + if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1)) + { + +#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + /* It does. Update how many we have received. */ + client_request_ptr -> nx_tftp_client_request_retransmits++; + + /* Decide if we should close the client request. */ + if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS) + { + + /* Not yet. Just drop the packet for now. */ + nx_packet_release(packet_ptr); + + return; + } + /* Else handle as an error. */ +#else + nx_packet_release(packet_ptr); + + /* (Let the retransmit timeout handler retransmit our ACK to the client.) */ + return; +#endif + } + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number"); + + /* Error, close the file, release the packet and delete the client request. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return; + } + + /* At this point we have a valid packet. */ + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + /* Reset the retransmit retry counter and retransmit timeout. */ + client_request_ptr -> nx_tftp_client_retransmit_retries = 0; + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; +#else + + /* Clear the count of retransmits from the other side. */ + client_request_ptr -> nx_tftp_client_request_retransmits = 0; +#endif + + /* Determine if there is anything to write. */ + if (packet_ptr -> nx_packet_length > 4) + { + + /* At this point, we need to write the next block of the file. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Determine if the current packet is chained. */ + if (packet_ptr -> nx_packet_next) + { + + NX_PACKET *temp_ptr; + + + /* Yes, the packet is chained. We have to copy the receive packet into a packet with the + a payload of at least 560 bytes so the write request can be supplied with just the + payload pointer. */ + status = nx_packet_copy(packet_ptr, &temp_ptr, server_ptr -> nx_tftp_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Check for successful packet copy. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Unable to allocate net packet, release the original. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + nx_packet_release(packet_ptr); + + memset(client_request_ptr,0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return; + } + + /* Successful packet copy. Release the original packet and reassign the packet pointer variable. */ + nx_packet_release(packet_ptr); + packet_ptr = temp_ptr; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Attempt to write the block to the file. */ + status = fx_file_write(&(client_request_ptr -> nx_tftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr+4, + packet_ptr -> nx_packet_length - 4); + + /* Check for successful file write. */ + if (status != NX_SUCCESS) + { + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Write Error"); + + /* Unable to write the file, close it and release the packet. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + nx_packet_release(packet_ptr); + + return; + } + } + + /* Check the last packet. */ + if (packet_ptr -> nx_packet_length - 4 < NX_TFTP_FILE_TRANSFER_MAX) + { + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + } + + status = _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_FALSE); + + if (status == NX_SUCCESS) + { + + /* Increment the number of total bytes received. */ + server_ptr -> nx_tftp_server_total_bytes_received += (packet_ptr -> nx_packet_length - 4); + + /* Determine if this was the last write. */ + if ((packet_ptr -> nx_packet_length - 4) < NX_TFTP_FILE_TRANSFER_MAX) + { + + /* No, nothing left to write. Close the file, release the packet and delete + the client request. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + } + } + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_ack_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an ACK to the previous file read */ +/* operation and prepares the next data packet to send if necessary. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* packet_ptr Pointer to TFTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* fx_file_close Close file on EOF or error */ +/* fx_file_read Read block from file */ +/* _nx_tftp_server_find_client_request Find client entry */ +/* _nx_tftp_server_send_error Send error message */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_copy Copy packet */ +/* nx_packet_release Release packet */ +/* nx_udp_socket_send Send TFTP data packet */ +/* nx_udp_source_extract Extract IP and port */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP Server thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +NXD_ADDRESS ip_address; +UINT port; +USHORT block_number; +UCHAR *buffer_ptr; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + + /* Extract the source IP and port numbers. */ + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + + /* Find a matching entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); + + /* Determine if there was a matching entry. */ + if (client_request_ptr == NX_NULL) + { + + /* Increment the unknown clients errors. */ + server_ptr -> nx_tftp_server_unknown_clients_errors++; + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection"); + + /* No more clients can be serviced, release the packet. */ + nx_packet_release(packet_ptr); + return; + } + + /* Setup a pointer to the block number. */ + buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); + + if (packet_ptr -> nx_packet_length < 4) + { + nx_packet_release(packet_ptr); + return; + } + + /* Pickup the block number. */ + block_number = (USHORT)(*buffer_ptr++); + block_number = (USHORT)((block_number << 8) | (*buffer_ptr)); + + /* Determine if this block number matches the request. */ + if (client_request_ptr -> nx_tftp_client_request_block_number != block_number) + { + + /* Check if this is a retransmitted ACK e.g. our previous data packet was dropped our + delayed. */ + if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1)) + { + +#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + /* It does. Update how many we have received. */ + client_request_ptr -> nx_tftp_client_request_retransmits++; + + /* Decide if we should close the client request. */ + if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS) + { + + /* Not yet. Just drop the packet for now. */ + nx_packet_release(packet_ptr); + + return; + } + + /* Else handle as an error. */ +#else + nx_packet_release(packet_ptr); + + /* (Let the retransmit timeout handler retransmit our data to the client.) */ + return; +#endif + } + + /* Send an error to the client. */ + _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number"); + + /* Error, close the file, release the packet and delete the client request. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + nx_packet_release(packet_ptr); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return; + } + + /* The block number matches, see if there is anything left to send. */ + if ((client_request_ptr -> nx_tftp_client_request_remaining_bytes == 0) && + (client_request_ptr -> nx_tftp_client_request_exact_fit == NX_FALSE)) + { + + /* No, nothing left to send. Close the file, release the packet and delete + the client request. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + nx_packet_release(packet_ptr); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return; + } + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + /* We have a valid ACK. Reset the retransmit retry counter and retransmit timeout. */ + client_request_ptr -> nx_tftp_client_retransmit_retries = 0; + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; +#endif + + /* At this point, we need to send the next block of the file. */ + _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_FALSE); + + /* Release the original packet. */ + nx_packet_release(packet_ptr); + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_send_data PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a data packet based on the last ACK received */ +/* and sends it out. This will also retransmit a data packet if */ +/* specified. On error it will close the file and the client request. */ +/* It does not update the Client request e.g. block number. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* client_request_ptr Pointer to Client request */ +/* retransmit Indicate if retransmiting a */ +/* previously sent ACK */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_server_close_client_request Terminate a client request */ +/* _nx_tftp_server_send_error Send error status to Client */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_udp_socket_send Send TFTP data packet */ +/* fx_file_seek Set location in file */ +/* fx_file_read Read from set location in file*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_timer_process TFTP timeout event */ +/* _nx_tftp_server_ack_process Process a received ACK */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit) +{ + +UINT status; +ULONG actual_size = 0; +NX_PACKET *new_packet; +UCHAR *buffer_ptr; + + + /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ + if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); + } + else + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); + } + + + /* Check for successful packet allocation. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Unable to allocate net packet, release the original. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return status; + } + + if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) + { + nx_packet_release(new_packet); + return(NX_SIZE_ERROR); + } + + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; + + /* Determine if there are more bytes to read. */ + if (client_request_ptr -> nx_tftp_client_request_remaining_bytes) + { + + status = NX_SUCCESS; + + /* Are we retransmitting? */ + if (retransmit) + { + + /* Yes, figure out where to reset the file pointer to the previous + file read so we can retrieve the previous data we sent. */ + UINT index = client_request_ptr -> nx_tftp_client_file_size - + client_request_ptr -> nx_tftp_client_request_remaining_bytes - + client_request_ptr -> nx_tftp_client_previous_write_size; + + status = fx_file_seek(&(client_request_ptr -> nx_tftp_client_request_file), index); + } + + /* Are we still ok to do a file read? */ + if (status == NX_SUCCESS) + { + + /* Yes. Attempt to read the requested file. */ + UINT status_read = fx_file_read(&(client_request_ptr -> nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4, + NX_TFTP_FILE_TRANSFER_MAX, &actual_size); + + /* Check for successful file read. */ + if ((status_read != NX_SUCCESS) || + ((client_request_ptr -> nx_tftp_client_request_remaining_bytes > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size < NX_TFTP_FILE_TRANSFER_MAX)) || + ((client_request_ptr -> nx_tftp_client_request_remaining_bytes < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != client_request_ptr -> nx_tftp_client_request_remaining_bytes))) + { + + /* Update our 'status' variable with the result from file read. */ + status = status_read; + } + } + + /* Are we ok to transmit more data? */ + if (status != NX_SUCCESS) + { + + /* No, send an error back to the client. */ + _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address, + client_request_ptr -> nx_tftp_client_request_port, + NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error"); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + /* Unable to read the file, close it and release the packet. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + nx_packet_release(new_packet); + + return status; + } + } + else + { + + /* Clear the exact fit flag since the only way we can be here is if the TFTP transfer size + evenly divided into the file size and we need to send a zero length data buffer to signal + the end of the file. */ + client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; + + /* Set the actual size to zero for exact fit case. */ + actual_size = 0; + } + + /* Increment the number of total bytes sent. */ + server_ptr -> nx_tftp_server_total_bytes_sent += actual_size; + + /* Is this new data being sent (not a retransmit)? */ + if (retransmit == NX_FALSE) + { + + /* Yes, so advance the block number and number of bytes of the file sent. */ + client_request_ptr -> nx_tftp_client_request_block_number++; + + client_request_ptr -> nx_tftp_client_request_remaining_bytes -= actual_size; + } + + client_request_ptr -> nx_tftp_client_previous_write_size = actual_size; + + /* Move the TFTP data code and block number into the payload before sending it to the client. */ + buffer_ptr = new_packet -> nx_packet_prepend_ptr; + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_DATA; + *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number >> 8); + *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF); + + /* Setup the packet pointers appropriately. */ + new_packet -> nx_packet_length = actual_size + 4; + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length; + + /* Send the data packet out. */ + status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address, + client_request_ptr -> nx_tftp_client_request_port); + + /* Release packet if send fails. */ + if (status) + { + nx_packet_release(new_packet); + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_send_ack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an ACK packet based on the last block of data */ +/* received, and sends it out. This will also retransmit an ACK if */ +/* specified. On error it will close the file and the client request. */ +/* It does not update the Client request e.g. block number. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* client_request_ptr Pointer to Client request */ +/* retransmit Indicate if retransmiting a */ +/* previously sent ACK */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tftp_server_close_client_request Terminate a client request */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_udp_socket_send Send TFTP data packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_timer_process TFTP timeout event */ +/* _nx_tftp_server_data_process Process a received packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit) +{ + +UINT status; +UCHAR *buffer_ptr; +NX_PACKET *new_packet; + + + /* Allocate packet for the ACK. Determine whether we are sending IP packets. */ + if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); + } + else + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); + } + + /* Check for successful packet allocation. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Unable to allocate net packet, release the original. */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + + memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + return status; + } + + if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) + { + nx_packet_release(new_packet); + return(NX_SIZE_ERROR); + } + + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; + + /* Now build the ACK message to the client. */ + buffer_ptr = new_packet -> nx_packet_prepend_ptr; + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_ACK; + + /* If we are retransmitting, send the block number of the previous ACK. */ + if (retransmit) + { + + *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) >> 8); + *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) & 0xFF); + } + else + { + + *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number) >> 8); + *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF); + } + + /* Setup the packet pointers appropriately. */ + new_packet -> nx_packet_length = 4; + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4; + + /* Send the ACK packet out. */ + status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address, + client_request_ptr -> nx_tftp_client_request_port); + + /* Release packet if send fails. */ + if (status) + { + nx_packet_release(new_packet); + } + + /* Is this ACK for new data received (e.g. not a retransmit)? */ + if (retransmit == NX_FALSE) + { + + /* Yes, so increase the block number. */ + client_request_ptr -> nx_tftp_client_request_block_number++; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_error_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an error sent by a client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* packet_ptr Pointer to TFTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_thread_entry TFTP Server thread task */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +UINT i; +UCHAR *buffer_ptr; +UINT port; +NXD_ADDRESS ip_address; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + + /* Pickup a pointer to the error code in the buffer. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; + + if (packet_ptr -> nx_packet_length < 4) + { + nx_packet_release(packet_ptr); + return; + } + + /* Set the error code in the server control block. */ + server_ptr -> nx_tftp_server_error_code = (((UINT) (*buffer_ptr)) << 8); + buffer_ptr++; + server_ptr -> nx_tftp_server_error_code |= ((UINT) (*buffer_ptr) & 0xFF); + buffer_ptr++; + + /* Loop to save error message. */ + server_ptr -> nx_tftp_server_error_string[sizeof(server_ptr -> nx_tftp_server_error_string) - 1] = NX_NULL; + for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++) + { + + /* Store desired file name. */ + server_ptr -> nx_tftp_server_error_string[i] = (CHAR) *buffer_ptr++; + + /* Check for NULL character. */ + if (server_ptr -> nx_tftp_server_error_string[i] == NX_NULL) + break; + + /* Check for packet buffer boundary. */ + if (buffer_ptr >= packet_ptr -> nx_packet_append_ptr) + break; + } + + /* Extract the source IP and port numbers. */ + + nxd_udp_source_extract(packet_ptr, &ip_address, &port); + + /* First, try to find a matching existing entry in the client request structure. */ + client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); + + /* Reset the retransmit timeout on the client request. */ + if (client_request_ptr) + { +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + + client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; + client_request_ptr -> nx_tftp_client_retransmit_retries = 0; +#else + + client_request_ptr -> nx_tftp_client_request_retransmits = 0; + +#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_find_client_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to find the specified IP and port number in */ +/* the client request array of this TFTP server instance. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* port Client port number */ +/* ip_address Client IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TFTP_CLIENT_REQUEST * NULL if not found */ +/* Non null if match found */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_ack_process ACK processing */ +/* _nx_tftp_server_data_process Data packet processing */ +/* _nx_tftp_server_open_for_write_process Open for write processing */ +/* _nx_tftp_server_open_for_read_process Open for read processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, NXD_ADDRESS *ip_address) +{ + +UINT i; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + /* First, find a free entry in the client request structure. */ + i = 0; + for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++) + { + client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]); + + /* First check if we are adding an address. If the caller sends in a blank + address and port, we are. */ + if (port == 0) + { + + /* We are adding an address. Now check if this slot is empty. */ + + if (client_request_ptr -> nx_tftp_client_request_port == 0) + { + + /* If there is no port number, this is an empty slot. But let's clear the slot anyway. */ + memset(&(server_ptr -> nx_tftp_server_client_list[i]), 0, sizeof(NX_TFTP_CLIENT_REQUEST)); + + break; + } + } + /* This is a valid address. Does it match the current entry? */ + else + { + /* Check if it is an IPv4 or IPv6 packet. */ + if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + +#ifndef NX_DISABLE_IPV4 + /* This is an IPv4 request packet. */ + if ((client_request_ptr -> nx_tftp_client_request_port == port) && + (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4 == ip_address -> nxd_ip_address.v4)) + { + + /* Yes, they match! */ + break; + } +#else + return NX_NULL; +#endif /* NX_DISABLE_IPV4 */ + } + else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) + { + +#ifndef FEATURE_NX_IPV6 + return NX_NULL; +#else + /* This is an IPv6 request packet. */ + if ((client_request_ptr -> nx_tftp_client_request_port == port) && + (CHECK_IPV6_ADDRESSES_SAME(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0], &ip_address -> nxd_ip_address.v6[0]))) + { + + /* Yes, they match! */ + break; + } +#endif + } + } + } + + /* Determine if a match was found. */ + if (i < NX_TFTP_MAX_CLIENTS) + { + /* Return a pointer to the matching client request. */ + return(&(server_ptr -> nx_tftp_server_client_list[i])); + } + else + { + /* Return a NULL pointer indicating no match found. */ + return((NX_TFTP_CLIENT_REQUEST *)NX_NULL); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tftp_server_send_error PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function send a TFTP error message to the client specified */ +/* by the port and IP address. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to TFTP server */ +/* ip_address Client IP address */ +/* port Client port number */ +/* error TFTP error code */ +/* error_message Error string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate error packet */ +/* nx_udp_socket_send Send TFPT error packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tftp_server_ack_process ACK processing */ +/* _nx_tftp_server_data_process Data packet processing */ +/* _nx_tftp_server_open_for_write_process Open for write processing */ +/* _nx_tftp_server_open_for_read_process Open for read processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, NXD_ADDRESS *ip_address, UINT port, UINT error, CHAR *error_message) +{ + +UINT status; +UCHAR *buffer_ptr; +NX_PACKET *new_packet; + + + /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ + if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); + } + else + { + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); + } + + /* Check for successful packet allocation. */ + if (status != NX_SUCCESS) + { + + /* Increment the number of server allocation errors. */ + server_ptr -> nx_tftp_server_allocation_errors++; + + /* Unable to allocate packet for error message, just return! */ + return; + } + + if (6u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) + { + nx_packet_release(new_packet); + return; + } + + new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; + + /* Move the TFTP error code and message into the payload before sending it to the client. */ + buffer_ptr = new_packet -> nx_packet_prepend_ptr; + *buffer_ptr++ = 0; + *buffer_ptr++ = NX_TFTP_CODE_ERROR; + *buffer_ptr++ = 0; + *buffer_ptr++ = (UCHAR) (error & 0xFF); + + /* Loop to copy the error message into the buffer. */ + do + { + + /* Copy a byte of the error message into the buffer. */ + *buffer_ptr = (UCHAR) *error_message; + + /* Determine if a NULL is present. */ + if (*buffer_ptr == NX_NULL) + { + + /* Yes, we are at the end of the string end the loop. */ + break; + } + + /* Move both pointers to the next character. */ + buffer_ptr++; + error_message++; + } while (buffer_ptr < (new_packet -> nx_packet_data_end - 1)); + + /* Ensure a NULL is in the last position! */ + *buffer_ptr++ = NX_NULL; + + /* Setup the packet pointers appropriately. */ + new_packet -> nx_packet_length = (ULONG)(buffer_ptr - new_packet -> nx_packet_prepend_ptr); + new_packet -> nx_packet_append_ptr = buffer_ptr; + + /* Send the data packet out. */ + status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port); + + /* Release packet if send fails. */ + if (status) + { + nx_packet_release(new_packet); + } +} diff --git a/addons/tftp/nxd_tftp_server.h b/addons/tftp/nxd_tftp_server.h new file mode 100644 index 00000000..c34fcc7b --- /dev/null +++ b/addons/tftp/nxd_tftp_server.h @@ -0,0 +1,384 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Duo Component */ +/** */ +/** Trivial File Transfer Protocol (TFTP) Server */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nxd_tftp_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ +/* Server for NetX Duo. It supports IPv4 and IPv6 networks. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_TFTP_SERVER_H +#define NXD_TFTP_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the TFTP ID. */ + +#define NXD_TFTP_SERVER_ID 0x54465461UL + +#ifndef NX_TFTP_NO_FILEX +#include "fx_api.h" +#else +#include "filex_stub.h" +#endif + +/* Define TFTP maximum error string. */ + +#ifndef NX_TFTP_ERROR_STRING_MAX +#define NX_TFTP_ERROR_STRING_MAX 64 /* Maximum error sting size */ +#endif + + +/* Define the maximum number of clients the TFTP Server can accommodate. */ + +#ifndef NX_TFTP_MAX_CLIENTS +#define NX_TFTP_MAX_CLIENTS 10 +#endif + + +/* Define TFTP UDP socket create options. */ + +#ifndef NX_TFTP_TYPE_OF_SERVICE +#define NX_TFTP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_TFTP_FRAGMENT_OPTION +#define NX_TFTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_TFTP_TIME_TO_LIVE +#define NX_TFTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 +#endif + +#ifndef NX_TFTP_SERVER_PRIORITY +#define NX_TFTP_SERVER_PRIORITY 16 +#endif + +#ifndef NX_TFTP_SERVER_TIME_SLICE +#define NX_TFTP_SERVER_TIME_SLICE 2 +#endif + + +/* To enable a retransmission on client requests (e.g. resend + ACK and data packets, as well apply a timeout on a Client request), + define this option. +#define NX_TFTP_SERVER_RETRANSMIT_ENABLE +*/ + + +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + +/* Define the timer expiration for updating time remaining on a TFTP Client + request activity timeout (in timer ticks). */ +#ifndef NX_TFTP_SERVER_TIMEOUT_PERIOD +#define NX_TFTP_SERVER_TIMEOUT_PERIOD 20 +#endif + +/* Define the interval before retransmitting an ACK or data packet (in timer ticks). */ +#ifndef NX_TFTP_SERVER_RETRANSMIT_TIMEOUT +#define NX_TFTP_SERVER_RETRANSMIT_TIMEOUT 200 +#endif + +/* Define the max number of retries retransmitting a data packet or ACK if no response or a previous + (duplicate) ACK or data packet, respectively, is received. */ +#ifndef NX_TFTP_SERVER_MAX_RETRIES +#define NX_TFTP_SERVER_MAX_RETRIES 5 +#endif + +#else + +/* Define the number of instances TFTP server receives a duplicate data or an ACK packet + without sending an error message. This does not utilize the retransmission timeout + and is available only if NX_TFTP_SERVER_RETRANSMIT_ENABLE is not defined. */ + +#ifndef NX_TFTP_MAX_CLIENT_RETRANSMITS +#define NX_TFTP_MAX_CLIENT_RETRANSMITS 2 +#endif + +#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ + + +#define NX_TFTP_QUEUE_DEPTH 5 + +#define NX_TFTP_FILE_TRANSFER_MAX 512 /* 512 byte maximum file transfer */ + + +/* Derive the maximum TFTP packet size, including Ethernet, IP and UDP headers, and + accounting for potential physical driver needs at the end of the packet. */ + +#define NX_TFTP_PACKET_SIZE (NX_UDP_PACKET + NX_TFTP_FILE_TRANSFER_MAX + NX_PHYSICAL_TRAILER) + + +/* Define open types. */ + +#define NX_TFTP_OPEN_FOR_READ 0x01 /* TFTP open for reading */ +#define NX_TFTP_OPEN_FOR_WRITE 0x02 /* TFTP open for writing */ + + +/* Define TFTP message codes. */ + +#define NX_TFTP_CODE_READ 0x01 /* TFTP read file request */ +#define NX_TFTP_CODE_WRITE 0x02 /* TFTP write file request */ +#define NX_TFTP_CODE_DATA 0x03 /* TFTP data packet */ +#define NX_TFTP_CODE_ACK 0x04 /* TFTP command/data acknowledgement */ +#define NX_TFTP_CODE_ERROR 0x05 /* TFTP error message */ + + +/* Define TFTP error code constants. */ + +#define NX_TFTP_ERROR_NOT_DEFINED 0x00 /* TFTP not defined error code, see error string */ +#define NX_TFTP_ERROR_FILE_NOT_FOUND 0x01 /* TFTP file not found error code */ +#define NX_TFTP_ERROR_ACCESS_VIOLATION 0x02 /* TFTP file access violation error code */ +#define NX_TFTP_ERROR_DISK_FULL 0x03 /* TFTP disk full error code */ +#define NX_TFTP_ERROR_ILLEGAL_OPERATION 0x04 /* TFTP illegal operation error code */ +#define NX_TFTP_CODE_ERROR 0x05 /* TFTP client request received error code from server */ +#define NX_TFTP_ERROR_FILE_EXISTS 0x06 /* TFTP file already exists error code */ +#define NX_TFTP_ERROR_NO_SUCH_USER 0x07 /* TFTP no such user error code */ +#define NX_INVALID_TFTP_SERVER_ADDRESS 0x08 /* Invalid TFTP server IP extraced from received packet */ +#define NX_TFTP_NO_ACK_RECEIVED 0x09 /* Did not receive TFTP server ACK response */ +#define NX_TFTP_INVALID_BLOCK_NUMBER 0x0A /* Invalid block number received from Server response */ +#define NX_TFTP_INVALID_ADDRESS_TYPE 0x0B /* Invalid IP version associated with client data */ +#define NX_TFTP_SESSION_TIMED_OUT 0x0C /* No response from client or retransmissions limit hit */ + + +/* Define offsets into the TFTP message buffer. */ + +#define NX_TFTP_CODE_OFFSET 0 /* Offset to TFTP code in buffer */ +#define NX_TFTP_FILENAME_OFFSET 2 /* Offset to TFTP filename in message */ +#define NX_TFTP_BLOCK_NUMBER_OFFSET 2 /* Offset to TFTP block number in buffer */ +#define NX_TFTP_DATA_OFFSET 4 /* Offset to TFTP data in buffer */ +#define NX_TFTP_ERROR_CODE_OFFSET 2 /* Offset to TFTP error code */ +#define NX_TFTP_ERROR_STRING_OFFSET 4 /* Offset to TFPT error string */ + + +/* Define return code constants. */ + +#define NX_TFTP_ERROR 0xC0 /* TFTP internal error */ +#define NX_TFTP_TIMEOUT 0xC1 /* TFTP timeout occurred */ +#define NX_TFTP_FAILED 0xC2 /* TFTP error */ +#define NX_TFTP_NOT_OPEN 0xC3 /* TFTP not opened error */ +#define NX_TFTP_NOT_CLOSED 0xC4 /* TFTP not closed error */ +#define NX_TFTP_END_OF_FILE 0xC5 /* TFTP end of file error */ +#define NX_TFTP_POOL_ERROR 0xC6 /* TFTP packet pool size error - less than 560 bytes */ + + +/* Define TFTP connection states. */ + +#define NX_TFTP_STATE_NOT_OPEN 0 /* TFTP connection not open */ +#define NX_TFTP_STATE_OPEN 1 /* TFTP connection open */ +#define NX_TFTP_STATE_WRITE_OPEN 2 /* TFTP connection open for writing */ +#define NX_TFTP_STATE_END_OF_FILE 3 /* TFTP connection at end of file */ +#define NX_TFTP_STATE_ERROR 4 /* TFTP error condition */ +#define NX_TFTP_STATE_FINISHED 5 /* TFTP finished writing condition */ + + +/* Define TFTP Server events. */ + +#define NX_TFTP_SERVER_RECEIVE_EVENT 0x01 /* TFTP received Client packet */ +#define NX_TFTP_SERVER_TIMER_EVENT 0x02 /* TFTP timer event */ +#define NX_SERVER_TFTP_ANY_EVENT 0x0F /* Any event */ + +/* Define the TFTP Server UDP port number */ + +#define NX_TFTP_SERVER_PORT 69 + +/* Define the per client request structure for the TFTP Server data structure. */ + +typedef struct NX_TFTP_CLIENT_REQUEST_STRUCT +{ + UINT nx_tftp_client_request_port; /* Port of client request */ + NXD_ADDRESS nx_tftp_client_request_ip_address; /* IP address of client */ + USHORT nx_tftp_client_request_block_number; /* Block number of file transfer */ + USHORT nx_tftp_client_request_reserved; /* Reserved for future use */ + UINT nx_tftp_client_request_open_type; /* Open type of client request */ + ULONG nx_tftp_client_request_remaining_bytes; /* Remaining bytes to send */ + UINT nx_tftp_client_request_exact_fit; /* Exact fit flag */ + ULONG nx_tftp_client_request_last_activity_time; /* Time of last activity */ + FX_FILE nx_tftp_client_request_file; /* File control block */ + ULONG nx_tftp_client_file_size; /* Size of file in bytes */ + ULONG nx_tftp_client_previous_write_size; /* Size of data in last data packet */ +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + UINT nx_tftp_client_retransmit_timeout; /* Time between retransmits from server */ + UINT nx_tftp_client_retransmit_retries; /* Number of retries on current data,ACK*/ +#else + UINT nx_tftp_client_request_retransmits; /* Number of retransmits from client */ +#endif +} NX_TFTP_CLIENT_REQUEST; + + +/* Define the TFTP Server data structure. */ + +typedef struct NX_TFTP_SERVER_STRUCT +{ + ULONG nx_tftp_server_id; /* TFTP Server ID */ + CHAR *nx_tftp_server_name; /* Name of this TFTP client */ + NX_IP *nx_tftp_server_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_tftp_server_packet_pool_ptr; /* Pointer to TFTP server packet pool */ + FX_MEDIA *nx_tftp_server_media_ptr; /* Pointer to media control block */ + ULONG nx_tftp_server_open_for_write_requests; /* Number of open for write requests */ + ULONG nx_tftp_server_open_for_read_requests; /* Number of open for read requests */ + ULONG nx_tftp_server_acks_received; /* Number of ACKs received */ + ULONG nx_tftp_server_data_blocks_received; /* Number of data blocks received */ + ULONG nx_tftp_server_errors_received; /* Number of errors received */ + ULONG nx_tftp_server_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_tftp_server_total_bytes_received; /* Number of total bytes received */ + ULONG nx_tftp_server_unknown_commands; /* Number of unknown commands received */ + ULONG nx_tftp_server_allocation_errors; /* Number of allocation errors */ + ULONG nx_tftp_server_clients_exceeded_errors; /* Number of maximum clients errors */ + ULONG nx_tftp_server_unknown_clients_errors; /* Number of unknown clients errors */ + UINT nx_tftp_server_error_code; /* Last error code received */ + CHAR nx_tftp_server_error_string[NX_TFTP_ERROR_STRING_MAX + 1]; + NX_TFTP_CLIENT_REQUEST /* TFTP client request array */ + nx_tftp_server_client_list[NX_TFTP_MAX_CLIENTS]; + NX_UDP_SOCKET nx_tftp_server_socket; /* TFTP Server UDP socket */ + TX_THREAD nx_tftp_server_thread; /* TFTP server thread */ + TX_EVENT_FLAGS_GROUP + nx_tftp_server_event_flags; /* TFTP server thread events */ +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE + TX_TIMER nx_tftp_server_timer; /* TFTP server activity timeout timer */ +#endif +} NX_TFTP_SERVER; + + +#ifndef NX_TFTP_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +/* NetX TFTP services mapped to NetX Duo TFTP services */ +#define nx_tftp_server_create _nxd_tftp_server_create +#define nx_tftp_server_delete _nxd_tftp_server_delete +#define nx_tftp_server_start _nxd_tftp_server_start +#define nx_tftp_server_stop _nxd_tftp_server_stop + +/* NetX Duo (IPv4 and IPv6 supported) TFTP services */ +#define nxd_tftp_server_create _nxd_tftp_server_create +#define nxd_tftp_server_delete _nxd_tftp_server_delete +#define nxd_tftp_server_start _nxd_tftp_server_start +#define nxd_tftp_server_stop _nxd_tftp_server_stop + +#else + +/* Services with error checking. */ + +/* NetX TFTP services mapped to NetX Duo TFTP services with error checking*/ +#define nx_tftp_server_create _nxde_tftp_server_create +#define nx_tftp_server_delete _nxde_tftp_server_delete +#define nx_tftp_server_start _nxde_tftp_server_start +#define nx_tftp_server_stop _nxde_tftp_server_stop + +/* NetX Duo (IPv4 and IPv6 supported) TFTP services with error checking */ +#define nxd_tftp_server_create _nxde_tftp_server_create +#define nxd_tftp_server_delete _nxde_tftp_server_delete +#define nxd_tftp_server_start _nxde_tftp_server_start +#define nxd_tftp_server_stop _nxde_tftp_server_stop + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); +UINT nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); + +#else + +/* TFTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxde_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); +UINT _nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); +UINT _nxde_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxde_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxde_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); + +#endif /* NX_TFTP_SOURCE_CODE */ + +/* Internal TFTP server functions */ + +void _nx_tftp_server_thread_entry(ULONG tftp_server); +void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +void _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, NXD_ADDRESS *ip_address); +VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, NXD_ADDRESS *ip_address, UINT port, UINT error, CHAR *error_message); +VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr); +VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr); +UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit); +UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit); +#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE +VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr); +VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address); +#endif +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_TFTP_SERVER_H */ diff --git a/addons/web/nx_tcpserver.c b/addons/web/nx_tcpserver.c new file mode 100644 index 00000000..09e51630 --- /dev/null +++ b/addons/web/nx_tcpserver.c @@ -0,0 +1,1426 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Multiple TCP Socket/TLS Session support module */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_TCPSERVER_SOURCE_CODE + +#include "nx_api.h" +#include "nx_tcpserver.h" + + +/* Define internal function prototypes. */ +static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr); +static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr); +static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port); +static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr); +static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr); +static VOID _nx_tcpserver_timeout(ULONG tcpserver_address); +static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr); +static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr); +static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr); +static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr); +static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address); + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_session_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function allocates a free socket (and TLS session, if */ +/* TLS is enabled) for an incoming client request. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to server structure */ +/* session_pptr Pointer to allocated socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_relisten */ +/* _nx_tcpserver_start */ +/* _nx_tcpserver_connect_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr) +{ +UINT i; +NX_TCP_SOCKET *socket_ptr; + + /* Reset. */ + *session_pptr = NX_NULL; + + /* Loop to find unused session. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + + /* Skip the listen session. */ + if(&server_ptr -> nx_tcpserver_sessions[i] == server_ptr -> nx_tcpserver_listen_session) + continue; + + socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); + + /* A closed or listening socket is available. */ + if((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) && + (socket_ptr -> nx_tcp_socket_bound_next == NX_NULL) && + (socket_ptr -> nx_tcp_socket_bind_in_progress == NX_NULL)) + { + + /* Reset expiration to zero. */ + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0; + + /* Return the socket. */ + *session_pptr = &server_ptr -> nx_tcpserver_sessions[i]; + return NX_SUCCESS; + } + } + + return NX_TCPSERVER_FAIL; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_relisten PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked whenever a connection is closed */ +/* to re-enable listening on that closed socket/session. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to server structure */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcpserver_session_allocate Allocate socket for listening */ +/* nx_tcp_server_socket_relisten Re-listen on free socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_connect_process */ +/* _nx_tcpserver_disconnect_process */ +/* _nx_tcpserver_timeout_process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr) +{ +UINT status; +NX_TCP_SESSION *session_ptr; + + /* Is any socket listening? */ + if(server_ptr -> nx_tcpserver_listen_session == NX_NULL) + { + + /* Get a socket to listen. */ + status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); + if(status) + { + return NX_TCPSERVER_FAIL; + } + + status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, + server_ptr -> nx_tcpserver_listen_port, + &session_ptr -> nx_tcp_session_socket); + if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + printf("%d, %d\n", status, __LINE__); + return NX_TCPSERVER_FAIL; + } + + /* Store listen socket. */ + server_ptr -> nx_tcpserver_listen_session = session_ptr; + } + else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, + server_ptr -> nx_tcpserver_listen_port, + &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); + if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + printf("%d, %d\n", status, __LINE__); + return NX_TCPSERVER_FAIL; + } + } + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* nx_tcpserver_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a socket server instance to handle multiple */ +/* incoming TCP or TLS client connections. The server utilizes an */ +/* internal thread and manages a queue of TCP sockets (and TLS */ +/* sessions if enabled) that are used to handle incoming requests. */ +/* The callback routines are used to handle individual requests. Each */ +/* socket (and TLS session) receives identical state so that each */ +/* incoming request is handled consistently. */ +/* */ +/* The number of available sockets and TLS sessions is determined by */ +/* the size of the sessions buffer and can be found by dividing the */ +/* buffer size by the size of the NX_TCP_SESSION structure. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance for this server */ +/* server_ptr Pointer to server structure */ +/* name Name string for this server */ +/* type_of_service Type of service for TCP */ +/* sockets */ +/* fragment Flag to enable IP fragmenting */ +/* time_to_live Time to live value for socket */ +/* window_size Size of socket's receive */ +/* window */ +/* new_connection Callback invoked for new */ +/* client connections */ +/* receive_data Callback invoked when data is */ +/* received from the client */ +/* connection_end Callback invoked when a */ +/* connection is closed */ +/* connection_timeout Callback invoked when a */ +/* connection times out */ +/* timeout Timeout value for all sockets */ +/* stack_ptr Stack buffer for internal */ +/* server thread */ +/* stack_size Size of thread stack buffer */ +/* sessions_buffer Buffer for per-session data */ +/* buffer_size Size of per-session buffer, */ +/* determines session number */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_create Create server thread */ +/* tx_event_flags_create Create thread event flags */ +/* tx_timer_create Create timeout timer */ +/* nx_tcp_socket_create Create TCP sockets */ +/* nx_tcp_socket_receive_notify Set TCP notification callback */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + ULONG timeout, VOID *stack_ptr, UINT stack_size, + VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option) +{ +UINT i; +UINT status; + + /* Initialize server struct. */ + server_ptr -> nx_tcpserver_ip = ip_ptr; + server_ptr -> nx_tcpserver_sessions = sessions_buffer; + server_ptr -> nx_tcpserver_sessions_count = buffer_size / sizeof(NX_TCP_SESSION); + server_ptr -> nx_tcpserver_listen_port = 0; + server_ptr -> nx_tcpserver_listen_session = NX_NULL; + server_ptr -> nx_tcpserver_new_connection = new_connection; + server_ptr -> nx_tcpserver_receive_data = receive_data; + server_ptr -> nx_tcpserver_connection_end = connection_end; + server_ptr -> nx_tcpserver_connection_timeout = connection_timeout; + server_ptr -> nx_tcpserver_timeout = timeout; + server_ptr -> nx_tcpserver_accept_wait_option = accept_wait_option; + + /* Create the tcpserver thread. */ + status = tx_thread_create(&server_ptr -> nx_tcpserver_thread, "TCPSERVER Thread", + _nx_tcpserver_thread_entry, (ULONG)server_ptr, stack_ptr, + stack_size, thread_priority, thread_priority, + TX_NO_TIME_SLICE, TX_DONT_START); + + /* Create the tcpserver event flags. */ + status += tx_event_flags_create(&server_ptr -> nx_tcpserver_event_flags, "TCPSERVER Events"); + + /* Create the timeout timer. */ + status += tx_timer_create(&server_ptr -> nx_tcpserver_timer, "TCPSERVER Timer", + _nx_tcpserver_timeout, (ULONG)server_ptr, + (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD), + (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE); + + /* Initialize buffer. */ + memset(sessions_buffer, 0, buffer_size); + + /* Initialize TCP sockets. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + status += nx_tcp_socket_create(ip_ptr, &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, name, type_of_service, fragment, time_to_live, + window_size, NX_NULL, _nx_tcpserver_disconnect_present); + + status += nx_tcp_socket_receive_notify(&server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, _nx_tcpserver_data_present); + + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket.nx_tcp_socket_reserved_ptr = server_ptr; + } + + return status; +} + + +#ifdef NX_TCPSERVER_ENABLE_TLS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_tls_setup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function configures a previously created NetX socket server */ +/* instance to use TLS. The parameters are used to configure all the */ +/* TLS sessions in the server with identical state so that each */ +/* incoming TLS client experiences consistent behavior. The number of */ +/* TLS sessions and TCP sockets is determined by the size of the */ +/* sessions buffer passed into nx_tcpserver_create. */ +/* */ +/* The cryptographic routine table (ciphersuite table) is shared */ +/* between all TLS sessions as it just contains function pointers. */ +/* */ +/* The metadata buffer and packet reassembly buffer are divided */ +/* equally between all TLS sessions. If the buffer size is not evenly */ +/* divisible by the number of sessions the remainder will be unused. */ +/* */ +/* The passed-in identity certificate is used by all sessions. During */ +/* TLS operation the server identity certificate is only read from so */ +/* copies are not needed for each session. */ +/* */ +/* The trusted certificates are added to the trusted store for each */ +/* TLS session in the server. This is used for client certificate */ +/* verification which is enabled if remote certificates are provided. */ +/* */ +/* The remote certificate array and buffer is shared by default */ +/* between all TLS sessions. This does mean that some sessions may */ +/* block during certificate validation. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to control block */ +/* crypto_table TLS cryptographic routines */ +/* metadata_buffer Cryptographic metadata buffer */ +/* metadata_size Size of metadata buffer */ +/* packet_buffer TLS packet buffer */ +/* packet_size Size of packet buffer */ +/* identity_certificate TLS server certificate */ +/* trusted_certificates TLS trusted certificates */ +/* trusted_certs_num Number of trusted certs */ +/* remote_certificates Remote certificates array */ +/* remote_certs_num Number of remote certificates */ +/* remote_certificate_buffer Buffer for remote certs */ +/* remote_cert_buffer_size Size of remote cert buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_create Create TLS Session */ +/* */ +/* nx_secure_tls_session_packet_buffer_set */ +/* Set TLS packet buffer */ +/* */ +/* nx_secure_tls_local_certificate_add */ +/* Add local TLS identity cert */ +/* */ +/* nx_secure_tls_session_client_verify_enable */ +/* Enable client cert verify */ +/* */ +/* nx_secure_tls_trusted_certificate_add Add a trusted TLS cert */ +/* */ +/* nx_secure_tls_remote_certificate_allocate */ +/* Allocate space for incoming */ +/* client certificates */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +/* Setup TLS state per server session. */ +UINT _nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size) +{ +NX_SECURE_TLS_SESSION *tls_session; +ULONG session_metadata_size; +UCHAR *session_metadata; +UCHAR *session_cert_buffer; +UINT session_cert_buffer_size = 0; +UINT session_pkt_buffer_size; +UINT num_sessions; +UINT i; +UINT cert_count; +UINT status; + + /* Get the number of sessions in the TCP server. */ + num_sessions = server_ptr -> nx_tcpserver_sessions_count; + + /* Get our per-session packet buffer size. */ + session_pkt_buffer_size = packet_buffer_size / num_sessions; + + /* Get our per-session metadata. */ + session_metadata = metadata_buffer; + session_metadata_size = metadata_size / num_sessions; + + /* It's OK to have zero remote certs allocated. */ + if(remote_certs_num > 0) + { + /* Divide the remote certificate buffer size by the total number of + remote certificates to get per-certificate size. */ + session_cert_buffer_size = remote_cert_buffer_size / remote_certs_num; + } + + /* Loop through all sessions, initialize each one. */ + for(i = 0; i < num_sessions; ++i) + { + /* This server instance is using TLS so mark as such. */ + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_using_tls = NX_TRUE; + + /* Setup per-session data. Get the session from the server structure, then initialize it. */ + tls_session = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session); + status = nx_secure_tls_session_create(tls_session, crypto_table, session_metadata, session_metadata_size); + + if(status != NX_SUCCESS) + { + return(status); + } + + /* Allocate space for packet reassembly. */ + status = nx_secure_tls_session_packet_buffer_set(tls_session, &packet_buffer[i * session_pkt_buffer_size], + session_pkt_buffer_size); + + if(status != NX_SUCCESS) + { + return(status); + } + + /* Add identity certificate. */ + status = nx_secure_tls_local_certificate_add(tls_session, identity_certificate); + + if(status != NX_SUCCESS) + { + return(status); + } + + /* See if remote certificates are provided. */ + if(remote_certs_num > 0) + { + /* We have remote certificates to allocate so enable client certificate authentication. */ + nx_secure_tls_session_client_verify_enable(tls_session); + + /* Add trusted certificates to each TLS session. */ + for(cert_count = 0; cert_count < trusted_certs_num; ++cert_count) + { + status = nx_secure_tls_trusted_certificate_add(tls_session, trusted_certificates[cert_count]); + + if(status != NX_SUCCESS) + { + return(status); + } + } + + /* Allocate remote certificates (if remote_certs_num > 0). The remote certificate + buffers are shared between all TLS Sessions. This is possible since they are only + needed for the certificate verification process and are freed immediately after. */ + session_cert_buffer = remote_certificate_buffer; + + for(cert_count = 0; cert_count < remote_certs_num; ++cert_count) + { + /* Allocate a remote certificate from the provided array. */ + status = nx_secure_tls_remote_certificate_allocate(tls_session, remote_certificates[i], + session_cert_buffer, session_cert_buffer_size); + + if(status != NX_SUCCESS) + { + return(status); + } + + /* Now get the next certificate and its buffer. */ + session_cert_buffer += session_cert_buffer_size; + } + } + + /* Advance metadata buffer. */ + session_metadata = &session_metadata[session_metadata_size]; + } + return(NX_SUCCESS); +} +#endif + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called by an application to start a socket server */ +/* that was previously created and configured. This routine starts the */ +/* internal server thread and timer. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to server structure */ +/* port Port for server to listen on */ +/* listen_queue_size Maximum number of TCP */ +/* connections queued */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcpserver_session_allocate Allocate socket for listening */ +/* nx_tcp_server_socket_listen Listen on free TCP socket */ +/* tx_timer_activate Start timeout timer */ +/* tx_thread_resume Start server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size) +{ +UINT status; +NX_TCP_SESSION *session_ptr; + + /* Check whether listen is done. */ + if(server_ptr -> nx_tcpserver_listen_port) + return NX_TCPSERVER_FAIL; + + /* Get a socket to listen. */ + status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); + if(status) + return status; + + /* Listen on port. */ + status = nx_tcp_server_socket_listen(server_ptr -> nx_tcpserver_ip, port, &session_ptr -> nx_tcp_session_socket, listen_queue_size, _nx_tcpserver_connect_present); + if(status) + return status; + + /* Store socket and port. */ + server_ptr -> nx_tcpserver_listen_session = session_ptr; + server_ptr -> nx_tcpserver_listen_port = port; + + /* Activate timer. */ + tx_timer_activate(&server_ptr -> nx_tcpserver_timer); + + /* Start thread. */ + tx_thread_resume(&server_ptr -> nx_tcpserver_thread); + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_connect_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is used for the TCP listen callback passed */ +/* into nx_tcp_server_socket_listen and is used to determine when an */ +/* incoming request has been received and is ready for processing. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* port Port of incoming request */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set thread event flag */ +/* */ +/* CALLED BY */ +/* */ +/* TCP stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port) +{ +NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + + NX_PARAMETER_NOT_USED(port); + + /* Set the connect event flag. */ + tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_CONNECT, TX_OR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_data_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is used for the TCP receive callback passed */ +/* into nx_tcp_socket_receive_notify and is used to determine when */ +/* data has been received and is ready for processing. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set thread event flag */ +/* */ +/* CALLED BY */ +/* */ +/* TCP stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr) +{ +NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the data event flag. */ + tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DATA, TX_OR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_disconnect_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is used for the TCP disconnect callback */ +/* passed into nx_tcp_socket_create and is used to determine when */ +/* a socket has been disconnected. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set thread event flag */ +/* */ +/* CALLED BY */ +/* */ +/* TCP stack */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr) +{ +NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; + + /* Set the disconnect event flag. */ + tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DISCONNECT, TX_OR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked whenever the internal timeout */ +/* timer expires, and is passed into tx_timer_create as the callback. */ +/* */ +/* INPUT */ +/* */ +/* tcpserver_address Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set thread event flag */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_timeout(ULONG tcpserver_address) +{ +NX_TCPSERVER *server_ptr = (NX_TCPSERVER *)tcpserver_address; + + /* Set the timeout event flag. */ + tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_TIMEOUT, TX_OR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_connect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked by the server thread whenever an */ +/* incoming connection request is received. It establishes the TCP */ +/* connection and if TLS is enabled, it begins the TLS handshake. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcpserver_session_allocate Get socket for listening */ +/* nx_tcp_server_socket_relisten Relisten on existing socket */ +/* nx_tcp_server_socket_accept Accept incoming TCP request */ +/* nx_secure_tls_session_start Start TLS handshake */ +/* nx_tcp_server_socket_unaccept Clear accepted socket */ +/* _nx_tcpserver_relisten Re-listen on all sockets */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr) +{ +UINT status; +NX_TCP_SESSION *session_ptr = NX_NULL; + + /* Is any socket listening? */ + if(server_ptr -> nx_tcpserver_listen_session == NX_NULL) + { + + /* No. Check whether listen is done. */ + if(server_ptr -> nx_tcpserver_listen_port == 0) + { + return; + } + + /* Get a socket to listen. */ + status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); + if(status) + { + return; + } + + status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, + server_ptr -> nx_tcpserver_listen_port, + &session_ptr -> nx_tcp_session_socket); + if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + return; + } + + /* Store listen socket. */ + server_ptr -> nx_tcpserver_listen_session = session_ptr; + } + else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + + status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, + server_ptr -> nx_tcpserver_listen_port, + &session_ptr -> nx_tcp_session_socket); + if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) + { + return; + } + } + + /* Accept connection. */ + status = nx_tcp_server_socket_accept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, server_ptr -> nx_tcpserver_accept_wait_option); + + if(status == NX_SUCCESS) + { + + /* Set default expiration. */ + server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout; + +#ifdef NX_TCPSERVER_ENABLE_TLS + /* If TLS, start the TLS handshake. */ + if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_using_tls == NX_TRUE) + { + status = nx_secure_tls_session_start(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_tls_session, + &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, NX_WAIT_FOREVER); + + if(status != NX_SUCCESS) + { + nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); + } + } + + if (status == NX_SUCCESS) +#endif + { + if(server_ptr -> nx_tcpserver_new_connection) + { + + /* Invoke new connection callback. */ + server_ptr -> nx_tcpserver_new_connection(server_ptr, server_ptr -> nx_tcpserver_listen_session); + } + + /* Clear listen socket. */ + server_ptr -> nx_tcpserver_listen_session = NX_NULL; + } + } + else + { + nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); + } + + /* Relisten */ + _nx_tcpserver_relisten(server_ptr); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_data_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked by the server thread whenever */ +/* data is received from the remote client. If the application passes */ +/* a receive callback to _nx_tcpserver_create, it will be invoked here.*/ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcpserver_receive_data Callback to process data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr) +{ +UINT i; +NX_TCP_SOCKET *socket_ptr; + + /* Do nothing if callback is not set. */ + if(server_ptr -> nx_tcpserver_receive_data == NX_NULL) + { + return; + } + + /* Initialize TCP sockets. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); + + if(socket_ptr -> nx_tcp_socket_receive_queue_count) + { + + /* Reset default expiration. */ + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout; + + /* Invoke receive data callback. */ + server_ptr -> nx_tcpserver_receive_data(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); + + /* Relisten */ + _nx_tcpserver_relisten(server_ptr); + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_disconnect_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked by the server thread whenever */ +/* a socket is disconnected. If the application passes a disconnect */ +/* callback to _nx_tcpserver_create, it will be invoked here. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcpserver_connection_end Callback for disconnections */ +/* _nx_tcpserver_relisten Re-listen on free sockets */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr) +{ +UINT i; +NX_TCP_SOCKET *socket_ptr; + + /* Do nothing if callback is not set. */ + if(server_ptr -> nx_tcpserver_connection_end == NX_NULL) + { + return; + } + + /* Initialize TCP sockets. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); + + if((socket_ptr -> nx_tcp_socket_state > NX_TCP_ESTABLISHED) || + ((socket_ptr -> nx_tcp_socket_state < NX_TCP_SYN_SENT) && + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration)) + { + + /* Invoke disconnect callback. */ + server_ptr -> nx_tcpserver_connection_end(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); + + /* Reset epiration of session. */ + server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0; + + /* Relisten */ + _nx_tcpserver_relisten(server_ptr); + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_timeout_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is invoked by the server thread whenever */ +/* a timeout event is encountered (triggered by the timeout timer). */ +/* If the application passes a disconnect callback to */ +/* _nx_tcpserver_create, it will be invoked here. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_tcpserver_connection_timeout Callback to process timeout */ +/* _nx_tcpserver_relisten Re-listen on free sockets */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcpserver_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr) +{ +UINT i; +NX_TCP_SESSION *session_ptr; + + /* Do nothing if callback is not set. */ + if(server_ptr -> nx_tcpserver_connection_timeout == NX_NULL) + { + return; + } + + /* Initialize TCP sockets. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + session_ptr = &server_ptr -> nx_tcpserver_sessions[i]; + + /* Skip socket that is not used. */ + if(session_ptr -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) + { + continue; + } + + /* Skip socket that is already timeout. */ + if(session_ptr -> nx_tcp_session_expiration == 0) + { + continue; + } + + /* Is the session timeout? */ + if(session_ptr -> nx_tcp_session_expiration > NX_TCPSERVER_TIMEOUT_PERIOD) + session_ptr -> nx_tcp_session_expiration -= NX_TCPSERVER_TIMEOUT_PERIOD; + else + { + + session_ptr -> nx_tcp_session_expiration = 0; + + /* Invoke timeout callback. */ + server_ptr -> nx_tcpserver_connection_timeout(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); + + /* Relisten */ + _nx_tcpserver_relisten(server_ptr); + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is the entry point for the socket server */ +/* thread. It continually loops, checking the event flags and */ +/* dispatching processing when events are encountered. */ +/* */ +/* INPUT */ +/* */ +/* tcpserver_address Pointer to socket server */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcpserver_connect_process Process new connection */ +/* _nx_tcpserver_data_process Process received data */ +/* _nx_tcpserver_disconnect_process Process disconnection event */ +/* _nx_tcpserver_timeout_process Process server timeout */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address) +{ +ULONG events; +UINT status; +NX_TCPSERVER *server_ptr = (NX_TCPSERVER *)tcpserver_address; + + + /* Loop to process events. */ + while(1) + { + status = tx_event_flags_get(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_ANY_EVENT, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); + + /* Check the return status. */ + if(status) + { + + /* If an error occurs, simply continue the loop. */ + continue; + } + + /* Otherwise, an event is present. Process according to the event. */ + + /* Check for a connect event. */ + if(events & NX_TCPSERVER_CONNECT) + { + + /* Call the connect processing. */ + _nx_tcpserver_connect_process(server_ptr); + } + + + /* Check for a data event. */ + if(events & NX_TCPSERVER_DATA) + { + + /* Call the receive data processing. */ + _nx_tcpserver_data_process(server_ptr); + } + + + /* Check for a disconnect event. */ + if(events & NX_TCPSERVER_DISCONNECT) + { + + /* Call the disconnect processing. */ + _nx_tcpserver_disconnect_process(server_ptr); + } + + + /* Check for a timeout event. */ + if(events & NX_TCPSERVER_TIMEOUT) + { + + /* Call the disconnect processing. */ + _nx_tcpserver_timeout_process(server_ptr); + } + + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called by an application to stop a currently */ +/* running socket server. It shuts down the server thread and stops */ +/* listening on all internal TCP sockets. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to server structure */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_suspend Stop server thread */ +/* tx_timer_deactivate Stop server timeout timer */ +/* nx_tcp_server_socket_unlisten Stop listening on TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcpserver_stop(NX_TCPSERVER *server_ptr) +{ +UINT status; + + /* Check whether listen is done. */ + if(server_ptr -> nx_tcpserver_listen_port == 0) + return NX_TCPSERVER_FAIL; + + /* Suspend thread. */ + tx_thread_suspend(&server_ptr -> nx_tcpserver_thread); + + /* Deactivate timer. */ + tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer); + + /* Unlisten. */ + status = nx_tcp_server_socket_unlisten(server_ptr -> nx_tcpserver_ip, server_ptr -> nx_tcpserver_listen_port); + + if(status == NX_SUCCESS) + { + + /* Clear. */ + server_ptr -> nx_tcpserver_listen_port = 0; + server_ptr -> nx_tcpserver_listen_session = NX_NULL; + } + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcpserver_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is called by an application to clean up a previously */ +/* created socket server. It cleans up the server thread and closes */ +/* deletes all internal TCP sockets and TLS sessions. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to server structure */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_terminate Stop server thread */ +/* tx_thread_delete Stop server timeout timer */ +/* tx_event_flags_delete Delete server event flags */ +/* tx_timer_deactivate Deactivate timeout timer */ +/* tx_timer_delete Delete timeout timer */ +/* nx_tcp_socket_disconnect Disconnect TCP sockets */ +/* nx_tcp_server_socket_unaccept Stop listening on TCP sockets */ +/* nx_tcp_socket_delete Delete TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcpserver_delete(NX_TCPSERVER *server_ptr) +{ +UINT i; +NX_TCP_SOCKET *socket_ptr; + + /* Terminate server thread. */ + tx_thread_terminate(&server_ptr -> nx_tcpserver_thread); + + /* Delete server thread. */ + tx_thread_delete(&server_ptr -> nx_tcpserver_thread); + + /* Delete the event flag group */ + tx_event_flags_delete(&server_ptr -> nx_tcpserver_event_flags); + + /* Deactivate and delete timer. */ + tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer); + tx_timer_delete(&server_ptr -> nx_tcpserver_timer); + + /* Delete all opened sockets. */ + for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) + { + + /* Get socket pointer. */ + socket_ptr = &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket; + + /* Disconnect the socket. */ + nx_tcp_socket_disconnect(socket_ptr, NX_NO_WAIT); + + /* unaccept the socket. */ + nx_tcp_server_socket_unaccept(socket_ptr); + + /* Delete the socket. */ + nx_tcp_socket_delete(socket_ptr); + } + + /* Return successful compeletion. */ + return NX_SUCCESS; +} diff --git a/addons/web/nx_tcpserver.h b/addons/web/nx_tcpserver.h new file mode 100644 index 00000000..234a0d62 --- /dev/null +++ b/addons/web/nx_tcpserver.h @@ -0,0 +1,191 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Multiple TCP Socket/TLS Session support module */ +/** */ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_tcpserver.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX TCP Server module component, */ +/* including all data types and external references. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_TCPSERVER_H +#define NX_TCPSERVER_H + +#include "tx_api.h" +#include "nx_api.h" +#ifdef NX_WEB_HTTPS_ENABLE + +/* Enable TLS for the TCPServer module to support HTTPS */ +#ifndef NX_TCPSERVER_ENABLE_TLS +#define NX_TCPSERVER_ENABLE_TLS +#endif + +#include "nx_secure_tls_api.h" +#endif /* NX_WEB_HTTPS_ENABLE */ + +#ifndef NX_TCPSERVER_ACCEPT_WAIT +#define NX_TCPSERVER_ACCEPT_WAIT 1 +#endif /* NX_TCPSERVER_ACCEPT_WAIT */ + +#ifndef NX_TCPSERVER_DISCONNECT_WAIT +#define NX_TCPSERVER_DISCONNECT_WAIT 1 +#endif /* NX_TCPSERVER_DISCONNECT_WAIT */ + +#ifndef NX_TCPSERVER_PRIORITY +#define NX_TCPSERVER_PRIORITY 4 +#endif /* NX_TCPSERVER_PRIORITY */ + +#ifndef NX_TCPSERVER_TIMEOUT_PERIOD +#define NX_TCPSERVER_TIMEOUT_PERIOD 1 +#endif /* NX_TCPSERVER_TIMEOUT_PERIOD */ + +/* Define thread events. */ +#define NX_TCPSERVER_CONNECT 0x00000001 +#define NX_TCPSERVER_DATA 0x00000002 +#define NX_TCPSERVER_DISCONNECT 0x00000004 +#define NX_TCPSERVER_TIMEOUT 0x00000008 +#define NX_TCPSERVER_ANY_EVENT 0xFFFFFFFF + +/* ERROR code */ +#define NX_TCPSERVER_FAIL 0x01 + +/* TCP Server session structure - contains individual + TCP sockets and TLS sessions. */ +typedef struct NX_TCP_SESSION_STRUCT +{ + /* TCP socket used for this session. */ + NX_TCP_SOCKET nx_tcp_session_socket; + + /* Expiration timeout for this socket. */ + ULONG nx_tcp_session_expiration; + + /* Reserved value for passing data to/from individual sessions. */ + ULONG nx_tcp_session_reserved; + +#ifdef NX_TCPSERVER_ENABLE_TLS + /* Flag set to NX_TRUE if using TLS. */ + UINT nx_tcp_session_using_tls; + + /* If TLS is enabled, we also have a TLS session to maintain. */ + NX_SECURE_TLS_SESSION nx_tcp_session_tls_session; +#endif + +} NX_TCP_SESSION; + +/* TCPSERVER structure */ +typedef struct NX_TCPSERVER_STRUCT +{ + NX_IP *nx_tcpserver_ip; + NX_TCP_SESSION *nx_tcpserver_sessions; + UINT nx_tcpserver_sessions_count; + UINT nx_tcpserver_listen_port; + NX_TCP_SESSION *nx_tcpserver_listen_session; + TX_THREAD nx_tcpserver_thread; + TX_TIMER nx_tcpserver_timer; + TX_EVENT_FLAGS_GROUP nx_tcpserver_event_flags; + ULONG nx_tcpserver_timeout; + ULONG nx_tcpserver_accept_wait_option; + VOID (*nx_tcpserver_new_connection)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); + VOID (*nx_tcpserver_receive_data)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); + VOID (*nx_tcpserver_connection_end)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); + VOID (*nx_tcpserver_connection_timeout)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); + ULONG nx_tcpserver_reserved; +} NX_TCPSERVER; + + +#ifndef NX_TCPSERVER_SOURCE_CODE + +/* APIs */ +#define nx_tcpserver_create _nx_tcpserver_create +#define nx_tcpserver_start _nx_tcpserver_start +#define nx_tcpserver_stop _nx_tcpserver_stop +#define nx_tcpserver_delete _nx_tcpserver_delete +#ifdef NX_TCPSERVER_ENABLE_TLS +#define nx_tcpserver_tls_setup _nx_tcpserver_tls_setup +#endif + +#ifdef NX_TCPSERVER_ENABLE_TLS +UINT nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, + UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size); +#endif + +UINT nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + ULONG timeout, VOID *stack_ptr, UINT stack_size, + VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option); + + +UINT nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size); + +UINT nx_tcpserver_stop(NX_TCPSERVER *server_ptr); + +UINT nx_tcpserver_delete(NX_TCPSERVER *server_ptr); + +#else + +#ifdef NX_TCPSERVER_ENABLE_TLS +UINT _nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, + UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size); +#endif + +UINT _nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), + ULONG timeout, VOID *stack_ptr, UINT stack_size, + VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option); + + +UINT _nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size); + +UINT _nx_tcpserver_stop(NX_TCPSERVER *server_ptr); + +UINT _nx_tcpserver_delete(NX_TCPSERVER *server_ptr); + +#endif + +#endif /* NX_TCPSERVER_H */ diff --git a/addons/web/nx_web_http_client.c b/addons/web/nx_web_http_client.c new file mode 100644 index 00000000..860501b3 --- /dev/null +++ b/addons/web/nx_web_http_client.c @@ -0,0 +1,8505 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Web Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) and */ +/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_WEB_HTTP_CLIENT_SOURCE_CODE + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_ipv6.h" + +#include "nx_web_http_client.h" + +#include "stdio.h" +#include "string.h" + + +/* Define global HTTPS variables and strings. */ + + +/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing + into this array yields the base64 representation of the 6bit number. */ + +CHAR _nx_web_http_client_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* Define status maps. */ +static NX_WEB_HTTP_CLIENT_STATUS_MAP _nx_web_http_client_status_maps[] = +{ + {"200", NX_SUCCESS}, + {"100", NX_WEB_HTTP_STATUS_CODE_CONTINUE}, + {"101", NX_WEB_HTTP_STATUS_CODE_SWITCHING_PROTOCOLS}, + {"201", NX_WEB_HTTP_STATUS_CODE_CREATED}, + {"202", NX_WEB_HTTP_STATUS_CODE_ACCEPTED}, + {"203", NX_WEB_HTTP_STATUS_CODE_NON_AUTH_INFO}, + {"204", NX_WEB_HTTP_STATUS_CODE_NO_CONTENT}, + {"205", NX_WEB_HTTP_STATUS_CODE_RESET_CONTENT}, + {"206", NX_WEB_HTTP_STATUS_CODE_PARTIAL_CONTENT}, + {"300", NX_WEB_HTTP_STATUS_CODE_MULTIPLE_CHOICES}, + {"301", NX_WEB_HTTP_STATUS_CODE_MOVED_PERMANETLY}, + {"302", NX_WEB_HTTP_STATUS_CODE_FOUND}, + {"303", NX_WEB_HTTP_STATUS_CODE_SEE_OTHER}, + {"304", NX_WEB_HTTP_STATUS_CODE_NOT_MODIFIED}, + {"305", NX_WEB_HTTP_STATUS_CODE_USE_PROXY}, + {"307", NX_WEB_HTTP_STATUS_CODE_TEMPORARY_REDIRECT}, + {"400", NX_WEB_HTTP_STATUS_CODE_BAD_REQUEST}, + {"401", NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED}, + {"402", NX_WEB_HTTP_STATUS_CODE_PAYMENT_REQUIRED}, + {"403", NX_WEB_HTTP_STATUS_CODE_FORBIDDEN}, + {"404", NX_WEB_HTTP_STATUS_CODE_NOT_FOUND}, + {"405", NX_WEB_HTTP_STATUS_CODE_METHOD_NOT_ALLOWED}, + {"406", NX_WEB_HTTP_STATUS_CODE_NOT_ACCEPTABLE}, + {"407", NX_WEB_HTTP_STATUS_CODE_PROXY_AUTH_REQUIRED}, + {"408", NX_WEB_HTTP_STATUS_CODE_REQUEST_TIMEOUT}, + {"409", NX_WEB_HTTP_STATUS_CODE_CONFLICT}, + {"410", NX_WEB_HTTP_STATUS_CODE_GONE}, + {"411", NX_WEB_HTTP_STATUS_CODE_LENGTH_REQUIRED}, + {"412", NX_WEB_HTTP_STATUS_CODE_PRECONDITION_FAILED}, + {"413", NX_WEB_HTTP_STATUS_CODE_ENTITY_TOO_LARGE}, + {"414", NX_WEB_HTTP_STATUS_CODE_URL_TOO_LARGE}, + {"415", NX_WEB_HTTP_STATUS_CODE_UNSUPPORTED_MEDIA}, + {"416", NX_WEB_HTTP_STATUS_CODE_RANGE_NOT_SATISFY}, + {"417", NX_WEB_HTTP_STATUS_CODE_EXPECTATION_FAILED}, + {"500", NX_WEB_HTTP_STATUS_CODE_INTERNAL_ERROR}, + {"501", NX_WEB_HTTP_STATUS_CODE_NOT_IMPLEMENTED}, + {"502", NX_WEB_HTTP_STATUS_CODE_BAD_GATEWAY}, + {"503", NX_WEB_HTTP_STATUS_CODE_SERVICE_UNAVAILABLE}, + {"504", NX_WEB_HTTP_STATUS_CODE_GATEWAY_TIMEOUT}, + {"505", NX_WEB_HTTP_STATUS_CODE_VERSION_ERROR}, +}; + +static UINT _nx_web_http_client_status_maps_size = sizeof(_nx_web_http_client_status_maps)/sizeof(NX_WEB_HTTP_CLIENT_STATUS_MAP); + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* client_name Name of HTTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* window_size Size of HTTP client rx window */ +/* http_client_size Size of HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_create Actual client create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id == NX_WEB_HTTP_CLIENT_ID) || + (pool_ptr == NX_NULL) || (http_client_size != sizeof(NX_WEB_HTTP_CLIENT))) + return(NX_PTR_ERROR); + + /* Pickup a packet from the supplied packet pool. */ + packet_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ + if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE) + return(NX_WEB_HTTP_POOL_ERROR); + + /* Call actual client create function. */ + status = _nx_web_http_client_create(client_ptr, client_name, ip_ptr, pool_ptr, window_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a HTTP client on the specified IP. In doing */ +/* so this function creates an TCP socket for subsequent HTTP */ +/* transfers. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* client_name Name of HTTP client */ +/* ip_ptr Pointer to IP instance */ +/* pool_ptr Pointer to packet pool */ +/* window_size Size of HTTP client rx window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create HTTP client socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size) +{ + +UINT status; + + + /* Clear the HTTP Client structure. */ + memset((void *) client_ptr, 0, sizeof(NX_WEB_HTTP_CLIENT)); + + /* Create the Client's TCP socket. */ + status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_web_http_client_socket), client_name, + NX_WEB_HTTP_TYPE_OF_SERVICE, NX_WEB_HTTP_FRAGMENT_OPTION, NX_WEB_HTTP_TIME_TO_LIVE, + window_size, NX_NULL, NX_NULL); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, return error code. */ + return(status); + } + + /* Save the Client name. */ + client_ptr -> nx_web_http_client_name = client_name; + + /* Save the IP pointer address. */ + client_ptr -> nx_web_http_client_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + client_ptr -> nx_web_http_client_packet_pool_ptr = pool_ptr; + + /* Set the client state to ready to indicate a get or put operation can be done. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + + /* Set the current method to "NONE". */ + client_ptr -> nx_web_http_client_method = NX_WEB_HTTP_METHOD_NONE; + + /* Set the Client ID to indicate the HTTP client thread is ready. */ + client_ptr -> nx_web_http_client_id = NX_WEB_HTTP_CLIENT_ID; + + /* Set the default port the client connects to the HTTP server on (80). */ + client_ptr -> nx_web_http_client_connect_port = NX_WEB_HTTP_SERVER_PORT; + + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete Actual client delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nx_web_http_client_delete(client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created HTTP client on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_delete Delete the HTTP client socket */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr) +{ + +#ifdef NX_WEB_HTTPS_ENABLE + + /* End TLS session if using HTTPS. */ + if (client_ptr->nx_web_http_client_is_https) + { + nx_secure_tls_session_end(&(client_ptr -> nx_web_http_client_tls_session), NX_WAIT_FOREVER); + nx_secure_tls_session_delete(&(client_ptr -> nx_web_http_client_tls_session)); + } +#endif + + /* Disconnect and unbind the socket. */ + nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), NX_WEB_HTTP_CLIENT_TIMEOUT); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); + + /* Delete the TCP socket. */ + nx_tcp_socket_delete(&(client_ptr -> nx_web_http_client_socket)); + + /* Clear the client ID to indicate the HTTP client is no longer ready. */ + client_ptr -> nx_web_http_client_id = 0; + + /* Release request packet. */ + if (client_ptr -> nx_web_http_client_request_packet_ptr) + { + nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); + client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; + } + + /* Release response packet. */ + if (client_ptr -> nx_web_http_client_response_packet) + { + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + } + + /* Clear out the entire structure in case it is used again. */ + memset(client_ptr, 0, sizeof(NX_WEB_HTTP_CLIENT)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_content_type_header_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is used to add the Content-Type HTTP header */ +/* to an outgoing request. It determines the resource type from the */ +/* resource string and then adds the complete header to the current */ +/* HTTP request packet allocated in the control block. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* resource Server resource name */ +/* wait_option Timeout for called functions */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_type_get Get resource content type */ +/* _nx_web_http_client_request_header_add */ +/* Add header to request packet */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_content_type_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *resource, ULONG wait_option) +{ +UINT j; +CHAR string1[20]; + + /* Now build the content-type entry. */ + j = _nx_web_http_client_type_get(resource, string1); + _nx_web_http_client_request_header_add(client_ptr, "Content-Type", 12, string1, j, wait_option); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_content_length_header_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This internal function is used to add the Content-Length HTTP */ +/* header to an outgoing request. It converts the passed-in length */ +/* value to an HTTP string and then adds the complete header to the */ +/* current HTTP request packet allocated in the control block. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* total_bytes Content length value */ +/* wait_option Timeout for called functions */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_number_convert Convert length to string */ +/* _nx_web_http_client_request_header_add */ +/* Add header to request packet */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_content_length_header_add(NX_WEB_HTTP_CLIENT *client_ptr, ULONG total_bytes, ULONG wait_option) +{ +UINT j; +CHAR string1[20]; + + /* Now build the content-length entry. */ + j = _nx_web_http_client_number_convert(total_bytes, string1); + _nx_web_http_client_request_header_add(client_ptr, "Content-Length", 14, string1, j, wait_option); + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo client get start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_start Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, CHAR *host, CHAR *username, CHAR *password, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_web_http_client_get_start(client_ptr, server_ip, server_port, resource, + host, username, password, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_get_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. The response is processed by calling */ +/* nx_web_http_client_response_body_get. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_start_extended */ +/* Actual client get start call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, CHAR *host, + CHAR *username, CHAR *password, ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_get_start_extended(client_ptr, server_ip, server_port, resource, + temp_resource_length, host, temp_host_length, username, + temp_username_length, password, temp_password_length, + wait_option)); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo client get start */ +/* call with string length. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_start_extended */ +/* Actual client get start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_web_http_client_get_start_extended(client_ptr, server_ip, server_port, resource, + resource_length, host, host_length, username, + username_length, password, password_length, + wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_get_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. The response is processed by calling */ +/* nx_web_http_client_response_body_get. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ + +UINT status; + + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_GET, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the GET state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; + + return(status); +} + +#ifdef NX_WEB_HTTPS_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_get_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure GET request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_secure_start Actual GET request processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_web_http_client_get_secure_start(client_ptr, server_ip, server_port, resource, + host, username, password, tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_get_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. This version of the function also requires a TLS setup */ +/* callback as the request is sent over TLS-secured HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_secure_start_extended */ +/* Actual GET request processing */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_get_secure_start_extended(client_ptr, server_ip, server_port, + resource, temp_resource_length, host, + temp_host_length, username, + temp_username_length, password, + temp_password_length, tls_setup, + wait_option)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_get_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure GET request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_get_secure_start_extended */ +/* Actual GET request processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET start routine. */ + status = _nx_web_http_client_get_secure_start_extended(client_ptr, server_ip, server_port, + resource, resource_length, host, + host_length, username, username_length, + password, password_length, tls_setup, + wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_get_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application GET request. The specified */ +/* resource (URL) is requested from the HTTP Server at the specified */ +/* IP address. This version of the function also requires a TLS setup */ +/* callback as the request is sent over TLS-secured HTTPS. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_secure_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ + +UINT status; + + /* Use default HTTPS port. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_GET, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the GET state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; + + return(status); +} + +#endif /* NX_WEB_HTTPS_ENABLE */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_get_server_response PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the initial response from the remote */ +/* server. The body of the response is retrieved by the application */ +/* by calling the GET response body API. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_receive Receive packet */ +/* nx_packet_data_append Put data into return packet */ +/* nx_packet_copy Copy packet data */ +/* nx_packet_release Release processed packets */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_get_server_response(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +NX_PACKET *head_packet_ptr; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; +UINT status; +NX_PACKET *work_ptr; +UINT crlf_found = 0; +NX_PACKET *tmp_ptr; + + + /* Default the return packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Wait for a response from server. */ + status = _nx_web_http_client_receive(client_ptr, &head_packet_ptr, wait_option); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Return an error condition. */ + return(status); + } + + crlf_found = 0; + work_ptr = head_packet_ptr; + + /* Build a pointer to the buffer area. */ + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + + do + { + + /* See if there is a blank line present in the buffer. */ + /* Search the buffer for a cr/lf pair. */ + while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) + { + if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) + { + + /* Found CR. */ + crlf_found++; + } + else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) + { + + /* Found LF. */ + crlf_found++; + } + else + { + + /* Reset the CRLF marker. */ + crlf_found = 0; + } + + if (crlf_found == 4) + { + + /* Yes, we have found the end of the HTTP response header. */ + + /* Set the return packet pointer. */ + *packet_ptr = head_packet_ptr; + + /* Return a successful completion. */ + return(NX_SUCCESS); + } + + /* Move the buffer pointer up. */ + buffer_ptr++; + } + + /* Determine if the packet has already overflowed into another packet. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + + if (work_ptr -> nx_packet_next != NX_NULL) + { + + /* Get the next packet in the chain. */ + work_ptr = work_ptr -> nx_packet_next; + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + } + else +#endif + { + /* Receive another packet from the HTTP server port. */ + status = _nx_web_http_client_receive(client_ptr, &new_packet_ptr, wait_option); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Release the current head packet. */ + nx_packet_release(head_packet_ptr); + + /* Return an error condition. */ + return(status); + } + + /* Successfully received another packet. Its contents now need to be placed in the head packet. */ + tmp_ptr = new_packet_ptr; + +#ifndef NX_DISABLE_PACKET_CHAIN + while (tmp_ptr) + { +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Copy the contents of the current packet into the head packet. */ + status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, + (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), + client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, an error is present. */ + + /* Release both packets. */ + nx_packet_release(head_packet_ptr); + nx_packet_release(new_packet_ptr); + + /* Return an error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + tmp_ptr = tmp_ptr -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Release the new packet. */ + nx_packet_release(new_packet_ptr); + } + + } while (status == NX_SUCCESS); + + /* Release the packet. */ + nx_packet_release(head_packet_ptr); + + return(NX_WEB_HTTP_ERROR); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_response_body_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client get packet call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Destination for packet pointer*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_response_body_get Actual client get packet call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual GET packet routine. */ + status = _nx_web_http_client_response_body_get(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_response_body_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets a data packet associated with the resource */ +/* specified by the previous GET start request. It can be called */ +/* repeatedly to get all of the packets for larger resources. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Destination for packet pointer*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_receive Receive a resource data packet*/ +/* _nx_web_http_client_get_server_response */ +/* Get server response header */ +/* _nx_web_http_client_content_length_get */ +/* Get Content Length value */ +/* _nx_web_http_client_process_header_fields */ +/* Process HTTP header fields */ +/* _nx_web_http_client_error_exit Close HTTP(S) session */ +/* _nx_web_http_client_response_chunked_get */ +/* Get chunked response packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option) +{ + +UINT status = NX_SUCCESS; +UINT length = 0, offset = 0; +NX_PACKET *response_packet_ptr = NX_NULL; +CHAR *buffer_ptr; +UINT i = 0; +UINT status_code = NX_SUCCESS; + + + /* Check if the request packet is sent out. */ + if ((client_ptr -> nx_web_http_client_state < NX_WEB_HTTP_CLIENT_STATE_GET) || + (client_ptr -> nx_web_http_client_state > NX_WEB_HTTP_CLIENT_STATE_DELETE)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Default the return packet to NULL. */ + *packet_pptr = NX_NULL; + + /* Check for a response from the Server. */ + if (!(client_ptr -> nx_web_http_client_response_header_received)) + { + + /* Pickup the response from the Server. */ + status = _nx_web_http_client_get_server_response(client_ptr, &response_packet_ptr, wait_option); + + /* Validate the response packet length. */ + if (status == NX_SUCCESS) + { + if (response_packet_ptr -> nx_packet_append_ptr - response_packet_ptr -> nx_packet_prepend_ptr < 12) + { + status = NX_WEB_HTTP_ERROR; + } + } + + /* Check for error processing received packet. */ + if (status != NX_SUCCESS) + { + + if (status != NX_NO_PACKET) + { + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Reenter the READY state. */ + client_ptr->nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + } + + return(status); + } + + /* Setup pointer to server response. */ + buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine which status code is reveived. */ + for (i = 0; i < _nx_web_http_client_status_maps_size; i++) + { + if ((buffer_ptr[9] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[0]) && + (buffer_ptr[10] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[1]) && + (buffer_ptr[11] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[2])) + { + status_code = _nx_web_http_client_status_maps[i].nx_web_http_client_status_code; + break; + } + } + + /* Check the status code. */ + if (i == _nx_web_http_client_status_maps_size) + { + + /* Received an unknown status code. */ + status = NX_WEB_HTTP_REQUEST_UNSUCCESSFUL_CODE; + } + else if (buffer_ptr[9] != '2') + { + + /* Received an error status code. */ + status = status_code; + } + /* Determine if the request was successful. */ + else + { + + /* Pickup the content length if it exists. */ + length = _nx_web_http_client_content_length_get(client_ptr, response_packet_ptr); + + /* Pickup the content offset and process other headers. */ + offset = _nx_web_http_client_process_header_fields(client_ptr, response_packet_ptr); + + /* Determine if the packet is valid. */ + if (!offset || + (response_packet_ptr -> nx_packet_length < offset) || + ((response_packet_ptr -> nx_packet_length > (offset + length)) && + (!client_ptr -> nx_web_http_client_response_chunked))) + { + + /* Bad packet length. */ + status = NX_WEB_HTTP_BAD_PACKET_LENGTH; + } + else + { + + /* Set the flag of response header received. */ + client_ptr -> nx_web_http_client_response_header_received = NX_TRUE; + + /* Store the total number of bytes to receive. + For HEAD request, just process the response header. */ + if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_HEAD) + { + client_ptr -> nx_web_http_client_total_receive_bytes = length; + } + else + { + client_ptr -> nx_web_http_client_total_receive_bytes = 0; + } + client_ptr -> nx_web_http_client_actual_bytes_received = 0; + + /* Adjust the pointers to skip over the response header. */ + response_packet_ptr -> nx_packet_prepend_ptr = response_packet_ptr -> nx_packet_prepend_ptr + offset; + + /* Reduce the length. */ + response_packet_ptr -> nx_packet_length = response_packet_ptr -> nx_packet_length - offset; + + /* Set for processing chunked response. */ + if (client_ptr -> nx_web_http_client_response_chunked) + { + client_ptr -> nx_web_http_client_response_packet = response_packet_ptr; + client_ptr -> nx_web_http_client_chunked_response_remaining_size = response_packet_ptr -> nx_packet_length; + } + } + } + } + else if (!client_ptr -> nx_web_http_client_response_chunked) + { + + /* Pickup the response from the Server. */ + status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, wait_option); + + /* Check for error processing received packet. */ + if (status != NX_SUCCESS) + { + + if (status != NX_NO_PACKET) + { + + /* Clear the flag of response header received. */ + client_ptr->nx_web_http_client_response_header_received = NX_FALSE; + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Reenter the READY state. */ + client_ptr->nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + } + + return(status); + } + + if (response_packet_ptr -> nx_packet_length > (client_ptr -> nx_web_http_client_total_receive_bytes - client_ptr -> nx_web_http_client_actual_bytes_received)) + { + + /* Bad packet length. */ + status = NX_WEB_HTTP_BAD_PACKET_LENGTH; + } + } + + if (status == NX_SUCCESS) + { + if (client_ptr -> nx_web_http_client_response_chunked) + { + + /* Process the chunked response. */ + status = _nx_web_http_client_response_chunked_get(client_ptr, &response_packet_ptr, wait_option); + + if (status == NX_NO_PACKET) + { + return(status); + } + } + else + { + + /* Adjust the actual received bytes. */ + client_ptr -> nx_web_http_client_actual_bytes_received = client_ptr -> nx_web_http_client_actual_bytes_received + + response_packet_ptr -> nx_packet_length; + + /* Determine if the GET packet operation is complete. */ + if (client_ptr -> nx_web_http_client_total_receive_bytes == client_ptr -> nx_web_http_client_actual_bytes_received) + { + + /* Yes, we are finished. */ + status = NX_WEB_HTTP_GET_DONE; + } + } + + /* Move the packet pointer into the return pointer. */ + *packet_pptr = response_packet_ptr; + } + + if (status != NX_SUCCESS) + { + + /* Error, break down the connection and return to the caller. */ + if ((status != NX_WEB_HTTP_GET_DONE) && response_packet_ptr) + { + + /* Release the invalid HTTP packet. */ + nx_packet_release(response_packet_ptr); + } + + if (client_ptr -> nx_web_http_client_response_chunked) + { + + /* If the response is chunked, reset the chunk info. */ + if (status != NX_WEB_HTTP_GET_DONE) + { + + /* If status is NX_WEB_HTTP_GET_DONE, return this packet. */ + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + } + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; + client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; + } + + /* Clear the flag of response header received. */ + client_ptr -> nx_web_http_client_response_header_received = NX_FALSE; + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + if ((status != NX_WEB_HTTP_GET_DONE) || !(client_ptr -> nx_web_http_client_keep_alive)) +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + { + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + } + + /* Reenter the READY state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + } + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_response_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the next data in byte. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* data Returned data */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_receive Receive another packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_response_read(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR *data, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; + + /* If there is no remaining data. */ + while (client_ptr -> nx_web_http_client_chunked_response_remaining_size == 0) + { + + /* Release the previous received packet. */ + if (client_ptr -> nx_web_http_client_response_packet) + { + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + } + + /* Receive another packet. */ + status = _nx_web_http_client_receive(client_ptr, &(client_ptr -> nx_web_http_client_response_packet), wait_option); + if (status) + { + return(status); + } + + /* Update the packet pointer, data pointer and remaining size. */ + (*current_packet_pptr) = client_ptr -> nx_web_http_client_response_packet; + (*current_data_pptr) = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; + client_ptr -> nx_web_http_client_chunked_response_remaining_size = client_ptr -> nx_web_http_client_response_packet -> nx_packet_length; + } + + /* Process the packet chain. */ + if ((*current_data_pptr) == (*current_packet_pptr) -> nx_packet_append_ptr) + { +#ifndef NX_DISABLE_PACKET_CHAIN + if ((*current_packet_pptr) -> nx_packet_next == NX_NULL) + { + return(NX_INVALID_PACKET); + } + + (*current_packet_pptr) = (*current_packet_pptr) -> nx_packet_next; + (*current_data_pptr) = (*current_packet_pptr) -> nx_packet_prepend_ptr; + + /* Release the processed packet in the packet chain. */ + if (client_ptr -> nx_web_http_client_response_packet) + { + client_ptr -> nx_web_http_client_response_packet -> nx_packet_next = NX_NULL; + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + client_ptr -> nx_web_http_client_response_packet = (*current_packet_pptr); + } +#else + return(NX_INVALID_PACKET); +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Set the returned data. */ + *data = *(*current_data_pptr); + + /* Update the data pointer and remaining size. */ + (*current_data_pptr)++; + client_ptr -> nx_web_http_client_chunked_response_remaining_size--; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_response_byte_expect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if next byte is the expected data. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* data Expected data */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Compare result */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_response_read Get next data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_response_byte_expect(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR data, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; +UCHAR tmp; + + /* Get next data. */ + status = _nx_web_http_client_response_read(client_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); + + if (status) + { + return(status); + } + + /* Return the compare result. */ + if (tmp != data) + { + return(NX_NOT_FOUND); + } + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_chunked_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the chunk size of the response packet chunk. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* chunk_size Returned chunk size */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_chunked_size_get Get chunk size */ +/* _nx_web_http_client_response_byte_expect */ +/* Check if next byte is expected*/ +/* nx_packet_release Release packet */ +/* nx_packet_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_chunked_size_get(NX_WEB_HTTP_CLIENT *client_ptr, UINT *chunk_size, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; +UINT size = 0; +UCHAR tmp; +UINT chunk_extension = 0; + + if (client_ptr -> nx_web_http_client_actual_bytes_received < client_ptr -> nx_web_http_client_total_receive_bytes) + { + + /* If there are bytes need to receive, set the size need to receive as chunk size. */ + *chunk_size = client_ptr -> nx_web_http_client_total_receive_bytes - client_ptr -> nx_web_http_client_actual_bytes_received; + } + else + { + + /* Get the chunk size. */ + while (1) + { + + /* Read next byte from request packet. */ + status = _nx_web_http_client_response_read(client_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); + if (status) + { + return(status); + } + + /* Skip the chunk extension. */ + if (chunk_extension && (tmp != '\r')) + { + continue; + } + + /* Calculate the size. */ + if ((tmp >= 'a') && (tmp <= 'f')) + { + size = (size << 4) + 10 + (UINT)(tmp - 'a'); + } + else if ((tmp >= 'A') && (tmp <= 'F')) + { + size = (size << 4) + 10 + (UINT)(tmp - 'A'); + } + else if ((tmp >= '0') && (tmp <= '9')) + { + size = (size << 4) + (UINT)(tmp - '0'); + } + else if (tmp == '\r') + { + + /* Find the end of chunk header. */ + break; + } + else if (tmp == ';') + { + + /* Find chunk extension. */ + chunk_extension = 1; + } + else + { + return(NX_NOT_FOUND); + } + } + + /* Expect '\n'. */ + status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, current_packet_pptr, current_data_pptr); + if (status) + { + return(status); + } + + *chunk_size = size; + } + + /* If there is no remaining data, receive another packet. */ + while (client_ptr -> nx_web_http_client_chunked_response_remaining_size == 0) + { + if (client_ptr -> nx_web_http_client_response_packet) + { + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + } + + status = _nx_web_http_client_receive(client_ptr, &(client_ptr -> nx_web_http_client_response_packet), wait_option); + if (status) + { + return(status); + } + + /* Update the current request packet, data pointer and remaining size. */ + (*current_packet_pptr) = client_ptr -> nx_web_http_client_response_packet; + (*current_data_pptr) = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; + client_ptr -> nx_web_http_client_chunked_response_remaining_size = client_ptr -> nx_web_http_client_response_packet -> nx_packet_length; + } + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_response_chunked_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the chunk data from chunked response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_pptr Pointer to the packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_chunked_size_get Get chunk size */ +/* _nx_web_http_client_response_byte_expect */ +/* Check if next byte is expected*/ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_response_chunked_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option) +{ +UINT status; +UINT chunk_size = 0, length = 0, temp_size = 0; +UINT remaining_size = 0; +NX_PACKET *packet_ptr; +NX_PACKET *current_packet_ptr = NX_NULL; +UCHAR *current_data_ptr = NX_NULL; + + /* Set pointer for processing packet data. */ + current_packet_ptr = client_ptr -> nx_web_http_client_response_packet; + + if (current_packet_ptr) + { + + /* Set current data pointer. */ + current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; + } + + /* Get chunk size. */ + status = _nx_web_http_client_chunked_size_get(client_ptr, &chunk_size, wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + /* Check if it's the end. */ + if (chunk_size == 0) + { + + /* Read CRLF. */ + status = _nx_web_http_client_response_byte_expect(client_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + /* Return an empty packet. */ + client_ptr -> nx_web_http_client_response_packet -> nx_packet_append_ptr = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; + client_ptr -> nx_web_http_client_response_packet -> nx_packet_length = 0; + *packet_pptr = client_ptr -> nx_web_http_client_response_packet; + + return(NX_WEB_HTTP_GET_DONE); + } + + /* Set the return packet. */ + *packet_pptr = client_ptr -> nx_web_http_client_response_packet; + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + packet_ptr = *packet_pptr; + packet_ptr -> nx_packet_prepend_ptr = current_data_ptr; + remaining_size = client_ptr -> nx_web_http_client_chunked_response_remaining_size; + + /* Process the chunk data. */ + if (chunk_size <= remaining_size) + { + + /* One or more chunk in the remaining data. */ + temp_size = chunk_size; + + /* Check if the chunk data is all in this packet. */ + while (temp_size > (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr)) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + if (current_packet_ptr -> nx_packet_next == NX_NULL) + { + return(NX_INVALID_PACKET); + } + + temp_size -= (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); + current_packet_ptr = current_packet_ptr -> nx_packet_next; + current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; +#else + return(NX_INVALID_PACKET); +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Skip the chunk data. */ + current_data_ptr += temp_size; + client_ptr -> nx_web_http_client_chunked_response_remaining_size -= chunk_size; + length = chunk_size; + + /* Read CRLF. */ + status = _nx_web_http_client_response_byte_expect(client_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + /* Check the remaining data. */ + if (client_ptr -> nx_web_http_client_chunked_response_remaining_size) + { + if (client_ptr -> nx_web_http_client_response_packet) + { + + /* If received new packet, adjust the prepend pointer of this packet. */ + client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr = current_data_ptr; + } + else + { + + /* Copy the remaining data to a new packet. */ + /* Allocate a packet. */ + status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, + &(client_ptr -> nx_web_http_client_response_packet), + 0, wait_option); + if (status) + { + return(status); + } + + /* Copy the remaining data in current packet to the new packet. */ + temp_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); + status = nx_packet_data_append(client_ptr -> nx_web_http_client_response_packet, + current_data_ptr, + temp_size, + client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + if (status) + { + return(status); + } + + /* Check if any remaining data not in current packet. */ + if (client_ptr -> nx_web_http_client_chunked_response_remaining_size > temp_size) + { +#ifndef NX_DISABLE_PACKET_CHAIN + + /* If there are chained packets, append the packets to the new packet. */ + if (current_packet_ptr -> nx_packet_next) + { + client_ptr -> nx_web_http_client_response_packet -> nx_packet_next = current_packet_ptr -> nx_packet_next; + client_ptr -> nx_web_http_client_response_packet -> nx_packet_last = current_packet_ptr -> nx_packet_last; + current_packet_ptr -> nx_packet_next = NX_NULL; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + { + return(NX_INVALID_PACKET); + } + } + } + + /* Update the packet length. */ + client_ptr -> nx_web_http_client_response_packet -> nx_packet_length = client_ptr -> nx_web_http_client_chunked_response_remaining_size; + } + } + else + { + + /* All the remaining data is in this chunk. */ + client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; + length = remaining_size; + } + + /* Set the received bytes. */ + client_ptr -> nx_web_http_client_total_receive_bytes = chunk_size; + client_ptr -> nx_web_http_client_actual_bytes_received = length; + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Set length of the packet chain header. */ + (*packet_pptr) -> nx_packet_length = length; + + /* Find the last packet. */ + while (packet_ptr -> nx_packet_next && + (length > (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr))) + { + length -= (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); + packet_ptr = packet_ptr -> nx_packet_next; + } + + /* Set the last packet. */ + (*packet_pptr) -> nx_packet_last = packet_ptr; + + /* Maybe the '\r\n' is in another packet, release this packet. */ + if (packet_ptr -> nx_packet_next) + { + nx_packet_release(packet_ptr -> nx_packet_next); + packet_ptr -> nx_packet_next = NX_NULL; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set packet length and append pointer. */ + /* If the packet is chained, set the length and append pointer of the last packet. */ + packet_ptr -> nx_packet_length = length; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + length; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_chunked_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP request chunked set */ +/* API call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* chunk_size Size of the chunk */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_chunked_set */ +/* Actual request chunked set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr) +{ +UINT status; + + /* Make sure the client instance makes sense. */ + if ((client_ptr == NX_NULL) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Call actual request chunked set function. */ + status = _nx_web_http_client_request_chunked_set(client_ptr, chunk_size, packet_ptr); + + /* Return success to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_chunked_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the chunked information of chunked request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* chunk_size Size of the chunk */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append the packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr) +{ +UINT status; +UINT temp_size, i, j; +CHAR temp_string[10]; +CHAR crlf[2] = {13,10}; + + /* Covert the size to ASCII. */ + temp_size = chunk_size; + i = 0; + + while (temp_size) + { + + for (j = i; j > 0; j--) + { + temp_string[j] = temp_string[j - 1]; + } + + if ((temp_size & 0x0F) < 10) + { + temp_string[0] = (CHAR)((temp_size & 0x0F) + '0'); + } + else + { + temp_string[0] = (CHAR)((temp_size & 0x0F) - 10 + 'a'); + } + temp_size = temp_size >> 4; + i++; + } + + if (i == 0) + { + temp_string[i++] = '0'; + } + + /* Place the chunk size in the packet. */ + status = nx_packet_data_append(packet_ptr, temp_string, i, client_ptr -> nx_web_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + if (status) + { + return(status); + } + + /* Place the CRLF to signal the end of the chunk size. */ + status = nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, NX_WAIT_FOREVER); + if (status) + { + return(status); + } + + /* Set the request chunked flag. */ + client_ptr -> nx_web_http_client_request_chunked = NX_TRUE; + + /* The total bytes need to transfer is chunk size plus chunk header length. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = chunk_size + i + 2; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP request packet send */ +/* API call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to the packet */ +/* more_data If there are more data to send*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_packet_send */ +/* Actual request packet send */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option) +{ +UINT status; + + /* Make sure the client instance makes sense. */ + if ((client_ptr == NX_NULL) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Now send the packet to the HTTP server. */ + status = _nx_web_http_client_request_packet_send(client_ptr, packet_ptr, more_data, wait_option); + + /* Return success to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends an HTTP request packet to a remote server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to the packet */ +/* more_data If there are more data to send*/ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_send Send data to server */ +/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option) +{ +UINT status; +CHAR crlf[2] = {13,10}; +UINT length = packet_ptr -> nx_packet_length; + + /* Check the packet length. */ + if (client_ptr -> nx_web_http_client_total_transfer_bytes < (client_ptr -> nx_web_http_client_actual_bytes_transferred + length)) + { + return(NX_INVALID_PACKET); + } + + /* If the request is chunked, add CRLF at the end of the chunk. */ + if (client_ptr -> nx_web_http_client_request_chunked) + { + + if (client_ptr -> nx_web_http_client_total_transfer_bytes == (client_ptr -> nx_web_http_client_actual_bytes_transferred + length)) + { + + /* Place an extra CRLF to signal the end of the chunk. */ + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + + /* If there are no more data to send, append the last chunk. */ + if (!more_data) + { + nx_packet_data_append(packet_ptr, "0\r\n\r\n", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + client_ptr -> nx_web_http_client_request_chunked = NX_FALSE; + } + } + } + + /* Now send the packet to the HTTP server. */ + status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + /* Update the transferred bytes. */ + client_ptr -> nx_web_http_client_actual_bytes_transferred += length; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_start Actual client put start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_web_http_client_put_start(client_ptr, server_ip, server_port, resource, host, + username, password, total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_put_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_start_extended */ +/* Actual client put start call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_put_start_extended(client_ptr, server_ip, server_port, resource, + temp_resource_length, host, temp_host_length, username, + temp_username_length, password, temp_password_length, + total_bytes, wait_option)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Duo Client put start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_start_extended */ +/* Actual client put start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_web_http_client_put_start_extended(client_ptr, server_ip, server_port, resource, + resource_length, host, host_length, username, + username_length, password, password_length, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_put_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to remote server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize PUT request */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option) +{ +UINT status; + + /* Set the port we are connecting to. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_PUT, + resource, + resource_length, + host, + host_length, + total_bytes, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Add approproate headers from input data. */ + _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + /* Enter the PUT state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; + + + return(status); +} + + +#ifdef NX_WEB_HTTPS_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_put_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure PUT request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to PUT */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_client_put_secure_start Actual PUT request processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_web_http_client_put_secure_start(client_ptr, server_ip, server_port, resource, + host, username, password, + total_bytes, tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_put_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. This version of the function also requires */ +/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to PUT */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_secure_start_extended */ +/* Actual PUT request processing */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_put_secure_start_extended(client_ptr, server_ip, server_port, + resource, temp_resource_length, host, + temp_host_length, username, + temp_username_length, password, + temp_password_length, total_bytes, + tls_setup, wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_put_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure PUT request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total number of bytes to PUT */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_secure_start_extended */ +/* Actual PUT request processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_web_http_client_put_secure_start_extended(client_ptr, server_ip, server_port, + resource, resource_length, host, + host_length, username, username_length, + password, password_length, total_bytes, + tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_put_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application PUT request. Transferring the*/ +/* specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. This version of the function also requires */ +/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total number of bytes to PUT */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_secure_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_error_exit Shutdown HTTPS session */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + + /* Use default HTTPS port. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_PUT, + resource, + resource_length, + host, + host_length, + total_bytes, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Add approproate headers from input data. */ + _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + /* Enter the PUT state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; + + return(status); +} + +#endif /* NX_WEB_HTTPS_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_post_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Client POST start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to POST */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_post_start Actual client post start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual PUT start routine. */ + status = _nx_web_http_client_post_start(client_ptr, server_ip, server_port, resource, host, + username, password, total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_post_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application POST request. Transferring */ +/* the specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to POST */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_post_start_extended */ +/* Actual client put start call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_post_start_extended(client_ptr, server_ip, server_port, resource, + temp_resource_length, host, temp_host_length, username, + temp_username_length, password, temp_password_length, + total_bytes, wait_option)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_post_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP Client POST start */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total number of bytes to POST */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_post_start_extended */ +/* Actual client post start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for invalid total bytes. */ + if (total_bytes == 0) + return(NX_SIZE_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual POST start routine. */ + status = _nx_web_http_client_post_start_extended(client_ptr, server_ip, server_port, resource, + resource_length, host, host_length, username, + username_length, password, password_length, + total_bytes, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_post_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application POST request. Transferring */ +/* the specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total bytes to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to remote server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize PUT request */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option) +{ +UINT status; + + + /* Set the port we are connecting to. */ + client_ptr -> nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr -> nx_web_http_client_connect_port, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_POST, + resource, + resource_length, + host, + host_length, + total_bytes, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Add approproate headers from input data. */ + _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + /* Enter the POST state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; + + + return(status); +} + + +#ifdef NX_WEB_HTTPS_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_post_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure POST request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to POST */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_client_post_secure_start */ +/* Actual POST processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual POST start routine. */ + status = _nx_web_http_client_post_secure_start(client_ptr, server_ip, server_port, resource, host, + username, password, total_bytes, tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_post_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application POST request. Transferring */ +/* the specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. This version of the function also requires */ +/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* server_port HTTP Server TCP port */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* total_bytes Total number of bytes to POST */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_post_secure_start_extended */ +/* Actual POST request processing*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_post_secure_start_extended(client_ptr, server_ip, server_port, + resource, temp_resource_length, host, + temp_host_length, username, + temp_username_length, password, + temp_password_length, total_bytes, + tls_setup, wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_post_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure POST request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total number of bytes to POST */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_post_secure_start_extended */ +/* Actual POST request processing*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual POST start routine. */ + status = _nx_web_http_client_post_secure_start_extended(client_ptr, server_ip, server_port, + resource, resource_length, host, + host_length, username, username_length, + password, password_length, total_bytes, + tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_post_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application POST request. Transferring */ +/* the specified resource (URL) is started by this routine. The */ +/* application must call put packet one or more times to transfer */ +/* the resource contents. This version of the function also requires */ +/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* total_bytes Total number of bytes to POST */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_secure_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* _nx_web_http_client_error_exit Close HTTPS session */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + + /* Use default HTTPS port. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_POST, + resource, + resource_length, + host, + host_length, + total_bytes, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Add approproate headers from input data. */ + _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + /* Enter the POST state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; + + return(status); +} + +#endif /* NX_WEB_HTTPS_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_head_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to start a HEAD request.*/ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_start Actual HEAD request call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, CHAR *host, CHAR *username, CHAR *password, + ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual HEAD start routine. */ + status = _nx_web_http_client_head_start(client_ptr, server_ip, server_port, resource, + host, username, password, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_head_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application HEAD request. HEAD is */ +/* identical to GET for the HTTP client, so the server response is */ +/* processed by calling nx_web_http_client_response_body_get. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_start_extended */ +/* Actual HEAD request call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_head_start_extended(client_ptr, server_ip, server_port, resource, + temp_resource_length, host, temp_host_length, username, + temp_username_length, password, temp_password_length, + wait_option)); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_head_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to start a HEAD request.*/ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_start_extended */ +/* Actual HEAD request call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual HEAD start routine. */ + status = _nx_web_http_client_head_start_extended(client_ptr, server_ip, server_port, resource, + resource_length, host, host_length, username, + username_length, password, password_length, + wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_head_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application HEAD request. HEAD is */ +/* identical to GET for the HTTP client, so the server response is */ +/* processed by calling nx_web_http_client_response_body_get. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to remote server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HEAD request */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ +UINT status; + + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_HEAD, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the HEAD state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; + + return(status); +} + +#ifdef NX_WEB_HTTPS_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_head_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure HEAD request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_secure_start */ +/* Actual HEAD request processing*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual HEAD start routine. */ + status = _nx_web_http_client_head_secure_start(client_ptr, server_ip, server_port, resource, + host, username, password, tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_head_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application HEAD request. The HTTP */ +/* header for the specified resource (URL) is requested from the HTTP */ +/* Server at the specified IP address and port. This version of the */ +/* function also requires a TLS setup callback as the request is sent */ +/* over TLS-secured HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_secure_start_extended */ +/* Actual HEAD request processing*/ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_head_secure_start_extended(client_ptr, server_ip, server_port, + resource, temp_resource_length, host, + temp_host_length, username, + temp_username_length, password, + temp_password_length, tls_setup, + wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_head_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure HEAD request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_head_secure_start_extended */ +/* Actual HEAD request processing*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual HEAD start routine. */ + status = _nx_web_http_client_head_secure_start_extended(client_ptr, server_ip, server_port, + resource, resource_length, host, + host_length, username, username_length, + password, password_length, + tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_head_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application HEAD request. The HTTP */ +/* header for the specified resource (URL) is requested from the HTTP */ +/* Server at the specified IP address and port. This version of the */ +/* function also requires a TLS setup callback as the request is sent */ +/* over TLS-secured HTTPS. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_secure_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ + +UINT status; + + /* Use default HTTPS port. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_HEAD, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the HEAD state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; + + return(status); +} + +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_delete_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to start a DELETE */ +/* request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_start Actual DELETE request call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, CHAR *host, CHAR *username, CHAR *password, + ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DELETE start routine. */ + status = _nx_web_http_client_delete_start(client_ptr, server_ip, server_port, resource, + host, username, password, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_delete_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application DELETE request. DELETE only */ +/* receives a simple response which can be processed with */ +/* nx_web_http_client_response_body_get. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_start_extended */ +/* Actual DELETE request call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_delete_start_extended(client_ptr, server_ip, server_port, resource, + temp_resource_length, host, temp_host_length, username, + temp_username_length, password, temp_password_length, + wait_option)); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_delete_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to start a DELETE */ +/* request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_start Actual DELETE request call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || (host == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DELETE start routine. */ + status = _nx_web_http_client_delete_start_extended(client_ptr, server_ip, server_port, resource, + resource_length, host, host_length, username, + username_length, password, password_length, + wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_delete_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application DELETE request. DELETE only */ +/* receives a simple response which can be processed with */ +/* nx_web_http_client_response_body_get. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to remote server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize DELETE request */ +/* _nx_web_http_client_content_type_header_add */ +/* Add content type header */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option) +{ + +UINT status; + + client_ptr -> nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr -> nx_web_http_client_connect_port, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_DELETE, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the DELETE state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; + + return(status); +} + +#ifdef NX_WEB_HTTPS_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_delete_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure DELETE request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_secure_start */ +/* Actual DELETE request call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DELETE start routine. */ + status = _nx_web_http_client_delete_secure_start(client_ptr, server_ip, server_port, resource, + host, username, password, tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_delete_secure_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application DELETE request. DELETE only */ +/* receives a simple response which can be processed with */ +/* nx_web_http_client_response_body_get. This version of the function */ +/* also requires a TLS setup callback as the request is sent over */ +/* TLS-secured HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip HTTP Server IP address */ +/* resource Pointer to resource (URL) */ +/* host Pointer to Host */ +/* username Pointer to username */ +/* password Pointer to password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_secure_start_extended */ +/* Actual DELETE processing */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_delete_secure_start_extended(client_ptr, server_ip, server_port, + resource, temp_resource_length, host, + temp_host_length, username, + temp_username_length, password, + temp_password_length, tls_setup, + wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_delete_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS secure DELETE request */ +/* processing call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_delete_secure_start_extended */ +/* Actual DELETE processing */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual DELETE start routine. */ + status = _nx_web_http_client_delete_secure_start_extended(client_ptr, server_ip, server_port, + resource, resource_length, host, + host_length, username, username_length, + password, password_length, + tls_setup, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_delete_secure_start_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an application DELETE request. DELETE only */ +/* receives a simple response which can be processed with */ +/* nx_web_http_client_response_body_get. This version of the function */ +/* also requires a TLS setup callback as the request is sent over */ +/* TLS-secured HTTPS. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip IP duo address of HTTP Server */ +/* resource Pointer to resource (URL) */ +/* resource_length String length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* username Pointer to username */ +/* username_length Length of username */ +/* password Pointer to password */ +/* password_length Length of password */ +/* tls_setup TLS setup callback function */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_secure_connect Connect to HTTPS server */ +/* _nx_web_http_client_request_initialize_extended */ +/* Initialize HTTP request */ +/* _nx_web_http_client_request_send Send HTTP request to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, + UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ + +UINT status; + + /* Use default HTTPS port. */ + client_ptr->nx_web_http_client_connect_port = server_port; + + /* Connect to the server. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Initialize HTTP request. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, + NX_WEB_HTTP_METHOD_DELETE, + resource, + resource_length, + host, + host_length, + 0, + NX_FALSE, /* If true, input_size is ignored. */ + username, + username_length, + password, + password_length, + wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Send the HTTP request we just built. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return(status); + } + + /* Enter the DELETE state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; + + return(status); +} + +#endif + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_put_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP client put packet call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Resource data packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_put_packet Actual client put packet call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; +NXD_ADDRESS *server_ip; +UINT header_size; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Get worker variables for use. */ + server_ip = &(client_ptr -> nx_web_http_client_server_address); + +#ifndef NX_DISABLE_IPV4 + if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) + { + header_size = NX_IPv4_TCP_PACKET; + } + else +#endif /* !NX_DISABLE_IPV4 */ + +#ifdef FEATURE_NX_IPV6 + if (server_ip -> nxd_ip_version == NX_IP_VERSION_V6) + { + header_size = NX_IPv6_TCP_PACKET; + } + else +#endif /* FEATURE_NX_IPV6 */ + { + return(NX_NOT_CONNECTED); + } + + /* Ensure there is enough room for the TCP packet header. */ + if ((UINT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < header_size) + { + + /* Return an invalid packet error. */ + return(NX_INVALID_PACKET); + } + + /* Call actual PUT data routine. */ + status = _nx_web_http_client_put_packet(client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_put_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a packet of resource data associated with */ +/* the previous PUT request. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Resource data packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_receive Check for server response */ +/* nx_packet_release Release the packet */ +/* _nx_web_http_client_error_exit Shutdown connection */ +/* _nx_web_http_client_send Send data to server */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +NX_PACKET *response_packet_ptr; +CHAR *buffer_ptr; +UINT length; +UINT status; + + + /* First, check and see if the client instance is still in the PUT state. */ + if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_PUT && + client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_POST) + { + + /* Client not ready, return error. */ + return(NX_WEB_HTTP_NOT_READY); + } + + /* Next, check and see if there is a response from the Server. */ + status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, NX_NO_WAIT); + + /* Check for an early response from the Server. */ + if (status == NX_SUCCESS) + { + + /* This is an error condition since the Server should not respond until the PUT is complete. */ + + /* Setup pointer to server response. */ + buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if it is an authentication error. */ + if (((buffer_ptr + 11) < (CHAR *)response_packet_ptr -> nx_packet_append_ptr) && + (buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) + { + + /* Inform caller of an authentication error. */ + status = NX_WEB_HTTP_AUTHENTICATION_ERROR; + } + else + { + + /* Inform caller of general Server failure. */ + status = NX_WEB_HTTP_INCOMPLETE_PUT_ERROR; + } + + /* Release the packet. */ + nx_packet_release(response_packet_ptr); + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return to the READY state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + + /* Return error to caller. */ + return(status); + } + + /* Otherwise, determine if the packet length fits in the available bytes to send. */ + if (packet_ptr -> nx_packet_length > + (client_ptr -> nx_web_http_client_total_transfer_bytes - client_ptr -> nx_web_http_client_actual_bytes_transferred)) + { + + /* Request doesn't fit into the remaining transfer window. */ + return(NX_WEB_HTTP_BAD_PACKET_LENGTH); + } + + /* Remember the packet length. */ + length = packet_ptr -> nx_packet_length; + + /* Now send the packet out. */ + status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return to the READY state. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; + + /* Return an error. */ + return(status); + } + + /* Otherwise, update the actual bytes transferred. */ + client_ptr -> nx_web_http_client_actual_bytes_transferred = client_ptr -> nx_web_http_client_actual_bytes_transferred + length; + + /* Return status to caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_put_start Start the PUT process */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_type_get(CHAR *name, CHAR *http_type_string) +{ + +UINT i; + + + /* First find the end of the string. */ + i = 0; + while (name[i] != (CHAR) NX_NULL) + { + i++; + } + + /* Now look backwards to find the last period that signals the + file extension. */ + while ((i) && (name[i] != '.')) + { + i--; + } + + /* Position forward again, past the period. */ + i++; + + /* Now see what HTTP file type to return. */ + + /* Check for .txt file extension. */ + if (((name[i] == 't') || (name[i] == 'T')) && + ((name[i+1] == 'x') || (name[i+1] == 'X')) && + ((name[i+2] == 't') || (name[i+2] == 'T'))) + { + + /* Yes, we have a plain text file. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'p'; + http_type_string[6] = 'l'; + http_type_string[7] = 'a'; + http_type_string[8] = 'i'; + http_type_string[9] = 'n'; + + /* Return the size of the HTTP ASCII type string. */ + return(10); + } + + /* Check for .htm[l] file extension. */ + else if (((name[i] == 'h') || (name[i] == 'H')) && + ((name[i+1] == 't') || (name[i+1] == 'T')) && + ((name[i+2] == 'm') || (name[i+2] == 'M'))) + { + + /* Yes, we have an HTML text file. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'h'; + http_type_string[6] = 't'; + http_type_string[7] = 'm'; + http_type_string[8] = 'l'; + + /* Return the size of the HTTP ASCII type string. */ + return(9); + } + + /* Check for .gif file extension. */ + else if (((name[i] == 'g') || (name[i] == 'G')) && + ((name[i+1] == 'i') || (name[i+1] == 'I')) && + ((name[i+2] == 'f') || (name[i+2] == 'F'))) + { + + /* Yes, we have a GIF image file. */ + http_type_string[0] = 'i'; + http_type_string[1] = 'm'; + http_type_string[2] = 'a'; + http_type_string[3] = 'g'; + http_type_string[4] = 'e'; + http_type_string[5] = '/'; + http_type_string[6] = 'g'; + http_type_string[7] = 'i'; + http_type_string[8] = 'f'; + + /* Return the size of the HTTP ASCII type string. */ + return(9); + } + + /* Check for .xbm file extension. */ + else if (((name[i] == 'x') || (name[i] == 'X')) && + ((name[i+1] == 'b') || (name[i+1] == 'B')) && + ((name[i+2] == 'm') || (name[i+2] == 'M'))) + { + + /* Yes, we have a x-xbitmap image file. */ + http_type_string[0] = 'i'; + http_type_string[1] = 'm'; + http_type_string[2] = 'a'; + http_type_string[3] = 'g'; + http_type_string[4] = 'e'; + http_type_string[5] = '/'; + http_type_string[6] = 'x'; + http_type_string[7] = '-'; + http_type_string[8] = 'x'; + http_type_string[9] = 'b'; + http_type_string[10] = 'i'; + http_type_string[11] = 't'; + http_type_string[12] = 'm'; + http_type_string[13] = 'a'; + http_type_string[14] = 'p'; + + /* Return the size of the HTTP ASCII type string. */ + return(15); + } + + /* Default to plain text. */ + else + { + + /* Default to plain text. */ + http_type_string[0] = 't'; + http_type_string[1] = 'e'; + http_type_string[2] = 'x'; + http_type_string[3] = 't'; + http_type_string[4] = '/'; + http_type_string[5] = 'p'; + http_type_string[6] = 'l'; + http_type_string[7] = 'a'; + http_type_string[8] = 'i'; + http_type_string[9] = 'n'; + + /* Return the size of the HTTP ASCII type string. */ + return(10); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the content length of the supplied HTTP */ +/* response packet. If the packet is no content or the packet is */ +/* invalid, a zero is returned. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* */ +/* OUTPUT */ +/* */ +/* client_ptr HTTP client control block */ +/* length Length of content */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_get_start Start the GET operation */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_content_length_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ + +UINT length; +CHAR *buffer_ptr; +UINT found = NX_FALSE; + + + NX_PARAMETER_NOT_USED(client_ptr); + + /* Default the content length to an invalid value. */ + length = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Content-length:" token first. */ + while ((buffer_ptr+14) < (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + + /* Check for the Content-length token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && + ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && + ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && + ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && + (*(buffer_ptr+7) == '-') && + ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && + ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && + ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && + ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && + ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && + ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && + (*(buffer_ptr+14) == ':')) + { + + /* Yes, found content-length token. */ + found = NX_TRUE; + + /* Move past the Content-Length: field. Exit the loop. */ + buffer_ptr += 15; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Check if found the content-length token. */ + if (found != NX_TRUE) + { + + /* No, return an invalid length indicating a bad HTTP packet. */ + return(length); + } + + /* Now skip over white space. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + buffer_ptr++; + } + + /* Now convert the length into a numeric value. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + { + + /* Update the content length. */ + length = length * 10; + length = length + (((UINT) (*buffer_ptr)) - 0x30); + + /* Move the buffer pointer forward. */ + buffer_ptr++; + } + + /* Determine if the content length was picked up properly. */ + if ((buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || + ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR)13))) + { + + /* Error, set the length to zero. */ + length = 0; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_memicmp PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares two pieces of memory case insensitive. */ +/* */ +/* INPUT */ +/* */ +/* src Pointer to source */ +/* src_length Length of source */ +/* dest Pointer to destination */ +/* dest_length Length of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_process_header_fields */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) +{ +UCHAR ch; + + /* Compare the length. */ + if(src_length != dest_length) + return NX_WEB_HTTP_FAILED; + + while(src_length) + { + + /* Is src lowercase? */ + if((*src >= 'a') && (*src <= 'z')) + ch = (UCHAR)(*src - 'a' + 'A'); + + /* Is src uppercase? */ + else if((*src >= 'A') && (*src <= 'Z')) + ch = (UCHAR)(*src - 'A' + 'a'); + else + ch = *src; + + /* Compare case insensitive. */ + if((*src != *dest) && (ch != *dest)) + return NX_WEB_HTTP_FAILED; + + /* Pickup next character. */ + src_length--; + src++; + dest++; + } + + return NX_SUCCESS; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_process_header_fields PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the HTTP headers received from the remote */ +/* server. It also calculates the byte offset to the start of the */ +/* HTTP response content area. This area immediately follows the HTTP */ +/* response header (which ends with a blank line). */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to request packet */ +/* */ +/* OUTPUT */ +/* */ +/* Byte Offset (0 implies no content) */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_memicmp Compile two strings */ +/* [nx_web_http_client_response_callback] */ +/* Application header callback */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_get_start Start GET processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_process_header_fields(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) +{ + +UINT offset; +CHAR *buffer_ptr; +CHAR *field_name; +UINT field_name_length; +CHAR *field_value; +UINT field_value_length; +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE +UINT version = 0; +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + + /* Default the content offset to zero. */ + offset = 0; + client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + if ((buffer_ptr + 7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) + { + version = (UCHAR)((buffer_ptr[5] - '0') << 4) | (UCHAR)(buffer_ptr[7] - '0'); + } + + /* Is a valid HTTP version found? */ + if(version == 0) + { + client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; + return 0; + } + + /* Initialize the keepalive flag. */ + if(version > 0x10) + client_ptr -> nx_web_http_client_keep_alive = NX_TRUE; + else + client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* Skip over the first HTTP line (e.g. HTTP/1.1 200 OK). */ + while(((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13) && (*(buffer_ptr + 1) != (CHAR) 10)) + { + buffer_ptr++; + offset++; + } + + /* Skip over the CR,LF. */ + buffer_ptr += 2; + offset += 2; + + /* Loop until we find the "cr,lf,cr,lf" token. */ + while (((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the token. This signals a blank line, which also + specifies the start of the content. */ + if ((*buffer_ptr == (CHAR) 13) && + (*(buffer_ptr+1) == (CHAR) 10)) + { + + /* Adjust the offset. */ + offset = offset + 2; + break; + } + + + /* We haven't seen the so we are still processing header data. + * Extract the field name and it's value. + */ + field_name = buffer_ptr; + field_name_length = 0; + + /* Look for the ':' that separates the field name from its value. */ + while(*buffer_ptr != ':') + { + buffer_ptr++; + field_name_length++; + } + offset += field_name_length; + + /* Skip ':'. */ + buffer_ptr++; + offset++; + + /* Now skip over white space. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + buffer_ptr++; + offset++; + } + + /* Now get the field value. */ + field_value = buffer_ptr; + field_value_length = 0; + + /* Loop until we see a . */ + while(((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13) && (*(buffer_ptr+1) != (CHAR) 10)) + { + buffer_ptr++; + field_value_length++; + } + offset += field_value_length; + + /* Skip over the CR,LF. */ + buffer_ptr += 2; + offset += 2; + + /* Check if the response packet is chunked. */ + if (_nx_web_http_client_memicmp((UCHAR *)field_name, field_name_length, (UCHAR *)"Transfer-Encoding", 17) == 0) + { + if (_nx_web_http_client_memicmp((UCHAR *)field_value, field_value_length, (UCHAR *)"chunked", 7) == 0) + { + client_ptr -> nx_web_http_client_response_chunked = NX_TRUE; + } + } + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + + /* If the "connection" field exist, and the value is "keep-alive", set the keep-alive flag to TRUE. */ + if (_nx_web_http_client_memicmp((UCHAR *)"connection", 10, (UCHAR *)field_name, field_name_length) == NX_SUCCESS) + { + if (_nx_web_http_client_memicmp((UCHAR *)"keep-alive", 10, (UCHAR *)field_value, field_value_length) == NX_SUCCESS) + { + client_ptr -> nx_web_http_client_keep_alive = NX_TRUE; + } + else if (_nx_web_http_client_memicmp((UCHAR *)"close", 5, (UCHAR *)field_value, field_value_length) == NX_SUCCESS) + { + client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; + } + } +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* Invoke the header callback if present. */ + /* If it was set, invoke the application response callback. */ + if(client_ptr -> nx_web_http_client_response_callback) + { + client_ptr -> nx_web_http_client_response_callback(client_ptr, field_name, field_name_length, field_value, field_value_length); + } + } + + /* Not find the "cr,lf,cr,lf" token. */ + if (((buffer_ptr+1) >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr == (CHAR) 0)) + { + offset = 0; + } + + /* Return the offset to the caller. */ + return(offset); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* string Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_get_start Start GET processing */ +/* _nx_web_http_client_put_start Start PUT processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_number_convert(UINT number, CHAR *string) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Default string to return '0'. */ + string[0] = '0'; + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while ((size < 10) && (number)) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string[j] = string[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + string[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + } + + /* Make the string NULL terminated. */ + string[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_base64_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the input string into a base64 */ +/* representation. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* length Length of name */ +/* base64name Encoded base64 name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_get_start Start GET processing */ +/* _nx_web_http_client_put_start Start PUT processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name) +{ + +UINT pad; +UINT i, j; +UINT step; + + + /* Adjust the length to represent the base64 name. */ + length = ((length * 8) / 6); + + /* Default padding to none. */ + pad = 0; + + /* Determine if an extra conversion is needed. */ + if ((length * 6) % 24) + { + + /* Some padding is needed. */ + + /* Calculate the number of pad characters. */ + pad = (length * 6) % 24; + pad = (24 - pad) / 6; + pad = pad - 1; + + /* Adjust the length to pickup the character fraction. */ + length++; + } + + /* Setup index into the base64name. */ + j = 0; + + /* Compute the base64name. */ + step = 0; + i = 0; + while (j < length) + { + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first 6 bits of name character for index. */ + base64name[j++] = _nx_web_http_client_base64_array[((UINT) name[i]) >> 2]; + step++; + } + else if (step == 1) + { + + /* Use last 2 bits of name character and first 4 bits of next name character for index. */ + base64name[j++] = _nx_web_http_client_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; + i++; + step++; + } + else if (step == 2) + { + + /* Use last 4 bits of name character and first 2 bits of next name character for index. */ + base64name[j++] = _nx_web_http_client_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; + i++; + step++; + } + else /* Step 3 */ + { + + /* Use last 6 bits of name character for index. */ + base64name[j++] = _nx_web_http_client_base64_array[(((UINT) name[i]) & 0x3F)]; + i++; + step = 0; + } + } + + /* Determine if the index needs to be advanced. */ + if (step != 3) + i++; + + /* Now add the PAD characters. */ + while ((pad--) && (j < NX_WEB_HTTP_MAX_STRING)) + { + + /* Pad base64name with '=' characters. */ + base64name[j++] = '='; + } + + /* Put a NULL character in. */ + base64name[j] = NX_NULL; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_https_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to connect the HTTP */ +/* client to a remote HTTP server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip Address of remote server */ +/* server_port HTTPS port on remote server */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Actual HTTP connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option) + +{ +UINT status; + + /* Check pointers. */ + if(client_ptr == NX_NULL || server_ip == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call actual function. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, server_port, wait_option); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_https_client_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a HTTP client on the specified IP. The TCP */ +/* socket is left open following this call, allowing multiple */ +/* operations (e.g. GET, PUT, etc.) on this client instance before */ +/* closing the HTTP connection. */ +/* */ +/* Note that multiple operations implies that the HTTP keepalive */ +/* header is present and supported by the remote host. Performing a */ +/* single operation and then disconnecting the socket is equivalent to */ +/* a standard non-keepalive HTTP session. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip Address of remote server */ +/* server_port HTTPS port on remote server */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_cleanup Rest the state */ +/* nx_tcp_client_socket_bind Bind TCP client socket */ +/* nxd_tcp_client_socket_connect Connect to remote server */ +/* nx_tcp_client_socket_unbind Unbind socket on error */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option) + +{ + +UINT status; + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + + /* If keep-alive is true, the client is already connected to the server. */ + if (client_ptr -> nx_web_http_client_keep_alive) + { + + /* Clean up and reset the state. */ + _nx_web_http_client_cleanup(client_ptr); + + if (nx_tcp_socket_state_wait(&(client_ptr -> nx_web_http_client_socket), NX_TCP_ESTABLISHED, 0) == NX_SUCCESS) + { + + /* No need to reconnect. */ + return(NX_SUCCESS); + } + else + { + + /* Server disconnected the connection, need to reconnect. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + } + } +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* Determine if the client is in a ready state. */ + if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_READY) + { + + /* Reset the state. */ + _nx_web_http_client_cleanup(client_ptr); + } + + /* Attempt to bind the client socket. */ + status = nx_tcp_client_socket_bind(&(client_ptr -> nx_web_http_client_socket), NX_ANY_PORT, wait_option); + + /* Check status of the bind. */ + if (status != NX_SUCCESS) + { + + /* Error binding to a port, return to caller. */ + return(status); + } + + client_ptr -> nx_web_http_client_connect_port = server_port; + + /* Connect to the HTTPS server with TCP. */ + status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_web_http_client_socket), server_ip, + client_ptr -> nx_web_http_client_connect_port, wait_option); + + /* Check for connection status. */ + if (status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); + return(status); + } + + /* At this point, the TCP socket to the remote HTTP server is connected. */ +#ifdef FEATURE_NX_IPV6 + COPY_NXD_ADDRESS(server_ip, &(client_ptr -> nx_web_http_client_server_address)); +#else + client_ptr -> nx_web_http_client_server_address.nxd_ip_version = NX_IP_VERSION_V4; + client_ptr -> nx_web_http_client_server_address.nxd_ip_address.v4 = server_ip -> nxd_ip_address.v4; +#endif + + return(NX_SUCCESS); +} + +#ifdef NX_WEB_HTTPS_ENABLE + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_https_client_secure_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the secure HTTPS connect call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip Address of remote server */ +/* server_port HTTPS port on remote server */ +/* tls_setup User-supplied callback */ +/* function to set up TLS */ +/* parameters. */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_https_client_secure_connect Actual secure connect call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + + + /* Check pointers. */ + if(client_ptr == NX_NULL || server_ip == NX_NULL || tls_setup == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call actual function. */ + status = _nx_web_http_client_secure_connect(client_ptr, server_ip, server_port, tls_setup, wait_option); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_https_client_secure_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function connects a HTTPS client on the specified IP. The TLS */ +/* session in the NX_WEB_HTTP_CLIENT structure is initialized using */ +/* application-supplied callback. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* server_ip Address of remote server */ +/* server_port HTTPS port on remote server */ +/* tls_setup User-supplied callback */ +/* function to set up TLS */ +/* parameters. */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_connect Connect to server with TCP */ +/* _nx_secure_tls_session_start Connect to server with TLS */ +/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option) +{ +UINT status; + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + + /* If keep-alive is true, the client is already connected to the server. */ + if (client_ptr -> nx_web_http_client_keep_alive && + (nx_tcp_socket_state_wait(&(client_ptr -> nx_web_http_client_socket), NX_TCP_ESTABLISHED, 0) == NX_SUCCESS)) + { + + /* Reset the state. */ + _nx_web_http_client_cleanup(client_ptr); + return(NX_SUCCESS); + } +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* We have an HTTPS client, mark it as such. */ + client_ptr -> nx_web_http_client_is_https = NX_TRUE; + + /* Attempt to connect to the HTTPS server using just TCP - we need to establish the TCP socket + before we attempt to perform a TLS handshake for HTTPS. */ + status = _nx_web_http_client_connect(client_ptr, server_ip, server_port, wait_option); + + if(status != NX_SUCCESS) + { + return(status); + } + + /* Call the TLS setup callback to initialize TLS configuration. */ + status = (*tls_setup)(client_ptr, &(client_ptr->nx_web_http_client_tls_session)); + + if(status != NX_SUCCESS) + { + + /* Error, unbind the port and return an error. */ + _nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), wait_option); + _nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); + return(status); + } + + /* Start TLS session after connecting TCP socket. */ + status = _nx_secure_tls_session_start(&(client_ptr -> nx_web_http_client_tls_session), &(client_ptr -> nx_web_http_client_socket), wait_option); + + if (status != NX_SUCCESS) + { + /* Error, unbind the port and return an error. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + return(status); + } + + /* At this point we have a connection setup with an HTTPS server! */ + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +#endif /* NX_WEB_HTTPS_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP request initialize call.*/ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* method HTTP request type (e.g. GET) */ +/* resource HTTP resource (e.g. URL) */ +/* host Pointer to Host */ +/* input_size Size of input for PUT/POST */ +/* transfer_encoding_chunked Chunked encoding flag */ +/* username Username for server access */ +/* password Password for server access */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_initialize */ +/* Actual request create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, /* GET, PUT, DELETE, POST, HEAD */ + CHAR *resource, + CHAR *host, + UINT input_size, /* Used by PUT and POST */ + UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ + CHAR *username, + CHAR *password, + UINT wait_option) +{ +UINT status; + + /* Check pointers. We need a control block and a resource but + username and password can be NULL. */ + if(client_ptr == NX_NULL || resource == NX_NULL || host == NX_NULL) + { + return(NX_PTR_ERROR); + } + + status = NX_SUCCESS; + + /* Check methods. */ + switch(method) + { + case NX_WEB_HTTP_METHOD_POST: + case NX_WEB_HTTP_METHOD_PUT: + /* PUT and POST need an input size. */ + if (!input_size && !transfer_encoding_chunked) + { + status = NX_WEB_HTTP_METHOD_ERROR; + } + break; + case NX_WEB_HTTP_METHOD_GET: + case NX_WEB_HTTP_METHOD_DELETE: + case NX_WEB_HTTP_METHOD_HEAD: + /* These are good as-is. */ + break; + case NX_WEB_HTTP_METHOD_NONE: + default: + /* Improper or missing method. */ + status = NX_WEB_HTTP_METHOD_ERROR; + } + + /* Check status from method creation. */ + if(status != NX_SUCCESS) + { + return(status); + } + + /* Call actual function. */ + status = _nx_web_http_client_request_initialize(client_ptr, method, resource, host, input_size, + transfer_encoding_chunked, username, password, + wait_option); + + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes an HTTP request using information */ +/* supplied by the caller. When a request is initialized, a packet is */ +/* allocated internally which can then be modified before sending the */ +/* final request to the server. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* method HTTP request type (e.g. GET) */ +/* resource HTTP resource (e.g. URL) */ +/* host Pointer to Host */ +/* input_size Size of input for PUT/POST */ +/* transfer_encoding_chunked Chunked encoding flag */ +/* username Username for server access */ +/* password Password for server access */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_initialize_extended */ +/* Actual request create call */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, /* GET, PUT, DELETE, POST, HEAD */ + CHAR *resource, + CHAR *host, + UINT input_size, /* Used by PUT and POST */ + UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ + CHAR *username, + CHAR *password, + UINT wait_option) +{ +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + return(_nx_web_http_client_request_initialize_extended(client_ptr, method, resource, + temp_resource_length, host, temp_host_length, + input_size, transfer_encoding_chunked, + username, temp_username_length, + password, temp_password_length, + wait_option)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_initialize_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP request initialize call.*/ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* method HTTP request type (e.g. GET) */ +/* resource HTTP resource (e.g. URL) */ +/* resource_length Length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* input_size Size of input for PUT/POST */ +/* transfer_encoding_chunked Chunked encoding flag */ +/* username Username for server access */ +/* username_length Length of username */ +/* password Password for server access */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_initialize_extended */ +/* Actual request create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, /* GET, PUT, DELETE, POST, HEAD */ + CHAR *resource, + UINT resource_length, + CHAR *host, + UINT host_length, + UINT input_size, /* Used by PUT and POST */ + UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ + CHAR *username, + UINT username_length, + CHAR *password, + UINT password_length, + UINT wait_option) +{ +UINT status; + + /* Check pointers. We need a control block and a resource but + username and password can be NULL. */ + if(client_ptr == NX_NULL || resource == NX_NULL || host == NX_NULL) + { + return(NX_PTR_ERROR); + } + + status = NX_SUCCESS; + + /* Check methods. */ + switch(method) + { + case NX_WEB_HTTP_METHOD_POST: + case NX_WEB_HTTP_METHOD_PUT: + /* PUT and POST need an input size. */ + if (!input_size && !transfer_encoding_chunked) + { + status = NX_WEB_HTTP_METHOD_ERROR; + } + break; + case NX_WEB_HTTP_METHOD_GET: + case NX_WEB_HTTP_METHOD_DELETE: + case NX_WEB_HTTP_METHOD_HEAD: + /* These are good as-is. */ + break; + case NX_WEB_HTTP_METHOD_NONE: + default: + /* Improper or missing method. */ + status = NX_WEB_HTTP_METHOD_ERROR; + } + + /* Check status from method creation. */ + if(status != NX_SUCCESS) + { + return(status); + } + + /* Call actual function. */ + status = _nx_web_http_client_request_initialize_extended(client_ptr, method, resource, resource_length, + host, host_length, input_size, + transfer_encoding_chunked, username, + username_length, password, password_length, + wait_option); + + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_initialize_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes an HTTP request using information */ +/* supplied by the caller. When a request is initialized, a packet is */ +/* allocated internally which can then be modified before sending the */ +/* final request to the server. */ +/* */ +/* Note: The strings of resource, host, username and password must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* method HTTP request type (e.g. GET) */ +/* resource HTTP resource (e.g. URL) */ +/* resource_length Length of resource */ +/* host Pointer to Host */ +/* host_length Length of host */ +/* input_size Size of input for PUT/POST */ +/* transfer_encoding_chunked Chunked encoding flag */ +/* username Username for server access */ +/* username_length Length of username */ +/* password Password for server access */ +/* password_length Length of password */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_packet_allocate */ +/* Allocate a request packet */ +/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ +/* nx_packet_data_append Append packet data */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, /* GET, PUT, DELETE, POST, HEAD */ + CHAR *resource, + UINT resource_length, + CHAR *host, + UINT host_length, + UINT input_size, /* Used by PUT and POST */ + UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ + CHAR *username, + UINT username_length, + CHAR *password, + UINT password_length, + UINT wait_option) +{ +UINT status; +NX_PACKET *packet_ptr; +CHAR string1[NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 2]; +CHAR string2[NX_WEB_HTTP_MAX_STRING + 1]; +CHAR crlf[2] = {13,10}; +UINT temp_resource_length; +UINT temp_host_length; +UINT temp_username_length = 0; +UINT temp_password_length = 0; +UINT string1_length; +UINT string2_length; + + /* If there is old request packet, just release it. */ + if (client_ptr -> nx_web_http_client_request_packet_ptr) + { + nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); + client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; + } + + if ((username) && (password)) + { + + /* Check username and password length. */ + if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || + _nx_utility_string_length_check(password, &temp_password_length, password_length)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Validate string length. */ + if ((username_length != temp_username_length) || + (password_length != temp_password_length)) + { + return(NX_WEB_HTTP_ERROR); + } + } + + /* Check resource and host length. */ + if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Validate string length. */ + if ((resource_length != temp_resource_length) || + (host_length != temp_host_length)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Allocate a packet for the request message. */ + status = _nx_web_http_client_request_packet_allocate(client_ptr, &(client_ptr -> nx_web_http_client_request_packet_ptr), wait_option); + + /* Check allocation status. */ + if (status != NX_SUCCESS) + { + /* Error, unbind the port and return an error. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + return(status); + } + + /* Get a working pointer to our newly-allocated packet. */ + packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; + + /* Determine the requested method. */ + status = NX_SUCCESS; + client_ptr -> nx_web_http_client_method = method; + switch(method) + { + case NX_WEB_HTTP_METHOD_GET: + /* Build the GET request. */ + nx_packet_data_append(packet_ptr, "GET ", 4, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + break; + case NX_WEB_HTTP_METHOD_PUT: + /* Additional information requested, build the POST request. */ + nx_packet_data_append(packet_ptr, "PUT ", 4, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = input_size; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + break; + case NX_WEB_HTTP_METHOD_POST: + /* Additional information requested, build the POST request. */ + nx_packet_data_append(packet_ptr, "POST ", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Store the total number of bytes to send. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = input_size; + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + break; + case NX_WEB_HTTP_METHOD_DELETE: + /* Build the DELETE request. */ + nx_packet_data_append(packet_ptr, "DELETE ", 7, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + break; + case NX_WEB_HTTP_METHOD_HEAD: + /* Build the HEAD request. */ + nx_packet_data_append(packet_ptr, "HEAD ", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + break; + case NX_WEB_HTTP_METHOD_NONE: + default: + status = NX_WEB_HTTP_METHOD_ERROR; + break; + } + + /* Check status from method creation. */ + if(status != NX_SUCCESS) + { + + /* Release the request packet. */ + nx_packet_release(packet_ptr); + client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; + return(status); + } + + /* Determine if the resource needs a leading "/". */ + if (resource[0] != '/') + { + + /* Is this another website e.g. begins with http or https and has a colon? */ + if ( + ((resource[0] == 'h') || (resource[0] == 'H')) && + ((resource[1] == 't') || (resource[1] == 'T')) && + ((resource[2] == 't') || (resource[2] == 'T')) && + ((resource[3] == 'p') || (resource[3] == 'P')) && + ( (resource[4] == ':') || + (((resource[4] == 's') || (resource[4] == 'S')) && (resource[5] == ':'))) + ) + { + + /* Yes, to send this string as is. */ + } + else + { + + /* Local file URI which needs a leading '/' character. */ + nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + } + } + /* Else URI string refers to root directory file, and has a leading '/' character already. */ + + /* Place the resource in the header. */ + nx_packet_data_append(packet_ptr, resource, resource_length, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Place the HTTP version in the header. */ + nx_packet_data_append(packet_ptr, " HTTP/1.1", 9, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Place the end of line character in the header. */ + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Place the Host in the header. */ + nx_packet_data_append(packet_ptr, "Host: ", 6, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + if (host_length) + { + nx_packet_data_append(packet_ptr, host, host_length, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + } + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Determine if basic authentication is required. */ + if ((username) && (password)) + { + + /* Yes, attempt to build basic authentication. */ + nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + /* Encode and append the "name:password" into next. */ + + /* Place the name and password in a single string. */ + + /* Copy the name into the merged string. */ + memcpy(string1, username, username_length); + + /* Insert the colon. */ + string1[username_length] = ':'; + + /* Copy the password into the merged string. */ + memcpy(&string1[username_length + 1], password, password_length); + + /* Make combined string NULL terminated. */ + string1[username_length + password_length + 1] = NX_NULL; + + /* Now encode the username:password string. */ + _nx_web_http_client_base64_encode(string1, username_length + password_length + 1, string2); + + /* Check string length. */ + _nx_utility_string_length_check(string2, &string2_length, NX_WEB_HTTP_MAX_STRING); + nx_packet_data_append(packet_ptr, string2, string2_length, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + } + + /* Check to see if a Content-Length field is needed. */ + if ((input_size) && (!transfer_encoding_chunked)) + { + + /* Now build the content-length entry. */ + nx_packet_data_append(packet_ptr, "Content-Length: ", 16, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + string1_length = _nx_web_http_client_number_convert(input_size, string1); + nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + } + + if (transfer_encoding_chunked) + { + + /* Place the Transfer Encoding in the header. */ + nx_packet_data_append(packet_ptr, "Transfer-Encoding: chunked", 26, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + } + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_header_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors when calling the custom header */ +/* addition routine. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* field_name HTTP header field name */ +/* name_length Length of field name string */ +/* field_value Value of header field */ +/* value_length Length of value string */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_request_header_add */ +/* Actual header add call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, + CHAR *field_value, UINT value_length, UINT wait_option) +{ +UINT status; + + /* Check pointers. */ + if(client_ptr == NX_NULL || field_name == NX_NULL || field_value == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call the actual function. */ + status = _nx_web_http_client_request_header_add(client_ptr, field_name, name_length, + field_value, value_length, wait_option); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_header_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a custom header to an HTTP(S) request that was */ +/* previously initialized with nx_web_http_client_request_initialize. */ +/* The field name and value are placed directly into the HTTP header */ +/* so it is up to the caller to assure that they are valid values. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* field_name HTTP header field name */ +/* name_length Length of field name string */ +/* field_value Value of header field */ +/* value_length Length of value string */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append data to request packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, + CHAR *field_value, UINT value_length, UINT wait_option) +{ +NX_PACKET *packet_ptr; +UINT status; +CHAR crlf[2] = {13,10}; + + + /* Make sure a request packet was allocated. */ + if(client_ptr -> nx_web_http_client_request_packet_ptr == NX_NULL) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Get a working pointer to our newly-allocated packet. */ + packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; + + + /* Add custom header fields to request packet. */ + status = nx_packet_data_append(packet_ptr, field_name, name_length, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + if(status != NX_SUCCESS) + { + return(status); + } + + status = nx_packet_data_append(packet_ptr, ": ", 2, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + if(status != NX_SUCCESS) + { + return(status); + } + + status = nx_packet_data_append(packet_ptr, field_value, value_length, client_ptr -> nx_web_http_client_packet_pool_ptr, + wait_option); + + if(status != NX_SUCCESS) + { + return(status); + } + + status = nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP request send API call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_client_request_send Actual request send call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option) +{ +UINT status; + + /* Make sure the client instance makes sense. */ + if(client_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Now send the packet to the HTTP server. */ + status = _nx_web_http_client_request_send(client_ptr, wait_option); + + /* Return success to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends an HTTP request to a remote server. The request */ +/* being sent must have been initialized previously with a call to */ +/* nx_web_http_client_request_initialize. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append packet data */ +/* nx_packet_release release packet */ +/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option) +{ +UINT status; +NX_PACKET *packet_ptr; +CHAR crlf[2] = {13,10}; + + + /* Make sure a request packet was allocated. */ + if(client_ptr -> nx_web_http_client_request_packet_ptr == NX_NULL) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Get a pointer to our current request packet. */ + packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; + + /* Clear the request packet pointer. */ + client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; + + /* Place an extra cr/lf to signal the end of the HTTP header. */ + nx_packet_data_append(packet_ptr, crlf, 2, + client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); + + /* Now send the packet to the HTTP server. */ + status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); + + /* Determine if the send was successful. */ + if (status != NX_SUCCESS) + { + + /* No, send was not successful. */ + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Disconnect and unbind the socket. */ + _nx_web_http_client_error_exit(client_ptr, wait_option); + + /* Return an error. */ + return(status); + } + + /* Set the appropriate state. */ + switch(client_ptr -> nx_web_http_client_method) + { + case NX_WEB_HTTP_METHOD_GET: + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; + break; + case NX_WEB_HTTP_METHOD_PUT: + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; + break; + case NX_WEB_HTTP_METHOD_POST: + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; + break; + case NX_WEB_HTTP_METHOD_DELETE: + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; + break; + case NX_WEB_HTTP_METHOD_HEAD: + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; + break; + case NX_WEB_HTTP_METHOD_NONE: + default: + status = NX_WEB_HTTP_METHOD_ERROR; + break; + } + + + /* Return success to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_request_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to allocate packets for */ +/* an HTTP(S) client session, as used for PUT and POST operations. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to allocated packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_client_request_packet_allocate */ +/* Actual packet allocation call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, + UINT wait_option) +{ +UINT status; + + /* Check our pointers. */ + if(client_ptr == NX_NULL || packet_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call the actual function. */ + status = _nx_web_http_client_request_packet_allocate(client_ptr, packet_ptr, wait_option); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_request_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a packet for Client HTTP(S) requests so */ +/* that clients needing to send large amounts of data (such as for */ +/* multi-part file upload) can allocated the needed packets and send */ +/* them with nx_web_http_client_request_packet_send. Note that the */ +/* appropriate headers must have been sent in the initial request. */ +/* Headers can be added to the HTTP request with */ +/* _nx_web_http_client_request_header_add. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to allocated packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_packet_allocate Allocate a TLS packet */ +/* nx_packet_allocate Allocate a TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, UINT wait_option) +{ +UINT status; +NXD_ADDRESS *server_ip; + + /* Get worker variables for use. */ + server_ip = &(client_ptr->nx_web_http_client_server_address); + +#ifdef NX_WEB_HTTPS_ENABLE + /* Allocate a packet for the GET (or POST) message. */ + if(client_ptr->nx_web_http_client_is_https) + { + status = nx_secure_tls_packet_allocate(&(client_ptr->nx_web_http_client_tls_session), client_ptr -> nx_web_http_client_packet_pool_ptr, + packet_ptr, wait_option); + } + else +#endif + if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) + { + status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, + packet_ptr, + NX_IPv4_TCP_PACKET, wait_option); + } + else + { + + status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, + packet_ptr, + NX_IPv6_TCP_PACKET, wait_option); + } + + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_client_response_header_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the set response callback */ +/* routine, */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* callback_function Pointer to callback routine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_response_header_callback_set */ +/* Actual set routine */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, + VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, + CHAR *field_name, + UINT field_name_length, + CHAR *field_value, + UINT field_value_length)) +{ +UINT status; + + + /* Check for NULL pointers. */ + if(client_ptr == NX_NULL || callback_function == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Invoke the real function. */ + status = _nx_web_http_client_response_header_callback_set(client_ptr, callback_function); + + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_response_header_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets a callback routine to be invoked when the HTTP */ +/* client receives a response from the remote server. The callback */ +/* allows the application to process the HTTP headers beyond the */ +/* normal processing done by the NetX Web HTTP library. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* callback_function Pointer to callback routine */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, + VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, + CHAR *field_name, + UINT field_name_length, + CHAR *field_value, + UINT field_value_length)) +{ + + /* Assign the function pointer to the HTTP client. */ + client_ptr -> nx_web_http_client_response_callback = callback_function; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends data to the remote server using either the TCP */ +/* socket for plain HTTP or the TLS session for HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to packet to send. */ +/* wait_option Indicates behavior if packet */ +/* cannot be sent. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_send Send data using TLS session */ +/* nx_secure_tcp_socket_send Send data using TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_client_put_packet */ +/* _nx_web_http_client_request_send */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + +#ifdef NX_WEB_HTTPS_ENABLE + /* End TLS session if using HTTPS. */ + if(client_ptr -> nx_web_http_client_is_https) + { + status = nx_secure_tls_session_send(&(client_ptr -> nx_web_http_client_tls_session), packet_ptr, wait_option); + } + else +#endif + { + status = nx_tcp_socket_send(&(client_ptr -> nx_web_http_client_socket), packet_ptr, wait_option); + } + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_client_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives data from the remote server using either the */ +/* TCP socket for plain HTTP or the TLS session for HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to packet to send. */ +/* wait_option Indicates behavior if packet */ +/* cannot be received */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_receive Receive data using TLS */ +/* nx_secure_tcp_socket_receive Receive data using TCP */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_client_receive(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + +#ifdef NX_WEB_HTTPS_ENABLE + /* End TLS session if using HTTPS. */ + if(client_ptr -> nx_web_http_client_is_https) + { + status = nx_secure_tls_session_receive(&(client_ptr -> nx_web_http_client_tls_session), packet_ptr, wait_option); + } + else +#endif + { + status = nx_tcp_socket_receive(&(client_ptr -> nx_web_http_client_socket), packet_ptr, wait_option); + } + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_https_client_error_exit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used whenever there is an error in the HTTP client */ +/* and the port needs to be unbound. If the client is using TLS for */ +/* HTTPS, then it also needs to end the TLS session. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* error_number Error status in caller */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_unbind Unbind TCP port */ +/* nx_secure_tls_session_delete Delete TLS session */ +/* nx_secure_tls_session_end End TLS session */ +/* nx_tcp_socket_disconnect Close TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_client_error_exit(NX_WEB_HTTP_CLIENT *client_ptr, UINT wait_option) +{ +#ifdef NX_WEB_HTTPS_ENABLE + /* End TLS session if using HTTPS. */ + if(client_ptr -> nx_web_http_client_is_https) + { + nx_secure_tls_session_end(&(client_ptr -> nx_web_http_client_tls_session), NX_WAIT_FOREVER); + nx_secure_tls_session_delete(&(client_ptr -> nx_web_http_client_tls_session)); + } +#endif + + nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), wait_option); + nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_https_client_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used to clean up the temporary variables and reset */ +/* the state. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* client_ptr Pointer to HTTP client */ +/* error_number Error status in caller */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_client_receive Receive a packet from server */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_client_cleanup(NX_WEB_HTTP_CLIENT *client_ptr) +{ +UINT status; +NX_PACKET *response_packet_ptr; + + /* Receive the early response from server. */ + while(1) + { + status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, NX_NO_WAIT); + + if (status) + { + break; + } + else + { + nx_packet_release(response_packet_ptr); + } + } + + /* Clean up the temporary variables. */ + client_ptr -> nx_web_http_client_total_transfer_bytes = 0; + + client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; + + client_ptr -> nx_web_http_client_total_receive_bytes = 0; + + client_ptr -> nx_web_http_client_actual_bytes_received = 0; + + client_ptr -> nx_web_http_client_response_header_received = NX_FALSE; + + /* Release the request packet. */ + if (client_ptr -> nx_web_http_client_request_packet_ptr) + { + nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); + client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; + } + + client_ptr -> nx_web_http_client_request_chunked = NX_FALSE; + + client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; + + client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; + + /* Release the response packet. */ + if (client_ptr -> nx_web_http_client_response_packet) + { + nx_packet_release(client_ptr -> nx_web_http_client_response_packet); + client_ptr -> nx_web_http_client_response_packet = NX_NULL; + } + + /* Reset the state to ready. */ + client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; +} + diff --git a/addons/web/nx_web_http_client.h b/addons/web/nx_web_http_client.h new file mode 100644 index 00000000..1194f928 --- /dev/null +++ b/addons/web/nx_web_http_client.h @@ -0,0 +1,655 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Web Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_web_http_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Web Hypertext Transfer Protocol (HTTP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_WEB_HTTP_CLIENT_H +#define NX_WEB_HTTP_CLIENT_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +#include "nx_api.h" + +/* Include common HTTP definitions. */ +#include "nx_web_http_common.h" + +/* Define the HTTP ID. */ +#define NX_WEB_HTTP_CLIENT_ID 0x48545450UL + +#ifndef NX_WEB_HTTP_CLIENT_TIMEOUT +#define NX_WEB_HTTP_CLIENT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE +#define NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE 600 +#endif + +/* Define HTTP Client states. */ + +#define NX_WEB_HTTP_CLIENT_STATE_READY 1 +#define NX_WEB_HTTP_CLIENT_STATE_GET 2 +#define NX_WEB_HTTP_CLIENT_STATE_PUT 3 +#define NX_WEB_HTTP_CLIENT_STATE_POST 4 +#define NX_WEB_HTTP_CLIENT_STATE_HEAD 5 +#define NX_WEB_HTTP_CLIENT_STATE_DELETE 6 + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + +/* Include the MD5 digest header file. */ + +#include "nx_md5.h" + +#endif + + +#ifdef NX_WEB_HTTPS_ENABLE +#include "nx_secure_tls_api.h" +#endif + +/* Define the */ +typedef struct NX_WEB_HTTP_CLIENT_STATUS_MAP_STRUCT +{ + CHAR *nx_web_http_client_status_string; /* String of status */ + UINT nx_web_http_client_status_code; /* Status code */ +} NX_WEB_HTTP_CLIENT_STATUS_MAP; + +/* Define the HTTP Client data structure. */ + +typedef struct NX_WEB_HTTP_CLIENT_STRUCT +{ + ULONG nx_web_http_client_id; /* HTTP Server ID */ + CHAR *nx_web_http_client_name; /* Name of this HTTP Client */ + UINT nx_web_http_client_state; /* Current state of HTTP Client */ + UINT nx_web_http_client_connect_port; /* Client port to connect to the server */ + NX_IP *nx_web_http_client_ip_ptr; /* Pointer to associated IP structure */ + NX_PACKET_POOL *nx_web_http_client_packet_pool_ptr; /* Pointer to HTTP Client packet pool */ + ULONG nx_web_http_client_total_transfer_bytes; /* Total number of bytes to transfer */ + ULONG nx_web_http_client_actual_bytes_transferred; /* Number of bytes actually transferred */ + ULONG nx_web_http_client_total_receive_bytes; /* Total number of bytes to receive */ + ULONG nx_web_http_client_actual_bytes_received; /* Number of bytes actually received */ + NX_TCP_SOCKET nx_web_http_client_socket; /* HTTP Client TCP socket */ + NXD_ADDRESS nx_web_http_client_server_address; /* IP address of remote server */ + NX_PACKET *nx_web_http_client_request_packet_ptr; /* Pointer to current request packet */ + UINT nx_web_http_client_method; /* Current method (e.g. GET, PUT) */ +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + UCHAR nx_web_http_client_keep_alive; /* Flag of keep alive */ +#else + UCHAR nx_web_http_client_reserved; /* Reserved */ +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + UCHAR nx_web_http_client_response_header_received; /* Flag of response header received */ + UCHAR nx_web_http_client_request_chunked; /* Flag for chunked request */ + UCHAR nx_web_http_client_response_chunked; /* Flag for chunked response */ + UINT nx_web_http_client_chunked_response_remaining_size; /* Remaining size of the response */ + NX_PACKET *nx_web_http_client_response_packet; /* Pointer to the received response */ + /* Pointer to application callback invoked for each field in the response header. */ + VOID (*nx_web_http_client_response_callback)(struct NX_WEB_HTTP_CLIENT_STRUCT *client_ptr, + CHAR *field_name, UINT field_name_length, + CHAR *field_value, UINT field_value_length); +#ifdef NX_WEB_HTTPS_ENABLE + UINT nx_web_http_client_is_https; /* If using TLS for HTTPS, set to true. */ + NX_SECURE_TLS_SESSION nx_web_http_client_tls_session; /* TLS session for HTTPS. */ +#endif +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + NX_MD5 nx_web_http_client_md5data; /* HTTP Client MD5 work area */ +#endif +} NX_WEB_HTTP_CLIENT; + + + +#ifndef NX_WEB_HTTP_CLIENT_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_web_http_client_create _nx_web_http_client_create +#define nx_web_http_client_delete _nx_web_http_client_delete +#define nx_web_http_client_get_start _nx_web_http_client_get_start +#define nx_web_http_client_get_start_extended _nx_web_http_client_get_start_extended +#define nx_web_http_client_put_start _nx_web_http_client_put_start +#define nx_web_http_client_put_start_extended _nx_web_http_client_put_start_extended +#define nx_web_http_client_post_start _nx_web_http_client_post_start +#define nx_web_http_client_post_start_extended _nx_web_http_client_post_start_extended +#define nx_web_http_client_head_start _nx_web_http_client_head_start +#define nx_web_http_client_head_start_extended _nx_web_http_client_head_start_extended +#define nx_web_http_client_delete_start _nx_web_http_client_delete_start +#define nx_web_http_client_delete_start_extended _nx_web_http_client_delete_start_extended +#define nx_web_http_client_get_secure_start _nx_web_http_client_get_secure_start +#define nx_web_http_client_get_secure_start_extended _nx_web_http_client_get_secure_start_extended +#define nx_web_http_client_put_secure_start _nx_web_http_client_put_secure_start +#define nx_web_http_client_put_secure_start_extended _nx_web_http_client_put_secure_start_extended +#define nx_web_http_client_post_secure_start _nx_web_http_client_post_secure_start +#define nx_web_http_client_post_secure_start_extended _nx_web_http_client_post_secure_start_extended +#define nx_web_http_client_head_secure_start _nx_web_http_client_head_secure_start +#define nx_web_http_client_head_secure_start_extended _nx_web_http_client_head_secure_start_extended +#define nx_web_http_client_delete_secure_start _nx_web_http_client_delete_secure_start +#define nx_web_http_client_delete_secure_start_extended _nx_web_http_client_delete_secure_start_extended +#define nx_web_http_client_response_body_get _nx_web_http_client_response_body_get +#define nx_web_http_client_put_packet _nx_web_http_client_put_packet +#define nx_web_http_client_response_header_callback_set _nx_web_http_client_response_header_callback_set +#define nx_web_http_client_request_initialize _nx_web_http_client_request_initialize +#define nx_web_http_client_request_initialize_extended _nx_web_http_client_request_initialize_extended +#define nx_web_http_client_request_send _nx_web_http_client_request_send +#define nx_web_http_client_request_header_add _nx_web_http_client_request_header_add +#define nx_web_http_client_connect _nx_web_http_client_connect +#define nx_web_http_client_secure_connect _nx_web_http_client_secure_connect +#define nx_web_http_client_request_packet_allocate _nx_web_http_client_request_packet_allocate +#define nx_web_http_client_request_packet_send _nx_web_http_client_request_packet_send +#define nx_web_http_client_request_chunked_set _nx_web_http_client_request_chunked_set + +#else + +/* Services with error checking. */ + +#define nx_web_http_client_create(p,n,i,pp,w) _nxe_web_http_client_create(p,n,i,pp,w, sizeof(NX_WEB_HTTP_CLIENT)) +#define nx_web_http_client_delete _nxe_web_http_client_delete +#define nx_web_http_client_get_start _nxe_web_http_client_get_start +#define nx_web_http_client_get_start_extended _nxe_web_http_client_get_start_extended +#define nx_web_http_client_put_start _nxe_web_http_client_put_start +#define nx_web_http_client_put_start_extended _nxe_web_http_client_put_start_extended +#define nx_web_http_client_post_start _nxe_web_http_client_post_start +#define nx_web_http_client_post_start_extended _nx_web_http_client_post_start_extended +#define nx_web_http_client_head_start _nxe_web_http_client_head_start +#define nx_web_http_client_head_start_extended _nxe_web_http_client_head_start_extended +#define nx_web_http_client_delete_start _nxe_web_http_client_delete_start +#define nx_web_http_client_delete_start_extended _nxe_web_http_client_delete_start_extended +#define nx_web_http_client_get_secure_start _nxe_web_http_client_get_secure_start +#define nx_web_http_client_get_secure_start_extended _nxe_web_http_client_get_secure_start_extended +#define nx_web_http_client_put_secure_start _nxe_web_http_client_put_secure_start +#define nx_web_http_client_put_secure_start_extended _nxe_web_http_client_put_secure_start_extended +#define nx_web_http_client_post_secure_start _nxe_web_http_client_post_secure_start +#define nx_web_http_client_post_secure_start_extended _nxe_web_http_client_post_secure_start_extended +#define nx_web_http_client_head_secure_start _nxe_web_http_client_head_secure_start +#define nx_web_http_client_head_secure_start_extended _nxe_web_http_client_head_secure_start_extended +#define nx_web_http_client_delete_secure_start _nxe_web_http_client_delete_secure_start +#define nx_web_http_client_delete_secure_start_extended _nxe_web_http_client_delete_secure_start_extended +#define nx_web_http_client_response_body_get _nxe_web_http_client_response_body_get +#define nx_web_http_client_put_packet _nxe_web_http_client_put_packet +#define nx_web_http_client_response_header_callback_set _nxe_web_http_client_response_header_callback_set +#define nx_web_http_client_request_initialize _nxe_web_http_client_request_initialize +#define nx_web_http_client_request_initialize_extended _nxe_web_http_client_request_initialize_extended +#define nx_web_http_client_request_send _nxe_web_http_client_request_send +#define nx_web_http_client_request_header_add _nxe_web_http_client_request_header_add +#define nx_web_http_client_connect _nxe_web_http_client_connect +#define nx_web_http_client_secure_connect _nxe_web_http_client_secure_connect +#define nx_web_http_client_request_packet_allocate _nxe_web_http_client_request_packet_allocate +#define nx_web_http_client_request_packet_send _nxe_web_http_client_request_packet_send +#define nx_web_http_client_request_chunked_set _nxe_web_http_client_request_chunked_set + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + + +#ifdef NX_DISABLE_ERROR_CHECKING +UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); +#else +UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); +#endif /* NX_DISABLE_ERROR_CHECKING */ + + +UINT nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); +UINT nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); +UINT nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); +UINT nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); + +UINT nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, + VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, + CHAR *field_name, + UINT field_name_length, + CHAR *field_value, + UINT field_value_length)); + +UINT nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); + +UINT nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + CHAR *host, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + CHAR *password, + UINT wait_option); + +UINT nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + UINT resource_length, + CHAR *host, + UINT host_length, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + UINT username_length, + CHAR *password, + UINT password_length, + UINT wait_option); + +UINT nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, + UINT wait_option); + +UINT nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, + CHAR *field_value, UINT value_length, UINT wait_option); + +UINT nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); + +UINT nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); + +UINT nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); + +#ifdef NX_WEB_HTTPS_ENABLE + +UINT nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); + +UINT nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); + +#endif +#else + +/* HTTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); +UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); +UINT _nxe_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); +UINT _nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); +UINT _nxe_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nxe_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxe_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); +UINT _nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); +UINT _nxe_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nxe_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option); +UINT _nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option); +UINT _nxe_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); +UINT _nxe_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option); +UINT _nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG total_bytes, + ULONG wait_option); +UINT _nxe_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxe_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); +UINT _nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); +UINT _nxe_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); +UINT _nxe_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); +UINT _nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, + UINT server_port, CHAR *resource, UINT resource_length, + CHAR *host, UINT host_length, CHAR *username, + UINT username_length, CHAR *password, + UINT password_length, ULONG wait_option); + + +UINT _nxe_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, + VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, + CHAR *field_name, + UINT field_name_length, + CHAR *field_value, + UINT field_value_length)); +UINT _nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, + VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, + CHAR *field_name, + UINT field_name_length, + CHAR *field_value, + UINT field_value_length)); +UINT _nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); +UINT _nxe_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); +UINT _nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + CHAR *host, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + CHAR *password, + UINT wait_option); +UINT _nxe_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + CHAR *host, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + CHAR *password, + UINT wait_option); +UINT _nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + UINT resource_length, + CHAR *host, + UINT host_length, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + UINT username_length, + CHAR *password, + UINT password_length, + UINT wait_option); +UINT _nxe_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, + UINT method, + CHAR *resource, + UINT resource_length, + CHAR *host, + UINT host_length, + UINT input_size, + UINT transfer_encoding_chunked, + CHAR *username, + UINT username_length, + CHAR *password, + UINT password_length, + UINT wait_option); + + +UINT _nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); +UINT _nxe_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); +UINT _nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, + UINT wait_option); +UINT _nxe_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, + UINT wait_option); + +UINT _nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, + CHAR *field_value, UINT value_length, UINT wait_option); +UINT _nxe_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, + CHAR *field_value, UINT value_length, UINT wait_option); + +UINT _nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); +UINT _nxe_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); + +UINT _nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); +UINT _nxe_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); + +#ifdef NX_WEB_HTTPS_ENABLE +UINT _nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); + +UINT _nxe_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, + CHAR *host, CHAR *username, CHAR *password, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nxe_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); +UINT _nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, + CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, + CHAR *username, UINT username_length, CHAR *password, UINT password_length, + UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), + ULONG wait_option); + + + +#endif + +/* Define internal HTTP functions. */ + +UINT _nx_web_http_client_type_get(CHAR *name, CHAR *http_type_string); +UINT _nx_web_http_client_content_length_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); +UINT _nx_web_http_client_process_header_fields(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); +UINT _nx_web_http_client_number_convert(UINT number, CHAR *string); +VOID _nx_web_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name); +UINT _nx_web_http_client_content_type_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *resource, ULONG wait_option); +UINT _nx_web_http_client_content_length_header_add(NX_WEB_HTTP_CLIENT *client_ptr, ULONG total_bytes, ULONG wait_option); +VOID _nx_web_http_client_error_exit(NX_WEB_HTTP_CLIENT *client_ptr, UINT wait_option); +UINT _nx_web_http_client_receive(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_web_http_client_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_web_http_client_get_server_response(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +VOID _nx_web_http_client_cleanup(NX_WEB_HTTP_CLIENT *client_ptr); +UINT _nx_web_http_client_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); +UINT _nx_web_http_client_response_read(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR *data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_client_response_byte_expect(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_client_chunked_size_get(NX_WEB_HTTP_CLIENT *client_ptr, UINT *chunk_size, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_client_response_chunked_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option); + +#endif /* NX_WEB_HTTP_CLIENT_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_WEB_HTTP_CLIENT_H */ diff --git a/addons/web/nx_web_http_common.h b/addons/web/nx_web_http_common.h new file mode 100644 index 00000000..81ae4e4a --- /dev/null +++ b/addons/web/nx_web_http_common.h @@ -0,0 +1,245 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_web_http_common.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Web Hypertext Transfer Protocol (HTTP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. If HTTPS is being used */ +/* then nx_secure_tls_api.h must also be included. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_WEB_HTTP_COMMON_H +#define NX_WEB_HTTP_COMMON_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* Define the HTTP version. */ +#define NX_WEB_HTTP_VERSION "HTTP/1.1" + +/* Define HTTP TCP socket create options. */ + +#ifndef NX_WEB_HTTP_TYPE_OF_SERVICE +#define NX_WEB_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL +#endif + +#ifndef NX_WEB_HTTP_FRAGMENT_OPTION +#define NX_WEB_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT +#endif + +#ifndef NX_WEB_HTTP_TIME_TO_LIVE +#define NX_WEB_HTTP_TIME_TO_LIVE 0x80 +#endif + +#ifndef NX_WEB_HTTP_MAX_RESOURCE +#define NX_WEB_HTTP_MAX_RESOURCE 40 +#endif + +#ifndef NX_WEB_HTTP_MAX_NAME +#define NX_WEB_HTTP_MAX_NAME 20 +#endif + +#ifndef NX_WEB_HTTP_MAX_PASSWORD +#define NX_WEB_HTTP_MAX_PASSWORD 20 +#endif + +/* To enabled HTTPS, define this symbol +#define NX_WEB_HTTPS_ENABLE +*/ + +/* To enable MD5 digest authentication, define this symbol +#define NX_WEB_HTTP_DIGEST_ENABLE +*/ + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 +#endif + +/* NX_WEB_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ +#define NX_WEB_HTTP_MAX_STRING ((NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 1 ) * 4 / 3 + 1) + +#define NX_WEB_HTTP_MAX_BINARY_MD5 16 +#define NX_WEB_HTTP_MAX_ASCII_MD5 32 + + +/* Define return code constants. */ +#define NX_WEB_HTTP_ERROR 0x30000 /* HTTP internal error */ +#define NX_WEB_HTTP_TIMEOUT 0x30001 /* HTTP timeout occurred */ +#define NX_WEB_HTTP_FAILED 0x30002 /* HTTP error */ +#define NX_WEB_HTTP_DONT_AUTHENTICATE 0x30003 /* HTTP authentication not needed */ +#define NX_WEB_HTTP_BASIC_AUTHENTICATE 0x30004 /* HTTP basic authentication requested */ +#define NX_WEB_HTTP_DIGEST_AUTHENTICATE 0x30005 /* HTTP digest authentication requested */ +#define NX_WEB_HTTP_NOT_FOUND 0x30006 /* HTTP request not found */ +#define NX_WEB_HTTP_DATA_END 0x30007 /* HTTP end of content area */ +#define NX_WEB_HTTP_CALLBACK_COMPLETED 0x30008 /* HTTP user callback completed the processing */ +#define NX_WEB_HTTP_POOL_ERROR 0x30009 /* HTTP supplied pool payload is too small */ +#define NX_WEB_HTTP_NOT_READY 0x3000A /* HTTP client not ready for operation */ +#define NX_WEB_HTTP_GET_DONE 0x3000C /* HTTP client get is complete */ +#define NX_WEB_HTTP_BAD_PACKET_LENGTH 0x3000D /* Invalid packet received - length incorrect */ +#define NX_WEB_HTTP_REQUEST_UNSUCCESSFUL_CODE 0x3000E /* Received an error code instead of 2xx from server */ +#define NX_WEB_HTTP_INCOMPLETE_PUT_ERROR 0x3000F /* Server responds before PUT is complete */ +#define NX_WEB_HTTP_PASSWORD_TOO_LONG 0x30011 /* Password exceeded expected length */ +#define NX_WEB_HTTP_USERNAME_TOO_LONG 0x30012 /* Username exceeded expected length */ +#define NX_WEB_HTTP_NO_QUERY_PARSED 0x30013 /* Server unable to find query in client request */ +#define NX_WEB_HTTP_METHOD_ERROR 0x30014 /* Client method (e.g. GET, POST) was missing required information. */ +#define NX_WEB_HTTP_IMPROPERLY_TERMINATED_PARAM 0x30015 /* Client request parameter not properly terminated */ +#define NX_WEB_HTTP_BOUNDARY_ALREADY_FOUND 0x30016 /* Boundary is already found. */ +#define NX_WEB_HTTP_MISSING_CONTENT_LENGTH 0x30017 /* The Content-Length header was not found. */ +#define NX_WEB_HTTP_EXTENSION_NOT_FOUND 0x30018 /* A searched-for HTTP type extension was not found. */ +#define NX_WEB_HTTP_EXTENSION_MIME_DEFAULT 0x30019 /* No matching extension found, return default. */ +#define NX_WEB_HTTP_STATUS_CODE_CONTINUE 0x3001A /* "100 Continue" */ +#define NX_WEB_HTTP_STATUS_CODE_SWITCHING_PROTOCOLS 0x3001B /* "101 Switching Protocols" */ +#define NX_WEB_HTTP_STATUS_CODE_CREATED 0x3001C /* "201 Created" */ +#define NX_WEB_HTTP_STATUS_CODE_ACCEPTED 0x3001D /* "202 Accepted" */ +#define NX_WEB_HTTP_STATUS_CODE_NON_AUTH_INFO 0x3001E /* "203 Non-Authoritative Information" */ +#define NX_WEB_HTTP_STATUS_CODE_NO_CONTENT 0x3001F /* "204 No Content" */ +#define NX_WEB_HTTP_STATUS_CODE_RESET_CONTENT 0x30020 /* "205 Reset Content" */ +#define NX_WEB_HTTP_STATUS_CODE_PARTIAL_CONTENT 0x30021 /* "206 Partial Content" */ +#define NX_WEB_HTTP_STATUS_CODE_MULTIPLE_CHOICES 0x30022 /* "300 Multiple Choices" */ +#define NX_WEB_HTTP_STATUS_CODE_MOVED_PERMANETLY 0x30023 /* "301 Moved Permanently" */ +#define NX_WEB_HTTP_STATUS_CODE_FOUND 0x30024 /* "302 Found" */ +#define NX_WEB_HTTP_STATUS_CODE_SEE_OTHER 0x30025 /* "303 See Other" */ +#define NX_WEB_HTTP_STATUS_CODE_NOT_MODIFIED 0x30026 /* "304 Not Modified" */ +#define NX_WEB_HTTP_STATUS_CODE_USE_PROXY 0x30027 /* "305 Use Proxy" */ +#define NX_WEB_HTTP_STATUS_CODE_TEMPORARY_REDIRECT 0x30028 /* "307 Temporary Redirect" */ +#define NX_WEB_HTTP_STATUS_CODE_BAD_REQUEST 0x30029 /* "400 Bad Request" */ +#define NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED 0x3002A /* "401 Unauthorized" */ +#define NX_WEB_HTTP_STATUS_CODE_PAYMENT_REQUIRED 0x3002B /* "402 Payment Required" */ +#define NX_WEB_HTTP_STATUS_CODE_FORBIDDEN 0x3002C /* "403 Forbidden" */ +#define NX_WEB_HTTP_STATUS_CODE_NOT_FOUND 0x3002D /* "404 Not Found" */ +#define NX_WEB_HTTP_STATUS_CODE_METHOD_NOT_ALLOWED 0x3002E /* "405 Method Not Allowed" */ +#define NX_WEB_HTTP_STATUS_CODE_NOT_ACCEPTABLE 0x3002F /* "406 Not Acceptable" */ +#define NX_WEB_HTTP_STATUS_CODE_PROXY_AUTH_REQUIRED 0x30030 /* "407 Proxy Authentication Required" */ +#define NX_WEB_HTTP_STATUS_CODE_REQUEST_TIMEOUT 0x30031 /* "408 Request Time-out" */ +#define NX_WEB_HTTP_STATUS_CODE_CONFLICT 0x30032 /* "409 Conflict" */ +#define NX_WEB_HTTP_STATUS_CODE_GONE 0x30033 /* "410 Gone" */ +#define NX_WEB_HTTP_STATUS_CODE_LENGTH_REQUIRED 0x30034 /* "411 Length Required" */ +#define NX_WEB_HTTP_STATUS_CODE_PRECONDITION_FAILED 0x30035 /* "412 Precondition Failed" */ +#define NX_WEB_HTTP_STATUS_CODE_ENTITY_TOO_LARGE 0x30036 /* "413 Request Entity Too Large" */ +#define NX_WEB_HTTP_STATUS_CODE_URL_TOO_LARGE 0x30037 /* "414 Request-URL Too Large" */ +#define NX_WEB_HTTP_STATUS_CODE_UNSUPPORTED_MEDIA 0x30038 /* "415 Unsupported Media Type" */ +#define NX_WEB_HTTP_STATUS_CODE_RANGE_NOT_SATISFY 0x30039 /* "416 Requested range not satisfiable" */ +#define NX_WEB_HTTP_STATUS_CODE_EXPECTATION_FAILED 0x3003A /* "417 Expectation Failed" */ +#define NX_WEB_HTTP_STATUS_CODE_INTERNAL_ERROR 0x3003B /* "500 Internal Server Error" */ +#define NX_WEB_HTTP_STATUS_CODE_NOT_IMPLEMENTED 0x3003C /* "501 Not Implemented" */ +#define NX_WEB_HTTP_STATUS_CODE_BAD_GATEWAY 0x3003D /* "502 Bad Gateway" */ +#define NX_WEB_HTTP_STATUS_CODE_SERVICE_UNAVAILABLE 0x3003E /* "503 Service Unavailable" */ +#define NX_WEB_HTTP_STATUS_CODE_GATEWAY_TIMEOUT 0x3003F /* "504 Gateway Time-out" */ +#define NX_WEB_HTTP_STATUS_CODE_VERSION_ERROR 0x30040 /* "505 HTTP Version not supported" */ +#define NX_WEB_HTTP_AUTHENTICATION_ERROR NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED /* HTTP client authentication failed */ + +/* Define the HTTP Server TCP port number */ + +#define NX_WEB_HTTP_SERVER_PORT 80 /* Port for HTTP server */ +#define NX_WEB_HTTPS_SERVER_PORT 443 /* Port for HTTPS server. */ + +/* Define constants for the various HTTP methods supported. */ +#define NX_WEB_HTTP_METHOD_NONE 0x0 +#define NX_WEB_HTTP_METHOD_GET 0x1 +#define NX_WEB_HTTP_METHOD_PUT 0x2 +#define NX_WEB_HTTP_METHOD_POST 0x3 +#define NX_WEB_HTTP_METHOD_DELETE 0x4 +#define NX_WEB_HTTP_METHOD_HEAD 0x5 + +/* Define status codes. */ +#define NX_WEB_HTTP_STATUS_CONTINUE "100 Continue" +#define NX_WEB_HTTP_STATUS_SWITCHING_PROTOCOLS "101 Switching Protocols" +#define NX_WEB_HTTP_STATUS_OK "200 OK" +#define NX_WEB_HTTP_STATUS_CREATED "201 Created" +#define NX_WEB_HTTP_STATUS_ACCEPTED "202 Accepted" +#define NX_WEB_HTTP_STATUS_NON_AUTH_INFO "203 Non-Authoritative Information" +#define NX_WEB_HTTP_STATUS_NO_CONTENT "204 No Content" +#define NX_WEB_HTTP_STATUS_RESET_CONTENT "205 Reset Content" +#define NX_WEB_HTTP_STATUS_PARTIAL_CONTENT "206 Partial Content" +#define NX_WEB_HTTP_STATUS_MULTIPLE_CHOICES "300 Multiple Choices" +#define NX_WEB_HTTP_STATUS_MOVED_PERMANETLY "301 Moved Permanently" +#define NX_WEB_HTTP_STATUS_FOUND "302 Found" +#define NX_WEB_HTTP_STATUS_SEE_OTHER "303 See Other" +#define NX_WEB_HTTP_STATUS_NOT_MODIFIED "304 Not Modified" +#define NX_WEB_HTTP_STATUS_USE_PROXY "305 Use Proxy" +#define NX_WEB_HTTP_STATUS_TEMPORARY_REDIRECT "307 Temporary Redirect" +#define NX_WEB_HTTP_STATUS_BAD_REQUEST "400 Bad Request" +#define NX_WEB_HTTP_STATUS_UNAUTHORIZED "401 Unauthorized" +#define NX_WEB_HTTP_STATUS_PAYMENT_REQUIRED "402 Payment Required" +#define NX_WEB_HTTP_STATUS_FORBIDDEN "403 Forbidden" +#define NX_WEB_HTTP_STATUS_NOT_FOUND "404 Not Found" +#define NX_WEB_HTTP_STATUS_METHOD_NOT_ALLOWED "405 Method Not Allowed" +#define NX_WEB_HTTP_STATUS_NOT_ACCEPTABLE "406 Not Acceptable" +#define NX_WEB_HTTP_STATUS_PROXY_AUTH_REQUIRED "407 Proxy Authentication Required" +#define NX_WEB_HTTP_STATUS_REQUEST_TIMEOUT "408 Request Time-out" +#define NX_WEB_HTTP_STATUS_CONFLICT "409 Conflict" +#define NX_WEB_HTTP_STATUS_GONE "410 Gone" +#define NX_WEB_HTTP_STATUS_LENGTH_REQUIRED "411 Length Required" +#define NX_WEB_HTTP_STATUS_PRECONDITION_FAILED "412 Precondition Failed" +#define NX_WEB_HTTP_STATUS_ENTITY_TOO_LARGE "413 Request Entity Too Large" +#define NX_WEB_HTTP_STATUS_URL_TOO_LARGE "414 Request-URL Too Large" +#define NX_WEB_HTTP_STATUS_UNSUPPORTED_MEDIA "415 Unsupported Media Type" +#define NX_WEB_HTTP_STATUS_RANGE_NOT_SATISFY "416 Requested range not satisfiable" +#define NX_WEB_HTTP_STATUS_EXPECTATION_FAILED "417 Expectation Failed" +#define NX_WEB_HTTP_STATUS_INTERNAL_ERROR "500 Internal Server Error" +#define NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED "501 Not Implemented" +#define NX_WEB_HTTP_STATUS_BAD_GATEWAY "502 Bad Gateway" +#define NX_WEB_HTTP_STATUS_SERVICE_UNAVAILABLE "503 Service Unavailable" +#define NX_WEB_HTTP_STATUS_GATEWAY_TIMEOUT "504 Gateway Time-out" +#define NX_WEB_HTTP_STATUS_VERSION_ERROR "505 HTTP Version not supported" + + +/* Define the max length of header field. */ + +#ifndef NX_WEB_HTTP_MAX_HEADER_FIELD +#define NX_WEB_HTTP_MAX_HEADER_FIELD 256 +#endif + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_WEB_HTTP_COMMON_H */ diff --git a/addons/web/nx_web_http_server.c b/addons/web/nx_web_http_server.c new file mode 100644 index 00000000..f0d77229 --- /dev/null +++ b/addons/web/nx_web_http_server.c @@ -0,0 +1,11103 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Web Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_WEB_HTTP_SERVER_SOURCE_CODE + + +/* Force error checking to be disabled in this module */ + +#ifndef NX_DISABLE_ERROR_CHECKING +#define NX_DISABLE_ERROR_CHECKING +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_web_http_server.h" + +#include "stdio.h" +#include "string.h" +#ifdef NX_WEB_HTTP_DIGEST_ENABLE +#include "nx_md5.h" +#endif + +#if defined(NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH) && !defined(NX_WEB_HTTP_KEEPALIVE_DISABLE) +#error "Content length needed when keepalive is enabled" +#endif /* NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH */ + +/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing + into this array yields the base64 representation of the 6bit number. */ + +CHAR _nx_web_http_server_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE +/* Define the default nonce, used only for MD5 authentication. For security reasons, this ASCII value should + change over time. */ + +CHAR _nx_web_http_server_nonce[] = "a4b8c8d7e0f6a7b2c3d2e4f5a4b7c5d2e7f"; +#endif + +/* Define date strings. */ +const CHAR _nx_web_http_server_weekday[][3] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +const CHAR _nx_web_http_server_month[][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +/* Define basic MIME maps. */ +static NX_WEB_HTTP_SERVER_MIME_MAP _nx_web_http_server_mime_maps[] = +{ + {"html", "text/html"}, + {"htm", "text/html"}, + {"txt", "text/plain"}, + {"gif", "image/gif"}, + {"jpg", "image/jpeg"}, + {"ico", "image/x-icon"}, +}; + + +/* Create two arrays to hold encoded and decoded username/password data. */ +static CHAR authorization_request[NX_WEB_HTTP_MAX_STRING + 1]; +static CHAR authorization_decoded[NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 2]; + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_content_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP content get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_content_get Actual server content get call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server content get function. */ + status = _nx_web_http_server_content_get(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_content_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the user's specified portion of the HTTP */ +/* content. Content is typically included in POST and PUT requests */ +/* from the client. This routine is designed to be called from the */ +/* application's request notify callback. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_content_get_extended */ +/* Get content data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ +UINT status; + + /* Get content data. */ + status = _nx_web_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_packet_content_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP packet content find */ +/* call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to pointer to the */ +/* packet that contains the */ +/* HTTP header */ +/* content_length Pointer to content length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_packet_content_find */ +/* Actual server packet content */ +/* find call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) +{ + + + /* Check for invalid packet pointer. */ + if((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (*packet_ptr == NX_NULL) || (content_length == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server content length get function. */ + return(_nx_web_http_server_packet_content_find(server_ptr, packet_ptr, content_length)); + +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_packet_content_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the content length specified in the HTTP */ +/* header, and move the nx_packet_prepend_ptr to the beginning of */ +/* the content. If the beginning of the content is not in the packet, */ +/* this function attempts to read the HTTP server socket for the */ +/* next packet. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to pointer to the */ +/* packet that contains the */ +/* HTTP header */ +/* content_length Pointer to content length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_content_length_get */ +/* Get content length */ +/* _nx_web_http_server_packet_get Receive another packet */ +/* _nx_web_http_server_calculate_content_offset */ +/* Pickup content offset */ +/* nx_packet_allocate Allocate a new packet */ +/* nx_packet_release Release the packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) +{ + +ULONG get_offset; +UINT status; +ULONG length = 0; +UINT packet_chunked; +NX_PACKET *header_packet_ptr; +NX_PACKET *new_packet_ptr; +ULONG temp_offset; + + /* Check if the packet is chunked. */ + packet_chunked = _nx_web_http_server_chunked_check(*packet_ptr); + + /* If the packet isn't chunked. */ + if (!packet_chunked) + { + + /* Get the content length header information. */ + status = _nx_web_http_server_content_length_get(*packet_ptr, &length); + + if (status != NX_SUCCESS) + { + return(status); + } + } + + /* Get the content offset. */ + get_offset = (ULONG)_nx_web_http_server_calculate_content_offset(*packet_ptr); + + /* Check packet length. */ + if((*packet_ptr) -> nx_packet_length == get_offset) + { + + /* If the packet doesn't contain any content, need to receive a new packet. */ + + /* If the received request packet is chunked. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* Initialize the request packet pointer and remaining size for processing chunked packet. */ + server_ptr -> nx_web_http_server_request_packet = NX_NULL; + server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; + } + + /* Make the receive call to obtain the next packet. */ + status = _nx_web_http_server_packet_get(server_ptr, packet_ptr); + + if(status != NX_SUCCESS) + { + return(NX_WEB_HTTP_TIMEOUT); + } + + } + else + { + + /* Separate the HTTP header and content. Copy the content to a new packet. */ + + /* Remember the packet pointer and content offset. */ + header_packet_ptr = *packet_ptr; + temp_offset = get_offset; + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* If the packet is chained, loop to find the end of the HTTP header. */ + while ((*packet_ptr) && (temp_offset > (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr))) + { + temp_offset -= (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr); + (*packet_ptr) = (*packet_ptr) -> nx_packet_next; + } + + /* If this packet contain no content, set next packet as the first packet of the content. */ + if (temp_offset == (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr)) + { + new_packet_ptr = (*packet_ptr) -> nx_packet_next; + } + else + { +#endif + + /* Allocate a new packet to store content. */ + status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, + &new_packet_ptr, 0, NX_WAIT_FOREVER); + if(status) + { + return(status); + } + + /* Copy the content part to the new packet. */ + nx_packet_data_append(new_packet_ptr, + (*packet_ptr) -> nx_packet_prepend_ptr + temp_offset, + (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr) - temp_offset, + server_ptr -> nx_web_http_server_packet_pool_ptr, + NX_WAIT_FOREVER); + + /* Update the append pointer of the header part. */ + (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + temp_offset; + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* Set the next packet of the content packet. */ + new_packet_ptr -> nx_packet_next = (*packet_ptr) -> nx_packet_next; + } + + /* Set the last packet of the content and header packet. */ + new_packet_ptr -> nx_packet_last = header_packet_ptr -> nx_packet_last; + header_packet_ptr -> nx_packet_last = (*packet_ptr); + (*packet_ptr) -> nx_packet_next = NX_NULL; +#endif + + /* Update the length of the header and content packet. */ + new_packet_ptr -> nx_packet_length = header_packet_ptr -> nx_packet_length - get_offset; + header_packet_ptr -> nx_packet_length = get_offset; + + /* Return the content packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* If the packet is chunked, set for processing chunked packet. */ + server_ptr -> nx_web_http_server_request_packet = new_packet_ptr; + server_ptr -> nx_web_http_server_chunked_request_remaining_size = new_packet_ptr -> nx_packet_length; + + /* Get the processed chunked packet. Set this packet as the returned packet. */ + status = _nx_web_http_server_packet_get(server_ptr, packet_ptr); + if (status) + { + return(status); + } + } + else + { + + /* Set the returned packet. */ + *packet_ptr = new_packet_ptr; + } + } + + /* Determine if there is content in this HTTP request. */ + if(content_length) + { + + if (packet_chunked) + { + + /* If the packet is chunked, set content length as packet length. */ + *content_length = (*packet_ptr) -> nx_packet_length; + } + else + { + + /* Set the content length as the length in HTTP header. */ + *content_length = length; + } + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_packet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server packet get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to the packet to */ +/* be returned. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_packet_get Actual server packet get call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ + + + /* Check for invalid packet pointer. */ + if((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server packet get function. */ + return(_nx_web_http_server_packet_get(server_ptr, packet_ptr)); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_packet_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function obtains the next packet from the HTTP server socket. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to the packet to */ +/* be returned. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_request_chunked_get */ +/* Get chunked request packet */ +/* _nx_web_http_server_receive Receive another packet */ +/* nx_packet_release Packet release */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ +NX_PACKET *new_packet_ptr; +UINT status; + + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* If the request packet is chunked, remove the chunk header and get the packet which contain the chunk data. */ + status = _nx_web_http_server_request_chunked_get(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); + } + else + { + + /* Receive another packet from client. */ + status = _nx_web_http_server_receive(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); + } + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* Reset the chunked info. */ + nx_packet_release(server_ptr -> nx_web_http_server_request_packet); + server_ptr -> nx_web_http_server_request_packet = NX_NULL; + server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; + server_ptr -> nx_web_http_server_request_chunked = NX_FALSE; + return(status); + } + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + *packet_ptr = new_packet_ptr; + + return(NX_SUCCESS); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_content_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP extended get content */ +/* service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_content_get_extended */ +/* Actual extended get content */ +/* get service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server content get function. */ + status = _nx_web_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_content_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the user's specified portion of the HTTP */ +/* content. Content is typically included in POST and PUT requests */ +/* from the client. This routine is designed to be called from the */ +/* application's request notify callback. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to HTTP request packet*/ +/* byte_offset Byte offset into content */ +/* destination_ptr Pointer to content destination*/ +/* destination_size Maximum size of destination */ +/* actual_size Actual amount of content */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_chunked_check Check if the packet is chunked*/ +/* _nx_web_http_server_packet_get Receive another packet */ +/* _nx_web_http_server_content_length_get */ +/* Get content length with error */ +/* status returned separately */ +/* content length value. */ +/* _nx_web_http_server_calculate_content_offset */ +/* Pickup content offset */ +/* _nx_web_http_server_packet_content_find */ +/* Get the content packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size) +{ + +ULONG content_length; +ULONG offset; +UINT status; +UINT remaining_bytes; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN +NX_PACKET *header_packet_ptr = NX_NULL; +#endif + + /* Default the actual size to zero. */ + *actual_size = 0; + + if (_nx_web_http_server_chunked_check(packet_ptr) == NX_FALSE) + { + + /* Determine if there is content in this HTTP request. */ + status = _nx_web_http_server_content_length_get(packet_ptr, &content_length); + + if (status != NX_SUCCESS) + { + return status; + } + + /* Make sure the content length is at least greater than the byte offset supplied. */ + if (content_length <= byte_offset) + { + + /* No more data in this buffer. */ + return(NX_WEB_HTTP_DATA_END); + } + + /* Determine if the destination size is greater than the content length. */ + if (destination_size > content_length) + { + + /* Yes, make the destination size equal to the content length. */ + destination_size = content_length; + } + + /* Add the byte offset with content offset. */ + byte_offset += ((ULONG) _nx_web_http_server_calculate_content_offset(packet_ptr)); + } + else + { +#ifdef NX_DISABLE_PACKET_CHAIN + + NX_PARAMETER_NOT_USED(server_ptr); + + return NX_WEB_HTTP_ERROR; +#else + + /* If never processed the chunked packet, need to separate the HTTP header and content. */ + if (!server_ptr -> nx_web_http_server_expect_receive_bytes) + { + + /* Remember the header packet. */ + header_packet_ptr = packet_ptr; + + /* Separate the HTTP header and get the first content packet. */ + status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); + if (status) + { + return(status); + } + } + else + { + + /* If the HTTP header and content is already separated, process this packet as normal packet. */ + byte_offset += ((ULONG) _nx_web_http_server_calculate_content_offset(packet_ptr)); + } +#endif + } + + /* Determine if we need to read one or more additional packets. */ + while (byte_offset >= packet_ptr -> nx_packet_length) + { + +#ifdef NX_DISABLE_PACKET_CHAIN + NX_PARAMETER_NOT_USED(server_ptr); + + return NX_WEB_HTTP_ERROR; +#else + /* Read another packet because the offset reaches past the current packet + length. */ + status = _nx_web_http_server_packet_get(server_ptr, &new_packet_ptr); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + /* Otherwise, we have a new packet to append to the head packet. */ + + /* Determine if the current packet is already chained. */ + if (packet_ptr -> nx_packet_next) + { + + /* Yes, link the current last packet to the new packet. */ + (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; + } + else + { + + /* Otherwise, this is our first chained packet. Link to the head. */ + packet_ptr -> nx_packet_next = new_packet_ptr; + } + + /* Is the new packet chained? */ + if (new_packet_ptr -> nx_packet_next) + { + + /* Yes, there is a last packet pointer. Point to this from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; + } + else + { + + /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ + packet_ptr -> nx_packet_last = new_packet_ptr; + } + + /* Update the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + +#ifndef NX_DISABLE_PACKET_CHAIN + if (header_packet_ptr) + { + + /* Append the content packet to the header packet. */ + if (header_packet_ptr -> nx_packet_next) + { + (header_packet_ptr -> nx_packet_last) -> nx_packet_next = packet_ptr; + } + else + { + header_packet_ptr -> nx_packet_next = packet_ptr; + } + + /* Update the last packet. */ + if (packet_ptr -> nx_packet_next) + { + header_packet_ptr -> nx_packet_last = packet_ptr -> nx_packet_last; + } + else + { + header_packet_ptr -> nx_packet_last = packet_ptr; + } + + /* Update the packet length. */ + header_packet_ptr -> nx_packet_length = header_packet_ptr -> nx_packet_length + packet_ptr -> nx_packet_length; + } +#endif + + /* Default the buffer pointer to NULL. */ + buffer_ptr = NX_NULL; + + /* Now find the packet that contains the offset. */ + offset = 0; + new_packet_ptr = packet_ptr; + do + { + + /* Determine if the get request falls into this packet. */ + if (byte_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) + { + + /* Yes, the get offset is in this packet. */ + + /* Setup the starting byte pointer. */ + buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (byte_offset - offset); + break; + } + + /* Otherwise update the offset. */ + offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + new_packet_ptr = NX_NULL; +#else + /* Move to next packet in the chain. */ + new_packet_ptr = new_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while (new_packet_ptr); + + /* Determine if an error occurred in the search. */ + if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) + return(NX_WEB_HTTP_ERROR); + + /* Now determine if the maximum buffer size has to be adjusted. */ + if (destination_size > (UINT) (packet_ptr -> nx_packet_length - byte_offset)) + { + + /* Adjust the destination size downward. */ + destination_size = (UINT) (packet_ptr -> nx_packet_length - byte_offset); + } + + /* Initialize the remaining bytes. */ + remaining_bytes = destination_size; + + /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ + while (remaining_bytes--) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + + /* If the packet is chained, copy the data in the chain. */ + if (buffer_ptr == (CHAR *)new_packet_ptr -> nx_packet_append_ptr) + { + new_packet_ptr = new_packet_ptr -> nx_packet_next; + buffer_ptr = (CHAR *)new_packet_ptr -> nx_packet_prepend_ptr; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Copy a byte to the destination. */ + *destination_ptr++ = *buffer_ptr++; + } + + /* Successful completion. */ + *actual_size = destination_size; + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP content length service. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP packet */ +/* content_length Pointer for returning content */ +/* length value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_content_length_get */ +/* Actual get content length call*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *content_length) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (content_length == NX_NULL)) + return(NX_PTR_ERROR); + + /* Call actual server content length get function. */ + status = _nx_web_http_server_content_length_get(packet_ptr, content_length); + + /* Return completion status. */ + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_content_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function find a valid content length field and returns a */ +/* successful completion status (NX_SUCCESS) if so. Otherwise it */ +/* it returns an error status. A valid content length value is */ +/* zero or more and matches the size of the message body. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* content_length Pointer to a valid Content */ +/* Length value */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Content length extracted */ +/* status Invalid content length */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Threads */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length) +{ + +CHAR *buffer_ptr; + + + /* Default the content length to no data. */ + *length = 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Content-length: " token first. */ + while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Content-length token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && + ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && + ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && + ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && + (*(buffer_ptr+7) == '-') && + ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && + ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && + ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && + ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && + ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && + ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && + (*(buffer_ptr+14) == ':') && + (*(buffer_ptr+15) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 16; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now convert the length into a numeric value. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + { + + /* Update the content length. */ + *length = *length * 10; + *length = *length + (((UINT) (*buffer_ptr)) - 0x30); + + /* Move the buffer pointer forward. */ + buffer_ptr++; + } + + /* Determine if the content length was picked up properly. */ + if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || + ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13))) + { + + /* Error, set the length to zero. */ + return NX_WEB_HTTP_INCOMPLETE_PUT_ERROR; + } + + /* Return successful completion status to the caller. */ + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server create call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* http_server_name Name of HTTP server */ +/* server_port Port to use for HTTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* authentication_check Pointer to application's */ +/* authentication checking */ +/* request_notify Pointer to application's */ +/* request notify service */ +/* http_server_size Size of HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_create Actual server create call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id == NX_WEB_HTTP_SERVER_ID) || + (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL) || + (http_server_size != sizeof(NX_WEB_HTTP_SERVER))) + return(NX_PTR_ERROR); + + /* Pickup a packet from the supplied packet pool. */ + packet_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ + if (((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) - NX_PHYSICAL_TRAILER) + < NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE) + return(NX_WEB_HTTP_POOL_ERROR); + + /* Call actual server create function. */ + status = _nx_web_http_server_create(http_server_ptr, http_server_name, ip_ptr, server_port, media_ptr, stack_ptr, stack_size, pool_ptr, + authentication_check, request_notify); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a HTTP server on the specified IP. In doing */ +/* so this function creates an TCP socket for subsequent HTTP */ +/* transfers and a thread for the HTTP server. */ +/* */ +/* Note: The string resource in callback functions authentication_check*/ +/* and request_notify is built by internal logic and always */ +/* NULL-terminated. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* http_server_name Name of HTTP server */ +/* server_port Port for HTTP server */ +/* ip_ptr Pointer to IP instance */ +/* media_ptr Pointer to media structure */ +/* stack_ptr Server thread's stack pointer */ +/* stack_size Server thread's stack size */ +/* pool_ptr Pointer to packet pool */ +/* authentication_check Pointer to application's */ +/* authentication checking */ +/* request_notify Pointer to application's */ +/* request notify service */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_create Create HTTP server socket */ +/* nx_tcp_socket_delete Delete the HTTP server socket */ +/* tx_thread_create Create the HTTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, + CHAR *http_server_name, NX_IP *ip_ptr, + UINT server_port, FX_MEDIA *media_ptr, + VOID *stack_ptr, ULONG stack_size, + NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, + UINT request_type, CHAR *resource, + CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, + CHAR *resource, NX_PACKET *packet_ptr)) +{ + +UINT status; + + + /* Clear the HTTP server structure. */ + memset((void *) http_server_ptr, 0, sizeof(NX_WEB_HTTP_SERVER)); + + /* Create the Server's TCP socket. */ + status = nx_tcpserver_create(ip_ptr, &http_server_ptr -> nx_web_http_server_tcpserver, http_server_name, + NX_WEB_HTTP_TYPE_OF_SERVICE, NX_WEB_HTTP_FRAGMENT_OPTION, NX_WEB_HTTP_TIME_TO_LIVE, + NX_WEB_HTTP_SERVER_WINDOW_SIZE, NX_NULL, + _nx_web_http_server_receive_data, _nx_web_http_server_connection_end, + _nx_web_http_server_connection_timeout, NX_WEB_HTTP_SERVER_TIMEOUT / NX_IP_PERIODIC_RATE, + stack_ptr, stack_size, http_server_ptr -> nx_web_http_server_session_buffer, + NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE, NX_WEB_HTTP_SERVER_PRIORITY, NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, return error code. */ + return(status); + } + + /* Store server ptr. */ + http_server_ptr -> nx_web_http_server_tcpserver.nx_tcpserver_reserved = (ULONG)http_server_ptr; + + /* Save the Server name. */ + http_server_ptr -> nx_web_http_server_name = http_server_name; + + /* Save the IP pointer address. */ + http_server_ptr -> nx_web_http_server_ip_ptr = ip_ptr; + + /* Save the packet pool pointer. */ + http_server_ptr -> nx_web_http_server_packet_pool_ptr = pool_ptr; + + /* Save the media pointer address. */ + http_server_ptr -> nx_web_http_server_media_ptr = media_ptr; + + /* Save the user-supplied routines, if specified. */ + http_server_ptr -> nx_web_http_server_authentication_check = authentication_check; + http_server_ptr -> nx_web_http_server_request_notify = request_notify; + + /* Set the server ID to indicate the HTTP server is ready. */ + http_server_ptr -> nx_web_http_server_id = NX_WEB_HTTP_SERVER_ID; + + /* Set the port to the default HTTP listening port (80). */ + http_server_ptr -> nx_web_http_server_listen_port = server_port; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server delete call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_delete Actual server delete call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_web_http_server_delete(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_socket_delete Delete the HTTP server socket */ +/* nx_tcp_socket_disconnect Disconnect HTTP server socket */ +/* nx_tcp_socket_unaccept Unaccept HTTP server connect */ +/* nx_tcp_socket_unlisten Unlisten on the HTTP port */ +/* tx_thread_delete Delete the HTTP server thread */ +/* tx_thread_suspend Suspend the HTTP server thread*/ +/* tx_thread_terminate Terminate the HTTP server */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr) +{ +UINT status; +NX_TCPSERVER *tcpserver_ptr = &(http_server_ptr -> nx_web_http_server_tcpserver); + + +#ifdef NX_WEB_HTTPS_ENABLE +UINT i; + + /* Stop TLS session if using HTTPS. */ + if(http_server_ptr -> nx_web_http_is_https_server) + { + for(i = 0; i < tcpserver_ptr -> nx_tcpserver_sessions_count; i++) + { + nx_secure_tls_session_end(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session), NX_WAIT_FOREVER); + nx_secure_tls_session_delete(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session)); + } + } + +#endif + + /* Delete the TCP server. */ + status = nx_tcpserver_delete(tcpserver_ptr); + + /* Clear the server ID to indicate the HTTP server is no longer ready. */ + http_server_ptr -> nx_web_http_server_id = 0; + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_param_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP parameter get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* param_number Parameter number (start at 0) */ +/* param_ptr Pointer to destination */ +/* max_param_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_param_get Actual server parameter get */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (param_ptr == NX_NULL) || (param_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server parameter get function. */ + status = _nx_web_http_server_param_get(packet_ptr, param_number, param_ptr, param_size, max_param_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_param_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the requested parameter specified in the URL */ +/* requested by the client. If the specified parameter is not present, */ +/* a not found error is returned to the caller. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* param_number Parameter number (start at 0) */ +/* param_ptr Pointer to destination */ +/* max_param_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size) +{ + +UINT i; +UINT current_param; +CHAR *buffer_ptr; + + + /* Set the destination string to NULL. */ + param_ptr[0] = (CHAR) NX_NULL; + *param_size = 0; + + /* Set current parameter to 0. */ + current_param = 0; + + /* Setup a pointer to the HTTP buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Position to the start of the URL. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Move the buffer pointer. */ + buffer_ptr++; + } + + /* Not find URL. */ + if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) + { + return(NX_WEB_HTTP_NOT_FOUND); + } + + /* Loop through the buffer to search for the specified parameter. */ + do + { + + /* Determine if the character is a semicolon, indicating a parameter + is present. */ + if (*buffer_ptr == ';') + { + + /* Yes, a parameter is present. */ + + /* Move the buffer pointer forward. */ + buffer_ptr++; + + /* Is this the parameter requested? */ + if (current_param == param_number) + { + + + /* Yes, we have found the parameter. */ + for (i = 0; i < max_param_size; i++) + { + + /* Check if reach the end of the packet data. */ + if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + return(NX_WEB_HTTP_NOT_FOUND); + } + + /* Check for end of parameter. */ + if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || + (*buffer_ptr == '&') || (*buffer_ptr == ' ') || + (*buffer_ptr == (CHAR) 13)) + { + + /* Yes, we are finished and need to get out of the loop. */ + break; + } + + /* Otherwise, store the character in the destination. */ + param_ptr[i] = *buffer_ptr++; + } + + /* NULL terminate the parameter. */ + if (i < max_param_size) + { + param_ptr[i] = (CHAR) NX_NULL; + } + + /* Return to caller. */ + if (param_ptr[i] == (CHAR) NX_NULL) + { + *param_size = i; + return(NX_SUCCESS); + } + else + { + return(NX_WEB_HTTP_IMPROPERLY_TERMINATED_PARAM); + } + } + else + { + + /* Increment the current parameter. */ + current_param++; + } + } + else + { + + /* Check for any other character that signals the end of the param list. */ + if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == '&')) + break; + + /* Update the buffer pointer. */ + buffer_ptr++; + } + + } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); + + /* Return a not found error. */ + return(NX_WEB_HTTP_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_query_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP query get call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* query_number Query number (start at 0) */ +/* query_ptr Pointer to destination */ +/* query_size Pointer to data size return */ +/* max_query_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_query_get Actual server query get */ +/* call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (query_ptr == NX_NULL) || (query_size == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server query get function. */ + status = _nx_web_http_server_query_get(packet_ptr, query_number, query_ptr, query_size, max_query_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_query_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the requested query specified in the URL */ +/* requested by the client. If the specified query is not present, */ +/* a not found error is returned to the caller. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to HTTP request packet*/ +/* query_number Query number (start at 0) */ +/* query_ptr Pointer to destination */ +/* query_size Pointer to data size return */ +/* max_query_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size) +{ + +UINT i; +UINT current_query; +CHAR *buffer_ptr; + + + /* Set the destination string to NULL. */ + query_ptr[0] = (CHAR) NX_NULL; + *query_size = 0; + + /* Set current query number to 0. */ + current_query = 0; + + /* Setup a pointer to the HTTP buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Position to the start of the URL. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Move the buffer pointer. */ + buffer_ptr++; + } + + /* Not find URL. */ + if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) + { + return(NX_WEB_HTTP_NOT_FOUND); + } + + /* Loop through the buffer to search for the specified query instance. */ + do + { + + /* Determine if the character is a '?' or a '&', indicating a query + is present. */ + if (((*buffer_ptr == '?') && (current_query == 0)) || + ((*buffer_ptr == '&') && (current_query != 0))) + { + + /* Yes, a query is present. */ + + /* Move the buffer pointer forward. */ + buffer_ptr++; + + /* Is this the query requested? */ + if (current_query == query_number) + { + + + /* Yes, we have found the query. */ + for (i = 0; i < max_query_size; i++) + { + + /* Check if reach the end of the packet data. */ + if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + return(NX_WEB_HTTP_NOT_FOUND); + } + + /* Check for end of query. */ + if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || + (*buffer_ptr == '&') || (*buffer_ptr == ' ') || + (*buffer_ptr == (CHAR) 13)) + { + + /* Yes, we are finished and need to get out of the loop. */ + break; + } + + /* Otherwise, store the character in the destination. */ + query_ptr[i] = *buffer_ptr++; + } + + /* NULL terminate the query. */ + query_ptr[i] = (CHAR) NX_NULL; + + /* Return to caller. */ + if (i) + { + *query_size = i; + return(NX_SUCCESS); + } + else + { + return(NX_WEB_HTTP_NO_QUERY_PARSED); + } + } + else + { + + /* Increment the current query. */ + current_query++; + } + } + else + { + + /* Check for any other character that signals the end of the query list. */ + if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == ';')) + break; + + /* Update the buffer pointer. */ + buffer_ptr++; + } + + } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); + + /* Return a not found error. */ + return(NX_WEB_HTTP_NOT_FOUND); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server start call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_start Actual server start call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nx_web_http_server_start(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_start PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function starts a previously created HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_server_socket_listen Start listening on HTTP port */ +/* tx_thread_resume Resume the HTTP server thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr) +{ + +UINT status; +UINT port; + + port = http_server_ptr -> nx_web_http_server_listen_port; + + /* Start listening on the HTTP server port. */ + status = nx_tcpserver_start(&http_server_ptr -> nx_web_http_server_tcpserver, port, NX_WEB_HTTP_SERVER_MAX_PENDING); + + /* Determine if the listen was unsuccessful. */ + if (status != NX_SUCCESS) + { + /* Just return an HTTP error. */ + return(status); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +#ifdef NX_WEB_HTTPS_ENABLE + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_secure_configure PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTPS configuration call. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* crypto_table TLS cryptographic routines */ +/* metadata_buffer Cryptographic metadata buffer */ +/* metadata_size Size of metadata buffer */ +/* packet_buffer TLS packet buffer */ +/* packet_size Size of packet buffer */ +/* identity_certificate TLS server certificate */ +/* trusted_certificates TLS trusted certificates */ +/* trusted_certs_num Number of trusted certs */ +/* remote_certificates Remote certificates array */ +/* remote_certs_num Number of remote certificates */ +/* remote_certificate_buffer Buffer for remote certs */ +/* remote_cert_buffer_size Size of remote cert buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_secure_configure Actual server configure call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, + UCHAR* packet_buffer, UINT packet_buffer_size, + NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], + UINT trusted_certs_num, + NX_SECURE_X509_CERT *remote_certificates[], + UINT remote_certs_num, + UCHAR *remote_certificate_buffer, + UINT remote_cert_buffer_size) +{ + +UINT status; + + + /* Check for invalid input pointers. Note that the remote certificates array and buffer + * may be NX_NULL for the HTTPS server since remote certificates are optional for TLS Server.*/ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + crypto_table == NX_NULL || metadata_buffer == NX_NULL || packet_buffer == NX_NULL || + identity_certificate == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call actual server start function. */ + status = _nx_web_http_server_secure_configure(http_server_ptr, crypto_table, metadata_buffer, metadata_size, + packet_buffer, packet_buffer_size, identity_certificate, + trusted_certificates, trusted_certs_num, + remote_certificates, remote_certs_num, remote_certificate_buffer, + remote_cert_buffer_size); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_secure_configure PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function configures a previously created NetX Web HTTP server */ +/* instance to use TLS for secure HTTPS communications. The parameters */ +/* are used to configure all the possible TLS sessions with identical */ +/* state so that each incoming HTTPS client experiences consistent */ +/* behavior. The number of TLS sessions is controlled using the macro */ +/* NX_WEB_HTTP_SERVER_SESSION_MAX. */ +/* */ +/* The cryptographic routine table (ciphersuite table) is shared */ +/* between all TLS sessions as it just contains function pointers. */ +/* */ +/* The metadata buffer and packet reassembly buffer are divided */ +/* equally between all TLS sessions. If the buffer size is not evenly */ +/* divisible by the number of sessions the remainder will be unused. */ +/* */ +/* The passed-in identity certificate is used by all sessions. During */ +/* TLS operation the server identity certificate is only read from so */ +/* copies are not needed for each session. */ +/* */ +/* The trusted certificates are added to the trusted store for each */ +/* TLS session in the server. This is used for client certificate */ +/* verification which is enabled if remote certificates are provided. */ +/* */ +/* The remote certificate array and buffer is shared by default */ +/* between all TLS sessions. This does mean that some sessions may */ +/* block during certificate validation. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* crypto_table TLS cryptographic routines */ +/* metadata_buffer Cryptographic metadata buffer */ +/* metadata_size Size of metadata buffer */ +/* packet_buffer TLS packet buffer */ +/* packet_size Size of packet buffer */ +/* identity_certificate TLS server certificate */ +/* trusted_certificates TLS trusted certificates */ +/* trusted_certs_num Number of trusted certs */ +/* remote_certificates Remote certificates array */ +/* remote_certs_num Number of remote certificates */ +/* remote_certificate_buffer Buffer for remote certs */ +/* remote_cert_buffer_size Size of remote cert buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcpserver_tls_setup Socket server TLS configure */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, + UCHAR* packet_buffer, UINT packet_buffer_size, + NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], + UINT trusted_certs_num, + NX_SECURE_X509_CERT *remote_certificates[], + UINT remote_certs_num, + UCHAR *remote_certificate_buffer, + UINT remote_cert_buffer_size) +{ + +UINT status; + + /* This is a secure HTTP server, so set HTTPS flag. */ + http_server_ptr -> nx_web_http_is_https_server = NX_TRUE; + + /* Configure TLS for the socket server. */ + status = nx_tcpserver_tls_setup(&http_server_ptr->nx_web_http_server_tcpserver, + crypto_table, metadata_buffer, metadata_size, + packet_buffer, packet_buffer_size, identity_certificate, + trusted_certificates, trusted_certs_num, + remote_certificates, remote_certs_num, + remote_certificate_buffer,remote_cert_buffer_size); + + /* Return result of TLS setup. */ + return(status); +} + +#endif /* NX_WEB_HTTPS_ENABLE */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP server stop call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_stop Actual server stop call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server stop function. */ + status = _nx_web_http_server_stop(http_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_stop PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function stops a previously started HTTP server on the */ +/* specified IP. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_tcpserver_stop Suspend the HTTP server thread*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr) +{ +UINT status; +NX_TCPSERVER *tcpserver_ptr = &(http_server_ptr -> nx_web_http_server_tcpserver); + +#ifdef NX_WEB_HTTPS_ENABLE +UINT i; + + /* Stop TLS session if using HTTPS. */ + if(http_server_ptr -> nx_web_http_is_https_server) + { + for(i = 0; i < tcpserver_ptr -> nx_tcpserver_sessions_count; i++) + { + nx_secure_tls_session_end(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session), NX_WAIT_FOREVER); + } + } +#endif + + /* Suspend the HTTP server thread. */ + status = nx_tcpserver_stop(tcpserver_ptr); + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_data_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the data send call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* data_ptr Pointer to data to send */ +/* data_length Length of data to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_callback_data_send */ +/* Actual function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) +{ +UINT status; + + /* Check pointers. */ + if(server_ptr == NX_NULL || data_ptr == NX_NULL || server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) + { + return(NX_PTR_ERROR); + } + + /* Actual function call. */ + status = _nx_web_http_server_callback_data_send(server_ptr, data_ptr, data_length); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_data_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends data to the client from the application */ +/* callback function. This is typically done to satisfy a GET or */ +/* POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* data_ptr Pointer to data to send */ +/* data_length Length of data to send */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_response_packet_allocate */ +/* Allocate a resonse packet */ +/* nx_packet_data_append Append data to packet */ +/* nx_tcp_socket_send Send TCP data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) +{ + +NX_PACKET *new_packet_ptr; +UINT status; + + + /* Allocate a new packet for data. */ + status = _nx_web_http_server_response_packet_allocate(server_ptr, &new_packet_ptr, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Error, return to caller. */ + return(NX_WEB_HTTP_ERROR); + } + + /* Now append the data to the packet. */ + status = nx_packet_data_append(new_packet_ptr, data_ptr, data_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Release the initial packet. */ + nx_packet_release(new_packet_ptr); + + /* Error, return to caller. */ + return(status); + } + + /* Send the data back to the client. */ + status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Determine if this is successful. */ + if (status != NX_SUCCESS) + { + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + } + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the response send call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* status_code Status-code and reason-phrase */ +/* information Pointer to HTTP info string */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_server_callback_response_send */ +/* Actual function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info) +{ +UINT status; + + if(server_ptr == NX_NULL || status_code == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Actual function call. */ + status = _nx_web_http_server_callback_response_send(server_ptr, status_code, information, additional_info); + + /* Return successful completion. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the completion response to the client from the */ +/* application callback function. This is typically done to satisfy a */ +/* GET or POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* status_code Status-code and reason-phrase */ +/* information Pointer to HTTP info string */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_response_send Send HTTP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info) +{ + +UINT status_code_length = 0; +UINT information_length = 0; +UINT additional_info_length = 0; +UINT status; + + + /* Check length of header, information and additional information. */ + if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || + (information && _nx_utility_string_length_check(information, &information_length, NX_MAX_STRING_LENGTH)) || + (additional_info && _nx_utility_string_length_check(additional_info, &additional_info_length, NX_MAX_STRING_LENGTH))) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + status = _nx_web_http_server_response_send(server_ptr, status_code, status_code_length, information, + information_length, additional_info, additional_info_length); + + /* Return status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_response_send_extended */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the response send call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* information Pointer to HTTP info string */ +/* information_length Length of information */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* additional_information_length Length of additional */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_server_callback_response_send_extended */ +/* Actual function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_info, + UINT additional_information_length) +{ +UINT status; + + if(server_ptr == NX_NULL || status_code == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Actual function call. */ + status = _nx_web_http_server_callback_response_send_extended(server_ptr, status_code, status_code_length, + information, information_length, + additional_info, additional_information_length); + + /* Return successful completion. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_response_send_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the completion response to the client from the */ +/* application callback function. This is typically done to satisfy a */ +/* GET or POST request that is processed completely by the application */ +/* callback function. */ +/* */ +/* Note: The strings of status_code, information and */ +/* additional_information must be NULL-terminated and length of each */ +/* string matches the length specified in the argument list. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* information Pointer to HTTP info string */ +/* information_length Length of information */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* additional_information_length Length of additional */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_response_send Send HTTP response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_info, + UINT additional_info_length) +{ +UINT temp_status_code_length = 0; +UINT temp_information_length = 0; +UINT temp_additional_info_length = 0; + + /* Check length of status_code, information and additional information. */ + if (_nx_utility_string_length_check(status_code, &temp_status_code_length, NX_MAX_STRING_LENGTH) || + (information && _nx_utility_string_length_check(information, &temp_information_length, NX_MAX_STRING_LENGTH)) || + (additional_info && _nx_utility_string_length_check(additional_info, &temp_additional_info_length, NX_MAX_STRING_LENGTH))) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Validate string length. */ + if ((temp_status_code_length != status_code_length) || + (information && (temp_information_length != information_length)) || + (additional_info && (temp_additional_info_length != additional_info_length))) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + return(_nx_web_http_server_response_send(server_ptr, status_code, status_code_length, information, + information_length, additional_info, additional_info_length)); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_connection_end PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is an internal callback used by the TCP server when a */ +/* TCP connection is ready to close. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tcpserver_ptr Pointer to TCP server */ +/* session_ptr Pointer to TCP session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_connection_disconnect */ +/* Disconnect TCP or TLS */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_connection_end(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) +{ +NX_WEB_HTTP_SERVER *server_ptr; + + + /* Get the HTTP server pointer. */ + server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; + + /* Disconnect the TCP server (and end TLS if used). */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_connection_timeout PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is an internal callback used by the TCP server when a */ +/* TCP connection times out. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* tcpserver_ptr Pointer to TCP server */ +/* session_ptr Pointer to TCP session */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_connection_disconnect */ +/* Disconnect TCP or TLS */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_connection_timeout(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) +{ +NX_WEB_HTTP_SERVER *server_ptr; + + + /* Get the HTTP server pointer. */ + server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; + + /* Disconnect the TCP server (and end TLS if used). */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_connection_present PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the callback function executed whenever a client */ +/* connection appears on the HTTP Server port. It is responsible for */ +/* waking up the HTTP Server thread. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to HTTP Server socket */ +/* port HTTP Server port */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_get_client_request */ +/* Get request from client */ +/* _nx_web_http_server_connection_disconnect */ +/* Disconnect connection */ +/* _nx_web_http_server_get_client_keepalive */ +/* Get keepalive flag */ +/* _nx_web_http_server_chunked_check Check if the packet is chunked*/ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* _nx_web_http_server_delete_process Process DELETE request */ +/* _nx_web_http_server_response_packet_allocate */ +/* Allocate a response packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_receive_data(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) +{ + +NX_WEB_HTTP_SERVER *server_ptr; +NX_PACKET *packet_ptr; +UCHAR *buffer_ptr; +UINT status; +NX_PACKET *response_pkt; + + + /* Set the HTTP server pointer. */ + server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; + + /* Store the current session. */ + server_ptr -> nx_web_http_server_current_session_ptr = session_ptr; + + /* Get the complete HTTP client request. */ + status = _nx_web_http_server_get_client_request(server_ptr, &packet_ptr); + + /* Check if the HTTP request is valid. */ + if (status == NX_SUCCESS) + { + if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 7) + { + nx_packet_release(packet_ptr); + status = NX_WEB_HTTP_ERROR; + } + } + + /* Determine if it was successful. */ + if (status != NX_SUCCESS) + { + + if(status != NX_NO_PACKET) + { + + /* Increment the number of invalid HTTP requests. */ + server_ptr -> nx_web_http_server_invalid_http_headers++; + } + + /* Disconnect from the current connection. */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); + + /* Return. */ + return; + } + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + /* Check whether keepalive is necessary. */ + _nx_web_http_server_get_client_keepalive(server_ptr, packet_ptr); +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* Check if the packet is chunked. */ + server_ptr -> nx_web_http_server_request_chunked = (UCHAR)_nx_web_http_server_chunked_check(packet_ptr); + server_ptr -> nx_web_http_server_expect_receive_bytes = 0; + server_ptr -> nx_web_http_server_actual_bytes_received = 0; + + /* Otherwise, we have received an HTTP client request successfully. */ + + /* Setup a pointer to packet buffer area. */ + buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Determine what type of request is present. */ + + /* Check for a GET request. */ + if ((buffer_ptr[0] == 'G') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) + { + + /* We have a HTTP GET request to get a resource from this HTTP Server. */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_GET_REQUEST; + + /* Increment the number of GET requests. */ + server_ptr -> nx_web_http_server_get_requests++; + + /* Process the GET request. */ + _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_GET_REQUEST, packet_ptr); + } + + /* Check for a PUT request. */ + else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'U') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) + { + + /* We have a HTTP PUT request to store a resource on this HTTP Server. */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_PUT_REQUEST; + + /* Increment the number of PUT requests. */ + server_ptr -> nx_web_http_server_put_requests++; + + /* Process the PUT request. */ + _nx_web_http_server_put_process(server_ptr, packet_ptr); + } + + /* Check for a DELETE request. */ + else if ((buffer_ptr[0] == 'D') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'L') && (buffer_ptr[3] == 'E') && + (buffer_ptr[4] == 'T') && (buffer_ptr[5] == 'E') && (buffer_ptr[6] == ' ')) + { + + /* We have a HTTP DELETE request to delete a resource from this HTTP Server. */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_DELETE_REQUEST; + + /* Increment the number of DELETE requests. */ + server_ptr -> nx_web_http_server_delete_requests++; + + /* Process the Delete request. */ + _nx_web_http_server_delete_process(server_ptr, packet_ptr); + } + + /* Check for a POST request. */ + else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'O') && (buffer_ptr[2] == 'S') && + (buffer_ptr[3] == 'T') && (buffer_ptr[4] == ' ')) + { + + /* We have a HTTP POST request to send data to this HTTP Server for processing. Note that the POST + request is nearly identical to the GET request, except the parameter/query data is found in the + content rather than as part of the URL (resource). */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_POST_REQUEST; + + /* Increment the number of POST requests. */ + server_ptr -> nx_web_http_server_post_requests++; + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + + /* Reset last received multipart packet. */ + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = NX_NULL; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + + /* Process the POST request. */ + _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_POST_REQUEST, packet_ptr); + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + /* Restore the packet to release. */ + if (server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet) + packet_ptr = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + } + + /* Check for a HEAD request. */ + else if ((buffer_ptr[0] == 'H') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'A') && + (buffer_ptr[3] == 'D') && (buffer_ptr[4] == ' ')) + { + + /* We have a HTTP HEAD request to get a resource header from this HTTP Server. Note that the HEAD + request is nearly identical to the GET request, except the requested content is not returned to + the client. */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_HEAD_REQUEST; + + /* Increment the number of HEAD requests. */ + server_ptr -> nx_web_http_server_head_requests++; + + /* Process the HEAD request. */ + _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_HEAD_REQUEST, packet_ptr); + } + + /* Unhandled request. */ + else + { + + /* We have an unhandled HTTP request. */ + server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_UNKNOWN_REQUEST; + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED, + sizeof(NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED) - 1, + "NetX HTTP Request Not Implemented", + sizeof("NetX HTTP Request Not Implemented") - 1, NX_NULL, 0); + + /* Increment the number of unhandled requests. */ + server_ptr -> nx_web_http_server_unknown_requests++; + } + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Release the unprocessed packet. */ + if (server_ptr -> nx_web_http_server_request_packet) + { + nx_packet_release(server_ptr -> nx_web_http_server_request_packet); + server_ptr -> nx_web_http_server_request_packet = NX_NULL; + } + + /* If there are no more data to send, append the last chunk. */ + if (server_ptr -> nx_web_http_server_response_chunked) + { + + /* Allocate a packet to send the chunk end. */ + status = _nx_web_http_server_response_packet_allocate(server_ptr, &response_pkt, NX_WAIT_FOREVER); + if (status) + { + + /* Disconnect from the current connection. */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); + return; + } + + nx_packet_data_append(response_pkt, "0\r\n\r\n", 5, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Send internal. */ + status = _nx_web_http_server_send(server_ptr, response_pkt, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + if (status) + { + + /* Disconnect from the current connection. */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); + + nx_packet_release(response_pkt); + return; + } + + server_ptr -> nx_web_http_server_response_chunked = NX_FALSE; + } + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + if(server_ptr -> nx_web_http_server_keepalive == NX_FALSE) + { +#endif + /* Disconnect from the current connection. */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + } +#endif + + return; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_get_client_request PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the complete HTTP client request in a single*/ +/* packet. Doing this makes the other parsing and searching */ +/* routines simple. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Destination for request */ +/* packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy packet */ +/* nx_packet_data_append Move data into packet */ +/* nx_packet_release Release packet */ +/* nx_tcp_socket_receive Receive an HTTP request packet*/ +/* */ +/* CALLED BY */ +/* _nx_web_http_server_receive_data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_get_client_request(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) +{ + +NX_PACKET *head_packet_ptr; +NX_PACKET *new_packet_ptr; +CHAR *buffer_ptr; +UINT status; +NX_PACKET *work_ptr; +UINT crlf_found = 0; +NX_PACKET *tmp_ptr; + + + /* Default the return packet pointer to NULL. */ + *packet_ptr = NX_NULL; + + /* Wait for a request on the HTTP TCP well known port 80, or if encryption is enabled 443. */ + status = _nx_web_http_server_receive(server_ptr, &head_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* At this point, the server has a connection with an HTTP Client */ + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Return an error condition. */ + return(status); + } + + /* Setup pointer to start of buffer. */ + buffer_ptr = (CHAR *) head_packet_ptr -> nx_packet_prepend_ptr; + + /* Determine if the packet is an HTTP request. */ + if ((buffer_ptr[0] != 'G') && (buffer_ptr[0] != 'g') && (buffer_ptr[0] != 'P') && (buffer_ptr[0] != 'p') && + (buffer_ptr[0] != 'D') && (buffer_ptr[0] != 'd') && (buffer_ptr[0] != 'H') && (buffer_ptr[0] != 'h') && + (buffer_ptr[0] != 'T') && (buffer_ptr[0] != 't')) + { + + /* Invalid first packet for HTTP request. */ + + /* Release the packet. */ + nx_packet_release(head_packet_ptr); + + /* Return an error. */ + return(NX_WEB_HTTP_ERROR); + } + + crlf_found = 0; + work_ptr = head_packet_ptr; + + /* Build a pointer to the buffer area. */ + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + + do + { + + /* See if there is a blank line present in the buffer. */ + /* Search the buffer for a cr/lf pair. */ + while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) + { + if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) + { + + /* Found CR. */ + crlf_found++; + } + else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) + { + + /* Found LF. */ + crlf_found++; + } + else + { + + /* Reset the CRLF marker. */ + crlf_found = 0; + } + + if (crlf_found == 4) + { + + /* Yes, we have found the end of the HTTP request header. */ + + /* Set the return packet pointer. */ + *packet_ptr = head_packet_ptr; + + /* Return a successful completion. */ + return(NX_SUCCESS); + } + + /* Move the buffer pointer up. */ + buffer_ptr++; + } + + /* Determine if the packet has already overflowed into another packet. */ + +#ifndef NX_DISABLE_PACKET_CHAIN + + if (work_ptr -> nx_packet_next != NX_NULL) + { + /* Get the next packet in the chain. */ + work_ptr = work_ptr -> nx_packet_next; + buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; + } + else + +#endif + { + /* Receive another packet from the HTTP server port. */ + status = _nx_web_http_server_receive(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Release the current head packet. */ + nx_packet_release(head_packet_ptr); + + /* Return an error condition. */ + return(status); + } + + /* Successfully received another packet. Its contents now need to be placed in the head packet. */ + tmp_ptr = new_packet_ptr; +#ifndef NX_DISABLE_PACKET_CHAIN + while (tmp_ptr) + { +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Copy the contents of the current packet into the head packet. */ + status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, + (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WEB_HTTP_SERVER_TIMEOUT); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Yes, an error is present. */ + + /* Release both packets. */ + nx_packet_release(head_packet_ptr); + nx_packet_release(new_packet_ptr); + + /* Return an error condition. */ + return(status); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + tmp_ptr = tmp_ptr -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Release the new packet. */ + nx_packet_release(new_packet_ptr); + } + + } while (status == NX_SUCCESS); + + /* Release the packet. */ + nx_packet_release(head_packet_ptr); + + return NX_WEB_HTTP_ERROR; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_get_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the GET, POST, and HEAD HTTP client */ +/* requests. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* request_type Type of request (GET, POST, */ +/* or HEAD) */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_basic_authenticate */ +/* Process basic authentication */ +/* _nx_web_http_server_digest_authenticate */ +/* Process digest authentication */ +/* _nx_web_http_server_calculate_content_offset */ +/* Retrieve content offset */ +/* _nx_web_http_server_content_length_get */ +/* Retrieve content length */ +/* _nx_web_http_server_response_send Send response back to client */ +/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ +/* _nx_web_http_server_type_get_extended Derive file type */ +/* _nx_web_http_server_packet_get Receive another packet */ +/* _nx_web_http_server_field_value_get Get field value */ +/* nx_tcp_socket_transmit_configure Configure the server socket */ +/* fx_directory_information_get Get length of resource file */ +/* fx_file_close Close resource file */ +/* fx_file_open Open resource file */ +/* fx_file_read Read data from resource file */ +/* _nx_web_http_server_reponse_packet_allocate */ +/* Allocate a response packet */ +/* nx_packet_release Release packet */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_receive_data HTTP receive processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_get_process(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr) +{ + +ULONG length = 0; +UINT file_type_length; +UINT status; +NX_PACKET *new_packet_ptr; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +ULONG temp; +CHAR temp_string[30]; +UINT auth_request_present = NX_FALSE; +NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; +UINT offset = 0; +UINT resource_length; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if a POST is present. */ + if (request_type == NX_WEB_HTTP_SERVER_POST_REQUEST) + { + + if (!server_ptr -> nx_web_http_server_request_chunked) + { + + /* It is. Check for a valid content-length field. */ + status = _nx_web_http_server_content_length_get(packet_ptr, &length); + + /* Check for errors. */ + if ( status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Length", + sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + } + + /* Check for an invalid content offset . */ + offset = _nx_web_http_server_calculate_content_offset(packet_ptr); + if (offset == 0) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Offset", + sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + /* Cleanup the multipart field. */ + memset(&server_ptr -> nx_web_http_server_multipart, 0, sizeof(NX_WEB_HTTP_SERVER_MULTIPART)); +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_web_http_server_authentication_check || + server_ptr -> nx_web_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || + (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#endif + + /* Determine if the authentication failed. */ + if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes it did. Inform the HTTP server application about the failed authentication. */ + if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) + { + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, request_type); + } + } + + return; + } + } + + /* Check whether a full response is necessary. */ + if((server_ptr -> nx_web_http_server_cache_info_get) && + (server_ptr -> nx_web_http_server_request_type == NX_WEB_HTTP_SERVER_GET_REQUEST)) + { + + /* Searching for "If-Modified-Since" header. */ + if(_nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"if-modified-since", 17, (UCHAR *)temp_string, sizeof(temp_string)) == NX_SUCCESS) + { + UINT max_age; + NX_WEB_HTTP_SERVER_DATE date; + CHAR date_string[30]; + + /* Get last modified date of this resource. */ + if(server_ptr -> nx_web_http_server_cache_info_get(server_ptr -> nx_web_http_server_request_resource, &max_age, &date) == NX_TRUE) + { + + /* Convert date to string, the return length is always 29. */ + temp = _nx_web_http_server_date_to_string(&date, date_string); + date_string[temp] = 0; + + /* Check the last modified date with if-modified-since. */ + if(memcmp(temp_string, date_string, temp + 1) == 0) + { + + /* Send not modified. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_MODIFIED, + sizeof(NX_WEB_HTTP_STATUS_NOT_MODIFIED) - 1, + NX_NULL, 0, NX_NULL, 0); + + /* Return to caller. */ + return; + } + } + } + } + + /* Setup the server socket with a specific packet transmit retry logic. */ + nx_tcp_socket_transmit_configure(socket_ptr, + NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH, + NX_WEB_HTTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, + NX_WEB_HTTP_SERVER_RETRY_MAX, + NX_WEB_HTTP_SERVER_RETRY_SHIFT); + + /* At this point, either there isn't any required authentication for this resource or the authentication is + complete. */ + + /* If the HTTP server receives an empty POST request (no message body, content length = 0, it is the + responsibility of the request notify callback to send a response (if any) to the HTTP Client. + The HTTP server will process the request no further. */ + + /* Determine if a user supplied get function has been specified. */ + if (server_ptr -> nx_web_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the get request. */ + status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, packet_ptr); + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + /* Release the packet that is not processed by callback function. */ + if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_next_packet) + nx_packet_release(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_next_packet); +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + + /* Determine if the user supplied routine is requesting the get should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) + { + + /* User callback routine already sent success response back to HTTP Client. */ + return; + } + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", + sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Yes, error was detected. Abort the remainder of the get processing. */ + return; + } + } + + /* If it's POST request, process the message body. */ + if (request_type == NX_WEB_HTTP_SERVER_POST_REQUEST) + { + + /* Was there a message body in the request? */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* Find the first chunk of the content. */ + status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); + if (status) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + nx_packet_release(packet_ptr); + } + else + { + if (length == 0) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + length -= (ULONG)(packet_ptr -> nx_packet_length - offset); + } + + /* If necessary, receive more packets from the TCP socket. */ + while (length || server_ptr -> nx_web_http_server_request_chunked) + { + + /* Wait for more packets. */ + status = _nx_web_http_server_packet_get(server_ptr, &new_packet_ptr); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + if (status == NX_WEB_HTTP_GET_DONE) + { + break; + } + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Receive Timeout", + sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + if (!server_ptr -> nx_web_http_server_request_chunked) + { + length -= new_packet_ptr -> nx_packet_length; + } + + nx_packet_release(new_packet_ptr); + } + } + + + /* Get the length of request resource. */ + if (_nx_utility_string_length_check(server_ptr -> nx_web_http_server_request_resource, &resource_length, + sizeof(server_ptr -> nx_web_http_server_request_resource) - 1)) + { + return; + } + + /* Open the specified file for reading. */ + status = fx_file_open(server_ptr -> nx_web_http_server_media_ptr, &(server_ptr -> nx_web_http_server_file), server_ptr -> nx_web_http_server_request_resource, FX_OPEN_FOR_READ); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_FOUND, + sizeof(NX_WEB_HTTP_STATUS_NOT_FOUND) - 1, + "NetX HTTP Server unable to find file: ", + sizeof("NetX HTTP Server unable to find file: ") - 1, + server_ptr -> nx_web_http_server_request_resource, + resource_length); + + /* Error, return to caller. */ + return; + } + + /* Calculate the size of the file. */ + length = 0; + fx_directory_information_get(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource, FX_NULL, + &length, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL); + + /* Derive the file type. We use whatever value is returned since if there is no + match this function will return a default value. */ + _nx_web_http_server_type_get_extended(server_ptr, server_ptr -> nx_web_http_server_request_resource, resource_length, temp_string, sizeof(temp_string), &file_type_length); + + temp = file_type_length; + temp_string[temp] = 0; + + /* Now build a response header. */ + status = _nx_web_http_server_generate_response_header(server_ptr, &new_packet_ptr, NX_WEB_HTTP_STATUS_OK, + sizeof(NX_WEB_HTTP_STATUS_OK) - 1, length, temp_string, + file_type_length, NX_NULL, 0); + if(status) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", + sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Close the file. */ + fx_file_close(&(server_ptr -> nx_web_http_server_file)); + + /* Error, return to caller. */ + return; + } + + /* Check to see if only a response is required. */ + if ((!length) || (request_type == NX_WEB_HTTP_SERVER_HEAD_REQUEST)) + { + + /* Yes, only a response is required... send it! */ + status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Determine if this is successful. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Force zero length. */ + length = 0; + } + } + + /* Get length of packet */ + temp = new_packet_ptr -> nx_packet_length; + + /* Now, loop to send the data contents. If the request type is "HEAD", skip this loop to output the + file contents. */ + while ((length) && (request_type != NX_WEB_HTTP_SERVER_HEAD_REQUEST)) + { + + /* Determine if we need to allocate a new packet for data. */ + if (!temp) + { + + /* Yes, allocate a new packet. */ + status = _nx_web_http_server_response_packet_allocate(server_ptr, &new_packet_ptr, NX_WAIT_FOREVER); + + /* Determine if an error is present. */ + if (status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Error, return to caller. */ + break; + } + } + + /* Calculate the maximum length. */ + temp = ((ULONG) (new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_append_ptr)) - NX_PHYSICAL_TRAILER; + + /* Determine if this exceeds the MSS of the peer. */ + if (temp > socket_ptr -> nx_tcp_socket_connect_mss) + { + + /* Yes, reduce the maximum size to the mss size. */ + temp = socket_ptr -> nx_tcp_socket_connect_mss; + } + + /* Read data from the file. */ + status = fx_file_read(&(server_ptr -> nx_web_http_server_file), new_packet_ptr -> nx_packet_append_ptr, + temp, &temp); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Error, return. */ + break; + } + + /* Update the packet information with the data read. */ + new_packet_ptr -> nx_packet_length = new_packet_ptr -> nx_packet_length + temp; + new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_append_ptr + temp; + + /* Send the packet out. */ + status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for success. */ + if (status != NX_SUCCESS) + { + + /* Release the packet. */ + nx_packet_release(new_packet_ptr); + + /* Return to caller. */ + break; + } + + /* Increment the bytes sent count. */ + server_ptr -> nx_web_http_server_total_bytes_sent = server_ptr -> nx_web_http_server_total_bytes_sent + temp; + + /* Adjust the file length based on what we have sent. */ + length = length - temp; + + /* Indicate new packet needed */ + temp = 0; + } + + /* Close the file. */ + fx_file_close(&(server_ptr -> nx_web_http_server_file)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_put_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the PUT HTTP client requests. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_basic_authenticate */ +/* Process basic authentication */ +/* _nx_web_http_server_digest_authenticate */ +/* Process digest authentication */ +/* _nx_web_http_server_calculate_content_offset */ +/* Retrieve content offset */ +/* _nx_web_http_server_content_length_get */ +/* Retrieve content length */ +/* _nx_web_http_server_response_send Send response back to client */ +/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ +/* _nx_web_http_server_packet_get Receive another packet */ +/* fx_file_close Close resource file */ +/* fx_file_create Create resource file */ +/* fx_file_open Open resource file */ +/* fx_file_write Write data to resource file */ +/* nx_packet_release Release packet */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_content_get Content get processing */ +/* _nx_web_http_server_get_process GET request processing */ +/* _nx_web_http_server_put_process PUT request processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_put_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +ULONG length = 0; +UINT offset; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +NX_PACKET *data_packet_ptr; +NX_PACKET *next_packet_ptr; +UINT auth_request_present = NX_FALSE; +NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", + sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + if (!server_ptr -> nx_web_http_server_request_chunked) + { + + /* Calculate the content length from the request. */ + status = _nx_web_http_server_content_length_get(packet_ptr, &length); + + /* Determine if the content length is valid. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Length", + sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + } + + /* Calculate the offset to the content (the two Cr LF tokens) in the request. */ + offset = _nx_web_http_server_calculate_content_offset(packet_ptr); + + /* Determine if the offset to the content is valid. */ + if (offset == 0) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP Invalid Content Offset", + sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_web_http_server_authentication_check || + server_ptr -> nx_web_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || + (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#endif + + /* Determine if the authentication is currently in progress. */ + if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ + if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) + { + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, NX_WEB_HTTP_SERVER_PUT_REQUEST); + } + } + + return; + } + } + + /* At this point, either there isn't any required authentication for this resource or the authentication is + complete. */ + + /* If the request is empty (content-length = 0) the request notify callback is where a response is generated + to return to the Client. NetX HTTP Server will not process an empty request further. */ + + /* Determine if a user supplied get function has been specified. */ + if (server_ptr -> nx_web_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the put request. */ + status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, packet_ptr); + + /* Determine if the user supplied routine is requesting the put should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) + { + + /* Send success response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_OK, + sizeof(NX_WEB_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); + return; + } + + /* No, an error was detected. Abort the remainder of the get processing. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", + sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + return; + } + } + + /* Was there a message body in the request? */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* Find the first chunk of the content. */ + status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); + if (status) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + offset = 0; + length = packet_ptr -> nx_packet_length; + } + else if (length == 0) + { + + /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ + return; + } + + /* Otherwise, everything is okay... complete the request. */ + + /* Create the specified file. */ + status = fx_file_create(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource); + + + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Create Failed", + sizeof("NetX HTTP File Create Failed") - 1, NX_NULL, 0); + + /* Release first chunked packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + nx_packet_release(packet_ptr); + } + + /* Error, return to caller. */ + return; + } + + /* Open the specified file for writing. */ + status = fx_file_open(server_ptr -> nx_web_http_server_media_ptr, &(server_ptr -> nx_web_http_server_file), server_ptr -> nx_web_http_server_request_resource, FX_OPEN_FOR_WRITE); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Open Failed", + sizeof("NetX HTTP File Open Failed") - 1, NX_NULL, 0); + + /* Release first chunked packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + nx_packet_release(packet_ptr); + } + + /* Error, return to caller. */ + return; + } + + /* Determine if there is any content in the first packet. */ + if ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) > offset) + { + + /* Write the content found in this packet. */ + status = fx_file_write(&(server_ptr -> nx_web_http_server_file), (packet_ptr -> nx_packet_prepend_ptr + offset), + ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", + sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Release first chunked packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + nx_packet_release(packet_ptr); + } + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); + + /* Increment the bytes received count. */ + server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + + ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); + } + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Loop to write chained packets out to the file. */ + next_packet_ptr = packet_ptr -> nx_packet_next; + while ((length) && (next_packet_ptr)) + { + + /* Write the content of the next packet. */ + status = fx_file_write(&(server_ptr -> nx_web_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", + sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Release first chunked packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + nx_packet_release(packet_ptr); + } + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Increment the bytes received count. */ + server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Move to the next pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Release first chunked packet. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + nx_packet_release(packet_ptr); + } + + /* If necessary, receive more packets from the TCP socket to complete the write request. */ + while (length || server_ptr -> nx_web_http_server_request_chunked) + { + + /* Wait for a request. */ + status = _nx_web_http_server_packet_get(server_ptr, &data_packet_ptr); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + if (status == NX_WEB_HTTP_GET_DONE) + { + break; + } + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Receive Timeout", + sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + if (server_ptr -> nx_web_http_server_request_chunked) + { + length = data_packet_ptr -> nx_packet_length; + } + + /* Loop to write the packet chain out to the file. */ + next_packet_ptr = data_packet_ptr; + do + { + + /* Write the content of this packet. */ + status = fx_file_write(&(server_ptr -> nx_web_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); + + /* Check the status. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Write Failed", + sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); + + /* Release the previous data packet. */ + nx_packet_release(data_packet_ptr); + + /* Error, return to caller. */ + return; + } + + /* Update the length. */ + length = length - (UINT)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + + /* Increment the bytes received count. */ + server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + + (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); + +#ifdef NX_DISABLE_PACKET_CHAIN + next_packet_ptr = NX_NULL; +#else + /* Move to the next pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; +#endif /* NX_DISABLE_PACKET_CHAIN */ + + } while ((length) && (next_packet_ptr)); + + /* Release the previous data packet. */ + nx_packet_release(data_packet_ptr); + } + + /* Success, at this point close the file and prepare a successful response for the client. */ + fx_file_close(&(server_ptr -> nx_web_http_server_file)); + + + /* Now build a response header. */ + status = _nx_web_http_server_generate_response_header(server_ptr, &data_packet_ptr, NX_WEB_HTTP_STATUS_OK, + sizeof(NX_WEB_HTTP_STATUS_OK) - 1, 0, + NX_NULL, 0, NX_NULL, 0); + if (status == NX_SUCCESS) + { + + /* Send the response back to the client. */ + status = _nx_web_http_server_send(server_ptr, data_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(data_packet_ptr); + } + } + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_delete_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the DELETE HTTP client requests. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_basic_authenticate */ +/* Process basic authentication */ +/* _nx_web_http_server_digest_authenticate */ +/* Process digest authentication */ +/* _nx_web_http_server_response_send Send response back to client */ +/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ +/* fx_file_delete Delete resource file */ +/* nx_packet_release Release packet */ +/* _nx_web_http_server_send Send packet to client */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_receive_data HTTP Server receive processing*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_delete_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + +UINT status; +CHAR *name_ptr; +CHAR *password_ptr; +CHAR *realm_ptr; +NX_PACKET *response_ptr; +UINT auth_request_present = NX_FALSE; +NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; +UINT name_length = 0; +UINT password_length = 0; +UINT realm_length = 0; +UINT temp_name_length = 0; +UINT temp_password_length = 0; +UINT temp_realm_length = 0; + + + /* Pickup the URL (resource) from the request. */ + status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); + + /* Determine if the resource was extracted successfully. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, + sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, + "NetX HTTP URL Bad", + sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Determine if the application has specified an authentication function for this server. */ + if (server_ptr -> nx_web_http_server_authentication_check || + server_ptr -> nx_web_http_server_authentication_check_extended) + { + + /* Determine if authentication is required for the specified resource. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended) + { + status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); + } + else + { + status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, + &name_ptr, &password_ptr, &realm_ptr); + } + + if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || + (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) + { + + /* Check name, password and realm string. */ + if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) + { + + /* Error, return to caller. */ + return; + } + + /* Validate string length. */ + if (server_ptr -> nx_web_http_server_authentication_check_extended && + ((realm_length != temp_realm_length) || + (name_length != temp_name_length) || + (password_length != temp_password_length))) + { + return; + } + } + + /* Determine what kind - if any - authentication is requested for this resource. */ + if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) + { + + /* Process basic authentication request. */ + status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) + { + + /* Process digest authentication request. */ + status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); + } +#endif + + /* Determine if the authentication is currently in progress. */ + if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) + { + + /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ + if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) + { + NXD_ADDRESS client_nxd_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); + + if (status == NX_SUCCESS) + { + /* Send this information to the host application. */ + (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, NX_WEB_HTTP_SERVER_DELETE_REQUEST); + } + } + + return; + } + } + + /* Determine if a user supplied notify function has been specified. */ + if (server_ptr -> nx_web_http_server_request_notify) + { + + /* Call the user supplied function to notify the user of the delete request. */ + status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, packet_ptr); + + /* Determine if the user supplied routine is requesting the delete should be aborted. */ + if (status != NX_SUCCESS) + { + + /* Determine if the user callback routine successfully completed the request processing. */ + if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) + { + + /* Send success response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_OK, + sizeof(NX_WEB_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); + return; + } + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP Request Aborted", + sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); + + /* Yes, error was detected. Abort the remainder of the delete processing. */ + return; + } + } + + /* Otherwise, everything is okay... complete the request. */ + + /* Delete the specified file. */ + status = fx_file_delete(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource); + + /* Check for error condition. */ + if (status != NX_SUCCESS) + { + + /* Send response back to HTTP Client. */ + _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, + sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, + "NetX HTTP File Delete Failed", + sizeof("NetX HTTP File Delete Failed") - 1, NX_NULL, 0); + + /* Error, return to caller. */ + return; + } + + /* Now build a response header. */ + status = _nx_web_http_server_generate_response_header(server_ptr, &response_ptr, NX_WEB_HTTP_STATUS_OK, + sizeof(NX_WEB_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); + if (status == NX_SUCCESS) + { + + /* Send the response back to the client. */ + status = _nx_web_http_server_send(server_ptr, response_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(response_ptr); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_invalid_userpassword_notify_set */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for service to set invalid */ +/* username password callback function. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* invalid_username_password_callback Pointer to application's */ +/* invalid username password */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) +{ + +UINT status; + + + if ((http_server_ptr == NX_NULL) || (invalid_username_password_callback == NX_NULL)) + { + return NX_PTR_ERROR; + } + + status = _nx_web_http_server_invalid_userpassword_notify_set(http_server_ptr, invalid_username_password_callback); + + return status; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_invalid_userpassword_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets invalid username password callback function */ +/* */ +/* Note: The string resource in callback function */ +/* invalid_username_password_callback is built by internal logic and */ +/* always NULL-terminated. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* invalid_username_password_callback Pointer to application's */ +/* invalid username password */ +/* callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) +{ + + http_server_ptr -> nx_web_http_server_invalid_username_password_callback = invalid_username_password_callback; + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_response_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the specified Server response to the requesting */ +/* HTTP client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* information Pointer to HTTP info string */ +/* information_length Length of information */ +/* additional_information Pointer to additional HTTP */ +/* information */ +/* additional_information_length Length of additional */ +/* information */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_generate_response_header */ +/* Generate response header */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* _nx_web_http_server_send Send HTTP Server response */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_receive HTTP receive processing */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* _nx_web_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_information, + UINT additional_information_length) +{ + +UINT status; +UINT length; +NX_PACKET *packet_ptr; + + /* Determine if there is additional information. */ + if(information) + { + + /* Calculate the size of the information field. */ + length = information_length; + + /* Determine if there is additional information. */ + if (additional_information) + { + + /* Update the length with it as well. */ + length = length + additional_information_length; + } + } + else + length = 0; + + /* Generate response header. */ + status = _nx_web_http_server_generate_response_header(server_ptr, &packet_ptr, status_code, + status_code_length, length, NX_NULL, 0, NX_NULL, 0); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Just return. */ + return(status); + } + + /* Determine if there is additional information. */ + if (information) + { + + /* Place the first informational field. */ + status = nx_packet_data_append(packet_ptr, information, information_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* If there is additional information, place it in the buffer as well. */ + if (additional_information) + { + + /* Now, place the additional informational field. */ + status += nx_packet_data_append(packet_ptr, additional_information, additional_information_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet and return. */ + nx_packet_release(packet_ptr); + return(status); + } + + /* Send the response back to the client. */ + status = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_basic_authenticate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for basic (name & password) authentication. */ +/* If found and correct, it returns a success. Otherwise, it returns */ +/* an authentication request to the requesting client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* name_ptr Pointer to name string */ +/* password_ptr Pointer to password string */ +/* realm_ptr Pointer to realm string */ +/* auth_request_present Indicate if authentication */ +/* must be performed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_retrieve_basic_authorization */ +/* Pickup authorization */ +/* _nx_web_http_base64_decode Decode authorization */ +/* _nx_web_http_server_response_packet_allocate */ +/* Allocate a response packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* _nx_web_http_server_send Send HTTP Server response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* _nx_web_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_basic_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present) +{ + +UINT i, j; +UINT status, status1; +CHAR quote[2] = {0x22, 0}; +CHAR crlf[2] = {13,10}; +UINT match; +UINT realm_length; +UINT length; + + /* Default to no authentication request detected. */ + *auth_request_present = NX_FALSE; + + /* Default the status to authenticate. */ + status = NX_WEB_HTTP_BASIC_AUTHENTICATE; + + memset(&authorization_request[0], 0, sizeof(authorization_request)); + + memset(&authorization_decoded[0], 0, sizeof(authorization_decoded)); + + /* Is the authorization request present? */ + length = _nx_web_http_server_retrieve_basic_authorization(packet_ptr, authorization_request); + if (length) + { + + /* Yes, an authorization request is present. */ + *auth_request_present = NX_TRUE; + + /* Convert the request from Base64 representation to ASCII. */ + _nx_web_http_base64_decode(authorization_request, length, authorization_decoded); + + /* See if it is valid. */ + + /* Compare the name. */ + i = 0; + match = NX_TRUE; + while (name_ptr[i] && (i < sizeof(authorization_decoded))) + { + + /* Is there a mismatch? */ + if (name_ptr[i] != authorization_decoded[i]) + { + + /* Name mismatch. Continue to avoid timing attack. */ + match = NX_FALSE; + } + + /* Move to next character. */ + i++; + } + + /* Determine if everything matches. */ + if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == ':')) + { + + /* Move the authorization index past the semicolon. */ + i++; + + /* Now compare the passwords. */ + j = 0; + match = NX_TRUE; + while (password_ptr[j] && (i < sizeof(authorization_decoded))) + { + + /* Is there a mismatch? */ + if (password_ptr[j] != authorization_decoded[i]) + { + + /* Password mismatch. Continue to avoid timing attack. */ + match = NX_FALSE; + } + + /* Move to next character. */ + i++; + j++; + } + + /* Determine if we have a match. */ + if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == (CHAR) NX_NULL)) + { + + /* Yes, we have successful authorization!! */ + status = NX_SUCCESS; + } + } + } + + /* Determine if we need to send back an unauthorized request. */ + if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) + { + + /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ + + if (_nx_utility_string_length_check(realm_ptr, &realm_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Allocate a packet for sending the response back. */ + status1 = _nx_web_http_server_response_packet_allocate(server_ptr, &packet_ptr, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if (status1 != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Just return. */ + return(status1); + } + + /* Insert the response header. */ + nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, NX_WEB_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_WEB_HTTP_STATUS_UNAUTHORIZED) - 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the type of authentication requested. */ + nx_packet_data_append(packet_ptr, "WWW-Authenticate: Basic realm=", 30, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the realm string into the buffer. */ + nx_packet_data_append(packet_ptr, realm_ptr, realm_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place another into the buffer to signal end of FULL HTTP response. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Send the response back to the client. */ + status1 = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status1) + { + + /* Return the internal NetX error. */ + status = status1; + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Return the result of the authentication request. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_retrieve_basic_authorization PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves basic authentication information from the */ +/* HTTP request packet. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Request packet pointer */ +/* authorization_request_ptr Pointer to destination for */ +/* authorization string */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_basic_authenticate */ +/* Basic authenticate processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr) +{ + +UINT length; +UINT found; +CHAR *buffer_ptr; + + + /* Set the found flag to false. */ + found = NX_FALSE; + + /* Default the authorization request to zero. */ + length = 0; + + /* Set the authorization request string to NULL. */ + authorization_request_ptr[0] = NX_NULL; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + + /* Find the "Authorization: " token first. */ + while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Authorization: token. */ + if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && + ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && + ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && + ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && + ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && + ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && + ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && + ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && + ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && + ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && + ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && + ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && + (*(buffer_ptr+13) == ':') && + (*(buffer_ptr+14) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 15; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now check for the "Basic " token. */ + while (((buffer_ptr+6) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Basic token. */ + if (((*buffer_ptr == 'b') || (*buffer_ptr == 'B')) && + ((*(buffer_ptr+1) == 'a') || (*(buffer_ptr+1) == 'A')) && + ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+3) == 'i') || (*(buffer_ptr+3) == 'I')) && + ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+4) == 'C')) && + (*(buffer_ptr+5) == ' ')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 6; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the authorization string. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_STRING)) + { + + /* Copy a character of the authorization string into the destination. */ + authorization_request_ptr[length] = *buffer_ptr++; + length++; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_retrieve_resource PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the resource (URL) portion of the request */ +/* and places it in the destination. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* destination Destination for resource */ +/* max_size Maximum size of destination */ +/* */ +/* OUTPUT */ +/* */ +/* Status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* _nx_web_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_retrieve_resource(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *destination, UINT max_size) +{ + +UINT i; +CHAR *buffer_ptr; + +#ifndef NX_WEB_HTTPS_ENABLE + NX_PARAMETER_NOT_USED(server_ptr); +#endif /* NX_WEB_HTTPS_ENABLE */ + + /* Set the destination to NULL. */ + destination[0] = (CHAR) 0; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the first space which is the start position of URI. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ')) + { + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Check for an error condition. */ + if (*buffer_ptr != ' ') + return(NX_WEB_HTTP_ERROR); + + buffer_ptr++; + +#ifdef NX_WEB_HTTPS_ENABLE + + if (server_ptr -> nx_web_http_is_https_server) + { + if ((buffer_ptr + 8 < (CHAR *)packet_ptr->nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Check whether it is an absoluteURI*/ + if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && + ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && + ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 2) == 'T')) && + ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 3) == 'P')) && + ((*(buffer_ptr + 4) == 's') || (*(buffer_ptr + 4) == 'S')) && + (*(buffer_ptr + 5) == ':') && + (*(buffer_ptr + 6) == '/') && + (*(buffer_ptr + 7) == '/')) + { + + /* Yes it is. Find the absolute path. */ + buffer_ptr += 8; + + /* Find the first slash character. The first slash marks the beginning of the URL. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR)0) && (*buffer_ptr != '/')) + { + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + } + } + + } + else +#endif + { + if ((buffer_ptr + 7 < (CHAR *)packet_ptr->nx_packet_append_ptr) && (*buffer_ptr != '/')) + { + + /* Check whether it is an absoluteURI*/ + if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && + ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && + ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 2) == 'T')) && + ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 3) == 'P')) && + (*(buffer_ptr + 4) == ':') && + (*(buffer_ptr + 5) == '/') && + (*(buffer_ptr + 6) == '/')) + { + + /* Yes it is. Find the absolute path. */ + buffer_ptr += 7; + + /* Find the first slash character. The first slash marks the beginning of the URL. */ + while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR)0) && (*buffer_ptr != '/')) + { + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + } + } + } + + /* Check for an error condition. */ + if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != '/')) + return(NX_WEB_HTTP_ERROR); + + /* Copy the rest of the resource to the destination. Space, semicolon, and question mark characters signal the + end of the resource. */ + i = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ') && (*buffer_ptr != ';') && (*buffer_ptr != '?') && (i < (max_size-1))) + { + + /* Check escape characters. */ + if(*buffer_ptr == '%') + { + + /* It is an escape character. */ + if((buffer_ptr + 2) < (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + + /* Convert the HEX number. */ + buffer_ptr++; + if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + destination[i] = (CHAR)(*buffer_ptr - '0'); + else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) + destination[i] = (CHAR)(*buffer_ptr - 'a' + 10); + else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) + destination[i] = (CHAR)(*buffer_ptr - 'A' + 10); + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_WEB_HTTP_ERROR); + } + destination[i] = (CHAR)(destination[i] << 4); + + /* Convert the HEX number. */ + buffer_ptr++; + if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - '0')); + else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'a' + 10)); + else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) + destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'A' + 10)); + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_WEB_HTTP_ERROR); + } + + /* Move to the next byte. */ + i++; + buffer_ptr++; + } + else + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_WEB_HTTP_ERROR); + } + } + else + { + + /* Copy the URL name into the destination. */ + destination[i++] = *buffer_ptr++; + } + } + + /* Determine if the resource was retrieved. */ + if ((destination[0] == (CHAR) 0) || (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || ((*buffer_ptr != ' ') && (*buffer_ptr != '?') && (*buffer_ptr != ';'))) + { + + /* Error picking up the resource. */ + destination[0] = (CHAR) 0; + return(NX_WEB_HTTP_ERROR); + } + + /* Everything is okay, place a NULL at the end of the resource. */ + destination[i] = (CHAR) 0; + + /* Return success. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_calculate_content_offset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function calculates the byte offset to the start of the */ +/* HTTP request content area. This area immediately follows the HTTP */ +/* request header (which ends with a blank line). */ +/* */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to request packet */ +/* */ +/* OUTPUT */ +/* */ +/* Byte Offset (0 implies no content) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_content_get Application content get */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_calculate_content_offset(NX_PACKET *packet_ptr) +{ + +UINT offset; +CHAR *buffer_ptr; +UINT crlf_found = 0; + + + /* Default the content offset to zero. */ + offset = 0; + + /* Find the "cr,lf,cr,lf" token. */ +#ifndef NX_DISABLE_PACKET_CHAIN + while(packet_ptr) + { +#endif + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + while(buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) + { + if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) + { + + /* Found CR. */ + crlf_found++; + } + else if ((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) + { + + /* Found LF. */ + crlf_found++; + } + else + { + + /* Reset the CRLF marker. */ + crlf_found = 0; + } + + offset++; + buffer_ptr++; + + if (crlf_found == 4) + { + + /* Return the offset to the caller. */ + return(offset); + } + } + +#ifndef NX_DISABLE_PACKET_CHAIN + packet_ptr = packet_ptr -> nx_packet_next; + } +#endif + + /* Not found the "cr,lf,cr,lf". */ + return(0); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_number_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a number into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* number Unsigned integer number */ +/* string Destination string */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* (0 implies an error) */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_response_send Send response to client */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_number_convert(UINT number, CHAR *string) +{ + +UINT j; +UINT digit; +UINT size; + + + /* Initialize counters. */ + size = 0; + + /* Loop to convert the number to ASCII. */ + while (size < 10) + { + + /* Shift the current digits over one. */ + for (j = size; j != 0; j--) + { + + /* Move each digit over one place. */ + string[j] = string[j-1]; + } + + /* Compute the next decimal digit. */ + digit = number % 10; + + /* Update the input number. */ + number = number / 10; + + /* Store the new digit in ASCII form. */ + string[0] = (CHAR) (digit + 0x30); + + /* Increment the size. */ + size++; + + /* Determine if the number is now zero. */ + if (number == 0) + break; + } + + /* Make the string NULL terminated. */ + string[size] = (CHAR) NX_NULL; + + /* Determine if there is an overflow error. */ + if (number) + { + + /* Error, return bad values to user. */ + size = 0; + string[0] = '0'; + } + + /* Return size to caller. */ + return(size); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for deriving the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* string_size Return HTTP type string size */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_type_get */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (name == NX_NULL) || (http_type_string == NX_NULL) || (string_size == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + status = _nx_web_http_server_type_get(server_ptr, name, http_type_string, string_size); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_type_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* http_type_string Destination HTTP type string */ +/* string_size Return HTTP type string size */ +/* */ +/* OUTPUT */ +/* */ +/* Size Number of bytes in string */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_memicmp */ +/* _nx_utility_string_length_check */ +/* memcpy */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_type_get_extended Get MIME type */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size) +{ +UINT temp_name_length; + + /* Check name length. */ + if (_nx_utility_string_length_check(name, &temp_name_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Call actual service type get function. */ + return(_nx_web_http_server_type_get_extended(server_ptr, name, temp_name_length, + http_type_string, NX_MAX_STRING_LENGTH + 1, + string_size)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_type_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for deriving the type of the resource. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* name_length Length of name string */ +/* http_type_string Destination HTTP type string */ +/* http_type_string_max_size Size of the destination string*/ +/* string_size Return HTTP type string size */ +/* */ +/* OUTPUT */ +/* */ +/* Status Web HTTP status code */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_type_get_extended Get MIME type */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, + CHAR *http_type_string, UINT http_type_string_max_size, + UINT *string_size) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (name == NX_NULL) || (http_type_string == NX_NULL) || (string_size == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_web_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, + http_type_string_max_size, string_size); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_type_get_extended PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function derives the type of the resource. */ +/* */ +/* Note: The string of name must be NULL-terminated and length of each */ +/* string matches the length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* name Name string */ +/* name_length Length of name string */ +/* http_type_string Destination HTTP type string */ +/* http_type_string_max_size Size of the destination string*/ +/* string_size Return HTTP type string size */ +/* */ +/* OUTPUT */ +/* */ +/* Status Web HTTP status code */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_memicmp Compare ignore case */ +/* _nx_utility_string_length_check String length check */ +/* memcpy Copy memory data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process Process GET request */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, + CHAR *http_type_string, UINT http_type_string_max_size, + UINT *string_size) +{ + +UINT i; +CHAR *ch; +UINT ext_length; +UINT map_ext_length; +UINT map_type_length; +UINT temp_name_length; + + /* Check name length. */ + if (_nx_utility_string_length_check(name, &temp_name_length, name_length)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Validate string length. */ + if (name_length != temp_name_length) + { + return(NX_WEB_HTTP_ERROR); + } + + /* First find the end of the string. */ + ch = name + name_length; + + /* Now look backwards to find the last period that signals the + file extension. */ + ext_length = 0; + while ((ch >= name) && (*ch != '.') &&(*ch != '/')) + { + ch--; + ext_length++; + } + + if(*ch != '.') + { + + /* No extension is found. Return the default mime type. */ + if(http_type_string_max_size < (sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME))) + { + /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into + the caller-supplied http_type_string. */ + return (NX_WEB_HTTP_ERROR); + } + + + /* No extension is found. Return the default mime type. */ + memcpy(http_type_string, NX_WEB_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME)); + *string_size = sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME) - 1; + return(NX_WEB_HTTP_EXTENSION_MIME_DEFAULT); + } + + /* Position forward again, past the period. */ + ch++; + ext_length--; + + /* Now see what HTTP file type to return. */ + /* Search user defined MIME maps first. */ + if(server_ptr -> nx_web_http_server_mime_maps_additional && + (server_ptr -> nx_web_http_server_mime_maps_additional_num > 0)) + { + for(i = 0; i < server_ptr -> nx_web_http_server_mime_maps_additional_num; i++) + { + + /* Check map extension and type length. */ + if (_nx_utility_string_length_check(server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_extension, + &map_ext_length, ext_length) || + _nx_utility_string_length_check(server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_type, + &map_type_length, http_type_string_max_size - 1)) + { + continue; + } + + if(_nx_web_http_server_memicmp((UCHAR *)ch, ext_length, + (UCHAR *)server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_extension, + map_ext_length) == NX_SUCCESS) + { + + /* Find the extension. Return the mapped MIME type. */ + memcpy(http_type_string, server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_type, map_type_length + 1); + *string_size = map_type_length; + return(NX_SUCCESS); + } + } + } + + /* Search default MIME maps. */ + for(i = 0; i < sizeof(_nx_web_http_server_mime_maps) / sizeof(NX_WEB_HTTP_SERVER_MIME_MAP); i++) + { + + /* Check map extension and type length. */ + if (_nx_utility_string_length_check(_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_extension, + &map_ext_length, ext_length) || + _nx_utility_string_length_check(_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_type, + &map_type_length, http_type_string_max_size - 1)) + { + continue; + } + + if(_nx_web_http_server_memicmp((UCHAR *)ch, ext_length, + (UCHAR *)_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_extension, + map_ext_length) == NX_SUCCESS) + { + + /* Find the extension. Return the mapped MIME type. */ + memcpy(http_type_string, _nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_type, map_type_length + 1); + *string_size = map_type_length; + return(NX_SUCCESS); + } + } + + /* No extension matches. Return the default mime type. */ + + if(http_type_string_max_size < (sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME))) + { + /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into + the caller-supplied http_type_string. */ + return (NX_WEB_HTTP_ERROR); + } + + memcpy(http_type_string, NX_WEB_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME)); + *string_size = sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME) - 1; + return(NX_WEB_HTTP_EXTENSION_MIME_DEFAULT); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_base64_encode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function encodes the input string into a base64 */ +/* representation. */ +/* */ +/* INPUT */ +/* */ +/* name Name string */ +/* name Length of name */ +/* base64name Encoded base64 name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_base64_encode(CHAR *name, UINT length, CHAR *base64name) +{ + +UINT pad; +UINT i, j; +UINT step; + + + /* Adjust the length to represent the base64 name. */ + length = ((length * 8) / 6); + + /* Default padding to none. */ + pad = 0; + + /* Determine if an extra conversion is needed. */ + if ((length * 6) % 24) + { + + /* Some padding is needed. */ + + /* Calculate the number of pad characters. */ + pad = (length * 6) % 24; + pad = (24 - pad) / 6; + pad = pad - 1; + + /* Adjust the length to pickup the character fraction. */ + length++; + } + + /* Setup index into the base64name. */ + j = 0; + + /* Compute the base64name. */ + step = 0; + i = 0; + while (j < length) + { + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first 6 bits of name character for index. */ + base64name[j++] = _nx_web_http_server_base64_array[((UINT) name[i]) >> 2]; + step++; + } + else if (step == 1) + { + + /* Use last 2 bits of name character and first 4 bits of next name character for index. */ + base64name[j++] = _nx_web_http_server_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; + i++; + step++; + } + else if (step == 2) + { + + /* Use last 4 bits of name character and first 2 bits of next name character for index. */ + base64name[j++] = _nx_web_http_server_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; + i++; + step++; + } + else /* Step 3 */ + { + + /* Use last 6 bits of name character for index. */ + base64name[j++] = _nx_web_http_server_base64_array[(((UINT) name[i]) & 0x3F)]; + i++; + step = 0; + } + } + + /* Determine if the index needs to be advanced. */ + if (step != 3) + i++; + + /* Now add the PAD characters. */ + while ((pad--) && (j < NX_WEB_HTTP_MAX_STRING)) + { + + /* Pad base64name with '=' characters. */ + base64name[j++] = '='; + } + + /* Put a NULL character in. */ + base64name[j] = NX_NULL; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_base64_decode PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function decodes the input base64 ASCII string and converts */ +/* it into a standard ASCII representation. */ +/* */ +/* INPUT */ +/* */ +/* base64name Encoded base64 name string */ +/* length Length of encoded base64 name */ +/* name Name string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_basic_authenticate */ +/* Basic authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_base64_decode(CHAR *base64name, UINT length, CHAR *name) +{ + +UINT i, j; +UINT value1, value2; +UINT step; + + + /* Adjust the length to represent the ASCII name. */ + length = ((length * 6) / 8); + + /* Setup index into the ASCII name. */ + j = 0; + + /* Compute the ASCII name. */ + step = 0; + i = 0; + while ((j < length) && (base64name[i]) && (base64name[i] != '=')) + { + + /* Derive values of the Base64 name. */ + if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) + value1 = (UINT) (base64name[i] - 'A'); + else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) + value1 = (UINT) (base64name[i] - 'a') + 26; + else if ((base64name[i] >= '0') && (base64name[i] <= '9')) + value1 = (UINT) (base64name[i] - '0') + 52; + else if (base64name[i] == '+') + value1 = 62; + else if (base64name[i] == '/') + value1 = 63; + else + value1 = 0; + + /* Derive value for the next character. */ + if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) + value2 = (UINT) (base64name[i+1] - 'A'); + else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) + value2 = (UINT) (base64name[i+1] - 'a') + 26; + else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) + value2 = (UINT) (base64name[i+1] - '0') + 52; + else if (base64name[i+1] == '+') + value2 = 62; + else if (base64name[i+1] == '/') + value2 = 63; + else + value2 = 0; + + /* Determine which step we are in. */ + if (step == 0) + { + + /* Use first value and first 2 bits of second value. */ + name[j++] = (CHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); + i++; + step++; + } + else if (step == 1) + { + + /* Use last 4 bits of first value and first 4 bits of next value. */ + name[j++] = (CHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); + i++; + step++; + } + else if (step == 2) + { + + /* Use first 2 bits and following 6 bits of next value. */ + name[j++] = (CHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); + i++; + i++; + step = 0; + } + } + + /* Put a NULL character in. */ + name[j] = NX_NULL; +} + + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_digest_authenticate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for digest (MD5 only) authentication. */ +/* If the digest is correct, it returns a success. Otherwise, it */ +/* returns an authentication request to the requesting client. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* packet_ptr Request packet pointer */ +/* name_ptr Pointer to name string */ +/* password_ptr Pointer to password string */ +/* realm_ptr Pointer to realm string */ +/* auth_request_present Indicate if authentication */ +/* must be performed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_retrieve_digest_authorization */ +/* Pickup authorization */ +/* _nx_web_http_server_digest_response_calculate */ +/* Calculate the digest */ +/* _nx_web_http_server_response_packet_allocate */ +/* Allocate a response packet */ +/* nx_packet_data_append Append information to response*/ +/* nx_packet_release Release packet */ +/* _nx_web_http_server_send Send HTTP Server response */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process Process GET request */ +/* _nx_web_http_server_put_process Process PUT request */ +/* _nx_web_http_server_delete_process Process DELETE request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_digest_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present) +{ + +CHAR authorization_response[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; +CHAR calculated_response[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; +CHAR authorization_uri[NX_WEB_HTTP_MAX_RESOURCE + 1]; +CHAR method[8]; +CHAR quote[2] = {0x22, 0}; +CHAR *buffer_ptr; +UINT i; +UINT status, status1, callback_status; +CHAR crlf[2] = {13,10}; +CHAR authorization_nc[NX_WEB_HTTP_MAX_RESOURCE + 1]; +CHAR authorization_cnonce[NX_WEB_HTTP_MAX_RESOURCE + 1]; +UINT realm_length; + + /* Default to no authentication request detected. */ + *auth_request_present = NX_FALSE; + + /* Default the status to authenticate. */ + status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; + + /* Is the authorization request present? */ + if (_nx_web_http_server_retrieve_digest_authorization(packet_ptr, authorization_response, authorization_uri, authorization_nc, authorization_cnonce)) + { + + /* Yes, an authorization request is present. */ + *auth_request_present = NX_TRUE; + + /* Pickup method from the packet. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + i = 0; + while (((buffer_ptr + i) < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (buffer_ptr[i] != ' ') && (i < (sizeof(method) - 1))) + { + + /* Copy bytes of method. */ + method[i] = buffer_ptr[i]; + i++; + } + + /* Null terminate method. */ + method[i] = (CHAR) NX_NULL; + + /* If the digest authenticate callback function is set, invoke the callback function. */ + if(server_ptr -> nx_web_http_server_digest_authenticate_callback) + { + callback_status = (server_ptr -> nx_web_http_server_digest_authenticate_callback)(server_ptr, name_ptr, realm_ptr, password_ptr, method, authorization_uri, authorization_nc, authorization_cnonce); + } + else + { + + /* If the digest authenticate callback is not set, assume it is success, for backward + compatibility reasons. */ + callback_status = NX_SUCCESS; + } + + /* Calculate what the MD5 should be. */ + _nx_web_http_server_digest_response_calculate(server_ptr, name_ptr, realm_ptr, password_ptr, _nx_web_http_server_nonce, method, authorization_uri, authorization_nc, authorization_cnonce, calculated_response); + + /* Determine if the calculated response is the same as the received response. */ + i = 0; + status = NX_SUCCESS; + while (i < NX_WEB_HTTP_MAX_ASCII_MD5 + 1) + { + /* Is there a mismatch? */ + if (calculated_response[i] != authorization_response[i]) + { + + /* Authorization mismatch. Continue to avoid timing attack. */ + status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; + } + + /* Otherwise, look at next character. */ + i++; + } + /* If digest authenticate callback function returns non-success value, the request is + considered unauthenticated. */ + if(callback_status != NX_SUCCESS) + status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; + } + + /* Determine if we need to send back an unauthorized request. */ + if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) + { + + /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ + + /* Check string length. */ + if (_nx_utility_string_length_check(realm_ptr, &realm_length, NX_MAX_STRING_LENGTH)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Allocate a packet for sending the response back. */ + status1 = _nx_web_http_server_response_packet_allocate(server_ptr, &packet_ptr, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if (status1 != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Return the internal NetX error. */ + return(status1); + } + + /* Insert the response header. */ + nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, NX_WEB_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_WEB_HTTP_STATUS_UNAUTHORIZED) - 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the type of authentication requested. */ + nx_packet_data_append(packet_ptr, "WWW-Authenticate: Digest realm=", 31, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the realm string into the buffer. */ + nx_packet_data_append(packet_ptr, realm_ptr, realm_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place a comma into the buffer. */ + nx_packet_data_append(packet_ptr, ",", 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the algorithm into the buffer. */ + nx_packet_data_append(packet_ptr, " algorithm=", 11, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the md5 tag into the buffer. */ + nx_packet_data_append(packet_ptr, "md5", 3, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place a comma into the buffer. */ + nx_packet_data_append(packet_ptr, ",", 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the nonce into the buffer. */ + nx_packet_data_append(packet_ptr, " nonce=", 7, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the nonce string into the buffer. */ + nx_packet_data_append(packet_ptr, _nx_web_http_server_nonce, sizeof(_nx_web_http_server_nonce) - 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert the double quote. */ + nx_packet_data_append(packet_ptr, quote, 1, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the qop="auth" parameter string into the buffer. */ + nx_packet_data_append(packet_ptr, ", qop=\"auth\"", 12, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place another into the buffer to signal end of FULL HTTP response. */ + nx_packet_data_append(packet_ptr, crlf, 2, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Send the response back to the client. */ + status1 = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + + /* Check for an error. */ + if (status1) + { + + /* Set the internal NetX error as the status return. */ + status = status1; + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + } + + /* Return the result of the authentication request. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_digest_response_calculate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the MD5 digest based on the supplied input */ +/* parameters. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr HTTP Server pointer */ +/* username Username string */ +/* realm Realm string */ +/* password Password string */ +/* nonce Authentication nonce string */ +/* method Request method string */ +/* uri Resource request string */ +/* nc Nonce count string */ +/* cnonce Client nonce string */ +/* result Computed digest string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_hex_ascii_convert Convert hex to ASCII */ +/* _nx_md5_initialize Initialize MD5 algorithm */ +/* _nx_md5_update Update MD5 digest */ +/* _nx_md5_digest_calculate Complete the MD5 algorithm */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_digest_authenticate */ +/* Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_digest_response_calculate(NX_WEB_HTTP_SERVER *server_ptr, CHAR *username, CHAR *realm, CHAR *password, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result) +{ + +CHAR md5_binary[NX_WEB_HTTP_MAX_BINARY_MD5]; +CHAR ha1_string[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; +CHAR ha2_string[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; +UINT username_length; +UINT password_length; +UINT realm_length; +UINT method_length; +UINT uri_length; +UINT nonce_length; +UINT nc_length; +UINT cnonce_length; + + /* Check string length. */ + if (_nx_utility_string_length_check(username, &username_length, NX_WEB_HTTP_MAX_NAME) || + _nx_utility_string_length_check(password, &password_length, NX_WEB_HTTP_MAX_PASSWORD) || + _nx_utility_string_length_check(realm, &realm_length, NX_MAX_STRING_LENGTH) || + _nx_utility_string_length_check(method, &method_length, 7) || + _nx_utility_string_length_check(uri, &uri_length, NX_WEB_HTTP_MAX_RESOURCE) || + _nx_utility_string_length_check(nonce, &nonce_length, sizeof(_nx_web_http_server_nonce) - 1) || + _nx_utility_string_length_check(nc, &nc_length, NX_WEB_HTTP_MAX_RESOURCE) || + _nx_utility_string_length_check(cnonce, &cnonce_length, NX_WEB_HTTP_MAX_RESOURCE)) + { + return; + } + + + /* Calculate the H(A1) portion of the digest. */ + _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) username, username_length); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) realm, realm_length); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) password, password_length); + _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); + + /* Convert this H(A1) portion to ASCII Hex representation. */ + _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, ha1_string); + + /* Make the H(A2) portion of the digest. */ + _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) method, method_length); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) uri, uri_length); + _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); + + /* Convert this H(A2) portion to ASCII Hex representation. */ + _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, ha2_string); + + /* Now make the final MD5 digest. */ + _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ha1_string, sizeof(ha1_string) - 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) nonce, nonce_length); + + /* Start of Internet Explorer bug work-around. */ + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) nc, nc_length); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) cnonce, cnonce_length); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":auth", 5); + /* End of Internet Explorer bug work-around. */ + + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); + _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ha2_string, sizeof(ha2_string) - 1); + _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); + + /* Finally, convert the response back to an ASCII string and place in + the destination. */ + _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, result); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_retrieve_digest_authorization PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the MD5 digest parameters from the */ +/* supplied request packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Request packet pointer */ +/* response Digest response pointer */ +/* uri URI from response pointer */ +/* nc Nonce count string */ +/* cnonce Client nonce string */ +/* */ +/* OUTPUT */ +/* */ +/* length Length of response (should be */ +/* 32). A value of 0 indicates */ +/* an error is present */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_digest_authenticate */ +/* Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce) +{ + +UINT length; +UINT found; +CHAR *buffer_ptr; +CHAR *saved_buffer_ptr; + + + /* Set the found flag to false. */ + found = NX_FALSE; + + /* Default the authorization request to zero. */ + length = 0; + + /* Set the response and uri strings to NULL. */ + response[0] = NX_NULL; + uri[0] = NX_NULL; + + /* Internet Explorer bug work-around. */ + nc[0] = NX_NULL; + cnonce[0] = NX_NULL; + + /* Setup pointer to buffer. */ + buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; + + /* Find the "Authorization: " token first. */ + while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Authorization: token. */ + if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && + ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && + ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && + ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && + ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && + ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && + ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && + ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && + ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && + ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && + ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && + ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && + (*(buffer_ptr+13) == ':') && + (*(buffer_ptr+14) == ' ')) + { + + /* Move the pointer up to the length token. */ + buffer_ptr = buffer_ptr + 15; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the first token was found. */ + if (!found) + { + + /* No, authorization is not present. Return a zero length. */ + return(length); + } + + /* Set the found flag back to false. */ + found = NX_FALSE; + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now check for the "Digest " token. */ + while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the Digest token. */ + if (((*buffer_ptr == 'd') || (*buffer_ptr == 'D')) && + ((*(buffer_ptr+1) == 'i') || (*(buffer_ptr+1) == 'I')) && + ((*(buffer_ptr+2) == 'g') || (*(buffer_ptr+2) == 'G')) && + ((*(buffer_ptr+3) == 'e') || (*(buffer_ptr+3) == 'E')) && + ((*(buffer_ptr+4) == 's') || (*(buffer_ptr+4) == 'S')) && + ((*(buffer_ptr+5) == 't') || (*(buffer_ptr+5) == 'T')) && + (*(buffer_ptr+6) == ' ')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 7; + + /* Set the found flag. */ + found = NX_TRUE; + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Determine if the second token was found. */ + if (!found) + { + + /* No, digest is not present. Return a zero length. */ + return(length); + } + + /* Now remove any extra blanks. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Start of Internet Explorer bug work-around (Parses nc and cnonce parameters). */ + + /* Save current buffer pointer, so each parameter search always starts from here. */ + saved_buffer_ptr = buffer_ptr; + + /* Now look for the nc in the digest response. */ + while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the nc token. */ + if (((*buffer_ptr == 'n') || (*buffer_ptr == 'N')) && + ((*(buffer_ptr+1) == 'c') || (*(buffer_ptr+1) == 'C')) && + (*(buffer_ptr+2) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 3; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes (should be no starting quote). */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the nc string (should be 8 hex characters; should not be quoted). */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote or comma is present (should be no ending quote). */ + if ((*buffer_ptr == (CHAR) 0x22) || (*buffer_ptr == ',')) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + nc[length++] = *buffer_ptr++; + } + + /* Null terminate the NC. */ + nc[length] = (CHAR) NX_NULL; + + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the cnonce in the digest response. */ + while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && + ((*(buffer_ptr+1) == 'n') || (*(buffer_ptr+1) == 'N')) && + ((*(buffer_ptr+2) == 'o') || (*(buffer_ptr+2) == 'O')) && + ((*(buffer_ptr+3) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+2) == 'C')) && + ((*(buffer_ptr+5) == 'e') || (*(buffer_ptr+2) == 'E')) && + (*(buffer_ptr+6) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 7; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the cnonce string. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + cnonce[length++] = *buffer_ptr++; + } + + /* Null terminate the CNONCE. */ + cnonce[length] = (CHAR) NX_NULL; + + /* End of Internet Explorer bug work-around. */ + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the uri in the digest response. */ + while (((buffer_ptr+4) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'u') || (*buffer_ptr == 'U')) && + ((*(buffer_ptr+1) == 'r') || (*(buffer_ptr+1) == 'R')) && + ((*(buffer_ptr+2) == 'i') || (*(buffer_ptr+2) == 'I')) && + (*(buffer_ptr+3) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 4; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and quotes. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Now pickup the uri string. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the authorization string into the destination. */ + uri[length++] = *buffer_ptr++; + } + + /* Null terminate the URI. */ + uri[length] = (CHAR) NX_NULL; + + /* Get saved buffer pointer. */ + buffer_ptr = saved_buffer_ptr; + + /* Now look for the digest response. */ + while (((buffer_ptr+9) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) + { + + /* Check for the uri token. */ + if (((*buffer_ptr == 'r') || (*buffer_ptr == 'R')) && + ((*(buffer_ptr+1) == 'e') || (*(buffer_ptr+1) == 'E')) && + ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+3) == 'p') || (*(buffer_ptr+2) == 'P')) && + ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+2) == 'O')) && + ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+2) == 'N')) && + ((*(buffer_ptr+6) == 's') || (*(buffer_ptr+2) == 'S')) && + ((*(buffer_ptr+7) == 'e') || (*(buffer_ptr+2) == 'E')) && + (*(buffer_ptr+8) == '=')) + { + + /* Move the pointer up to the actual authorization string. */ + buffer_ptr = buffer_ptr + 9; + + break; + } + + /* Move the pointer up to the next character. */ + buffer_ptr++; + } + + /* Now remove any extra blanks and leading quote. */ + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) + { + + /* Move the pointer up one character. */ + buffer_ptr++; + } + + /* Finally, pickup the response. */ + length = 0; + while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (*buffer_ptr != (CHAR) 0x3A) && (length < NX_WEB_HTTP_MAX_ASCII_MD5)) + { + + /* Determine if the ending quote is present. */ + if (*buffer_ptr == (CHAR) 0x22) + { + + break; + } + + /* Copy a character of the response string into the destination. */ + response[length++] = *buffer_ptr++; + } + + /* Null terminate response. */ + response[length] = (CHAR) NX_NULL; + + /* Check for an error. */ + if ((length != 32) || (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != (CHAR) 0x22)) + { + + /* Error, clear the length and the response string. */ + length = 0; + response[0] = (CHAR) NX_NULL; + } + + /* Return the length to the caller. */ + return(length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_hex_ascii_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts hexadecimal characters into an ASCII string. */ +/* */ +/* INPUT */ +/* */ +/* source Source hex string */ +/* source_length Length of source string */ +/* destination Pointer to destination string */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_digest_response_calculate */ +/* Digest authentication */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) +{ + +UINT i,j; +CHAR digit; + + + /* Setup destination index. */ + j = 0; + + /* Loop to process the entire source string. */ + for (i = 0; i < source_length; i++) + { + + /* Pickup the first nibble. */ + digit = (source[i] >> 4) & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + + /* Pickup the second nibble. */ + digit = source[i] & 0xF; + + /* Convert to ASCII and store. */ + if (digit <= 9) + destination[j++] = (CHAR)(digit + '0'); + else + destination[j++] = (CHAR)(digit + 'a' - 10); + } + + /* Finally, place a NULL in the destination string. */ + destination[j] = (CHAR) NX_NULL; +} +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_get_entity_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for getting the entity header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* entity_header_buffer Buffer to get entity header */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_get_entity_header */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) +{ + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (entity_header_buffer == NX_NULL)) + return NX_PTR_ERROR; + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_web_http_server_get_entity_header(server_ptr, packet_pptr, entity_header_buffer, buffer_size); +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(entity_header_buffer); + NX_PARAMETER_NOT_USED(buffer_size); + + return NX_WEB_HTTP_ERROR; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_get_entity_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the entity header and skip header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* entity_header_buffer Buffer to get entity header */ +/* buffer_size Size of buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_field_value_get */ +/* _nx_web_http_server_memicmp */ +/* _nx_web_http_server_boundary_find */ +/* nx_packet_release */ +/* nx_tcp_socket_receive */ +/* _nx_utility_string_length_check */ +/* memmove */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) +{ + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE +NX_WEB_HTTP_SERVER_MULTIPART *multipart_ptr; +UINT status; +UINT offset; +NX_PACKET *available_packet; +UINT crlf_match_count = 0; +UINT end_boundary_count = 2; +UINT skip_count = 2; +UCHAR *ch; +UINT index; + + /* Get multipart context. */ + multipart_ptr = &server_ptr -> nx_web_http_server_multipart; + + /* Is the multipart context initialized? */ + if(multipart_ptr -> nx_web_http_server_multipart_boundary[0] == 0) + { + ULONG field_length; + UINT quotation_index; + UINT i; + + /* No, it is not initialized. */ + + /* Get content type. */ + status = _nx_web_http_server_field_value_get(*packet_pptr, (UCHAR *)"content-type", 12, + multipart_ptr -> nx_web_http_server_multipart_boundary, NX_WEB_HTTP_MAX_HEADER_FIELD + 1); + if(status) + return status; + + /* Is the content type "multipart"? */ + /* Check the length. The length of "multipart/" is 10. */ + if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_web_http_server_multipart_boundary, (UINT *)&field_length, NX_WEB_HTTP_MAX_HEADER_FIELD)) + return NX_WEB_HTTP_ERROR; + if(field_length < 10) + return NX_WEB_HTTP_NOT_FOUND; + + /* Check the data. */ + if(_nx_web_http_server_memicmp(multipart_ptr -> nx_web_http_server_multipart_boundary, 10, + (UCHAR *)"multipart/", 10) != NX_SUCCESS) + return NX_WEB_HTTP_NOT_FOUND; + + /* Find the boundary. The length of "boundary=" is 9. */ + index = 0; + while((index + 9) < field_length) + { + if(_nx_web_http_server_memicmp(&multipart_ptr -> nx_web_http_server_multipart_boundary[index], 9, + (UCHAR *)"boundary=", 9) == NX_SUCCESS) + { + + break; + } + + /* Move the pointer up to the next character. */ + index++; + } + + /* Move the pointer up to the boundary value. */ + index += 9; + + /* Is boundary string found? */ + if((field_length - index) <= 1) + { + + /* Boundary not found or no boundary value. */ + return NX_WEB_HTTP_NOT_FOUND; + } + + /* Boundary is started with "CRLF--". */ + multipart_ptr -> nx_web_http_server_multipart_boundary[0] = 13; + multipart_ptr -> nx_web_http_server_multipart_boundary[1] = 10; + multipart_ptr -> nx_web_http_server_multipart_boundary[2] = '-'; + multipart_ptr -> nx_web_http_server_multipart_boundary[3] = '-'; + + /* Remove quotation. */ + if(multipart_ptr -> nx_web_http_server_multipart_boundary[index] == '"') + { + + /* Find the right quotation. */ + index++; + for(quotation_index = field_length; quotation_index > index; quotation_index--) + { + if(multipart_ptr -> nx_web_http_server_multipart_boundary[quotation_index] == '"') + break; + } + + /* Is the right quotation found? */ + if(quotation_index > index) + multipart_ptr -> nx_web_http_server_multipart_boundary[quotation_index] = 0; + else + { + + /* Boundary not valid. */ + return NX_WEB_HTTP_NOT_FOUND; + } + + /* Leave boundary string only. */ + memmove(&multipart_ptr -> nx_web_http_server_multipart_boundary[4], + &multipart_ptr -> nx_web_http_server_multipart_boundary[index], + quotation_index - index + 1); + } + else + { + + /* Directly copy boundary string to the head field. */ + i = 4; + index -= 4; + do + { + multipart_ptr -> nx_web_http_server_multipart_boundary[i] = multipart_ptr -> nx_web_http_server_multipart_boundary[index + i]; + i++; + }while((multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] != 0) && + (multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] != ' ')); + + /* Set the terminal character. */ + multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] = 0; + } + } + + /* If the received request is chunked. */ + if (server_ptr -> nx_web_http_server_request_chunked) + { + + /* If never processed the chunked packet, need to separate the HTTP header and content. */ + if (!server_ptr -> nx_web_http_server_expect_receive_bytes) + { + + available_packet = *packet_pptr; + + /* Separate the HTTP header and get the first content packet. */ + status = _nx_web_http_server_packet_content_find(server_ptr, &available_packet, NX_NULL); + if (status) + { + return(status); + } + + /* Append '\r\n' to the start of the packet. */ + available_packet -> nx_packet_prepend_ptr -= 2; + available_packet -> nx_packet_prepend_ptr[0] = 13; + available_packet -> nx_packet_prepend_ptr[1] = 10; + + /* Update packet length. */ + available_packet -> nx_packet_length += 2; + + /* Store the packet. */ + nx_packet_release(*packet_pptr); + *packet_pptr = available_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; + + /* Reset the offset. */ + multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; + } + } + + /* Find the boundary. */ + while(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_FALSE) + { + if(_nx_web_http_server_boundary_find(server_ptr, packet_pptr) != NX_SUCCESS) + break; + } + + /* Whether the boundary is found? */ + if(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_FALSE) + return NX_WEB_HTTP_NOT_FOUND; + + /* Update the packet and offset. */ + _nx_web_http_server_boundary_find(server_ptr, packet_pptr); + + /* Get offset of available data in the packet. */ + offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; + + /* Skip data that are not header. */ + available_packet = *packet_pptr; + + if(offset >= available_packet -> nx_packet_length) + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* All data has been processed. Get a new packet. */ + if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; + } +#ifndef NX_DISABLE_PACKET_CHAIN + else + { + while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) + { + offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); + + /* Get next packet. */ + available_packet = available_packet -> nx_packet_next; + } + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Get entity header. */ + ch = available_packet -> nx_packet_prepend_ptr + offset; + index = 0; + while((entity_header_buffer == NX_NULL) || (index < buffer_size)) + { + + /* Calculate valid CRLF. */ + if((*ch == 13) && ((crlf_match_count & 1) == 0)) + crlf_match_count++; + else if((*ch == 10) && ((crlf_match_count & 1) == 1)) + crlf_match_count++; + else if(*ch == '-') + { + + /* Check whether the last boundary is found. */ + if(end_boundary_count < 3) + end_boundary_count--; + + if(end_boundary_count == 0) + break; + } + else + { + end_boundary_count = 0xFF; + crlf_match_count = 0; + } + + /* Copy data to buffer. */ + if(skip_count >0) + skip_count--; + else + { + if(entity_header_buffer) + entity_header_buffer[index] = *ch; + index++; + } + multipart_ptr -> nx_web_http_server_multipart_available_offset++; + + /* Check whether two CRLFs are found. */ + if(crlf_match_count == 4) + break; + + /* Get next character. */ + if((ch + 1) >= available_packet -> nx_packet_append_ptr) + { + + /* ch points to the end of this packet. */ +#ifndef NX_DISABLE_PACKET_CHAIN + if(available_packet -> nx_packet_next) + { + + /* Copy data from next packet. */ + available_packet = available_packet -> nx_packet_next; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* Get a new packet and copy data from it. */ + status = _nx_web_http_server_packet_get(server_ptr, &available_packet); + + /* Check the return status. */ + if (status != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; + + /* Reset the offset. */ + multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; + } + + ch = available_packet -> nx_packet_prepend_ptr; + } + else + ch++; + + } + + /* Check whether two CRLFs are found. */ + if(crlf_match_count == 4) + { + + /* Set terminal 0. */ + if(entity_header_buffer) + entity_header_buffer[index - 4] = 0; + return NX_SUCCESS; + } + else + return NX_WEB_HTTP_NOT_FOUND; +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(entity_header_buffer); + NX_PARAMETER_NOT_USED(buffer_size); + + return NX_WEB_HTTP_ERROR; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_get_entity_content PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for getting the entity content. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* available_offset Return the offset */ +/* available_length Return the length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_get_entity_content */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) +{ + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (available_offset == NX_NULL) || (available_length == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check whether boundary is found. */ + if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_boundary[0] == 0) + return(NX_WEB_HTTP_ERROR); + + return _nx_web_http_server_get_entity_content(server_ptr, packet_pptr, available_offset, available_length); +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(available_offset); + NX_PARAMETER_NOT_USED(available_length); + + return NX_WEB_HTTP_ERROR; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_get_entity_content PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the entity content. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* available_offset Return the offset */ +/* available_length Return the length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_boundary_find */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) +{ + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE +UINT status; + + /* Whether the boundary is found? */ + if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_boundary_find == NX_TRUE) + return NX_WEB_HTTP_BOUNDARY_ALREADY_FOUND; + + status = _nx_web_http_server_boundary_find(server_ptr, packet_pptr); + if(status) + return status; + + /* Set the offset and length. */ + *available_offset = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_available_offset; + *available_length = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_available_length; + + return NX_SUCCESS; +#else + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(packet_pptr); + NX_PARAMETER_NOT_USED(available_offset); + NX_PARAMETER_NOT_USED(available_length); + + return NX_WEB_HTTP_ERROR; +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ +} + + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_boundary_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds boundary in packet even if it is chained. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_release */ +/* nx_tcp_socket_receive */ +/* _nx_web_http_server_match_string */ +/* _nx_utility_string_length_check */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_entity_header */ +/* _nx_web_http_server_get_entity_content */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_boundary_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr) +{ + +NX_WEB_HTTP_SERVER_MULTIPART *multipart_ptr; +NX_PACKET *available_packet; +UINT offset; +ULONG match_count = 0; +UCHAR *match_end_ptr; +UINT boundary_length; + + /* Get multipart context. */ + multipart_ptr = &server_ptr -> nx_web_http_server_multipart; + + /* Is boundary already found? */ + if(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_TRUE) + { + + /* Yes. Update the packet and offset. */ + if(multipart_ptr -> nx_web_http_server_multipart_next_packet != NX_NULL) + { + nx_packet_release(*packet_pptr); + *packet_pptr = multipart_ptr -> nx_web_http_server_multipart_next_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = multipart_ptr -> nx_web_http_server_multipart_next_packet; + } + + multipart_ptr -> nx_web_http_server_multipart_available_offset = multipart_ptr -> nx_web_http_server_multipart_next_available_offset; + + /* Reset next packet and available offset. */ + multipart_ptr -> nx_web_http_server_multipart_next_packet = NX_NULL; + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; + + /* Reset boundary find. */ + multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_FALSE; + + return NX_SUCCESS; + } + + /* Is the boundary in the next packet? */ + if(multipart_ptr -> nx_web_http_server_multipart_next_packet) + { + + /* Yes, we're done with this packet. */ + nx_packet_release(*packet_pptr); + + /* Update the packet and multipart offset. */ + *packet_pptr = multipart_ptr -> nx_web_http_server_multipart_next_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = multipart_ptr -> nx_web_http_server_multipart_next_packet; + multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; + } + else if(multipart_ptr -> nx_web_http_server_multipart_next_available_offset) + { + + /* Find boundary in this packet. */ + /* Update the offset. */ + multipart_ptr -> nx_web_http_server_multipart_available_offset = multipart_ptr -> nx_web_http_server_multipart_next_available_offset; + } + else + { + + /* Find boundary from this packet. */ + /* Initialize the offset. */ + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; + } + + /* Reset next packet. */ + multipart_ptr -> nx_web_http_server_multipart_next_packet = NX_NULL; + + /* Reset boundary find. */ + multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_FALSE; + + + /* Get offset of available data in the packet. */ + offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; + + /* Skip data that are not header. */ + available_packet = *packet_pptr; + + if(offset >= available_packet -> nx_packet_length) + { + + /* Release the packet that has been processed. */ + nx_packet_release(*packet_pptr); + + /* All data has been processed. Get a new packet. */ + if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + /* Store the packet. */ + *packet_pptr = available_packet; + server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; + + /* Reset the offset. */ + multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; + offset = 0; + } + else + { +#ifndef NX_DISABLE_PACKET_CHAIN + while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) + { + offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); + + /* Get next packet. */ + available_packet = available_packet -> nx_packet_next; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Check boundary length. */ + if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_web_http_server_multipart_boundary, &boundary_length, NX_WEB_HTTP_MAX_HEADER_FIELD)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Look for the boundary string in the (next) packet. */ + while(_nx_web_http_server_match_string(available_packet -> nx_packet_prepend_ptr + offset, + available_packet -> nx_packet_append_ptr, + multipart_ptr -> nx_web_http_server_multipart_boundary, + boundary_length, + &match_count, &match_end_ptr) != NX_SUCCESS) + { + + /* Match string in the next packet. */ +#ifndef NX_DISABLE_PACKET_CHAIN + if(available_packet -> nx_packet_next) + { + multipart_ptr -> nx_web_http_server_multipart_next_available_offset += (UINT)((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) - offset); + available_packet = available_packet -> nx_packet_next; + offset = 0; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + break; + } + + /* Is boundary matched? */ + if(match_end_ptr) + { + + /* Yes. Found a match. */ + multipart_ptr -> nx_web_http_server_multipart_next_available_offset += (UINT)((UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) - offset); + multipart_ptr -> nx_web_http_server_multipart_available_length = multipart_ptr -> nx_web_http_server_multipart_next_available_offset - multipart_ptr -> nx_web_http_server_multipart_available_offset - match_count; + multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_TRUE; + + } + else if(match_count) + { + + /* Set the available length to all remaining data. */ + multipart_ptr -> nx_web_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_web_http_server_multipart_available_offset; + + /* Partial match. Get another packet. */ + if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) + { + + /* Error, return to caller. */ + return(NX_WEB_HTTP_TIMEOUT); + } + + /* Match the boundary again. */ + if(_nx_web_http_server_match_string(available_packet -> nx_packet_prepend_ptr, + available_packet -> nx_packet_append_ptr, + multipart_ptr -> nx_web_http_server_multipart_boundary, + boundary_length, + &match_count, &match_end_ptr) == NX_SUCCESS) + { + + /* Yes. Find a match. */ + if((ULONG)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) < match_count) + { + + /* The boundary is between two packets. */ + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = (UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr); + multipart_ptr -> nx_web_http_server_multipart_available_length -= boundary_length - multipart_ptr -> nx_web_http_server_multipart_next_available_offset; + multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_TRUE; + } + else + { + + /* The boundary is in the next packet. */ + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; + } + } + else + { + + /* The boundary is not found. */ + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; + } + + /* Store the packet. */ + multipart_ptr -> nx_web_http_server_multipart_next_packet = available_packet; + + } + else + { + + /* Set the available length to all remaining data. */ + multipart_ptr -> nx_web_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_web_http_server_multipart_available_offset; + multipart_ptr -> nx_web_http_server_multipart_next_available_offset = (*packet_pptr) -> nx_packet_length; + } + + return NX_SUCCESS; +} +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_match_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares a target string in specified memory area. */ +/* */ +/* INPUT */ +/* */ +/* src_start Pointer to start of source */ +/* src_end Pointer to end of source */ +/* target Pointer to target */ +/* target_length Length to target */ +/* match_count Return the match count */ +/* match_end_ptr Return the end match position */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* memcmp Compare memory data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_boundary_find */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr) +{ + +UCHAR *ch; +ULONG pre_match = *match_count; +ULONG remain_match; + + /* Initialize. */ + *match_end_ptr = NX_NULL; + + /* Process part match. */ + while(pre_match) + { + + /* Compare pre-match. */ + if(memcmp(target, target + (*match_count - pre_match), pre_match) == 0) + { + + /* Calculate the remain match. */ + remain_match = target_length - pre_match; + + /* The pre-match is the same. */ + if((ULONG)(src_end - src_start) < remain_match) + remain_match = (ULONG)(src_end - src_start); + + if(memcmp(target + pre_match, src_start, remain_match) == 0) + { + + /* Remain part matches. */ + *match_count = pre_match + remain_match; + + if(*match_count < target_length) + { + + /* Part match. */ + return NX_WEB_HTTP_NOT_FOUND; + } + + /* Full match. */ + *match_end_ptr = src_start + remain_match; + return NX_SUCCESS; + } + } + + pre_match--; + } + + ch = src_start; + + /* Perform full match. */ + *match_count = target_length; + while(ch + *match_count <= src_end) + { + if(memcmp(ch, target, *match_count) == 0) + { + + /* Find a match. */ + *match_end_ptr = ch + *match_count; + return NX_SUCCESS; + } + + ch++; + } + + /* Perform part match. */ + for(*match_count = target_length - 1; *match_count > 0; *match_count = *match_count - 1) + { + if(ch + *match_count <= src_end) + { + if(memcmp(ch, target, *match_count) == 0) + { + + /* Find a match. */ + return NX_WEB_HTTP_NOT_FOUND; + } + + ch++; + } + } + + return NX_WEB_HTTP_NOT_FOUND; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_field_value_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets field value by field name from HTTP header. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet */ +/* field_name Name of field in header */ +/* name_length Length of name field */ +/* field_value Return of field value */ +/* field_value_size Size of field value */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_memicmp Compare ignore case */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process */ +/* _nx_web_http_server_get_entity_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size) +{ + +UCHAR *ch; +UINT index; + + + /* Initialize. */ + ch = packet_ptr -> nx_packet_prepend_ptr; + + /* Loop to find field name. */ + while(ch + name_length < packet_ptr -> nx_packet_append_ptr) + { + if(_nx_web_http_server_memicmp(ch, name_length, field_name, name_length) == NX_SUCCESS) + { + + /* Field name found. */ + break; + } + + /* Move the pointer up to the next character. */ + ch++; + } + + /* Skip field name and ':'. */ + ch += name_length + 1; + + /* Is field name found? */ + if(ch >= packet_ptr -> nx_packet_append_ptr) + return NX_WEB_HTTP_NOT_FOUND; + + /* Skip white spaces. */ + while(*ch == ' ') + { + if(ch >= packet_ptr -> nx_packet_append_ptr) + return NX_WEB_HTTP_NOT_FOUND; + + /* Get next character. */ + ch++; + } + + /* Copy field value. */ + index = 0; + while(index < field_value_size) + { + + /* Whether the end of line CRLF is not found? */ + if(ch + 2 > packet_ptr -> nx_packet_append_ptr) + return NX_WEB_HTTP_NOT_FOUND; + + /* Compare CRLF. */ + if((*ch == 13) && (*(ch + 1) == 10)) + break; + + /* Copy data. */ + field_value[index++] = *ch++; + } + + /* Buffer overflow? */ + if(index == field_value_size) + return NX_WEB_HTTP_NOT_FOUND; + + /* Trim white spaces. */ + while((index > 0) && (field_value[index - 1] == ' ')) + index--; + + /* Append terminal 0. */ + field_value[index] = 0; + + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_memicmp PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function compares two pieces of memory case insensitive. */ +/* */ +/* INPUT */ +/* */ +/* src Pointer to source */ +/* src_length Length of source */ +/* dest Pointer to destination */ +/* dest_length Length of destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_entity_header */ +/* _nx_web_http_server_field_value_get */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) +{ +UCHAR ch; + + /* Compare the length. */ + if(src_length != dest_length) + return NX_WEB_HTTP_FAILED; + + while(src_length) + { + + /* Is src lowercase? */ + if((*src >= 'a') && (*src <= 'z')) + ch = (UCHAR)(*src - 'a' + 'A'); + + /* Is src uppercase? */ + else if((*src >= 'A') && (*src <= 'Z')) + ch = (UCHAR)(*src - 'A' + 'a'); + else + ch = *src; + + /* Compare case insensitive. */ + if((*src != *dest) && (ch != *dest)) + return NX_WEB_HTTP_FAILED; + + /* Pickup next character. */ + src_length--; + src++; + dest++; + } + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_generate_response_header PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function generates HTTP response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_response_packet_allocate */ +/* Allocate response packet */ +/* nx_packet_data_append Append packet data */ +/* memcmp Compare string */ +/* _nx_web_http_server_number_convert Convert number to ASCII */ +/* _nx_web_http_server_date_to_string Convert data to string */ +/* nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process */ +/* _nx_web_http_server_put_process */ +/* _nx_web_http_server_delete_process */ +/* _nx_web_http_server_response_send */ +/* _nx_web_http_server_callback_generate_response_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT status_code_length, + UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, + UINT additional_header_length) +{ + +UINT status; +UINT temp; +CHAR temp_string[30]; +CHAR crlf[2] = {13,10}; +NX_PACKET *packet_ptr; +CHAR status_code_ok; +CHAR status_code_not_modified; + + + /* Allocate a packet for sending the response back. */ + status = _nx_web_http_server_response_packet_allocate(server_ptr, packet_pptr, NX_WAIT_FOREVER); + + /* Determine if an error occurred in the packet allocation. */ + if(status != NX_SUCCESS) + { + + /* Indicate an allocation error occurred. */ + server_ptr -> nx_web_http_server_allocation_errors++; + + /* Just return. */ + return status; + } + else + packet_ptr = *packet_pptr; + + /* Check status code. */ + if(memcmp(status_code, NX_WEB_HTTP_STATUS_OK, sizeof(NX_WEB_HTTP_STATUS_OK)) == 0) + status_code_ok = NX_TRUE; + else + status_code_ok = NX_FALSE; + + if(memcmp(status_code, NX_WEB_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_WEB_HTTP_STATUS_NOT_MODIFIED)) == 0) + status_code_not_modified = NX_TRUE; + else + status_code_not_modified = NX_FALSE; + + /* Insert the status line. */ + /* Place HTTP-Version. */ + status = nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert space. */ + status += nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + status += nx_packet_data_append(packet_ptr, status_code, status_code_length, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Determine if there is content_type. */ + if(content_type) + { + + /* Insert the content type. */ + status += nx_packet_data_append(packet_ptr, "Content-Type: ", 14, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + status += nx_packet_data_append(packet_ptr, content_type, content_type_length, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + +#ifndef NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH + /* Determine if there is content_length. */ + if(content_length || (status_code_not_modified == NX_TRUE)) + { +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + + /* Place the "Connection" field in the header. */ + if(server_ptr -> nx_web_http_server_keepalive == NX_TRUE) + { + + /* Keepalive. */ + status += nx_packet_data_append(packet_ptr, "Connection: keep-alive", 22, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + else +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + { + + /* Close. */ + status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if(content_length) + { + + /* Convert the content_length to ASCII representation. */ + temp = _nx_web_http_server_number_convert(content_length, temp_string); + + /* Place the "Content-Length" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Content-Length: ", 16, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + status += nx_packet_data_append(packet_ptr, temp_string, temp, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + } + else +#endif /* NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH */ + { + + /* Place the "Connection" field in the header. */ + + /* Force close the connection since there's no content-length. */ + status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + server_ptr -> nx_web_http_server_keepalive = NX_FALSE; +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Insert Date header if callback function is set. */ + if(server_ptr -> nx_web_http_server_gmt_get) + { + NX_WEB_HTTP_SERVER_DATE date; + + /* Get current date. */ + server_ptr -> nx_web_http_server_gmt_get(&date); + + /* Convert date to string. */ + temp = _nx_web_http_server_date_to_string(&date, temp_string); + + /* Place the "Date" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Date: ", 6, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert date. */ + status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Set Cache Control if callback function is set. */ + if((server_ptr -> nx_web_http_server_cache_info_get) && + ((status_code_ok == NX_TRUE) || (status_code_not_modified == NX_TRUE)) && + (server_ptr -> nx_web_http_server_request_type == NX_WEB_HTTP_SERVER_GET_REQUEST)) + { + UINT max_age; + + /* Get cache infomation. */ + if(server_ptr -> nx_web_http_server_cache_info_get(server_ptr -> nx_web_http_server_request_resource, &max_age, &date) == NX_TRUE) + { + + /* Place "Cache-control" header. */ + status += nx_packet_data_append(packet_ptr, "Cache-Control: max-age=", 23, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Convert the max-age to ASCII representation. */ + temp = _nx_web_http_server_number_convert(max_age, temp_string); + status += nx_packet_data_append(packet_ptr, temp_string, temp, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if(status_code_ok == NX_TRUE) + { + + /* Convert date to string. */ + temp = _nx_web_http_server_date_to_string(&date, temp_string); + + /* Place the "Last-Modified" field in the header. */ + status += nx_packet_data_append(packet_ptr, "Last-Modified: ", 15, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Insert date. */ + status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + } + } + } + + /* Insert additional header. */ + if(additional_header) + { + status += nx_packet_data_append(packet_ptr, additional_header, additional_header_length, + server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Place the into the buffer. */ + status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + + if (status != NX_SUCCESS) + { + + /* Just release the packet. */ + nx_packet_release(packet_ptr); + } + + return status; +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_request_read PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the next data in byte. */ +/* */ +/* INPUT */ +/* */ +/* Server_ptr Pointer to HTTP server */ +/* data Returned data */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_receive Receive another packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_request_byte_expect */ +/* Checks next byte is expected */ +/* _nx_web_http_server_chunked_size_get Gets chunk size of request */ +/* packet chunk */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_request_read(NX_WEB_HTTP_SERVER *server_ptr, UCHAR *data, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; + + /* If there is no remaining data. */ + while (server_ptr -> nx_web_http_server_chunked_request_remaining_size == 0) + { + + /* Release the previous received packet. */ + if (server_ptr -> nx_web_http_server_request_packet) + { + nx_packet_release(server_ptr -> nx_web_http_server_request_packet); + server_ptr -> nx_web_http_server_request_packet = NX_NULL; + } + + /* Receive another packet. */ + status = _nx_web_http_server_receive(server_ptr, &(server_ptr -> nx_web_http_server_request_packet), wait_option); + if (status) + { + return(status); + } + + /* Update the packet pointer, data pointer and remaining size. */ + (*current_packet_pptr) = server_ptr -> nx_web_http_server_request_packet; + (*current_data_pptr) = server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr; + server_ptr -> nx_web_http_server_chunked_request_remaining_size = server_ptr -> nx_web_http_server_request_packet -> nx_packet_length; + } + + /* Process the packet chain. */ + if ((*current_data_pptr) == (*current_packet_pptr) -> nx_packet_append_ptr) + { +#ifndef NX_DISABLE_PACKET_CHAIN + if ((*current_packet_pptr) -> nx_packet_next == NX_NULL) + { + return(NX_INVALID_PACKET); + } + + (*current_packet_pptr) = (*current_packet_pptr) -> nx_packet_next; + (*current_data_pptr) = (*current_packet_pptr) -> nx_packet_prepend_ptr; + + /* Release the processed packet in the packet chain. */ + if (server_ptr -> nx_web_http_server_request_packet) + { + server_ptr -> nx_web_http_server_request_packet -> nx_packet_next = NX_NULL; + nx_packet_release(server_ptr -> nx_web_http_server_request_packet); + server_ptr -> nx_web_http_server_request_packet = (*current_packet_pptr); + } +#else + return(NX_INVALID_PACKET); +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Set the returned data. */ + *data = *(*current_data_pptr); + + /* Update the data pointer and remaining size. */ + (*current_data_pptr)++; + server_ptr -> nx_web_http_server_chunked_request_remaining_size--; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_request_byte_expect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if next byte is the expected data. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* data Expected data */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Compare result */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_request_read Get next data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_chunked_size_get Gets chunk size of request */ +/* _nx_web_http_server_request_chunked_get */ +/* Get chunk data from request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_request_byte_expect(NX_WEB_HTTP_SERVER *server_ptr, UCHAR data, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; +UCHAR tmp; + + /* Get next data. */ + status = _nx_web_http_server_request_read(server_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); + + if (status) + { + return(status); + } + + /* Return the compare result. */ + if (tmp != data) + { + return(NX_NOT_FOUND); + } + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_chunked_size_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the chunk size of the request packet chunk. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* chunk_size Returned chunk size */ +/* wait_option Suspension option */ +/* current_packet_pptr Pointer to the packet being */ +/* processed */ +/* current_data_ptr Pointer to the data will be */ +/* processed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_chunked_size_get Get chunk size */ +/* _nx_web_http_server_request_byte_expect */ +/* Check if next byte is expected*/ +/* nx_packet_release Release packet */ +/* nx_packet_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_chunked_size_get(NX_WEB_HTTP_SERVER *server_ptr, UINT *chunk_size, ULONG wait_option, + NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) +{ +UINT status; +UINT size = 0; +UCHAR tmp; +UINT chunk_extension = 0; + + if (server_ptr -> nx_web_http_server_actual_bytes_received < server_ptr -> nx_web_http_server_expect_receive_bytes) + { + + /* If there are bytes need to receive, set the size need to receive as chunk size. */ + *chunk_size = server_ptr -> nx_web_http_server_expect_receive_bytes - server_ptr -> nx_web_http_server_actual_bytes_received; + } + else + { + + /* Get the chunk size. */ + while (1) + { + + /* Read next byte from request packet. */ + status = _nx_web_http_server_request_read(server_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); + if (status) + { + return(status); + } + + /* Skip the chunk extension. */ + if (chunk_extension && (tmp != '\r')) + { + continue; + } + + /* Calculate the size. */ + if ((tmp >= 'a') && (tmp <= 'f')) + { + size = (size << 4) + 10 + (UINT)(tmp - 'a'); + } + else if ((tmp >= 'A') && (tmp <= 'F')) + { + size = (size << 4) + 10 + (UINT)(tmp - 'A'); + } + else if ((tmp >= '0') && (tmp <= '9')) + { + size = (size << 4) + (UINT)(tmp - '0'); + } + else if (tmp == '\r') + { + + /* Find the end of chunk header. */ + break; + } + else if (tmp == ';') + { + + /* Find chunk extension. */ + chunk_extension = 1; + } + else + { + return(NX_NOT_FOUND); + } + } + + /* Expect '\n'. */ + status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, current_packet_pptr, current_data_pptr); + if (status) + { + return(status); + } + + *chunk_size = size; + } + + /* If there is no remaining data, receive another packet. */ + while (server_ptr -> nx_web_http_server_chunked_request_remaining_size == 0) + { + if (server_ptr -> nx_web_http_server_request_packet) + { + nx_packet_release(server_ptr -> nx_web_http_server_request_packet); + } + + status = _nx_web_http_server_receive(server_ptr, &(server_ptr -> nx_web_http_server_request_packet), wait_option); + if (status) + { + return(status); + } + + /* Update the current request packet, data pointer and remaining size. */ + (*current_packet_pptr) = server_ptr -> nx_web_http_server_request_packet; + (*current_data_pptr) = server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr; + server_ptr -> nx_web_http_server_chunked_request_remaining_size = server_ptr -> nx_web_http_server_request_packet -> nx_packet_length; + } + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_request_chunked_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function gets the chunk data from chunked request. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to the packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_chunked_size_get Get chunk size */ +/* _nx_web_http_server_request_byte_expect */ +/* Check if next byte is expected*/ +/* nx_packet_allocate Allocate packet */ +/* nx_packet_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_packet_get Get next packet from HTTP */ +/* server socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_request_chunked_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG wait_option) +{ +UINT status; +UINT chunk_size = 0, length = 0, temp_size = 0; +UINT remaining_size = 0; +NX_PACKET *packet_ptr; +NX_PACKET *current_packet_ptr = NX_NULL; +UCHAR *current_data_ptr = NX_NULL; + + /* Set pointer for processing packet data. */ + current_packet_ptr = server_ptr -> nx_web_http_server_request_packet; + + if (current_packet_ptr) + { + + /* Set current data pointer. */ + current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; + } + + /* Get chunk size. */ + status = _nx_web_http_server_chunked_size_get(server_ptr, &chunk_size, wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + /* Check if it's the end. */ + if (chunk_size == 0) + { + + /* Read CRLF. */ + status = _nx_web_http_server_request_byte_expect(server_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + *packet_pptr = NX_NULL; + + return(NX_WEB_HTTP_GET_DONE); + } + + /* Set the return packet. */ + *packet_pptr = server_ptr -> nx_web_http_server_request_packet; + server_ptr -> nx_web_http_server_request_packet = NX_NULL; + packet_ptr = *packet_pptr; + packet_ptr -> nx_packet_prepend_ptr = current_data_ptr; + remaining_size = server_ptr -> nx_web_http_server_chunked_request_remaining_size; + + /* Process the chunk data. */ + if (chunk_size <= remaining_size) + { + + /* One or more chunk in the remaining data. */ + temp_size = chunk_size; + + /* Check if the chunk data is all in this packet. */ + while (temp_size > (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr)) + { + +#ifndef NX_DISABLE_PACKET_CHAIN + if (current_packet_ptr -> nx_packet_next == NX_NULL) + { + return(NX_INVALID_PACKET); + } + + temp_size -= (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); + current_packet_ptr = current_packet_ptr -> nx_packet_next; + current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; +#else + return(NX_INVALID_PACKET); +#endif /* NX_DISABLE_PACKET_CHAIN */ + } + + /* Skip the chunk data. */ + current_data_ptr += temp_size; + server_ptr -> nx_web_http_server_chunked_request_remaining_size -= chunk_size; + length = chunk_size; + + /* Read CRLF. */ + status = _nx_web_http_server_request_byte_expect(server_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); + if (status) + { + return(status); + } + + /* Check the remaining data. */ + if (server_ptr -> nx_web_http_server_chunked_request_remaining_size) + { + if (server_ptr -> nx_web_http_server_request_packet) + { + + /* If received new packet, adjust the prepend pointer of this packet. */ + server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr = current_data_ptr; + } + else + { + + /* Copy the remaining data to a new packet. */ + /* Allocate a packet. */ + status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, + &(server_ptr -> nx_web_http_server_request_packet), + 0, wait_option); + if (status) + { + return(status); + } + + /* Copy the remaining data in current packet to the new packet. */ + temp_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); + status = nx_packet_data_append(server_ptr -> nx_web_http_server_request_packet, + current_data_ptr, + temp_size, + server_ptr -> nx_web_http_server_packet_pool_ptr, + wait_option); + if (status) + { + return(status); + } + + /* Check if any remaining data not in current packet. */ + if (server_ptr -> nx_web_http_server_chunked_request_remaining_size > temp_size) + { +#ifndef NX_DISABLE_PACKET_CHAIN + + /* If there are chained packets, append the packets to the new packet. */ + if (current_packet_ptr -> nx_packet_next) + { + server_ptr -> nx_web_http_server_request_packet -> nx_packet_next = current_packet_ptr -> nx_packet_next; + server_ptr -> nx_web_http_server_request_packet -> nx_packet_last = current_packet_ptr -> nx_packet_last; + current_packet_ptr -> nx_packet_next = NX_NULL; + } + else +#endif /* NX_DISABLE_PACKET_CHAIN */ + { + return(NX_INVALID_PACKET); + } + } + } + + /* Update the packet length. */ + server_ptr -> nx_web_http_server_request_packet -> nx_packet_length = server_ptr -> nx_web_http_server_chunked_request_remaining_size; + } + } + else + { + + /* All the remaining data is in this chunk. */ + server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; + length = remaining_size; + } + + /* Set the received bytes. */ + server_ptr -> nx_web_http_server_expect_receive_bytes = chunk_size; + server_ptr -> nx_web_http_server_actual_bytes_received = length; + +#ifndef NX_DISABLE_PACKET_CHAIN + /* Set length of the packet chain header. */ + (*packet_pptr) -> nx_packet_length = length; + + /* Find the last packet. */ + while (packet_ptr -> nx_packet_next && + (length > (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr))) + { + length -= (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); + packet_ptr = packet_ptr -> nx_packet_next; + } + + /* Set the last packet. */ + (*packet_pptr) -> nx_packet_last = packet_ptr; + + /* Maybe the '\r\n' is in another packet, release this packet. */ + if (packet_ptr -> nx_packet_next) + { + nx_packet_release(packet_ptr -> nx_packet_next); + packet_ptr -> nx_packet_next = NX_NULL; + } +#endif /* NX_DISABLE_PACKET_CHAIN */ + + /* Set packet length and append pointer. */ + /* If the packet is chained, set the length and append pointer of the last packet. */ + packet_ptr -> nx_packet_length = length; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + length; + + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_response_chunked_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the HTTP response chunked set */ +/* API call. */ +/* */ +/* INPUT */ +/* */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* chunk_size Size of the chunk */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_response_chunked_set */ +/* Actual response chunked set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr) +{ +UINT status; + + /* Make sure the client instance makes sense. */ + if ((server_ptr == NX_NULL) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Call actual response chunked set function. */ + status = _nx_web_http_server_response_chunked_set(server_ptr, chunk_size, packet_ptr); + + /* Return success to the caller. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_response_chunked_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the chunked information of chunked response. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* chunk_size Size of the chunk */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_data_append Append the packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr) +{ +UINT status; +UINT temp_size, i, j; +CHAR temp_string[10]; +CHAR crlf[2] = {13,10}; + + /* Covert the size to ASCII. */ + temp_size = chunk_size; + i = 0; + + while (temp_size) + { + + for (j = i; j > 0; j--) + { + temp_string[j] = temp_string[j - 1]; + } + + if ((temp_size & 0x0F) < 10) + { + temp_string[0] = (CHAR)((temp_size & 0x0F) + '0'); + } + else + { + temp_string[0] = (CHAR)((temp_size & 0x0F) - 10 + 'a'); + } + temp_size = temp_size >> 4; + i++; + } + + if (i == 0) + { + temp_string[i++] = '0'; + } + + /* Place the chunk size in the packet. */ + status = nx_packet_data_append(packet_ptr, temp_string, i, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + if (status) + { + return(status); + } + + /* Place the CRLF to signal the end of the chunk size. */ + status = nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + if (status) + { + return(status); + } + + /* Set the request chunked flag. */ + server_ptr -> nx_web_http_server_response_chunked = NX_TRUE; + + /* The total bytes need to transfer is chunk size plus chunk header length. */ + server_ptr -> nx_web_http_server_expect_transfer_bytes = chunk_size + i + 2; + server_ptr -> nx_web_http_server_actual_bytes_transferred = 0; + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_chunked_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks if the packet is chunked. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to the packet */ +/* */ +/* OUTPUT */ +/* */ +/* status The packet is chunked or not */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_field_value_get Get filed value */ +/* _nx_web_http_server_memicmp Compare two strings */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_packet_content_find */ +/* Find content length in the */ +/* HTTP header */ +/* _nx_web_http_server_content_get_extended */ +/* Get user specified portion of */ +/* HTTP header */ +/* _nx_web_http_server_receive_data HTTP Server receive processing*/ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_chunked_check(NX_PACKET *packet_ptr) +{ +UINT status; +CHAR temp_string[20]; +UINT temp_string_length; + + /* Check if the packet is chunked. */ + status = _nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"Transfer-Encoding", 17, (UCHAR *)temp_string, sizeof(temp_string)); + + if ((status == NX_SUCCESS) && + (_nx_utility_string_length_check(temp_string, &temp_string_length, sizeof(temp_string) - 1) == NX_SUCCESS) && + (_nx_web_http_server_memicmp((UCHAR *)temp_string, temp_string_length, (UCHAR *)"chunked", 7) == 0)) + { + return(NX_TRUE); + } + + return(NX_FALSE); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_response_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the call to allocate packets for */ +/* an HTTP(S) server session, as used for PUT and POST operations. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP client */ +/* packet_ptr Pointer to allocated packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nxe_web_http_server_response_packet_allocate */ +/* Actual packet allocation call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, + UINT wait_option) +{ +UINT status; + + /* Check our pointers. */ + if(server_ptr == NX_NULL || packet_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Call the actual function. */ + status = _nx_web_http_server_response_packet_allocate(server_ptr, packet_ptr, wait_option); + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_response_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates a packet for Server HTTP(S) responses so */ +/* that servers needing to send large amounts of data (such as for */ +/* multi-part file upload) can allocated the needed. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to allocated packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_packet_allocate Allocate a TLS packet */ +/* nx_packet_allocate Allocate a TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, + UINT wait_option) +{ +UINT status; + + /* Allocate a packet. */ +#ifdef NX_WEB_HTTPS_ENABLE + if(server_ptr -> nx_web_http_is_https_server) + { + status = nx_secure_tls_packet_allocate(&(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session), + server_ptr -> nx_web_http_server_packet_pool_ptr, + packet_ptr, wait_option); + } + else +#endif + { + status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, + packet_ptr, + NX_TCP_PACKET, wait_option); + } + + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_generate_response_header */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for generating HTTP response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* content_length Length of content */ +/* content_type Type of content */ +/* additional_header Other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_callback_generate_response_header */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (status_code == NX_NULL)) + return(NX_PTR_ERROR); + + return _nx_web_http_server_callback_generate_response_header(server_ptr, packet_pptr, status_code, content_length, content_type, additional_header); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_generate_response_header */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to generate HTTP */ +/* response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* content_length Length of content */ +/* content_type Type of content */ +/* additional_header Other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_generate_response_header */ +/* Generate response header */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header) +{ +UINT status_code_length = 0; +UINT content_type_length = 0; +UINT additional_header_length = 0; + + /* Check status code, content type and additional header length. */ + if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || + (content_type && _nx_utility_string_length_check(content_type, &content_type_length, NX_MAX_STRING_LENGTH)) || + (additional_header && _nx_utility_string_length_check(additional_header, &additional_header_length, NX_MAX_STRING_LENGTH))) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + return _nx_web_http_server_generate_response_header(server_ptr, packet_pptr, status_code, + status_code_length, content_length, + content_type, content_type_length, + additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_generate_response_header_extended */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for generating HTTP response header. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_callback_generate_response_header_extended */ +/* Actual generate header */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, + NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, + CHAR *content_type, UINT content_type_length, + CHAR *additional_header, UINT additional_header_length) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || + (packet_pptr == NX_NULL) || (status_code == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + return _nx_web_http_server_callback_generate_response_header_extended(server_ptr, packet_pptr, status_code, + status_code_length, content_length, + content_type, content_type_length, + additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_generate_response_header_extended */ +/* PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to generate HTTP */ +/* response header. */ +/* */ +/* Note: The strings of status_code, content_type and additional_header*/ +/* must be NULL-terminated and length of each string matches the */ +/* length specified in the argument list. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_pptr Pointer to packet */ +/* status_code Status-code and reason-phrase */ +/* status_code_length Length of status-code */ +/* content_length Length of content */ +/* content_type Type of content */ +/* content_type_length Length of content type */ +/* additional_header Other HTTP headers */ +/* additional_header_length Length of other HTTP headers */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_generate_response_header */ +/* Generate response header */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, + NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, + CHAR *content_type, UINT content_type_length, + CHAR *additional_header, UINT additional_header_length) +{ +UINT temp_status_code_length = 0; +UINT temp_content_type_length = 0; +UINT temp_add_header_length = 0; + + /* Check status code, content type and additional header length. */ + if (_nx_utility_string_length_check(status_code, &temp_status_code_length, status_code_length) || + (content_type && _nx_utility_string_length_check(content_type, &temp_content_type_length, content_type_length)) || + (additional_header && _nx_utility_string_length_check(additional_header, &temp_add_header_length, additional_header_length))) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Validate string length. */ + if ((status_code_length != temp_status_code_length) || + (content_type && content_type_length != temp_content_type_length) || + (additional_header && additional_header_length != temp_add_header_length)) + { + return(NX_WEB_HTTP_ERROR); + } + + /* Call the internal HTTP response send function. */ + return _nx_web_http_server_generate_response_header(server_ptr, packet_pptr, status_code, + status_code_length, content_length, + content_type, content_type_length, + additional_header, additional_header_length); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_callback_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for sending a packet. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_callback_packet_send */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + return _nx_web_http_server_callback_packet_send(server_ptr, packet_ptr); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_callback_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used in callback function to send a packet. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_send Send packet to client */ +/* nx_packet_data_append Append packet data */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ +UINT status; +CHAR crlf[2] = {13,10}; +UINT length = packet_ptr -> nx_packet_length; + + /* If the request is chunked, add CRLF at the end of the chunk. */ + if (server_ptr -> nx_web_http_server_response_chunked) + { + + /* Check the packet length. */ + if (server_ptr -> nx_web_http_server_expect_transfer_bytes < (server_ptr -> nx_web_http_server_actual_bytes_transferred + length)) + { + return(NX_INVALID_PACKET); + } + + if (server_ptr -> nx_web_http_server_expect_transfer_bytes == (server_ptr -> nx_web_http_server_actual_bytes_transferred + length)) + { + + /* Place an extra CRLF to signal the end of the chunk. */ + nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); + } + + /* Update the transferred bytes. */ + server_ptr -> nx_web_http_server_actual_bytes_transferred += length; + } + + /* Send internal. */ + status = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); + if (status) + { + return(status); + } + + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_gmt_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting gmt callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* gmt_get Pointer to application's */ +/* GMT time function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_gmt_callback_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (gmt_get == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_web_http_server_gmt_callback_set(server_ptr, gmt_get); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_gmt_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets gmt callback function. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* gmt_get Pointer to application's */ +/* GMT time function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the function pointer. */ + server_ptr -> nx_web_http_server_gmt_get = gmt_get; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_cache_info_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting cache info callback function.*/ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* cache_info_get Pointer to application's */ +/* cache information function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_cache_info_callback_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (cache_info_get == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_web_http_server_cache_info_callback_set(server_ptr, cache_info_get); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_cache_info_callback_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets cache info callback function. */ +/* */ +/* Note: The string resource in callback functions authentication_check*/ +/* and request_notify is built by internal logic and always */ +/* NULL-terminated. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* cache_info_get Pointer to application's */ +/* cache information function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the function pointer. */ + server_ptr -> nx_web_http_server_cache_info_get = cache_info_get; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_date_to_string PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts from date to string. */ +/* */ +/* INPUT */ +/* */ +/* date Pointer to HTTP date */ +/* string Pointer to output buffer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_date_convert */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_get_process */ +/* _nx_web_http_server_generate_response_header */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_date_to_string(NX_WEB_HTTP_SERVER_DATE *date, CHAR *string) +{ + +UINT index = 0; + + /* RDC1122-date. */ + /* Append weekday. */ + string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][0]; + string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][1]; + string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][2]; + string[index++] = ','; + string[index++] = ' '; + + /* Convert and append day. */ + _nx_web_http_server_date_convert(date -> nx_web_http_server_day, 2, &string[index]); + index += 2; + string[index++] = ' '; + + /* Append month. */ + string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][0]; + string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][1]; + string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][2]; + string[index++] = ' '; + + /* Convert and append year. */ + _nx_web_http_server_date_convert(date -> nx_web_http_server_year, 4, &string[index]); + index += 4; + string[index++] = ' '; + + /* Convert and append hour. */ + _nx_web_http_server_date_convert(date -> nx_web_http_server_hour, 2, &string[index]); + index += 2; + string[index++] = ':'; + + /* Convert and append minute. */ + _nx_web_http_server_date_convert(date -> nx_web_http_server_minute, 2, &string[index]); + index += 2; + string[index++] = ':'; + + /* Convert and append second. */ + _nx_web_http_server_date_convert(date -> nx_web_http_server_second, 2, &string[index]); + index += 2; + string[index++] = ' '; + string[index++] = 'G'; + string[index++] = 'M'; + string[index++] = 'T'; + + return index; +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_date_convert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function converts a date from number to string. */ +/* */ +/* INPUT */ +/* */ +/* date The number to convert */ +/* count Digital count for string */ +/* string Pointer to output buffer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_date_to_string */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_date_convert(UINT date, UINT count, CHAR *string) +{ + +UINT digit; + + /* Initialize all 4 bytes to digit 0. */ + *((ULONG*)string) = 0x30303030; + string[count] = 0; + + /* Loop to convert the number to ASCII. */ + while(count > 0) + { + count--; + + /* Compute the next decimal digit. */ + digit = date % 10; + + /* Update the input date. */ + date = date / 10; + + /* Store the new digit in ASCII form. */ + string[count] = (CHAR) (digit + 0x30); + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_mime_maps_additional_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks error for setting additional MIME maps. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* mime_maps Pointer MIME map array */ +/* mime_maps_num Number of MIME map array */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_mime_maps_additional_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) +{ + + /* Check for invalid input pointers. */ + if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (mime_maps == NX_NULL)) + return(NX_PTR_ERROR); + + /* Send internal. */ + return _nx_web_http_server_mime_maps_additional_set(server_ptr, mime_maps, mime_maps_num); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_mime_maps_additional_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets additional MIME maps. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* mime_maps Pointer MIME map array */ +/* mime_maps_num Number of MIME map array */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Lockout interrupts. */ + TX_DISABLE + + /* Set the mime maps. */ + server_ptr -> nx_web_http_server_mime_maps_additional = mime_maps; + server_ptr -> nx_web_http_server_mime_maps_additional_num = mime_maps_num; + + /* Restore interrupts. */ + TX_RESTORE + + return NX_SUCCESS; +} + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_get_client_keepalive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function indicates whether this connection will keep alive. */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_field_value_get Get field value */ +/* _nx_web_http_server_memicmp Compare two strings */ +/* _nx_utility_string_length_check Check string length */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_receive_data */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_get_client_keepalive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) +{ +UCHAR *ch; +UINT version = 0; +UCHAR connection_value[16]; +UINT connection_value_length; + + + /* Locate to HTTP version. */ + ch = packet_ptr -> nx_packet_prepend_ptr; + while(ch + 11 < packet_ptr -> nx_packet_append_ptr) + { + if((*ch == ' ') && + (*(ch + 1) == 'H') && + (*(ch + 2) == 'T') && + (*(ch + 3) == 'T') && + (*(ch + 4) == 'P') && + (*(ch + 5) == '/')) + { + + /* Find the HTTP version. */ + ch += 6; + if((*ch >= '0') && + (*ch <= '9') && + (*(ch + 1) == '.') && + (*(ch + 2) >= '0') && + (*(ch + 2) <= '9')) + { + + /* Get the version. */ + version = (UCHAR)((*ch - '0') << 4) | (UCHAR)(*(ch + 2) - '0'); + } + + break; + } + else if((*ch == 13) && (*(ch + 1) == 10)) + { + + /* Find the end of line. */ + break; + } + + /* Move to the next byte. */ + ch++; + } + + /* Is a valid HTTP version found? */ + if(version == 0) + { + server_ptr -> nx_web_http_server_keepalive = NX_FALSE; + return; + } + + /* Initialize the keepalive flag. */ + if(version > 0x10) + server_ptr -> nx_web_http_server_keepalive = NX_TRUE; + else + server_ptr -> nx_web_http_server_keepalive = NX_FALSE; + + /* Searching for 'connection' header. */ + if(_nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"connection", 10, connection_value, sizeof(connection_value)) == NX_SUCCESS) + { + _nx_utility_string_length_check((CHAR *)connection_value, &connection_value_length, sizeof(connection_value) - 1); + + if(_nx_web_http_server_memicmp(connection_value, connection_value_length, (UCHAR *)"keep-alive", 10) == NX_SUCCESS) + server_ptr -> nx_web_http_server_keepalive = NX_TRUE; + else if(_nx_web_http_server_memicmp(connection_value, connection_value_length, (UCHAR *)"close", 5) == NX_SUCCESS) + server_ptr -> nx_web_http_server_keepalive = NX_FALSE; + } +} +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends data to the remote host using either the TCP */ +/* socket for plain HTTP or the TLS session for HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet to send. */ +/* wait_option Indicates behavior if packet */ +/* cannot be sent. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_send Send data using TLS session */ +/* nx_secure_tcp_socket_send Send data using TCP socket */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; +NX_TCP_SOCKET *tcp_socket; +#ifdef NX_WEB_HTTPS_ENABLE +NX_SECURE_TLS_SESSION *tls_session; +#endif + + tcp_socket = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket); + +#ifdef NX_WEB_HTTPS_ENABLE + + tls_session = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session); + + /* End TLS session if using HTTPS. */ + if(server_ptr -> nx_web_http_is_https_server) + { + status = nx_secure_tls_session_send(tls_session, packet_ptr, wait_option); + } + else +#endif + { + status = nx_tcp_socket_send(tcp_socket, packet_ptr, wait_option); + } + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives data from the remote host using either the */ +/* TCP socket for plain HTTP or the TLS session for HTTPS. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* packet_ptr Pointer to packet to send. */ +/* wait_option Indicates behavior if packet */ +/* cannot be received */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_secure_tls_session_receive Receive data using TLS */ +/* nx_secure_tcp_socket_receive Receive data using TCP */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_web_http_server_packet_get Get next packet from HTTP */ +/* server socket. */ +/* _nx_web_http_server_get_client_request */ +/* Get complete HTTP request */ +/* _nx_web_http_server_request_read Get the next data in byte */ +/* _nx_web_http_server_chunked_size_get Get chunk size of the request */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_receive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; +NX_TCP_SOCKET *tcp_socket; +#ifdef NX_WEB_HTTPS_ENABLE +NX_SECURE_TLS_SESSION *tls_session; +#endif + + tcp_socket = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket); + +#ifdef NX_WEB_HTTPS_ENABLE + tls_session = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session); + + /* End TLS session if using HTTPS. */ + if(server_ptr -> nx_web_http_is_https_server) + { + status = nx_secure_tls_session_receive(tls_session, packet_ptr, wait_option); + } + else +#endif + { + status = nx_tcp_socket_receive(tcp_socket, packet_ptr, wait_option); + } + + /* Return status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_connection_reset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used whenever the HTTP server needs to close the */ +/* network connection and reset to receive new requests. If the server */ +/* is using TLS for HTTPS, then it also ends the TLS session. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* session_ptr Pointer to session */ +/* error_number Error status in caller */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_connection_disconnect */ +/* End TLS session, and calls */ +/* Disconnect and unaccept on the*/ +/* socket */ +/* _nx_tcp_server_socket_relisten Reset socket to accept another*/ +/* connection */ +/* */ +/* CALLED BY */ +/* */ +/* Application code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_connection_reset(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option) +{ +NX_TCP_SOCKET *tcp_socket; + + + tcp_socket = &(session_ptr -> nx_tcp_session_socket); + + /* Disconnect the server connection. */ + _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, wait_option); + + /* Relisten on the HTTP(S) Server port. */ + nx_tcp_server_socket_relisten(server_ptr -> nx_web_http_server_ip_ptr, server_ptr -> nx_web_http_server_listen_port, tcp_socket); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_connection_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is used whenever the HTTP server needs to close the */ +/* network connection completely. If the server is using TLS for HTTPS */ +/* then it also ends the TLS session. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* server_ptr Pointer to HTTP server */ +/* session_ptr Pointer to session */ +/* wait_option Wait option for TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_secure_tls_session_end End TLS session */ +/* */ +/* CALLED BY */ +/* */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_web_http_server_connection_disconnect(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option) +{ +NX_TCP_SOCKET *tcp_socket; +#ifdef NX_WEB_HTTPS_ENABLE +NX_SECURE_TLS_SESSION *tls_session; +#endif + +#ifndef NX_WEB_HTTPS_ENABLE + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(wait_option); +#endif /* NX_WEB_HTTPS_ENABLE */ + + tcp_socket = &(session_ptr -> nx_tcp_session_socket); + +#ifdef NX_WEB_HTTPS_ENABLE + + tls_session = &(session_ptr -> nx_tcp_session_tls_session); + + /* End TLS session if using HTTPS. */ + if(server_ptr -> nx_web_http_is_https_server) + { + _nx_secure_tls_session_end(tls_session, wait_option); + } +#endif + + /* Disconnect from the current connection. */ + nx_tcp_socket_disconnect(tcp_socket, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); + + /* Unaccept the connection. */ + nx_tcp_server_socket_unaccept(tcp_socket); + +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_digest_authenticate_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for service to set digest */ +/* authenticate callback function. */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* digest_authenticate_callback Pointer to application's */ +/* digest authenticate callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_web_http_server_digest_authenticate_notify_set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)) +{ + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (digest_authenticate_callback == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + return(_nx_web_http_server_digest_authenticate_notify_set(http_server_ptr, digest_authenticate_callback)); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_digest_authenticate_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets digest authenticate callback function. */ +/* */ +/* Note: The strings name_ptr, realm_ptr, password_ptr, method, */ +/* authorization_uri, authorization_nc and authorization_cnonce in */ +/* callback function digest_authenticate_callback is built by internal */ +/* logic and always NULL-terminated. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* digest_authenticate_callback Pointer to application's */ +/* digest authenticate callback */ +/* function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)) +{ + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + http_server_ptr -> nx_web_http_server_digest_authenticate_callback = digest_authenticate_callback; + + return(NX_SUCCESS); +#else + NX_PARAMETER_NOT_USED(http_server_ptr); + NX_PARAMETER_NOT_USED(digest_authenticate_callback); + + return(NX_NOT_SUPPORTED); +#endif +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_web_http_server_authentication_check_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks errors for setting authentication checking */ +/* callback function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* authentication_check_extended Pointer to application's */ +/* authentication checking */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_http_server_authentication_check_set */ +/* Set authentication callback */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) +{ +UINT status; + + /* Check for invalid input pointers. */ + if ((http_server_ptr == NX_NULL) || (authentication_check_extended == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call the actual authentication checking set function. */ + status= _nx_web_http_server_authentication_check_set(http_server_ptr, authentication_check_extended); + + /* Return staus. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_web_http_server_authentication_check_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the callback function of authentication checking.*/ +/* */ +/* Note: The strings of name, password and realm must be */ +/* NULL-terminated and length of each string matches the length */ +/* specified in the argument list. The string resource in callback */ +/* function authentication_check and request_notify is built by */ +/* internal logic and always NULL-terminated. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* http_server_ptr Pointer to HTTP server */ +/* authentication_check_extended Pointer to application's */ +/* authentication checking */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) +{ + + /* Set the extended authentication checking function. */ + http_server_ptr -> nx_web_http_server_authentication_check_extended = authentication_check_extended; + + /* Return success. */ + return(NX_SUCCESS); +} diff --git a/addons/web/nx_web_http_server.h b/addons/web/nx_web_http_server.h new file mode 100644 index 00000000..eebd1005 --- /dev/null +++ b/addons/web/nx_web_http_server.h @@ -0,0 +1,674 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Web Component */ +/** */ +/** Hypertext Transfer Protocol (HTTP) */ +/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_web_http_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ +/* component, including all data types and external references. */ +/* It is assumed that nx_api.h and nx_port.h have already been */ +/* included, along with fx_api.h and fx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NXD_HTTP_SERVER_H +#define NXD_HTTP_SERVER_H + +/* Determine if a C++ compiler is being used. If so, ensure that standard + C is used to process the API information. */ + +#ifdef __cplusplus + +/* Yes, C++ compiler is present. Use standard C. */ +extern "C" { + +#endif + +/* If HTTPS is enabled, make sure TLS is enabled in the TCP server. */ +#ifdef NX_WEB_HTTPS_ENABLE +#ifndef NX_TCPSERVER_ENABLE_TLS +#define NX_TCPSERVER_ENABLE_TLS +#endif +#endif + +#include "nx_api.h" +/* If not using FileX, define this option and define the file writing services + declared in filex_stub.h. */ +/* #define NX_WEB_HTTP_NO_FILEX */ + +#ifndef NX_WEB_HTTP_NO_FILEX +#include "fx_api.h" +#else +#include "filex_stub.h" +#endif + +/* Include common HTTP definitions. */ +#include "nx_web_http_common.h" + +/* Include multiple-socket TCP/TLS support. */ +#include "nx_tcpserver.h" + +/* Define the HTTP Server ID. */ +#define NX_WEB_HTTP_SERVER_ID 0x48545451UL + +/* Enable Digest authentication. +#define NX_WEB_HTTP_DIGEST_ENABLE +*/ + +/* Define HTTP TCP socket create options. */ +#ifndef NX_WEB_HTTP_SERVER_PRIORITY +#define NX_WEB_HTTP_SERVER_PRIORITY 4 +#endif + +#ifndef NX_WEB_HTTP_SERVER_WINDOW_SIZE +#define NX_WEB_HTTP_SERVER_WINDOW_SIZE 8192 +#endif + +#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT +#define NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT (1 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE +#define NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_SEND +#define NX_WEB_HTTP_SERVER_TIMEOUT_SEND (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT +#define NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_SERVER_TIMEOUT +#define NX_WEB_HTTP_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) +#endif + +#ifndef NX_WEB_HTTP_SERVER_SESSION_MAX +#define NX_WEB_HTTP_SERVER_SESSION_MAX 2 +#endif + +#ifndef NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE +#define NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE (sizeof(NX_TCP_SESSION) * NX_WEB_HTTP_SERVER_SESSION_MAX) +#endif + +#ifndef NX_WEB_HTTP_SERVER_MAX_PENDING +#define NX_WEB_HTTP_SERVER_MAX_PENDING (NX_WEB_HTTP_SERVER_SESSION_MAX << 1) +#endif + +#ifndef NX_WEB_HTTP_SERVER_THREAD_TIME_SLICE +#define NX_WEB_HTTP_SERVER_THREAD_TIME_SLICE 2 +#endif + + +#ifndef NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE +#define NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE 600 +#endif + +/* Define the HTTP server retry parameters. */ + +#ifndef NX_WEB_HTTP_SERVER_RETRY_SECONDS +#define NX_WEB_HTTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ +#endif + +#ifndef NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH +#define NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ +#endif + +#ifndef NX_WEB_HTTP_SERVER_RETRY_MAX +#define NX_WEB_HTTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ +#endif + +#ifndef NX_WEB_HTTP_SERVER_RETRY_SHIFT +#define NX_WEB_HTTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ +#endif + +/* Define HTTP Server request types. */ + +#define NX_WEB_HTTP_SERVER_UNKNOWN_REQUEST 0 +#define NX_WEB_HTTP_SERVER_GET_REQUEST 1 +#define NX_WEB_HTTP_SERVER_POST_REQUEST 2 +#define NX_WEB_HTTP_SERVER_HEAD_REQUEST 3 +#define NX_WEB_HTTP_SERVER_PUT_REQUEST 4 +#define NX_WEB_HTTP_SERVER_DELETE_REQUEST 5 + + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + +/* Include the MD5 digest header file. */ + +#include "nx_md5.h" + +#endif + +#ifdef NX_WEB_HTTPS_ENABLE +/* Include TLS for HTTPS support. */ +#include "nx_secure_tls_api.h" +#endif + +/* Define default MIME type. */ +/* Page 14, Section 5.2, RFC 2045 */ +#define NX_WEB_HTTP_SERVER_DEFAULT_MIME "text/plain" + + +/* Define the MIME map structure. */ + +typedef struct NX_WEB_HTTP_SERVER_MIME_MAP_STRUCT +{ + CHAR *nx_web_http_server_mime_map_extension; /* Extension of file */ + CHAR *nx_web_http_server_mime_map_type; /* MIME type of file */ +} NX_WEB_HTTP_SERVER_MIME_MAP; + + +/* Define the date structure. */ + +typedef struct NX_WEB_HTTP_SERVER_DATE_STRUCT +{ + USHORT nx_web_http_server_year; /* Year */ + UCHAR nx_web_http_server_month; /* Month */ + UCHAR nx_web_http_server_day; /* Day */ + UCHAR nx_web_http_server_hour; /* Hour */ + UCHAR nx_web_http_server_minute; /* Minute */ + UCHAR nx_web_http_server_second; /* Second */ + UCHAR nx_web_http_server_weekday; /* Weekday */ +} NX_WEB_HTTP_SERVER_DATE; + +/* Define the multipart context data structure. */ + +typedef struct NX_WEB_HTTP_SERVER_MULTIPART_STRUCT +{ + + /* Boundary string. */ + UCHAR nx_web_http_server_multipart_boundary[NX_WEB_HTTP_MAX_HEADER_FIELD + 1]; + + /* Offset of available data. */ + UINT nx_web_http_server_multipart_available_offset; + + /* Length of available data. */ + UINT nx_web_http_server_multipart_available_length; + + /* Boundary find status. */ + volatile UINT nx_web_http_server_multipart_boundary_find; + + /* The next packet to process. */ + NX_PACKET *nx_web_http_server_multipart_next_packet; + + /* Offset of next available data. */ + UINT nx_web_http_server_multipart_next_available_offset; + + /* The packet returned at last. */ + NX_PACKET *nx_web_http_server_multipart_last_packet; + +} NX_WEB_HTTP_SERVER_MULTIPART; + + +/* Define the HTTP Server data structure. */ + +typedef struct NX_WEB_HTTP_SERVER_STRUCT +{ + ULONG nx_web_http_server_id; /* HTTP Server ID */ + CHAR *nx_web_http_server_name; /* Name of this HTTP Server */ + NX_IP *nx_web_http_server_ip_ptr; /* Pointer to associated IP structure */ + CHAR nx_web_http_server_request_resource[NX_WEB_HTTP_MAX_RESOURCE + 1]; + /* Uniform Resource Locator (URL) */ + NX_PACKET_POOL *nx_web_http_server_packet_pool_ptr; /* Pointer to HTTP Server packet pool */ + FX_MEDIA *nx_web_http_server_media_ptr; /* Pointer to media control block */ + ULONG nx_web_http_server_get_requests; /* Number of get requests */ + ULONG nx_web_http_server_head_requests; /* Number of head requests */ + ULONG nx_web_http_server_put_requests; /* Number of put requests */ + ULONG nx_web_http_server_delete_requests; /* Number of delete requests */ + ULONG nx_web_http_server_post_requests; /* Number of post requests */ + ULONG nx_web_http_server_unknown_requests; /* Number of unknown requests */ + ULONG nx_web_http_server_total_bytes_sent; /* Number of total bytes sent */ + ULONG nx_web_http_server_total_bytes_received; /* Number of total bytes received */ + ULONG nx_web_http_server_allocation_errors; /* Number of allocation errors */ + ULONG nx_web_http_server_invalid_http_headers; /* Number of invalid http headers */ + FX_FILE nx_web_http_server_file; /* HTTP file control block */ + + NX_TCPSERVER nx_web_http_server_tcpserver; /* TCP server with multiple sessions */ + NX_TCP_SESSION *nx_web_http_server_current_session_ptr; /* Current session in process */ + UCHAR nx_web_http_server_session_buffer[NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE]; + /* Size of session buffer */ + + NX_TCP_SOCKET nx_web_http_server_socket; /* HTTP Server TCP socket */ + UINT nx_web_http_server_listen_port; /* HTTP(S) listening port. */ +#ifdef NX_WEB_HTTPS_ENABLE + UINT nx_web_http_is_https_server; /* If using TLS for HTTPS, set to true. */ +#endif + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + NX_MD5 nx_web_http_server_md5data; /* HTTP server MD5 work area */ +#endif /* NX_WEB_HTTP_DIGEST_ENABLE */ + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE + NX_WEB_HTTP_SERVER_MULTIPART + nx_web_http_server_multipart; /* HTTP multipart area */ +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + + UINT nx_web_http_server_request_type; /* HTTP request type */ + NX_WEB_HTTP_SERVER_MIME_MAP + *nx_web_http_server_mime_maps_additional; /* Additional HTTP MIME maps */ + UINT nx_web_http_server_mime_maps_additional_num; /* Number of additional HTTP MIME maps */ + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE + UCHAR nx_web_http_server_keepalive; /* HTTP keepalive flag */ + UCHAR nx_web_http_server_reserved; /* Reserved */ +#else + UCHAR nx_web_http_server_reserved[2]; /* Reserved */ +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + + UCHAR nx_web_http_server_response_chunked; /* Flag for chunked response */ + UCHAR nx_web_http_server_request_chunked; /* Flag for chunked request */ + UINT nx_web_http_server_expect_transfer_bytes; /* The bytes expected to transfer */ + UINT nx_web_http_server_actual_bytes_transferred; /* The actual transferred bytes */ + UINT nx_web_http_server_expect_receive_bytes; /* The bytes expected to receive */ + UINT nx_web_http_server_actual_bytes_received; /* The actual received bytes */ + UINT nx_web_http_server_chunked_request_remaining_size; /* Remaining size of the chunked request*/ + NX_PACKET *nx_web_http_server_request_packet; /* Pointer to the received request */ + + /* Define the user supplied routines that are used to inform the application of particular server requests. */ + + UINT (*nx_web_http_server_authentication_check)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm); + UINT (*nx_web_http_server_authentication_check_extended)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length); + UINT (*nx_web_http_server_request_notify)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr); +#ifdef __PRODUCT_NETXDUO__ + UINT (*nx_web_http_server_invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type); +#else + UINT (*nx_web_http_server_invalid_username_password_callback)(CHAR *resource, ULONG client_address, UINT request_type); +#endif + VOID (*nx_web_http_server_gmt_get)(NX_WEB_HTTP_SERVER_DATE *date); + UINT (*nx_web_http_server_cache_info_get)(CHAR *resource, UINT *max_age, NX_WEB_HTTP_SERVER_DATE *last_modified); +#ifdef NX_WEB_HTTP_DIGEST_ENABLE + UINT (*nx_web_http_server_digest_authenticate_callback)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce); +#endif +} NX_WEB_HTTP_SERVER; + + +#ifndef NX_WEB_HTTP_SERVER_SOURCE_CODE + +/* Application caller is present, perform API mapping. */ + +/* Determine if error checking is desired. If so, map API functions + to the appropriate error checking front-ends. Otherwise, map API + functions to the core functions that actually perform the work. + Note: error checking is enabled by default. */ + +#ifdef NX_DISABLE_ERROR_CHECKING + +/* Services without error checking. */ + +#define nx_web_http_server_callback_data_send _nx_web_http_server_callback_data_send +#define nx_web_http_server_callback_response_send _nx_web_http_server_callback_response_send +#define nx_web_http_server_callback_response_send_extended _nx_web_http_server_callback_response_send_extended +#define nx_web_http_server_content_get _nx_web_http_server_content_get +#define nx_web_http_server_create _nx_web_http_server_create +#define nx_web_http_server_delete _nx_web_http_server_delete +#define nx_web_http_server_param_get _nx_web_http_server_param_get +#define nx_web_http_server_query_get _nx_web_http_server_query_get +#define nx_web_http_server_start _nx_web_http_server_start +#define nx_web_http_server_secure_configure _nx_web_http_server_secure_configure +#define nx_web_http_server_stop _nx_web_http_server_stop +#define nx_web_http_server_content_get_extended _nx_web_http_server_content_get_extended +#define nx_web_http_server_content_length_get _nx_web_http_server_content_length_get +#define nx_web_http_server_get_entity_header _nx_web_http_server_get_entity_header +#define nx_web_http_server_get_entity_content _nx_web_http_server_get_entity_content +#define nx_web_http_server_callback_generate_response_header _nx_web_http_server_callback_generate_response_header +#define nx_web_http_server_callback_generate_response_header_extended _nx_web_http_server_callback_generate_response_header_extended +#define nx_web_http_server_callback_packet_send _nx_web_http_server_callback_packet_send +#define nx_web_http_server_gmt_callback_set _nx_web_http_server_gmt_callback_set +#define nx_web_http_server_cache_info_callback_set _nx_web_http_server_cache_info_callback_set +#define nx_web_http_server_mime_maps_additional_set _nx_web_http_server_mime_maps_additional_set +#define nx_web_http_server_type_get _nx_web_http_server_type_get +#define nx_web_http_server_type_get_extended _nx_web_http_server_type_get_extended +#define nx_web_http_server_packet_content_find _nx_web_http_server_packet_content_find +#define nx_web_http_server_packet_get _nx_web_http_server_packet_get +#define nx_web_http_server_invalid_userpassword_notify_set _nx_web_http_server_invalid_userpassword_notify_set +#define nx_web_http_server_response_chunked_set _nx_web_http_server_response_chunked_set +#define nx_web_http_server_response_packet_allocate _nx_web_http_server_response_packet_allocate +#define nx_web_http_server_digest_authenticate_notify_set _nx_web_http_server_digest_authenticate_notify_set +#define nx_web_http_server_authentication_check_set _nx_web_http_server_authentication_check_set + +#else + +/* Services with error checking. */ + +#define nx_web_http_server_callback_data_send _nxe_web_http_server_callback_data_send +#define nx_web_http_server_callback_response_send _nxe_web_http_server_callback_response_send +#define nx_web_http_server_callback_response_send_extended _nxe_web_http_server_callback_response_send_extended +#define nx_web_http_server_content_get _nxe_web_http_server_content_get +#define nx_web_http_server_content_length_get _nxe_web_http_server_content_length_get +#define nx_web_http_server_create(p,n,i,pn,m,sp,ss,pp,a,r) _nxe_web_http_server_create(p,n,i,pn,m,sp,ss,pp,a,r,sizeof(NX_WEB_HTTP_SERVER)) +#define nx_web_http_server_delete _nxe_web_http_server_delete +#define nx_web_http_server_param_get _nxe_web_http_server_param_get +#define nx_web_http_server_query_get _nxe_web_http_server_query_get +#define nx_web_http_server_start _nxe_web_http_server_start +#define nx_web_http_server_secure_configure _nxe_web_http_server_secure_configure +#define nx_web_http_server_stop _nxe_web_http_server_stop +#define nx_web_http_server_content_get_extended _nxe_web_http_server_content_get_extended +#define nx_web_http_server_get_entity_header _nxe_web_http_server_get_entity_header +#define nx_web_http_server_get_entity_content _nxe_web_http_server_get_entity_content +#define nx_web_http_server_callback_generate_response_header _nxe_web_http_server_callback_generate_response_header +#define nx_web_http_server_callback_generate_response_header_extended _nxe_web_http_server_callback_generate_response_header_extended +#define nx_web_http_server_callback_packet_send _nxe_web_http_server_callback_packet_send +#define nx_web_http_server_gmt_callback_set _nxe_web_http_server_gmt_callback_set +#define nx_web_http_server_cache_info_callback_set _nxe_web_http_server_cache_info_callback_set +#define nx_web_http_server_mime_maps_additional_set _nxe_web_http_server_mime_maps_additional_set +#define nx_web_http_server_type_get _nxe_web_http_server_type_get +#define nx_web_http_server_type_get_extended _nxe_web_http_server_type_get_extended +#define nx_web_http_server_packet_content_find _nxe_web_http_server_packet_content_find +#define nx_web_http_server_packet_get _nxe_web_http_server_packet_get +#define nx_web_http_server_invalid_userpassword_notify_set _nxe_web_http_server_invalid_userpassword_notify_set +#define nx_web_http_server_response_chunked_set _nxe_web_http_server_response_chunked_set +#define nx_web_http_server_response_packet_allocate _nxe_web_http_server_response_packet_allocate +#define nx_web_http_server_digest_authenticate_notify_set _nxe_web_http_server_digest_authenticate_notify_set +#define nx_web_http_server_authentication_check_set _nxe_web_http_server_authentication_check_set + +#endif + +/* Define the prototypes accessible to the application software. */ + + +UINT nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_info, + UINT additional_info_length); +UINT nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); + +#ifdef NX_DISABLE_ERROR_CHECKING +UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); +#else +UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size); +#endif /* NX_DISABLE_ERROR_CHECKING */ + +UINT nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); +UINT nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); +UINT nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); +#ifdef NX_WEB_HTTPS_ENABLE +UINT nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, + UCHAR* packet_buffer, UINT packet_buffer_size, + NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], + UINT trusted_certs_num, + NX_SECURE_X509_CERT *remote_certificates[], + UINT remote_certs_num, + UCHAR *remote_certificate_buffer, + UINT remote_cert_buffer_size); +#endif /* NX_WEB_HTTPS_ENABLE */ +UINT nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length); +UINT nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, + NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, + CHAR *content_type, UINT content_type_length, + CHAR *additional_header, UINT additional_header_length); +UINT nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)); +UINT nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); +UINT nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); +UINT nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, + CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); + +UINT nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); + +UINT nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); +UINT nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); +UINT nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + + +#else + +/* HTTP source code is being compiled, do not perform any API mapping. */ + +UINT _nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT _nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT _nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_info, + UINT additional_info_length); +UINT _nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); +UINT _nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT _nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); +UINT _nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); +UINT _nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); +#ifdef NX_WEB_HTTPS_ENABLE +UINT _nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, + UCHAR* packet_buffer, UINT packet_buffer_size, + NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], + UINT trusted_certs_num, + NX_SECURE_X509_CERT *remote_certificates[], + UINT remote_certs_num, + UCHAR *remote_certificate_buffer, + UINT remote_cert_buffer_size); +#endif /* NX_WEB_HTTPS_ENABLE */ +UINT _nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT _nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length); +UINT _nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT _nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT _nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT _nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, + NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, + CHAR *content_type, UINT content_type_length, + CHAR *additional_header, UINT additional_header_length); +UINT _nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_callback)(NX_WEB_HTTP_SERVER_DATE *)); +UINT _nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); +UINT _nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT _nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); +UINT _nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT _nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); +UINT _nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT _nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + + +/* Define internal HTTP Server functions. */ + +VOID _nx_web_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); +UINT _nx_web_http_server_get_client_request(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +VOID _nx_web_http_server_get_process(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr); +VOID _nx_web_http_server_put_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +VOID _nx_web_http_server_delete_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nx_web_http_server_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_information, + UINT additional_information_length); +UINT _nx_web_http_server_basic_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present); +UINT _nx_web_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr); +UINT _nx_web_http_server_retrieve_resource(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *destination, UINT max_size); +UINT _nx_web_http_server_calculate_content_offset(NX_PACKET *packet_ptr); +UINT _nx_web_http_server_number_convert(UINT number, CHAR *string); +UINT _nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); +UINT _nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, + CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); +VOID _nx_web_http_base64_encode(CHAR *name, UINT length, CHAR *base64name); +VOID _nx_web_http_base64_decode(CHAR *base64name, UINT length, CHAR *name); + +UINT _nx_web_http_server_receive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_web_http_server_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +VOID _nx_web_http_server_connection_reset(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option); +VOID _nx_web_http_server_connection_disconnect(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option); + +#ifdef NX_WEB_HTTP_DIGEST_ENABLE +UINT _nx_web_http_server_digest_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present); +VOID _nx_web_http_server_digest_response_calculate(NX_WEB_HTTP_SERVER *server_ptr, CHAR *username, CHAR *realm, CHAR *password, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result); +UINT _nx_web_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce); +VOID _nx_web_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); +#endif + +#ifdef NX_WEB_HTTP_MULTIPART_ENABLE +UINT _nx_web_http_server_boundary_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr); +#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ + +UINT _nx_web_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr); +UINT _nx_web_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size); +UINT _nx_web_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); + +UINT _nx_web_http_server_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT status_code_length, + UINT content_length, CHAR *content_type, + UINT content_type_length, CHAR* additional_header, + UINT additional_header_length); +UINT _nx_web_http_server_date_to_string(NX_WEB_HTTP_SERVER_DATE *date, CHAR *string); +VOID _nx_web_http_server_date_convert(UINT date, UINT count, CHAR *string); + +VOID _nx_web_http_server_receive_data(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); +VOID _nx_web_http_server_connection_end(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); +VOID _nx_web_http_server_connection_timeout(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); + + +#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE +VOID _nx_web_http_server_get_client_keepalive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ + +UINT _nx_web_http_server_chunked_check(NX_PACKET *packet_ptr); +UINT _nx_web_http_server_request_read(NX_WEB_HTTP_SERVER *server_ptr, UCHAR *data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_server_request_byte_expect(NX_WEB_HTTP_SERVER *server_ptr, UCHAR data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_server_chunked_size_get(NX_WEB_HTTP_SERVER *server_ptr, UINT *chunk_size, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); +UINT _nx_web_http_server_request_chunked_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG wait_option); +UINT _nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); +UINT _nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); +UINT _nxe_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); +UINT _nxe_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); +UINT _nxe_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); +UINT _nxe_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); +UINT _nxe_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, + UINT status_code_length, CHAR *information, + UINT information_length, CHAR *additional_info, + UINT additional_info_length); +UINT _nxe_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nxe_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); +UINT _nxe_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); +UINT _nxe_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, + CHAR *destination_ptr, UINT destination_size, UINT *actual_size); +UINT _nxe_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *content_length); +UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, + UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), + UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size); +UINT _nxe_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT _nxe_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); +UINT _nxe_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); +UINT _nxe_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); +#ifdef NX_WEB_HTTPS_ENABLE +UINT _nxe_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, + VOID *metadata_buffer, ULONG metadata_size, + UCHAR* packet_buffer, UINT packet_buffer_size, + NX_SECURE_X509_CERT *identity_certificate, + NX_SECURE_X509_CERT *trusted_certificates[], + UINT trusted_certs_num, + NX_SECURE_X509_CERT *remote_certificates[], + UINT remote_certs_num, + UCHAR *remote_certificate_buffer, + UINT remote_cert_buffer_size); +#endif /* NX_WEB_HTTPS_ENABLE */ +UINT _nxe_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); +UINT _nxe_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)); +UINT _nxe_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); +UINT _nxe_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, + CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); +UINT _nxe_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); +UINT _nxe_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); +UINT _nxe_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, + CHAR *status_code, UINT content_length, CHAR *content_type, + CHAR* additional_header); +UINT _nxe_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, + NX_PACKET **packet_pptr, CHAR *status_code, + UINT status_code_length, UINT content_length, + CHAR *content_type, UINT content_type_length, + CHAR *additional_header, UINT additional_header_length); +UINT _nxe_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); +UINT _nxe_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)); +UINT _nxe_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); +UINT _nxe_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); +UINT _nxe_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, + CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, + CHAR *authorization_uri, CHAR *authorization_nc, + CHAR *authorization_cnonce)); +UINT _nxe_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, + UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); + +#endif /* NX_WEB_HTTP_SERVER_SOURCE_CODE */ + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NXD_HTTP_SERVER_H */ diff --git a/protocol_handlers/BSD/nxd_bsd.c b/protocol_handlers/BSD/nxd_bsd.c deleted file mode 100644 index afaa8a8e..00000000 --- a/protocol_handlers/BSD/nxd_bsd.c +++ /dev/null @@ -1,14542 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** BSD 4.3 Socket API Compatible Interface to NetX Duo */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/* Include necessary files. */ -#include "nx_api.h" -#include "nx_packet.h" -#include "nx_tcp.h" -#include "nx_ip.h" - -#include "nx_ipv6.h" -#include "nx_ipv4.h" -#include "nxd_bsd.h" - -#ifdef NX_BSD_ENABLE_DNS -#include "nxd_dns.h" -#endif - - -#include "nx_udp.h" -#include "nx_igmp.h" -#include "nx_system.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_icmpv6.h" -#endif -#include "tx_timer.h" - -/* Define a NetX packet pool pointer for BSD use. */ - -NX_PACKET_POOL *nx_bsd_default_packet_pool; - - -/* Define the default IP instance for BSD use. */ - -NX_IP *nx_bsd_default_ip; - - -/* Define the single mutex protection for the BSD layer calls. */ - -TX_MUTEX *nx_bsd_protection_ptr; - - -/* Define IP fast periodic timer entry. */ -VOID (*nx_bsd_ip_fast_periodic_timer_entry)(ULONG id); - -/* Define BSD system clock time. The precision depends on _nx_ip_fast_timer_rate. */ -ULONG nx_bsd_system_clock; - -/* Define BSD system clock timer rate. */ -ULONG nx_bsd_timer_rate; - -/* Define the event flag group for notifying threads suspended on BSD sockets to wakeup. */ - -TX_EVENT_FLAGS_GROUP nx_bsd_events; - - -/* Define the array of BSD managed sockets. */ - -NX_BSD_SOCKET nx_bsd_socket_array[NX_BSD_MAX_SOCKETS]; - -/* Define the raw socket protocol hash table. */ - -NX_BSD_SOCKET *nx_bsd_socket_raw_protocol_table[NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE]; - -/* Create some buffer space for number string conversions. */ -#define NX_BSD_URL_BUFSIZE 18 -CHAR nx_bsd_url_buffer[NX_BSD_URL_BUFSIZE]; - -/* Define the search index for the BSD array. */ - -UINT nx_bsd_socket_array_index; - - -/* Define the block pool that will be used to dynamically allocate either NetX UDP or TCP sockets. */ - -TX_BLOCK_POOL nx_bsd_socket_block_pool; - -/* Define the memory area for the socket block pool... use TCP socket size, since it is the larger. */ - -static UCHAR nx_bsd_socket_pool_memory[NX_BSD_MAX_SOCKETS*(sizeof(NX_TCP_SOCKET)+sizeof(VOID *))]; - -/* Define the block pool that will be used to dynamically allocate addrinfo struct. */ - -TX_BLOCK_POOL nx_bsd_addrinfo_block_pool; - -/* Define the memory area for addrinfo pool. sizeof(addrinfo) is the MAX of: - * {sizeof(addrinfo)== 32, sizeof(sockaddr_in) == 16, or sizeof(sockaddr_in6)} = 28. - * Every address may be mapped to 3 socktypes, SOCK_STREAM, SOCK_DGRAM and SOCK_RAW, - * 3 blocks for addrinfo) + 1 block for IP adddress = 4 blocks */ - -static UCHAR nx_bsd_addrinfo_pool_memory[(NX_BSD_IPV4_ADDR_MAX_NUM + NX_BSD_IPV6_ADDR_MAX_NUM)* 4 - *(sizeof(struct addrinfo) + sizeof(VOID *))]; - -#ifdef NX_BSD_ENABLE_DNS - -/* The global DNS client instance. */ -extern NX_DNS *_nx_dns_instance_ptr; - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/* Define the block pool that will be used to dynamically allocate canonical name buffer. */ -TX_BLOCK_POOL nx_bsd_cname_block_pool; - -/* Here we just support a CNAME per IP address. */ -static UCHAR nx_bsd_cname_pool_memory[(NX_BSD_IPV4_ADDR_MAX_NUM + NX_BSD_IPV6_ADDR_MAX_NUM) * - (NX_DNS_NAME_MAX + 1)]; -#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ -#endif /* NX_BSD_ENABLE_DNS */ - -/* Buffer used to store IP address get from DNS. */ -static ULONG nx_bsd_ipv4_addr_buffer[NX_BSD_IPV4_ADDR_PER_HOST]; -static ULONG nx_bsd_ipv6_addr_buffer[NX_BSD_IPV6_ADDR_PER_HOST * 4]; - -/* Utility character type functions*/ -static UINT nx_bsd_isspace(UCHAR c); -static UINT nx_bsd_islower(UCHAR c); -static UINT nx_bsd_isdigit(UCHAR c); -static UINT nx_bsd_isxdigit(UCHAR c); - -/* Standard BSD callback functions to register with NetX Duo. */ - -static VOID nx_bsd_tcp_receive_notify(NX_TCP_SOCKET *socket_ptr); -static VOID nx_bsd_tcp_socket_disconnect_notify(NX_TCP_SOCKET *socket_ptr); -static VOID nx_bsd_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -static UINT nx_bsd_raw_packet_filter(NX_IP *ip_ptr, ULONG protocol, NX_PACKET *packet_ptr); -#ifdef FEATURE_NX_IPV6 -static VOID _nxd_bsd_swap_ipv6_extension_headers(NX_PACKET *packet_ptr, UCHAR header_type); -#endif /* FEATURE_NX_IPV6 */ -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ -#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT -static VOID nx_bsd_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr); -#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ -static VOID nx_bsd_select_wakeup(UINT sock_id, UINT fdsets); -static VOID nx_bsd_set_error_code(NX_BSD_SOCKET *bsd_socket_ptr, UINT status_code); -static VOID nx_bsd_udp_packet_received(INT sockID, NX_PACKET *packet_ptr); -static UINT nx_bsd_tcp_syn_received_notify(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr); -static INT nx_bsd_tcp_create_listen_socket(INT master_sockid, INT backlog); -static VOID nx_bsd_tcp_pending_connection(UINT local_port, NX_TCP_SOCKET *socket_ptr); -static INT nx_bsd_find_interface_by_source_addr(UINT addr_family, ULONG* ip_addr); -#ifndef NX_DISABLE_IPV4 -static VOID _nxd_bsd_ipv4_packet_send(NX_PACKET *packet_ptr); -#endif /* NX_DISABLE_IPV4 */ -static INT nx_bsd_send_internal(INT sockID, const CHAR *msg, INT msgLength, INT flags, - NXD_ADDRESS *dst_address, USHORT dst_port, UINT local_interface_index); - -#ifdef FEATURE_NX_IPV6 -static VOID _nxd_bsd_ipv6_packet_send(NX_PACKET *packet_ptr, ULONG *src_addr, ULONG *dest_addr); -#endif /* FEATURE_NX_IPV6 */ - -static INT inet_ntoa_internal(const VOID *src, CHAR *dst, ULONG dst_size); -static INT bsd_string_to_number(const CHAR *string, UINT *number); -static ULONG _nx_bsd_string_length(CHAR * string); - -#ifdef NX_BSD_RAW_PPPOE_SUPPORT -static INT nx_bsd_pppoe_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, - INT flags, struct sockaddr* destAddr, INT destAddrLen); -static UINT nx_bsd_socket_create_id = 0; -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - -#ifdef NX_BSD_RAW_SUPPORT -static INT _nx_bsd_hardware_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, - INT flags, struct sockaddr* destAddr, INT destAddrLen); -static VOID _nx_bsd_hardware_packet_received(NX_PACKET *packet_ptr, UCHAR *consumed); -#endif /* NX_BSD_RAW_SUPPORT */ -static VOID _nx_bsd_fast_periodic_timer_entry(ULONG id); - -#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER -TX_THREAD nx_bsd_task_thread; -static VOID nx_bsd_thread_entry(ULONG info); -#else -static TX_TIMER nx_bsd_timer; -static VOID nx_bsd_timer_entry(ULONG info); -#endif -UINT bsd_number_convert(UINT number, CHAR *string, ULONG buffer_len, UINT base); -VOID nx_bsd_socket_timed_wait_callback(NX_TCP_SOCKET *tcp_socket_ptr); - -#define FDSET_READ 1 -#define FDSET_WRITE 2 -#define FDSET_EXCEPTION 4 - -extern TX_THREAD *_tx_thread_current_ptr; - -static ULONG _nx_bsd_serv_list_len; -static struct NX_BSD_SERVICE_LIST *_nx_bsd_serv_list_ptr; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* bsd_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up all data structures and NetX, and ThreadX */ -/* resources needed by the BSD compatibility layer. It is recommended */ -/* to call this routine from tx_application_define. */ -/* */ -/* INPUTS */ -/* */ -/* *default_ip NX_IP created for BSD API */ -/* *default_pool Packet Pool used by BSD API */ -/* *bsd_thread_stack_area Stack memory pointer for the */ -/* BSD thread stack space */ -/* bsd_thread_stack_size Size of thread stack */ -/* bsd_thread_priority BSD thread priority */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_BSD_BLOCK_POOL_ERROR Error creating socket block */ -/* pool */ -/* NX_BSD_EVENT_ERROR Error creating the event flag */ -/* group */ -/* NX_BSD_MUTEX_ERROR Error creating mutex */ -/* NX_BSD_ENVIRONMENT_ERROR Error environment */ -/* */ -/* CALLS */ -/* */ -/* memset Set memory */ -/* tx_block_pool_create Create a block pool */ -/* tx_block_pool_delete Delete a block pool */ -/* tx_event_flags_create Create event flag group */ -/* tx_mutex_create Create protection mutex */ -/* tx_mutex_delete Delete protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Start-up code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT bsd_initialize(NX_IP *default_ip, NX_PACKET_POOL *default_pool, CHAR *bsd_thread_stack_area, - ULONG bsd_thread_stack_size, UINT bsd_thread_priority) -{ - -INT i; -UINT status; -ULONG info; - -#ifndef NX_ENABLE_EXTENDED_NOTIFY_SUPPORT - - /* Error, return the error message. */ - /* BSD doesn't work with out NX_ENABLE_EXTENDED_NOTIFY_SUPPORT option. */ - NX_BSD_ERROR(NX_BSD_ENVIRONMENT_ERROR, __LINE__); - return(NX_BSD_ENVIRONMENT_ERROR); -#endif /* NX_ENABLE_EXTENDED_NOTIFY_SUPPORT */ - - /* Create a block pool for dynamically allocating sockets. */ - status = tx_block_pool_create(&nx_bsd_socket_block_pool, "NetX BSD Socket Block Pool", sizeof(NX_TCP_SOCKET), - nx_bsd_socket_pool_memory, sizeof(nx_bsd_socket_pool_memory)); - - /* Determine if the pool was created. */ - if (status) - { - - /* Error, return the error message. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - return(NX_BSD_BLOCK_POOL_ERROR); - } - - /* Create a block pool for dynamically allocating addrinfo. */ - status = tx_block_pool_create(&nx_bsd_addrinfo_block_pool, "NetX BSD Addrinfo Block Pool", sizeof(struct addrinfo), - nx_bsd_addrinfo_pool_memory, sizeof(nx_bsd_addrinfo_pool_memory)); - - /* Determine if the pool was created. */ - if(status) - { - - /* Error, return the error messafe. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Delete the block pool. */ - tx_block_pool_delete(&nx_bsd_socket_block_pool); - return(NX_BSD_BLOCK_POOL_ERROR); - - } - -#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) - /* Create a block pool for dynamically allocating canonical name buffer. */ - status = tx_block_pool_create(&nx_bsd_cname_block_pool, "NetX BSD CNAME Block Pool", (NX_DNS_NAME_MAX + 1), - nx_bsd_cname_pool_memory, sizeof(nx_bsd_cname_pool_memory)); - - /* Determine if the pool was created. */ - if(status) - { - - /* Error, return the error messafe. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Delete the block pool. */ - tx_block_pool_delete(&nx_bsd_socket_block_pool); - tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); - return(NX_BSD_BLOCK_POOL_ERROR); - - } -#endif - - nx_bsd_protection_ptr = &default_ip -> nx_ip_protection; - - /* Create the BSD event flag group. */ - status = tx_event_flags_create(&nx_bsd_events, "NetX BSD Events"); - - /* Check the return status. */ - if (status) - { - /* Delete the block pool. */ - tx_block_pool_delete(&nx_bsd_socket_block_pool); - tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); -#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) - tx_block_pool_delete(&nx_bsd_cname_block_pool); -#endif - - /* Error present, return error code. */ - NX_BSD_ERROR(NX_BSD_EVENT_ERROR, __LINE__); - return(NX_BSD_EVENT_ERROR); - } - - /* Set the array index to 0. */ - nx_bsd_socket_array_index = 0; - - /* Loop through the BSD socket array and clear it out! */ - for (i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* Clear the BSD socket structure. */ - memset((VOID*) &nx_bsd_socket_array[i], 0, sizeof(NX_BSD_SOCKET)); - } - - /* Save the IP instance and NX_PACKET_POOL for BSD Socket API. */ - nx_bsd_default_ip = default_ip; - nx_bsd_default_packet_pool = default_pool; - - - if ((bsd_thread_stack_area == TX_NULL) || (bsd_thread_stack_size == 0)) - { - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - -#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER - /* Create a thread for BSD socket features requiring periodic tasks. */ - info = 0 ; - status = tx_thread_create(&nx_bsd_task_thread, "BSD thread task", nx_bsd_thread_entry, info, - bsd_thread_stack_area, bsd_thread_stack_size, bsd_thread_priority, - bsd_thread_priority, 1, TX_AUTO_START); - - if (status != TX_SUCCESS) - { - /* Delete the event flag group. */ - tx_event_flags_delete(&nx_bsd_events); - - /* Delete the block pool. */ - tx_block_pool_delete(&nx_bsd_socket_block_pool); - tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); -#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) - tx_block_pool_delete(&nx_bsd_cname_block_pool); -#endif - - /* Error, return the error message. */ - NX_BSD_ERROR(NX_BSD_THREAD_ERROR, __LINE__); - - /* Return an error. */ - return(NX_IP_INTERNAL_ERROR); - } -#else - - info = 0 ; - - /* Create a one shot timer. Do not activate it. We will use it if - a socket being disconnected is NOT enabled for REUSEADDR socket option. */ - status = tx_timer_create(&nx_bsd_timer, "BSD Timer", - nx_bsd_timer_entry, info, - NX_BSD_TIMER_RATE, NX_BSD_TIMER_RATE, TX_AUTO_START); - - if (status != TX_SUCCESS) - { - - /* Delete the event flag group. */ - tx_event_flags_delete(&nx_bsd_events); - - /* Delete the block pool. */ - tx_block_pool_delete(&nx_bsd_socket_block_pool); - tx_block_pool_delete(&nx_bsd_addrinfo_block_pool); -#if defined(NX_BSD_ENABLE_DNS) && defined (NX_DNS_ENABLE_EXTENDED_RR_TYPES) - tx_block_pool_delete(&nx_bsd_cname_block_pool); -#endif - -#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER - /* Delete the thread. */ - tx_thread_delete(&nx_bsd_task_thread); -#endif - /* Error, return the error message. */ - NX_BSD_ERROR(NX_BSD_THREAD_ERROR, __LINE__); - - /* Return an error. */ - return(NX_IP_INTERNAL_ERROR); - } -#endif - -#ifdef NX_BSD_RAW_SUPPORT - _nx_driver_hardware_packet_received_callback = _nx_bsd_hardware_packet_received; -#endif /* NX_BSD_RAW_SUPPORT */ - - /* Calculate BSD system timer rate. */ - nx_bsd_timer_rate = (NX_IP_PERIODIC_RATE + (NX_IP_FAST_TIMER_RATE - 1)) / NX_IP_FAST_TIMER_RATE; - - /* Return success! */ - return(NX_SOC_OK); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_timeout_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for sockets waiting to make a TCP connection. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain exclusive access to */ -/* tx_mutex_put Release exclusive access */ -/* nx_tcp_server_socket_unaccept Remove socket from listen list */ -/* nx_tcp_server_socket_relisten Restore socket to listening */ -/* nx_tcp_server_socket_accept Accept to connection request */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_timeout_process() -{ - -INT i; -ULONG status; -INT master_socket_index; -NX_BSD_SOCKET *bsd_socket_ptr; - - - /* Obtain the BSD lock. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - if(status) - { - /* Mutex operation failed. This should be fatal. */ - return; - } - - for( i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* Skip the unused sockets. */ - if(!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - continue; - } - - /* Skip if it is not TCP server socket. */ - if((nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket == NX_NULL) || - ((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT))) - { - continue; - } - - /* Check for sockets trying to make a TCP connection. - Detect that the socket state is CLOSED, which is an indication - that the attempted connection failed, and we shall signal any pending - select on the socket. */ - if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) - { - - /* Is the NetX socket closed? */ - if(nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket -> nx_tcp_socket_state == NX_TCP_CLOSED) - { - - /* Yes. Set up a local pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[i]; - - /* Is this a secondary socket (passive open)? */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) - { - - /* Yes; Is the socket is connected yet? */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED)) - { - - /* No; Turn off the disconnection_request flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_DISCONNECTION_REQUEST); - - /* Remove the underlying NetX socket from the listen state. */ - nx_tcp_server_socket_unaccept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - - /* Check if a listen request is queued up for this socket. */ - nx_bsd_tcp_pending_connection(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - - /* Relisten on this socket. */ - status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - /* Set the socket to accept the connection. */ - nx_tcp_server_socket_accept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket, NX_NO_WAIT); - - /* Check the result of the relisten call. */ - if(status == NX_CONNECTION_PENDING) - { - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; - } - else if(status != NX_SUCCESS) - { - - - /* Failed the relisten on the secondary socket. Set the error code on the - master socket, and wake it up. */ - - master_socket_index = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id; - - nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - nx_bsd_set_error_code(&nx_bsd_socket_array[master_socket_index], status); - - nx_bsd_select_wakeup((UINT)master_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); - } - } - } - else - { - /* The underlying socket is closed. This indicates an error, and since is a non-blocking - socket, we need to wake up the corresponding thread. */ - - /* Mark this socket as error, and remove the CONNECT and INPROGRESS flags */ - nx_bsd_socket_array[i].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - nx_bsd_socket_array[i].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); - nx_bsd_socket_array[i].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); - nx_bsd_socket_array[i].nx_bsd_socket_error_code = ECONNREFUSED; - - /* Wake up the socket that could be listening on it. */ - /* Notice that on error the both read and write are selectable. */ - nx_bsd_select_wakeup((UINT)i, FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION); - } - } - } - } - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for events indicating BSD TCP socket tasks are */ -/* waiting to be performed. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Check for registered events */ -/* nx_bsd_timeout_process Process BSD tasks */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_BSD_TIMEOUT_PROCESS_IN_TIMER -VOID nx_bsd_thread_entry(ULONG info) -{ - NX_PARAMETER_NOT_USED(info); - - while(1) - { - - /* Wait for timeout. */ - tx_thread_sleep(NX_BSD_TIMER_RATE); - - /* Timeout process. */ - nx_bsd_timeout_process(); - } -} -#endif - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* socket PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Creates a TCP or UDP socket, which may then be used as an end point */ -/* of communication for sending and receiving data using the specified */ -/* protocol. */ -/* */ -/* INPUT */ -/* */ -/* protocolFamily Protocol family e.g AF_INET */ -/* type Type of the socket TCP or UDP */ -/* protocol Socket protocol */ -/* */ -/* OUTPUT */ -/* */ -/* socket descriptor On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* memset Clears memory */ -/* nx_tcp_socket_create Create TCP BSD Socket */ -/* nx_udp_socket_create Create UDP BSD Socket */ -/* nx_tcp_socket_receive_notify TCP receive notify function */ -/* nx_udp_socket_receive_notify UDP receive notify function */ -/* tx_block_allocate Allocate socket memory */ -/* tx_block_release Release socket memory */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT socket(INT protocolFamily, INT type, INT protocol) -{ - -INT i; -UINT status; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -VOID *socket_memory = NX_NULL; -NX_BSD_SOCKET *bsd_socket_ptr; - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -UINT index; -#else - - NX_PARAMETER_NOT_USED(protocol); -#endif - - /* Check for a supported protocol family. */ -#ifndef NX_DISABLE_IPV4 - if (protocolFamily == AF_INET) - { - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (protocolFamily == AF_INET6) - { - } - else -#endif /* FEATURE_NX_IPV6 */ -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) - if (protocolFamily == AF_PACKET) - { - } - else -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - { - - /* Set the socket error. */ - set_errno(EAFNOSUPPORT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check for a supported socket type. */ -#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) - if ((type != SOCK_STREAM) && (type != SOCK_DGRAM) && (type != SOCK_RAW)) -#else - if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) -#endif - { - - /* Set the socket error. */ - set_errno(EPROTOTYPE); - - /* Invalid type. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) - /* An extra check when BSD RAW Packet type is enabled: - Only RAW_SOCKET type is supported in AF_PACKET family. */ - if((protocolFamily == AF_PACKET) && (type != SOCK_RAW)) - { - /* Set the socket error. */ - set_errno(EPROTOTYPE); - - /* Invalid type. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - - - /* Obtain the BSD protection socket. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error. */ - set_errno(EACCES); - - /* Error getting the protection mutex. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check whether IP fast timer is created or not. */ - if ((nx_bsd_ip_fast_periodic_timer_entry == NX_NULL) || - (nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function != _nx_bsd_fast_periodic_timer_entry)) - { - - /* BSD socket requires a fast periodic timer to calculate wait option in recv() function. */ - /* Create IP fast periodic timer. */ - _nx_ip_fast_periodic_timer_create(nx_bsd_default_ip); - - /* Replace timer expiration function entry. */ - nx_bsd_ip_fast_periodic_timer_entry = nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function; - nx_bsd_default_ip -> nx_ip_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function = _nx_bsd_fast_periodic_timer_entry; - } - - /* Now find a free slot in the BSD socket array. */ - for (i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* See if this entry is available. Check the in use flag. */ - if (!(nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Yes, Ok to use this socket. */ - - /* Clear the entire structure. */ - memset((VOID*) &nx_bsd_socket_array[nx_bsd_socket_array_index], 0, sizeof(NX_BSD_SOCKET)); - nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_id = (INT)nx_bsd_socket_array_index; - - /* Mark this socket as in-use. */ - nx_bsd_socket_array[nx_bsd_socket_array_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_IN_USE; - - /* Get out of the loop. */ - break; - } - else - { - - /* Try the next socket. */ - nx_bsd_socket_array_index++; - - /* Check if we need to wrap around to the start of the socket table. */ - if (nx_bsd_socket_array_index >= NX_BSD_MAX_SOCKETS) - { - - /* Reset the index to 0. */ - nx_bsd_socket_array_index = 0; - } - } - } - - /* Check if a free socket was found. */ - if (i >= NX_BSD_MAX_SOCKETS) - { - - /* No, set the error status and return. */ - - /* Set the socket error. */ - set_errno(ENFILE); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Mark the location of the free socket. */ - i = (INT)nx_bsd_socket_array_index; - - /* Update the socket index to the next entry. */ - nx_bsd_socket_array_index++; - - /* Check if we need to wrap around to the start of the table. */ - if (nx_bsd_socket_array_index >= NX_BSD_MAX_SOCKETS) - { - - /* Reset the index to 0. */ - nx_bsd_socket_array_index = 0; - } - - /* Set up a pointer to the BSD socket to use. */ - bsd_socket_ptr = &nx_bsd_socket_array[i]; - - /* For TCP or UDP sockets we need to allocate memory to create the NetX Duo socket - (not necessary for raw socket). */ - - if ((type == SOCK_STREAM) || (type == SOCK_DGRAM)) - { - - /* Allocate a socket from the block pool. */ - status = tx_block_allocate(&nx_bsd_socket_block_pool, &socket_memory, NX_BSD_TIMEOUT); - - /* Check for error status. */ - if (status != TX_SUCCESS) - { - - /* Set the socket error. */ - set_errno(ENOMEM); - - /* Clear the allocated internal BSD socket. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_IN_USE); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Clear the socket memory. */ - memset((VOID*) socket_memory, 0, sizeof(NX_TCP_SOCKET)); - - } - - /* Is this a stream socket e.g. TCP? */ - if (type == SOCK_STREAM) - { - bsd_socket_ptr -> nx_bsd_socket_protocol = NX_PROTOCOL_TCP; - - /* Mark the master/secondary socket id as invalid. */ - (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; - (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = NX_BSD_MAX_SOCKETS; - - /* Yes, allocate memory for a TCP socket. */ - tcp_socket_ptr = (NX_TCP_SOCKET *) socket_memory; - - /* Create a NetX TCP socket. */ - /* Note that the nx_bsd_tcp_socket_disconnect_notify is invoked when an - established connection is disconnected. - The disconnect_complete_notify is called for all types of disconnect, - including the ones covered by tcp_socket_disconnect_notify. */ - - status = nx_tcp_socket_create(nx_bsd_default_ip, tcp_socket_ptr, "NetX BSD TCP Socket", - NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, NX_BSD_TCP_WINDOW, NX_NULL, - nx_bsd_tcp_socket_disconnect_notify); - - /* Check for a successful status. */ - if (status == NX_SUCCESS) - { - - /* Register a receive notify callback. */ - status = nx_tcp_socket_receive_notify(tcp_socket_ptr, nx_bsd_tcp_receive_notify); - - /* Check for invalid input. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Release the allocated socket memory block. */ - tx_block_release(socket_memory); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - -#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT - - /* Set the SYN received notify function */ - tcp_socket_ptr -> nx_tcp_socket_syn_received_notify = nx_bsd_tcp_syn_received_notify; -#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ - -#ifdef NX_ENABLE_TCP_KEEPALIVE - /* Set the keep alive feature to disabled. */ - tcp_socket_ptr -> nx_tcp_socket_keepalive_enabled = NX_FALSE; -#endif /* NX_ENABLE_TCP_KEEPALIVE */ - - /* Set the socket reuse feature to enabled. This is the default NetX socket behavior. */ - bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; - -#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT - /* Register an establish notify callback for the specified server socket with NetX. */ - nx_tcp_socket_establish_notify(tcp_socket_ptr, nx_bsd_tcp_establish_notify); - - /* Register a disconnect complete notify callback for the specified server socket with NetX. */ - /* The callback function is the same as the one used for TCP disconnect callback. */ - status += nx_tcp_socket_disconnect_complete_notify(tcp_socket_ptr, nx_bsd_tcp_socket_disconnect_notify); -#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ - - /* Return successful completion. */ - - /* Save the TCP pointer in the appropriate place. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket = tcp_socket_ptr; - - /* Set up pointer in the NetX socket back to the BSD socket. */ - tcp_socket_ptr -> nx_tcp_socket_reserved_ptr = (VOID *) i; - - - } - } - else if (type == SOCK_DGRAM) - { - - bsd_socket_ptr -> nx_bsd_socket_protocol = NX_PROTOCOL_UDP; - - /* Make a double circular list. */ - bsd_socket_ptr -> nx_bsd_socket_next = bsd_socket_ptr; - bsd_socket_ptr -> nx_bsd_socket_previous = bsd_socket_ptr; - - /* Allocate memory for a UDP socket. */ - udp_socket_ptr = (NX_UDP_SOCKET *) socket_memory; - - /* Create a NetX UDP socket */ - status = nx_udp_socket_create(nx_bsd_default_ip, udp_socket_ptr, "NetX BSD UDP Socket", - NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, - (nx_bsd_default_packet_pool -> nx_packet_pool_total)/8+1); - - /* Check for successful result. */ - if (status == NX_SUCCESS) - { - - /* Register a receive notify callback. */ - status = nx_udp_socket_receive_notify(udp_socket_ptr, nx_bsd_udp_receive_notify); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Release the allocated socket memory block. */ - tx_block_release(socket_memory); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Save the UDP pointer in the BSD socket. */ - bsd_socket_ptr -> nx_bsd_socket_udp_socket = udp_socket_ptr; - - /* Set the reserved UDP socket pointer back to the BSD socket. */ - udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID *) (i + 0x00010000); - } - } -#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) - else if (type == SOCK_RAW) - { - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - /* Check if raw sockets are enabled in NetX Duo. */ - if (((protocolFamily == AF_INET) || - (protocolFamily == AF_INET6)) && - (nx_bsd_default_ip -> nx_ip_raw_ip_processing == NX_NULL)) - { - /* No, Enable raw socket handling in NetX Duo. */ - status = nx_ip_raw_packet_enable(nx_bsd_default_ip); - - if (status != NX_SUCCESS) - { - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - set_errno(EPROTONOSUPPORT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - - /* Check if we set the packet filter already. */ - if (((protocolFamily == AF_INET) || - (protocolFamily == AF_INET6)) && - (nx_bsd_default_ip -> nx_ip_raw_packet_filter == NX_NULL)) - { - - /* We have not. Do so now. Set the raw packet filter to the IP instance. */ - status = nx_ip_raw_packet_filter_set(nx_bsd_default_ip, nx_bsd_raw_packet_filter); - - /* Has a raw packet filter been successfully set? */ - if (status != NX_SUCCESS) - { - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - set_errno(EPROTONOSUPPORT); - - /* No, return error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - - /* For IPv6 raw socket, by default the header is not included in the received packet. */ - if(protocolFamily == AF_INET6) - { - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_RX_NO_HDR; - } - - /* Set the raw socket protocol to the BSD raw socket. */ - bsd_socket_ptr -> nx_bsd_socket_protocol = (USHORT)protocol; - bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_RAW_SOCKET; - - /* Calculate the hash index in the raw socket protocol table. */ - index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); - - /* Determine if the list is NULL. */ - if(nx_bsd_socket_raw_protocol_table[index]) - { - /* There are already sockets on the list... just add this one to the end. */ - bsd_socket_ptr -> nx_bsd_socket_next = nx_bsd_socket_raw_protocol_table[index]; - bsd_socket_ptr -> nx_bsd_socket_previous = (nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous; - ((nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr; - (nx_bsd_socket_raw_protocol_table[index]) -> nx_bsd_socket_previous = bsd_socket_ptr; - } - else - { - /* Nothing is on the list. Add this one to an empty list. */ - bsd_socket_ptr -> nx_bsd_socket_next = bsd_socket_ptr; - bsd_socket_ptr -> nx_bsd_socket_previous = bsd_socket_ptr; - nx_bsd_socket_raw_protocol_table[index] = bsd_socket_ptr; - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - if(protocolFamily == AF_PACKET) - { -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - bsd_socket_ptr -> nx_bsd_socket_create_id = nx_bsd_socket_create_id; - nx_bsd_socket_create_id++; -#elif defined(NX_BSD_RAW_SUPPORT) - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - } - - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER || NX_BSD_RAW_PPPOE_SUPPORT || NX_BSD_RAW_SUPPORT */ - - else - { - /* Not a supported socket type. */ - set_errno(EOPNOTSUPP); - - /* Invalid type. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set the protocol family: AF_INET or AF_INET6. */ - bsd_socket_ptr -> nx_bsd_socket_family = (ULONG)protocolFamily; - - /* For UDP and RAW sockets, set the maximum receive queue depth. */ - if(bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - { - - bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max = NX_BSD_SOCKET_QUEUE_MAX; - } - - /* Check for error creating the NetX Duo socket. */ - if (status != NX_SUCCESS) - { - - /* Release the BSD protection. */ - - /* Clear the BSD socket in use flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_IN_USE); - - if ((type == SOCK_DGRAM) || (type == SOCK_STREAM)) - { - /* Release the socket memory block allocated for TCP or UDP socket. */ - tx_block_release(socket_memory); - } - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Error present, return error code. */ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return success! */ - return(i + NX_BSD_SOCKFD_START); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Establishes a connection between a client socket and a remote server*/ -/* socket associated with the remote address, if any. Upon returning */ -/* successfully, the given socket's local and remote IP address and */ -/* port information are filled in. If the socket was not previously */ -/* bound to a local port, one is assigned randomly. */ -/* */ -/* For TCP sockets, connect() completes with a connection handshake is */ -/* complete, or if an error occurs. A TCP negotiation is performed */ -/* to open a connection and success implies the existence of a reliable*/ -/* channel to that socket. */ -/* */ -/* For UDP sockets, the connection is established simply by setting the*/ -/* supplied destination (remote) IP address and port for the remote */ -/* host. */ -/* */ -/* For non blocking sockets, the function returns immediately if a */ -/* connection is not possible. The socket thread error is set to */ -/* EINPROGRESS to distinguish from blocking sockets. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket descriptor */ -/* *remoteAddress Remote address structure */ -/* addressLength Address structure length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) If success */ -/* NX_SOC_ERROR (-1) If failure or if called with */ -/* an UDP socket */ -/* */ -/* CALLS */ -/* */ -/* nx_ip_status_check Check to make sure link is up */ -/* nx_tcp_client_socket_bind Bind a TCP socket to a port */ -/* nxd_tcp_client_socket_connect Connect to a TCP server */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT connect(INT sockID, struct sockaddr *remoteAddress, INT addressLength) -{ -UINT status; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -NX_BSD_SOCKET *bsd_socket_ptr; -ULONG timeout; -ULONG actual_status; - - /* Check for a valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Adjust the sockID to index into the BSD socket table. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Ensure the IP instance has been initialized. */ - status = nx_ip_status_check(nx_bsd_default_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error. */ - set_errno(EFAULT); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Make sure the socket is valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Socket is no longer in use. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Obtain the BSD protection. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check whether supplied address structure and length is valid */ - if (remoteAddress == NX_NULL ) - { - - /* For UDP socket or RAW socket, a NULL remoteAddress dis-associate - a remote address bound to the socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - { - memset(&bsd_socket_ptr -> nx_bsd_socket_peer_ip, 0, sizeof(NXD_ADDRESS)); - bsd_socket_ptr -> nx_bsd_socket_peer_port = 0; - - /* Clear the connect flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); - - /* All done. Return. */ - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - - } - else - { - /* For TCP socket, each socket can only be connected once, and - the remote address must be set correctly. */ - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - /* Set the socket error if extended socket options enabled. */ - set_errno(EAFNOSUPPORT); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - - - /* Check if the remote address family matches the local BSD socket address family. */ - if((remoteAddress -> sa_family != bsd_socket_ptr -> nx_bsd_socket_family) || - ((remoteAddress -> sa_family == AF_INET) && (addressLength != sizeof(struct sockaddr_in))) || - ((remoteAddress -> sa_family == AF_INET6) && (addressLength != sizeof(struct sockaddr_in6)))) - { - - /* Mismatch! */ - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EAFNOSUPPORT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(ERROR); - } - -#ifndef NX_DISABLE_IPV4 - /* Check the socket family type. */ - if(remoteAddress -> sa_family == AF_INET) - { - - /* This is an IPv4 socket type. */ - - /* Set the UDP remote host IP address and port for the UDP 'connection'; for NetX Duo - set the IP version. */ - /* NetX API expects multi byte values to be in host byte order. - Therefore ntohl/s are used to make the conversion. */ - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_version = NX_IP_VERSION_V4; - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4 = htonl(((struct sockaddr_in *) remoteAddress ) -> sin_addr.s_addr); - bsd_socket_ptr -> nx_bsd_socket_peer_port = htons(((struct sockaddr_in *) remoteAddress ) -> sin_port); - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 - if(remoteAddress -> sa_family == AF_INET6) - { - - /* This is an IPv6 enabled socket family type). */ - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_version = NX_IP_VERSION_V6; - /* NetX API expects multi byte values to be in host byte order. - Therefore ntohl/s are used to make the conversion. */ - /* Get remote address and port. */ - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[0]); - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[1]); - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[2]); - bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3] = htonl(((struct sockaddr_in6*)remoteAddress) -> sin6_addr._S6_un._S6_u32[3]); - - bsd_socket_ptr -> nx_bsd_socket_peer_port = htons(((struct sockaddr_in6 *) remoteAddress ) -> sin6_port); - - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Address family not supported. */ - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EAFNOSUPPORT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(ERROR); - } - - - /* Handle the UDP 'connection' request. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; - - /* Check to see if the UDP socket is already bound. */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) - { - - /* Not yet, bind to a randomly selected available free port. */ - status = nx_udp_socket_bind(udp_socket_ptr, NX_ANY_PORT, NX_BSD_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error based on NetX error status return. */ - nx_bsd_set_error_code(bsd_socket_ptr, status); - - /* Return an error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - /* Bind is successful. Obtain the port number. */ - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)udp_socket_ptr -> nx_udp_socket_port; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - } - - /* Mark the socket as connected. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return successful status. */ - return(NX_SOC_OK); - } - else if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - { - - /* This is not UDP or TCP socket. So it must be raw socket. */ - /* We treat raw socket the same as UDP socket. For connec, raw socket - associates the remote address as its default destination address when - transmit, and also limit the reception of data from that remote address. */ - - /* Mark the socket as connected. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return successful status. */ - return(NX_SOC_OK); - } - - /* This is a TCP BSD socket. */ - - /* If the socket is already connected. */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) - { - - /* If INPROGRESS is set, clear the INPROGRESS flag and return OK. - The INPROGRESS flag needs to be cleared so the next connect call would return EISCONN */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) - { - - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - - /* Already connected. */ - set_errno(EISCONN); - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - - } - - /* If the socket is marked as EINPROGRESS, return EALREADY. */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) - { - - - set_errno(EALREADY); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - - } - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & ((ULONG)(~NX_BSD_SOCKET_ERROR)); - - set_errno(errcode); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Set a NetX tcp pointer. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - - /* Mark this as a client TCP socket. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CLIENT; - - /* Is the TCP socket already bound? */ - if (tcp_socket_ptr -> nx_tcp_socket_port == 0) - { - - /* Not yet; bind to a randomly selected available free port. */ - - /* Call NetX TCP bind service with NX_NO_WAIT. */ - status = nx_tcp_client_socket_bind(tcp_socket_ptr, NX_ANY_PORT, NX_NO_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Clear the client socket flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CLIENT); - - /* Set the socket error depending on NetX error status return. */ - nx_bsd_set_error_code(bsd_socket_ptr, status); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_ERROR); - } - - /* Mark the socket as bound. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)tcp_socket_ptr -> nx_tcp_socket_port; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; - - } - - /* Mark this BSD socket as busy. */ - bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); - - /* Attempt to make the connection. If the socket is non-blocking, - set the timeout to 0. Otherwise, use wait-forever */ - if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) - { - - /* Yes, the socket is enabled for non blocking. Do not wait. */ - timeout = 0; - } - else - { - /* This call may be blocked internally. Release the mutex - so the nx_tcp_client_socket_connect can suspend waiting - for a connection. */ - timeout = NX_WAIT_FOREVER; - tx_mutex_put(nx_bsd_protection_ptr); - } - - /* Make the connection. */ - status = nxd_tcp_client_socket_connect(tcp_socket_ptr, &(bsd_socket_ptr -> nx_bsd_socket_peer_ip), bsd_socket_ptr -> nx_bsd_socket_peer_port, timeout); - if(timeout != 0) - { - /* The mutex was released prior to the call. Accquire the mutex - again. */ - tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Verify that the socket is still valid. */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* The socket is no longer in use. */ - - /* Set the socket error code. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if (status == NX_NOT_CONNECTED) - { - - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) || - (tcp_socket_ptr -> nx_tcp_socket_timeout_retries >= tcp_socket_ptr -> nx_tcp_socket_timeout_max_retries)) - { - - /* Connect timeouts since NX_BSD_SOCKET_ERROR is not set or - * number of timeout retry has been exceeded. */ - status = NX_WAIT_ABORTED; - } - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - bsd_socket_ptr -> nx_bsd_socket_error_code = ENOTCONN; - } - } - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error depending on NetX error status return. */ - nx_bsd_set_error_code(bsd_socket_ptr, status); - - - /* Make sure this thread is still the owner. */ - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - - /* Clear the busy flag. */ - bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* At this point NX TCP connect service returns success, so the connection is established. */ - - /* Mark the socket as connected. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; - - /* Clear the CONNECTION_INPROGRESS flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); - - /* Mark the connection_request flag */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; - - /* Make sure thread making the bind call is the current thread. */ - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - - /* OK to clear the busy flag. */ - bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; - - /* Check if the connect call was successful. */ - if (status == NX_SUCCESS) - { - - /* It was. Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Successful connection. Return the success status. */ - return(NX_SOC_OK); - } - } - - /* Error condition: the thread that was executing connect is not the current thread. */ - - /* Clear the connected flags and peer infomration .*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_REQUEST); - memset(&bsd_socket_ptr -> nx_bsd_socket_source_ip_address, 0, sizeof(NXD_ADDRESS)); - bsd_socket_ptr -> nx_bsd_socket_source_port = 0; - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error. */ - set_errno(EINTR); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* bind PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function binds a socket to a local port. The port in the struct*/ -/* in the struct sockaddr structure may be wildcarded, in which case */ -/* NetX will select a port number. */ -/* */ -/* To wildcard the port, set the sin_port field of the address to 0. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket descriptor */ -/* *localAddress Populated socket address */ -/* addressLength Socket address length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) If success */ -/* NX_SOC_ERROR (-1) If failure */ -/* */ -/* CALLS */ -/* */ -/* nx_ip_status_check Check for link up */ -/* nx_tcp_client_socket_bind Binds a TCP socket to a port */ -/* nx_udp_client_socket_bind Binds a UDP socket to a port */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Gets the current thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT bind(INT sockID, struct sockaddr *localAddress, INT addressLength) -{ - -INT local_port = 0; -UINT status; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -NX_BSD_SOCKET *bsd_socket_ptr; -INT i; -INT address_conflict; - - - /* Check for invalid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error. */ - set_errno(EBADF); - - /* Error, invalid socket ID. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check for a valid input local address and address length input buffer. */ - if ((localAddress == NX_NULL ) || (addressLength == 0)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EFAULT); - - /* Error, invalid local address. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if (((localAddress -> sa_family == AF_INET) && (addressLength != sizeof(struct sockaddr_in))) || - ((localAddress -> sa_family == AF_INET6) && (addressLength != sizeof(struct sockaddr_in6)))) - { - set_errno(EAFNOSUPPORT); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set up a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* See if the socket is still in use. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Socket is no longer in use. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(bsd_socket_ptr -> nx_bsd_socket_error_code); - - /* Clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Check the address family. */ - if (bsd_socket_ptr -> nx_bsd_socket_family != localAddress -> sa_family) - { - set_errno(EAFNOSUPPORT); - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check to see if the socket is already bound. */ - if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND) - { - - /* It is. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Zero out the local bind info */ - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = 0; - -#ifndef NX_DISABLE_IPV4 - if(localAddress -> sa_family == AF_INET) - { - - ULONG local_addr; - INT if_index; - - /* Pickup the local port. */ - local_port = ntohs(((struct sockaddr_in *) localAddress) -> sin_port); - - /* Pick up the local IP address */ - local_addr = ntohl(((struct sockaddr_in*)localAddress) -> sin_addr.s_addr); - - if(local_addr == INADDR_ANY) - { - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; - } - else - { - - for(if_index = 0; if_index < NX_MAX_IP_INTERFACES; if_index++) - { - - if((nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid) && - (nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_address == local_addr)) - { - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ip_interface[if_index]); - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = (UINT)if_index; - break; - } - } - } - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(localAddress -> sa_family == AF_INET6) - { - - ULONG ipv6_addr[4]; - INT if_index; - - /* Pickup the local port. */ - local_port = ntohs(((struct sockaddr_in6 *) localAddress) -> sin6_port); - - ipv6_addr[0] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[0]); - ipv6_addr[1] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[1]); - ipv6_addr[2] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[2]); - ipv6_addr[3] = ntohl((((struct sockaddr_in6*)localAddress)) -> sin6_addr._S6_un._S6_u32[3]); - - if((ipv6_addr[0] | ipv6_addr[1] | ipv6_addr[2] | ipv6_addr[3]) == 0) - { - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; - } - else - { - - for(if_index = 0; if_index < NX_MAX_IPV6_ADDRESSES; if_index++) - { - - if((nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[0] == ipv6_addr[0]) && - (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[1] == ipv6_addr[1]) && - (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[2] == ipv6_addr[2]) && - (nx_bsd_default_ip -> nx_ipv6_address[if_index].nxd_ipv6_address[3] == ipv6_addr[3])) - { - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ipv6_address[if_index]); - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = (UINT)if_index; - break; - } - } - } - } -#endif -#ifdef NX_BSD_RAW_SUPPORT - if ((localAddress -> sa_family == AF_PACKET) && (addressLength == sizeof(struct sockaddr_ll))) - { - UINT if_index; - - if_index = (UINT)(((struct sockaddr_ll *)localAddress) -> sll_ifindex); - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = (ULONG)(&nx_bsd_default_ip -> nx_ip_interface[if_index]); - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = if_index; - } -#endif /* NX_BSD_RAW_SUPPORT */ - - /* Check if the bind information is correctly set. */ - if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EADDRNOTAVAIL); - - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* At this point the local bind interface and port are known. - If port number is specified, we need to go through the existing sockets - and make sure there is no conflict. */ - address_conflict = 0; - - if(local_port) - { - - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* Skip its own entry. */ - if((i == sockID) || - /* Skip invalid entries. */ - (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) || - /* Skip the entries with different protocol ID */ - (nx_bsd_socket_array[i].nx_bsd_socket_protocol != bsd_socket_ptr -> nx_bsd_socket_protocol) || - /* Skip the unbound entries */ - (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND))) - { - - continue; - } - - /* Check for port number and interface ID */ - if(nx_bsd_socket_array[i].nx_bsd_socket_local_port == (USHORT)local_port) - { - - address_conflict = 1; - - if((nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface) && - (nx_bsd_socket_array[i].nx_bsd_socket_family == bsd_socket_ptr -> nx_bsd_socket_family)) - { - - /* This is completely duplicate binding. */ - - /* If it is a TCP non-listen socket (in other words a TCP server socket that is - already in connection, and the REUSEADDR is set, it is OK. */ - if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) && - (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT)) && - (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR)) - { - - address_conflict = 0; - } - } - else - { - - /* If the REUSEADDR option is set, the socket can be bound to its specififed local address. */ - if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR) - { - - address_conflict = 0; - - if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - UINT counter; - - /* For UDP socket, it needs to share the underlying NetX UDP socket. */ - nx_udp_socket_delete(bsd_socket_ptr -> nx_bsd_socket_udp_socket); - - /* Free the memory. */ - memset((VOID*)bsd_socket_ptr -> nx_bsd_socket_udp_socket, 0, sizeof(NX_UDP_SOCKET)); - - tx_block_release((VOID*)bsd_socket_ptr -> nx_bsd_socket_udp_socket); - - /* Add this bsd udp socket to the list that map to the same NetX udp socket. */ - - /* See if this is the only bsd udp socket on the list. */ - if ((&nx_bsd_socket_array[i]) == nx_bsd_socket_array[i].nx_bsd_socket_next) - { - - /* Yes, the only bsd udp socket on the list. */ - /* Update the list. */ - bsd_socket_ptr -> nx_bsd_socket_next = &nx_bsd_socket_array[i]; - bsd_socket_ptr -> nx_bsd_socket_previous = &nx_bsd_socket_array[i]; - nx_bsd_socket_array[i].nx_bsd_socket_next = bsd_socket_ptr; - nx_bsd_socket_array[i].nx_bsd_socket_previous = bsd_socket_ptr; - - } - else - { - - /* At least one more bsd udp socket on this list. */ - /* Update the list. */ - bsd_socket_ptr -> nx_bsd_socket_next = nx_bsd_socket_array[i].nx_bsd_socket_next; - bsd_socket_ptr -> nx_bsd_socket_previous = &nx_bsd_socket_array[i]; - (nx_bsd_socket_array[i].nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr; - nx_bsd_socket_array[i].nx_bsd_socket_next = bsd_socket_ptr; - } - - - bsd_socket_ptr -> nx_bsd_socket_udp_socket = nx_bsd_socket_array[i].nx_bsd_socket_udp_socket; - - /* Increase the counter. */ - counter = (UINT)bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_reserved_ptr; - counter = ((counter & 0xFFFF0000) + 0x00010000 + (counter & 0x0000FFFF)) & 0xFFFFFFFF; - - bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_reserved_ptr = (VOID*)counter; - - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) - { - - /* Just point this BSD TCP socket to the same secondary socket. */ - (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id; - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; -#if defined(__PRODUCT_NETXDUO__) && !defined(NX_DISABLE_IPV4) - /* Handle client sockets differently. Share the port here for sockets with different IP/IPv6 addresses. */ - if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type == NX_TRUE) - { - - /* Handle client sockets differently. Share the port here for sockets with different IP/IPv6 addresses. */ - if (((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) && (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_INET)) || - ((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) && (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_INET6))) - - { - - NX_IP *ip_ptr = nx_bsd_default_ip; - NX_TCP_SOCKET *socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - - - /* Calculate the hash index in the TCP port array of the associated IP instance. */ - UINT index = (UINT) ((local_port + (local_port >> 8)) & NX_TCP_PORT_TABLE_MASK); - - /* This non server socket needs to share a port with the other client socket. */ - socket_ptr -> nx_tcp_socket_port = (UINT)local_port; - - - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Add this socket to the list of bound sockets. */ - socket_ptr -> nx_tcp_socket_bound_next = ip_ptr -> nx_ip_tcp_port_table[index]; - socket_ptr -> nx_tcp_socket_bound_previous = (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous; - ((ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next = socket_ptr; - (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous = socket_ptr; - - - tx_mutex_put(&ip_ptr -> nx_ip_protection); - } - } -#endif - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - } - } - - if(address_conflict) - { - - break; /* Break out of the for loop */ - } - } - } - } - -#ifdef NX_BSD_RAW_SUPPORT - if (localAddress -> sa_family == AF_PACKET) - { - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* Skip its own entry. */ - if((i == sockID) || - /* Skip invalid entries. */ - (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) || - /* Skip the entries with different protocol ID */ - (nx_bsd_socket_array[i].nx_bsd_socket_protocol != bsd_socket_ptr -> nx_bsd_socket_protocol) || - /* Skip the entries with different address family. */ - (nx_bsd_socket_array[i].nx_bsd_socket_family != bsd_socket_ptr -> nx_bsd_socket_family) || - /* Skip the unbound entries */ - (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND))) - { - - continue; - } - - if (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface_index == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index) - { - - /* Bind to same interface. */ - address_conflict = 1; - break; - } - - if (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) - { - - /* A socket is bound to any interface. */ - address_conflict = 1; - break; - } - } - } -#endif /* NX_BSD_RAW_SUPPORT */ - - if(address_conflict) - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EADDRINUSE); - - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Mark this BSD socket as busy. */ - bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); - - /* Determine what type of bind is required. */ - if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - - /* Setup TCP socket pointer. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - - /* Call NetX to bind the client socket. */ - status = nx_tcp_client_socket_bind(tcp_socket_ptr, (UINT)local_port, NX_NO_WAIT); - - /* Update the port. */ - if((status == NX_SUCCESS) && (local_port == 0)) - local_port = (INT)(tcp_socket_ptr -> nx_tcp_socket_port); - - } - else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) - { - - /* Set up a pointer to the UDP socket. */ - udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; - - /* Bind the UDP socket to the specified port in NetX. */ - status = nx_udp_socket_bind(udp_socket_ptr, (UINT)local_port, NX_BSD_TIMEOUT); - - /* Update the port. */ - if((status == NX_SUCCESS) && (local_port == 0)) - local_port = (INT)(udp_socket_ptr -> nx_udp_socket_port); - } - else - { - - /* Raw socket. All done. Just need to set status = NX_SUCCESS and continue. */ - status = NX_SUCCESS; - } - - - /* Check if we were able to bind the port. */ - if (status == NX_SUCCESS) - { - - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)local_port; - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - - - /* Make sure this thread is still the owner. */ - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - - /* Clear the busy flag. */ - bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return successful status. */ - return(NX_SOC_OK); - - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if extended socket options enabled, depending on the status returned by NetX. */ - nx_bsd_set_error_code(bsd_socket_ptr, status); - - /* Return an error, unsuccessful socket bind call. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* listen PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the given socket ready to accept incoming client */ -/* connections. The socket must already be associated with a local port*/ -/* which means the bind() must have been called previously. */ -/* After this call, incoming TCP connections requests addressed to the */ -/* local port (and IP address, if specified previously) will be */ -/* completed & queued until they are passed to the program via accept()*/ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* backlog Maximum number of new */ -/* connections queued */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) If success */ -/* NX_SOC_ERROR (-1) If failure. */ -/* */ -/* CALLS */ -/* */ -/* socket Create a server socket */ -/* nx_tcp_server_socket_listen Enable a server socket listen */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT listen(INT sockID, INT backlog) -{ - -UINT status; -NX_BSD_SOCKET *bsd_socket_ptr; -NX_BSD_SOCKET *bsd_secondary_socket; -INT secondary_sockID; -INT ret; - - - /* Check whether supplied socket ID is valid. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set up a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Determine if the socket is a UDP socket or raw */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - { - - /* The underlying protocol is not TCP, therefore it does not support the listen operation. */ - set_errno(EOPNOTSUPP); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check if the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Have we already started listening? */ - if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) - { - - /* Error, socket is already listening. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check if this is a secondary server socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) - { - - /* Error, socket is a secondary server socket. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EOPNOTSUPP); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check if bound to a port. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error code. */ - set_errno(EDESTADDRREQ); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check if this master (listening) socket's secondary socket is not marked invalid. If not, it means this socket will - share the secondary socket with another master socket. */ - if((bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id != NX_BSD_MAX_SOCKETS) - { - - /* It is set. */ - - secondary_sockID = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; - - bsd_secondary_socket = &nx_bsd_socket_array[secondary_sockID]; - - /* Now check if the other master socket is in listen mode. */ - if(bsd_secondary_socket -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) - { - - /* It is ready.. we are ready to listen on this socket. */ - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - } - - if(backlog < NX_BSD_TCP_LISTEN_MIN_BACKLOG) - { - backlog = NX_BSD_TCP_LISTEN_MIN_BACKLOG; - } - - /* We need to set up this socket as a listen socket. */ - ret = nx_bsd_tcp_create_listen_socket(sockID, backlog); - - /* Release the mutex protection. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return success. */ - return(ret); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* accept PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function blocks while waiting for connections addressed to the */ -/* IP address and port to which this socket is bound. A listen() must */ -/* previously have been called on this given socket. */ -/* */ -/* When a connection arrives and the TCP handshake is successfully */ -/* completed, this function returns with a new socket with local and */ -/* remote address and port numbers filled in. */ -/* */ -/* For non blocking sockets, this function returns immediately. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* clientAddress Originating socket IP address */ -/* and port. */ -/* addressLength Length of sockaddr buffer (in)*/ -/* returned address (out) */ -/* */ -/* OUTPUT */ -/* */ -/* socket id Socket ID for new connection */ -/* NX_SOC_ERROR (-1) If failure */ -/* */ -/* CALLS */ -/* */ -/* memset Clears memory */ -/* socket Create a server socket */ -/* nx_tcp_server_socket_relisten Relisten with a new TCP soc */ -/* nx_tcp_server_socket_accept Accept a client connection */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Gets the current thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT accept(INT sockID, struct sockaddr *ClientAddress, INT *addressLength) -{ -/* Define the accept function if NetX BSD accept() is not set to asynchronous (on automatic callback). */ - -UINT status; -NX_BSD_SOCKET *bsd_socket_ptr; -NX_BSD_SOCKET *bsd_secondary_socket; -INT sec_sock_id; -INT ret = 0; -INT connected = 0; -ULONG requested_events; -INT secondary_socket_id = 0; -#ifndef NX_DISABLE_IPV4 -struct sockaddr_in peer4_address; -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 -struct sockaddr_in6 peer6_address; -#endif - - - /* Check for valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return an error.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Setup pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error.*/ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Determine if the socket is a UDP socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - { - - /* Error, UDP or raw sockets do not perform listen. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EOPNOTSUPP); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Has listening been enabled on this socket? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN)) - { - - /* No, this socket is not ready to accept TCP connections. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Make sure the accept call operates on the master socket. */ - if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) == 0) - { - /* This is not a master socket. - BSD accept is only allowed on the master socket. - Return. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Validate the secondary server socket. */ - if ((bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id >= NX_BSD_MAX_SOCKETS) - { - - /* This secondary socket is not available yet. This could happen if the - previous accept call fails to allocate a new secondary socket. */ - ret = nx_bsd_tcp_create_listen_socket(sockID, 0); - - if(ret < 0) - { - - /* Failed to allocate a secondary socket, release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Errno is already set inside nx_bsd_tcp_create_listen_socket. Therefore - there is no need to set errno here. */ - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - - /* At this point, we have found and marked a secondary server socket for the connection request. */ - - /* Set up a pointer to the secondary server socket. */ - sec_sock_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; - bsd_secondary_socket = &nx_bsd_socket_array[sec_sock_id]; - - /* Mark this BSD socket as busy. */ - bsd_socket_ptr -> nx_bsd_socket_busy = tx_thread_identify(); - - /* If the master socket is marked as non-blocking, we just need to check if the - secondary socket has a connection already. */ - while(!connected) - { - - secondary_socket_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; - - if((secondary_socket_id < NX_BSD_MAX_SOCKETS) && - (nx_bsd_socket_array[secondary_socket_id].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id == sockID) && - (nx_bsd_socket_array[secondary_socket_id].nx_bsd_socket_status_flags & (NX_BSD_SOCKET_CONNECTED | NX_BSD_SOCKET_ERROR))) - { - - connected = 1; - bsd_secondary_socket = &nx_bsd_socket_array[secondary_socket_id]; - bsd_secondary_socket -> nx_bsd_socket_family = bsd_socket_ptr -> nx_bsd_socket_family; - bsd_secondary_socket -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); - - } - else - { - - if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) - { - - /* No connection yet. Return EWOULDBLOCK */ - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EWOULDBLOCK); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - bsd_socket_ptr -> nx_bsd_socket_busy = NX_NULL; - } - return(NX_SOC_ERROR); - } - - tx_mutex_put(nx_bsd_protection_ptr); - tx_event_flags_get(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR_CLEAR, &requested_events, TX_WAIT_FOREVER); - tx_mutex_get(nx_bsd_protection_ptr, TX_WAIT_FOREVER); - - /* Verify the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* The socket is no longer in use. */ - - /* Set the socket error code. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - } - - /* If we get here, we should have a valid connection, or an error occured. */ - if(bsd_secondary_socket -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - INT errcode = bsd_secondary_socket -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_secondary_socket -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_secondary_socket -> nx_bsd_socket_status_flags = - bsd_secondary_socket -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Update the BSD socket source port and sender IP address. */ - status = nxd_tcp_socket_peer_info_get(bsd_secondary_socket -> nx_bsd_socket_tcp_socket, - &bsd_secondary_socket -> nx_bsd_socket_source_ip_address, - (ULONG *)(&bsd_secondary_socket -> nx_bsd_socket_source_port)); - - memcpy(&bsd_secondary_socket -> nx_bsd_socket_peer_ip, &bsd_secondary_socket -> nx_bsd_socket_source_ip_address, sizeof(NXD_ADDRESS)); - - bsd_secondary_socket -> nx_bsd_socket_peer_port = (USHORT)(bsd_secondary_socket -> nx_bsd_socket_source_port); - - /* Record the peer information. */ -#ifndef NX_DISABLE_IPV4 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4 = - bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4; - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]; - bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]; - bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]; - bsd_secondary_socket -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3] = bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]; - } -#endif - - /* Attempt to obtain peer address if ClientAddress is not NULL. */ - if(ClientAddress && addressLength != 0) - { - -#ifndef NX_DISABLE_IPV4 - /* Handle the IPv4 socket type. */ - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - /* Update the Client address with socket family, remote host IPv4 address and port. */ - peer4_address.sin_family = AF_INET; - peer4_address.sin_addr.s_addr = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4); - peer4_address.sin_port = ntohs((USHORT)bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); - - /* Copy the peer address/port info to the ClientAddress. Truncate if - addressLength is smaller than the size of struct sockaddr_in */ - if(*addressLength > (INT)sizeof(struct sockaddr_in)) - { - - memcpy(ClientAddress, &peer4_address, sizeof(struct sockaddr_in)); - *addressLength = sizeof(struct sockaddr_in); - } - else - { - memcpy(ClientAddress, &peer4_address, (UINT)(*addressLength)); - } - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - /* Update the Client address with socket family, remote host IPv6 address and port. */ - peer6_address.sin6_family = AF_INET6; - - peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]); - peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]); - peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]); - peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]); - - peer6_address.sin6_port = ntohs((USHORT)bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); - - if((*addressLength) > (INT)sizeof(peer6_address)) - { - - memcpy(ClientAddress, &peer6_address, sizeof(peer6_address)); - *addressLength = sizeof(peer6_address); - } - else - { - memcpy(ClientAddress, &peer6_address, (UINT)(*addressLength)); - } - } - else -#endif /* !FEATURE_NX_IPV6 */ - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Make sure this thread is still the owner. */ - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - - /* Clear the busy flag. */ - bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; - } - - /* Error, IPv6 support is not enabled. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - } - - /* Mark the sock_id field in both the master and secondary socket invalid. */ - (bsd_secondary_socket -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; - - /* Clear the master socket connect flags. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTED); - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_REQUEST); - - /* Reset the master_socket_id */ - ret = nx_bsd_tcp_create_listen_socket(sockID, 0); - - if(ret < 0) - { - (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = NX_BSD_MAX_SOCKETS; - } - - /* Make sure this thread is still the owner. */ - if (bsd_socket_ptr -> nx_bsd_socket_busy == tx_thread_identify()) - { - - /* Clear the busy flag. */ - bsd_socket_ptr -> nx_bsd_socket_busy = TX_NULL; - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(secondary_socket_id + NX_BSD_SOCKFD_START); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_send_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is sends a message to a given destination address/port */ -/* */ -/* INPUT */ -/* */ -/* sockID BSD Socket ID */ -/* msg Pointer to the outgoing */ -/* message */ -/* msgLength The Size of the message */ -/* flags Control flags, support */ -/* MSG_DONTWAIT */ -/* dst_address The Destination Address */ -/* dst_port The Destination Port */ -/* local_inteterface_index The local outgoing interface */ -/* to use */ -/* */ -/* OUTPUT */ -/* */ -/* data_sent */ -/* */ -/* CALLS */ -/* */ -/* set_errno Sets the BSD errno */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_append Append data to the packet */ -/* tx_mutex_get Get Mutex protction */ -/* tx_mutex_put Release Mutex protection */ -/* nx_packet_release Release the packet on error */ -/* nx_udp_socket_send UDP packet send */ -/* nx_udp_socket_interface_send UDP packet send via a */ -/* specific interface */ -/* nx_tcp_socket_send TCP packet send */ -/* _nxd_bsd_ipv4_packet_send Raw IPv4 packet with header */ -/* included */ -/* _nxd_bsd_ipv6_packet_send Raw IPv6 packet with header */ -/* included */ -/* nxd_ip_raw_packet_interface_send Raw packet send via a */ -/* specific interface */ -/* CALLED BY */ -/* */ -/* send */ -/* sendto */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT nx_bsd_send_internal(INT sockID, const CHAR *msg, INT msgLength, INT flags, - NXD_ADDRESS *dst_address, USHORT dst_port, UINT local_interface_index) -{ -UINT status; -NX_PACKET *packet_ptr; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -NX_BSD_SOCKET *bsd_socket_ptr; -UINT packet_type = 0; -UINT wait_option; -ULONG data_sent = (ULONG)msgLength; - - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - -#ifndef NX_DISABLE_IPV4 - /* Determine the socket family for allocating a packet. */ - if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - /* This is for an IPv4 socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - /* Allocate an IPv4 UDP packet. */ - packet_type = NX_IPv4_UDP_PACKET; - } - else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) - { - - /* Allocate an IPv4 TCP packet. */ - packet_type = NX_IPv4_TCP_PACKET; - } - else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) - { - - packet_type = NX_PHYSICAL_HEADER; - } - else - { - - /* Raw socket. */ - packet_type = NX_IPv4_PACKET; - } - } -#endif /* NX_DISABLE_IPV4 */ - if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - /* This is for an IPv6 socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - /* Allocate an IPv4 UDP packet. */ - packet_type = NX_IPv6_UDP_PACKET; - } - else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) - { - /* Allocate an IPv4 TCP packet. */ - packet_type = NX_IPv6_TCP_PACKET; - } - else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) - { - packet_type = NX_PHYSICAL_HEADER; - } - else - { - /* Raw socket. */ - packet_type = NX_IPv6_PACKET; - } - } - - /* Allocate the packet for sending. */ - if(packet_type == 0) - { - /* Set the socket error. */ - set_errno(EINVAL); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Is this a non blocking socket? */ - if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || - (flags & MSG_DONTWAIT)) - { - - /* Yes, set to wait to zero on the NetX call. */ - wait_option = 0 ; - } - /* Does this socket have a send timeout option set? */ - else if (bsd_socket_ptr -> nx_bsd_option_send_timeout) - { - - /* Yes, this is our wait option. */ - wait_option = bsd_socket_ptr -> nx_bsd_option_send_timeout; - } - else - wait_option = TX_WAIT_FOREVER; - - status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, packet_type, wait_option); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - /* Now copy the data into the NetX packet. */ - status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, wait_option); - - /* Was the data copy successful? */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - - /* Determine if the socket is a UDP socket. */ - if (bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - /* Pickup the NetX UDP socket. */ - udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; - - /* Send the UDP packet. */ - if(local_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) - status = nxd_udp_socket_send(udp_socket_ptr, packet_ptr, dst_address, dst_port); - else - status = nxd_udp_socket_interface_send(udp_socket_ptr, packet_ptr, dst_address, dst_port, local_interface_index); - } - else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) - { - - /* We have a TCP socket and a packet ready to send. */ - - /* Set a pointer to the TCP BSD socket. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - - if(wait_option != TX_NO_WAIT) - { - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - } - - /* Send the TCP packet. */ - status = nx_tcp_socket_send(tcp_socket_ptr, packet_ptr, wait_option); - - /* Check partial data sent. */ - if (status) - { - - /* Get length of data sent. */ - data_sent -= packet_ptr -> nx_packet_length; - - if (data_sent) - { - - /* Partial data sent. Mark as success. */ - status = NX_SUCCESS; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - } - - if(wait_option != TX_NO_WAIT) - { - /* Obtain the protection mutex. */ - tx_mutex_get(nx_bsd_protection_ptr, TX_WAIT_FOREVER); - } - } - else - { - /* Is this BSD socket configured to append the IP header? */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) - { - - /* Yes it is. Make sure the packet source and destination interface are set. */ - ULONG *ip_addr_ptr; - UINT src_interface; - -#ifndef NX_DISABLE_IPV4 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - ip_addr_ptr = (ULONG*)(packet_ptr -> nx_packet_prepend_ptr + 12); - - src_interface = (UINT)nx_bsd_find_interface_by_source_addr(AF_INET, ip_addr_ptr); - - if(src_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - src_interface = 0; - - packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &(nx_bsd_default_ip -> nx_ip_interface[src_interface]); - - /* If the IP ID field is non-zero, the current nx_ip_packet_id - value is modified */ - if((*(packet_ptr -> nx_packet_prepend_ptr + 4) == 0) && - (*(packet_ptr -> nx_packet_prepend_ptr + 5) == 0)) - { - - *(packet_ptr -> nx_packet_prepend_ptr + 4) = (UCHAR)(((nx_bsd_default_ip -> nx_ip_packet_id) & 0xFFFF) >> 8); - *(packet_ptr -> nx_packet_prepend_ptr + 5) = (UCHAR)((nx_bsd_default_ip -> nx_ip_packet_id) & 0xFF); - } - - /* Clear the checksum field. */ - *(packet_ptr -> nx_packet_prepend_ptr + 10) = 0; - *(packet_ptr -> nx_packet_prepend_ptr + 11) = 0; - - _nxd_bsd_ipv4_packet_send(packet_ptr); - - status = NX_SUCCESS; - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - ip_addr_ptr = (ULONG*)(packet_ptr -> nx_packet_prepend_ptr + 8); - src_interface = (UINT)nx_bsd_find_interface_by_source_addr(AF_INET6, ip_addr_ptr); - - if(src_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - { - status = NX_NOT_SUCCESSFUL; - } - - else - { - - NX_IPV6_HEADER *ipv6_header; - ULONG src_addr[4], dest_addr[4]; - - packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr; - - packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = &nx_bsd_default_ip -> nx_ipv6_address[src_interface]; - - ipv6_header = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_ip_header; - - /* Set up source / Destination IP */ - COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_destination_ip, dest_addr); - COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_source_ip, src_addr); - NX_IPV6_ADDRESS_CHANGE_ENDIAN(dest_addr); - NX_IPV6_ADDRESS_CHANGE_ENDIAN(src_addr); - - - _nxd_bsd_ipv6_packet_send(packet_ptr, src_addr, dest_addr); - - status = NX_SUCCESS; - } - } -#endif - } - else - { - - /* Raw socket without any IP header appended yet. We can send this directly to the NetX Duo IP packet handler. */ - if(local_interface_index == NX_BSD_LOCAL_IF_INADDR_ANY) - local_interface_index = 0; - - status = nxd_ip_raw_packet_interface_send(nx_bsd_default_ip, packet_ptr, dst_address, - local_interface_index, bsd_socket_ptr -> nx_bsd_socket_protocol, - NX_IP_TIME_TO_LIVE, NX_IP_NORMAL); - } - } - - /* Was the packet send successful? */ - if (status != NX_SUCCESS) - { - - /* No, release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the socket error. */ - - /* Set the socket error according to the NetX error status returned. */ - switch (status) - { - - case NX_IP_ADDRESS_ERROR: - set_errno(EDESTADDRREQ); - break; - - case NX_NOT_ENABLED: - set_errno(EPROTONOSUPPORT); - break; - - case NX_NOT_CONNECTED: - set_errno(ENOTCONN); - break; - - case NX_NO_PACKET: - case NX_UNDERFLOW: - set_errno(ENOBUFS); - break; - - case NX_WINDOW_OVERFLOW: - case NX_WAIT_ABORTED: - case NX_TX_QUEUE_DEPTH: - if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || - (flags & MSG_DONTWAIT)) - set_errno( EWOULDBLOCK); - else - set_errno(ETIMEDOUT); - break; - - default: - /* NX_NOT_BOUND */ - /* NX_PTR_ERROR */ - /* NX_INVALID_PACKET */ - set_errno(EINVAL); - break; - } - - /* Return an error status. */ - NX_BSD_ERROR(status, __LINE__); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_ERROR); - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return((INT)data_sent); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a packet out the given socket. */ -/* When the call returns, the data has been queued for transmission */ -/* over the connection. The return value indicates the number of byes */ -/* actually transmitted. */ -/* */ -/* The flags argument is provided for consistency with the BSD send */ -/* service. It allows various protocol features, such as out-of-bound */ -/* out-of-bound data, to be accessed. However, none of these features */ -/* are implemented. */ -/* */ -/* If packets are being sent out a UDP socket which is not bound to a */ -/* local port, this function find an available free port to bind to the*/ -/* socket. For TCP sockets, the socket must already by connected (so */ -/* also bound to port) */ -/* */ -/* Note: send() does not support raw sockets. Use the sendto() service */ -/* to transmit raw packets. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket */ -/* msg Data to be transmitted */ -/* msgLength Number of bytes to be sent */ -/* flags Control flags, support */ -/* MSG_DONTWAIT */ -/* */ -/* OUTPUT */ -/* */ -/* number of bytes sent If successful */ -/* NX_SOC_ERROR (-1) If failure */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_send Send a packet */ -/* nx_packet_allocate Get a free packet */ -/* nx_packet_data_append Copy data into packet */ -/* nx_packet_release Free a packet used to send */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT send(INT sockID, const CHAR *msg, INT msgLength, INT flags) -{ - -NX_BSD_SOCKET *bsd_socket_ptr; - - - /* Check for invalid socket IDd. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Set up a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Send() requires the socket be connected. A connected socket implies the socket is bound.*/ - if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) - { - - /* For AF_PACKET family, user shall use the sendto call. */ -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) - { - /* Set the socket error */ - set_errno(ENOTCONN); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - - /* However if the socket is raw socket and HDR_INCLUDE is set, it is OK. */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE)) - { - /* Set the socket error */ - set_errno(ENOTCONN); - - /* Return an error status.*/ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - - return nx_bsd_send_internal(sockID, msg, msgLength, flags, - &bsd_socket_ptr -> nx_bsd_socket_peer_ip, - bsd_socket_ptr -> nx_bsd_socket_peer_port, - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* sendto PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a packet out the given socket. */ -/* When the call returns, the data has been queued for transmission */ -/* over the connection. To use sendto on a TCP BSD socket, the */ -/* socket must already be in connected state. */ -/* */ -/* The flags argument is provided for consistency with the BSD send */ -/* service. It allows various protocol features, such as out-of-bound */ -/* out-of-bound data, to be accessed. However, none of these features */ -/* are implemented. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket (must be connected). */ -/* msg Data to transmit. */ -/* msgLength Number of bytes to send */ -/* flags Control flags, support */ -/* MSG_DONTWAIT */ -/* sockaddr Destination address */ -/* destAddrLen Length of destination address */ -/* */ -/* OUTPUT */ -/* */ -/* Number of bytes sent If no error occurs */ -/* NX_SOC_ERROR (-1) In case of socket error */ -/* */ -/* CALLS */ -/* */ -/* bind Bind NetX UDP sockets */ -/* nx_packet_allocate Get a free packet */ -/* nx_packet_data_append Copy data into packet */ -/* nx_packet_release Free the nx_packet used */ -/* nx_tcp_socket_send Send packet over a TCP Socket */ -/* nx_udp_socket_send Send packet over a UDP Socket */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT sendto(INT sockID, CHAR *msg, INT msgLength, INT flags, struct sockaddr *destAddr, INT destAddrLen) -{ -UINT status; -NX_BSD_SOCKET *bsd_socket_ptr; -NXD_ADDRESS peer_ip_address; -USHORT peer_port = 0; - - /* Check for a valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set up a socket pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID - NX_BSD_SOCKFD_START]; - - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. Application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - /* For TCP, make sure the socket is already connected. */ - if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) - { - if((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) - { - set_errno(ENOTCONN); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - return nx_bsd_send_internal((sockID - NX_BSD_SOCKFD_START), msg, msgLength, flags, NX_NULL, 0, - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); - } - else - { - - /* This is a UDP or raw socket. */ - - /* Check whther or not the socket is AF_PACKET family. */ - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) - { - -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - /* nx_bsd_pppoe_internal_sendto shall returns */ - status = (UINT)nx_bsd_pppoe_internal_sendto(bsd_socket_ptr, msg, msgLength, flags, destAddr, destAddrLen); -#elif defined(NX_BSD_RAW_SUPPORT) - /* _nx_bsd_hardware_internal_sendto shall returns */ - status = (UINT)_nx_bsd_hardware_internal_sendto(bsd_socket_ptr, msg, msgLength, flags, destAddr, destAddrLen); -#else - NX_PARAMETER_NOT_USED(destAddrLen); - status = (UINT)NX_SOC_ERROR; -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - return((INT)status); - - } - - /* Perform error checkings on the remote address if the socket is - not raw socket, or HDRINCL is not set for the raw socket. */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE)) - { - - /* Check for an invalid destination. */ - if (destAddr == NX_NULL) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Validate the destination address. */ - if(bsd_socket_ptr -> nx_bsd_socket_family != destAddr -> sa_family) - { - set_errno(EAFNOSUPPORT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - } - - /* For UDP socket, make sure the socket is bound. */ - if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) - { - status = nx_udp_socket_bind(bsd_socket_ptr -> nx_bsd_socket_udp_socket, NX_ANY_PORT, NX_NO_WAIT); - if((status != NX_SUCCESS) && (status != NX_ALREADY_BOUND)) - { - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index = NX_BSD_LOCAL_IF_INADDR_ANY; - bsd_socket_ptr -> nx_bsd_socket_local_port = (USHORT)(bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_port); - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - } - - } - - - - if(destAddr) - { - /* Get the destination IP and port for this UDP socket. */ -#ifndef NX_DISABLE_IPV4 - if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - /* This is for an IPv4 packet. */ - peer_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - peer_ip_address.nxd_ip_address.v4 = htonl(((struct sockaddr_in *) destAddr) -> sin_addr.s_addr); - peer_port = htons(((struct sockaddr_in *) destAddr) -> sin_port); - - /* Local interface ID is set to invalid value, so the send routine needs to - find the best interface to send the packet based on destination IP address. */ - - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - /* This is for an IPv6 packet. Set the NetX Duo IP address version. */ - peer_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - peer_ip_address.nxd_ip_address.v6[0] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[0]); - peer_ip_address.nxd_ip_address.v6[1] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[1]); - peer_ip_address.nxd_ip_address.v6[2] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[2]); - peer_ip_address.nxd_ip_address.v6[3] = ntohl(((struct sockaddr_in6*)destAddr) -> sin6_addr._S6_un._S6_u32[3]); - - peer_port = htons(((struct sockaddr_in6 *) destAddr) -> sin6_port); - - } -#endif - } - - /* Call the internal send routine to finish the send process. */ - /* Local interface ID is set to a special marker, so the send routine needs to - find the best interface to send the packet based on destination IP address. */ - return nx_bsd_send_internal((sockID - NX_BSD_SOCKFD_START), msg, msgLength, flags, - &peer_ip_address, peer_port, - bsd_socket_ptr -> nx_bsd_socket_local_bind_interface_index); - - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* recv PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies up to a specified number of bytes received on */ -/* the socket into specified location. The given socket must be in the */ -/* connected state. Normally, the call blocks until either at least one*/ -/* byte is returned or the connection closes.The return value indicates*/ -/* the number of bytes actually copied into the buffer starting at the */ -/* specified location. */ -/* */ -/* For a stream socket, the bytes are delivered in the same order as */ -/* they were transmitted, without omissions. For a datagram socket, */ -/* each recv() returns the data from at most one send(), and order is */ -/* not necessarily preserved. */ -/* */ -/* For non blocking sockets, a receive status of NX_NO_PACKET from NetX*/ -/* results in an error status returned from BSD, and the socket error */ -/* set to EWOULDBLOCK (if BSD extended socket features are enabled. */ -/* */ -/* Likewise, an event flag status of TX_NO_EVENTS returned from ThreadX*/ -/* on a non blocking socket sets the socket error to EWOULDBLOCK. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket (must be connected). */ -/* rcvBuffer Pointer to put data received. */ -/* bufferLength Maximum bytes in buffer */ -/* flags Control flags, support */ -/* MSG_PEEK and MSG_DONTWAIT */ -/* */ -/* OUTPUT */ -/* */ -/* Number of bytes received If success */ -/* NX_SOC_ERROR (-1) If failure */ -/* 0 socket disconnected */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive a Packet */ -/* nx_packet_allocate Allocate packet for receive */ -/* nx_packet_release Free the nx_packet after use */ -/* nx_packet_data_extract_offset Retrieve packet data */ -/* tx_event_flags_get Wait for data to arrive */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT recv(INT sockID, VOID *rcvBuffer, INT bufferLength, INT flags) -{ - -UINT status; -NX_PACKET *packet_ptr; -NX_BSD_SOCKET *bsd_socket_ptr; -NX_TCP_SOCKET *tcp_socket_ptr; -ULONG requested_events; -ULONG bytes_received; -UINT wait_option; -UINT remaining_wait_option; -ULONG offset; -INT header_size = 0; -ULONG start_time = nx_bsd_system_clock; - - - /* Check for a valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Set up a pointer to the socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Set the receive wait time to FOREVER for blocking sockets. */ - wait_option = NX_WAIT_FOREVER; - - /* Is this a nonblocking socket?: */ - if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || - (flags & MSG_DONTWAIT)) - { - - /* Yes, set to receive wait option to no wait (zero). */ - wait_option = 0; - } - /* Does this socket have a receive timeout option set? */ - else if (bsd_socket_ptr -> nx_bsd_option_receive_timeout) - { - - /* Yes, this is our wait option. */ - wait_option = bsd_socket_ptr -> nx_bsd_option_receive_timeout; - } - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* If the socket has an error */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - - INT errcode = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = - bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - - set_errno(errcode); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* At this point the error flag is cleared. The application should - detect and handle the error codition. This socket is still bound - to the port (either the application called bind(), or a bind - operation was executed as part of the connect call) and is able to - handle another "connect" call, or be closed. */ - return(NX_SOC_ERROR); - } - - /* Set pointers to the BSD NetX Duo sockets. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - - /* Loop to check for a received packet. */ - do - { - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check if the BSD socket already has received a packet. */ - packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; - - if (packet_ptr) - { - - /* Got one. Break out of the loop. */ - break; - } - - /* Check if there is an incoming packet on this socket. */ - else - { - - /* Determine if this is a TCP BSD socket. */ - if (tcp_socket_ptr) - { - - /* It is, check the socket TCP receive queue with a zero wait option (no suspension). */ - status = nx_tcp_socket_receive(tcp_socket_ptr, &packet_ptr, TX_NO_WAIT); - - /* Check for no packet on the queue. */ - if (status == NX_NOT_CONNECTED) - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Is peer shutdown orderly? */ - if ((tcp_socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSE_WAIT) || - (tcp_socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSING)) - { - - /* Yes. Return 0. */ - return(NX_SUCCESS); - } - - /* Set the socket status (not really an error). */ - set_errno(ENOTCONN); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if (status == NX_SUCCESS) - { - - /* Increase the received count. */ - bsd_socket_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count++; - } - } - - /* Have we found a new packet? */ - if ((status == NX_SUCCESS) && (packet_ptr)) - { - - /* Setup the bsd socket with the packet information. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr; - bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; - - /* Get out of the loop. */ - break; - } - } - - /* No packet is available. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Calculate remaining wait option. */ - remaining_wait_option = (UINT)(wait_option - (nx_bsd_system_clock - start_time)); - if (remaining_wait_option > wait_option) - { - - /* Wait option expired. */ - status = TX_NO_EVENTS; - } - else - { - - /* Suspend this socket on a RECEIVE event (incoming packet) for the specified wait time. */ - status = tx_event_flags_get(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR_CLEAR, &requested_events, remaining_wait_option); - } - - /* Check for any events. */ - if (status == TX_NO_EVENTS) - { - - /* No packets received. */ - - /* Set the socket error depending if this is a non blocking socket. */ - if ((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) || - (wait_option == NX_WAIT_FOREVER) || - (flags & MSG_DONTWAIT)) - set_errno(EWOULDBLOCK); - else - set_errno (EAGAIN); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - else if (status != TX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Re-obtain the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* The socket is no longer in use. */ - - /* Set the socket error code. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - } while (1); - - /* At this point, the socket has received a packet. */ - - - /* Obtain sender information for UDP socket. */ - if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_UDP) - { - - /* Get the sender and port from the UDP packet. */ - nxd_udp_source_extract(packet_ptr, &bsd_socket_ptr -> nx_bsd_socket_source_ip_address, (UINT *)&bsd_socket_ptr -> nx_bsd_socket_source_port); - } - -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) - else if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) - { - - /* Validate the packet length. */ - if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 14) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return an error. */ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - /* Pick up the sender's MAC address. */ - bsd_socket_ptr -> nx_bsd_socket_sll_addr[0] = packet_ptr -> nx_packet_prepend_ptr[6]; - bsd_socket_ptr -> nx_bsd_socket_sll_addr[1] = packet_ptr -> nx_packet_prepend_ptr[7]; - bsd_socket_ptr -> nx_bsd_socket_sll_addr[2] = packet_ptr -> nx_packet_prepend_ptr[8]; - bsd_socket_ptr -> nx_bsd_socket_sll_addr[3] = packet_ptr -> nx_packet_prepend_ptr[9]; - bsd_socket_ptr -> nx_bsd_socket_sll_addr[4] = packet_ptr -> nx_packet_prepend_ptr[10]; - bsd_socket_ptr -> nx_bsd_socket_sll_addr[5] = packet_ptr -> nx_packet_prepend_ptr[11]; - - /* Pick up the sender's protocol */ - bsd_socket_ptr -> nx_bsd_socket_sll_protocol = (USHORT)((packet_ptr -> nx_packet_prepend_ptr[12] << 8) | - (packet_ptr -> nx_packet_prepend_ptr[13])); - if (bsd_socket_ptr -> nx_bsd_socket_sll_protocol == 0x8100) - { - - /* Skip VLAN tag. */ - bsd_socket_ptr -> nx_bsd_socket_sll_protocol = (USHORT)((packet_ptr -> nx_packet_prepend_ptr[16] << 8) | - (packet_ptr -> nx_packet_prepend_ptr[17])); - } - - /* Find the IF Index */ - bsd_socket_ptr -> nx_bsd_socket_sll_ifindex = packet_ptr -> nx_packet_ip_interface -> nx_interface_index; - - } -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - /* For raw socket, make sure the source address is extracted. */ - else if(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) - { - - /* Get the sender IP address from the raw packet. */ - status = nx_bsd_raw_packet_info_extract(packet_ptr, &(bsd_socket_ptr -> nx_bsd_socket_source_ip_address), NX_NULL); - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - /* Pickup the current offset. */ - offset = bsd_socket_ptr -> nx_bsd_socket_received_packet_offset; - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - /* Perform extra processing on this packet if it processed as a raw packet. */ - if((bsd_socket_ptr -> nx_bsd_socket_family != AF_PACKET) && - (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) - { - - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & (NX_BSD_SOCKET_RX_NO_HDR)) - { - header_size = 0; - } - else - { -#ifndef NX_DISABLE_IPV4 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - - header_size = packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header; - - /* Byte-Swap the basic IPv4 header. The NetX Duo IP receive process does not - examine the extension header. Therefore it does not perform byte swap - on extension headers. */ - NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_0)); - NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_1)); - NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_word_2)); - NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_source_ip)); - NX_CHANGE_ULONG_ENDIAN((((NX_IPV4_HEADER*)(packet_ptr -> nx_packet_ip_header)) -> nx_ip_header_destination_ip)); - - if(bufferLength < header_size) - { - header_size = bufferLength; - } - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - NX_IPV6_HEADER *ipv6_header_ptr; - UCHAR next_header_type; - - header_size = (INT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_ip_header); - - if(bufferLength < header_size) - { - - header_size = bufferLength; - } - - ipv6_header_ptr = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_ip_header; - - /* Pick up the next header. */ - next_header_type = (ipv6_header_ptr -> nx_ip_header_word_1 >> 8) & 0xFF; - - NX_CHANGE_ULONG_ENDIAN(ipv6_header_ptr -> nx_ip_header_word_0); - NX_CHANGE_ULONG_ENDIAN(ipv6_header_ptr -> nx_ip_header_word_1); - NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_header_ptr -> nx_ip_header_destination_ip); - NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_header_ptr -> nx_ip_header_source_ip); - - /* Go through the rest of the IPv6 extension headers. */ - _nxd_bsd_swap_ipv6_extension_headers(packet_ptr, next_header_type); - } -#endif - - memcpy(rcvBuffer, packet_ptr -> nx_packet_ip_header, (UINT)header_size); - } - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - - /* Copy the packet data into the supplied buffer. */ - status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID*)((INT)rcvBuffer + header_size), (ULONG) (bufferLength - header_size), &bytes_received); - - /* Check for an error. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return an error. */ - NX_BSD_ERROR( status, __LINE__); - return(NX_SOC_ERROR); - } - - if((flags & MSG_PEEK) == 0) - { - - /* Calculate the new offset. */ - offset = offset + bytes_received; - - /* Determine if all the packet data was consumed. */ - if(packet_ptr -> nx_packet_length <= offset) - { - - bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr -> nx_packet_queue_next; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Clear the offset. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; - } - else if((bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - || (bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - ) - { - - /* For UDP or raw socket, We extracted as much as can fit in the caller's buffer. - We will discard the remaining bytes. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr -> nx_packet_queue_next; - - bytes_received = packet_ptr -> nx_packet_length; - - /* No need to retain the packet. */ - nx_packet_release(packet_ptr); - - /* Clear the offset. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = 0; - } - else - { - - /* For TCP, the remaining data is saved for the next recv call. - Just update the offset. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet_offset = offset; - } - bsd_socket_ptr -> nx_bsd_socket_received_byte_count -= bytes_received; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count--; - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Successful received a packet. Return the number of bytes copied to buffer. */ - return((INT)bytes_received + (INT)header_size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* recvfrom PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies up to a specified number of bytes, received on */ -/* the socket into a specified location. To use recvfrom() on a TCP */ -/* socket requires the socket to be in the connected state. */ -/* */ -/* This function is identical to recv() except for returning the sender*/ -/* address and length if non null arguments are supplied. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket(must be connected) */ -/* buffer Pointer to hold data received */ -/* bufferSize Maximum number of bytes */ -/* flags Control flags, support */ -/* MSG_PEEK and MSG_DONTWAIT */ -/* fromAddr Address data of sender */ -/* fromAddrLen Length of address structure */ -/* */ -/* OUTPUT */ -/* */ -/* number of bytes received If no error occurs */ -/* NX_SOC_ERROR (-1) In case of any error */ -/* */ -/* CALLS */ -/* */ -/* memset Clear memory */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_extract_offset Extract packet data */ -/* nx_packet_release Free the packet used */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_event_flags_get Wait for data to arrive */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT recvfrom(INT sockID, CHAR *rcvBuffer, INT bufferLength, INT flags, struct sockaddr *fromAddr, INT *fromAddrLen) -{ - -INT bytes_received; -NX_BSD_SOCKET *bsd_socket_ptr; -#ifndef NX_DISABLE_IPV4 -struct sockaddr_in peer4_address; -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 -struct sockaddr_in6 peer6_address; -#endif - - /* Check for a valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set up a pointer to the socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID - NX_BSD_SOCKFD_START]; - - /* Socket error checking is done inside recv() call. */ - - /* Call the equivalent recv() function. */ - bytes_received = recv(sockID, rcvBuffer, bufferLength, flags); - - /* Check for error. */ - if (bytes_received < 0) - { - - /* Return an error status. */ - return NX_SOC_ERROR; - } - /* If no bytes are received do not handle as an error. */ - else if (bytes_received == 0) - { - return NX_SOC_OK; - } - - /* At this point we did receive a packet. */ - /* Supply the sender address if valid pointer is supplied. */ - if(fromAddr && (*fromAddrLen != 0)) - { - -#ifndef NX_DISABLE_IPV4 - /* Handle the IPv4 socket type. */ - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - /* Update the Client address with socket family, remote host IPv4 address and port. */ - peer4_address.sin_family = AF_INET; - if(bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - peer4_address.sin_addr.s_addr = htonl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4); - peer4_address.sin_port = htons(bsd_socket_ptr -> nx_bsd_socket_peer_port); - } - else - { - peer4_address.sin_addr.s_addr = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4); - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - if(!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - peer4_address.sin_port = ntohs((USHORT)bsd_socket_ptr -> nx_bsd_socket_source_port); - } - /* Copy the peer address/port info to the ClientAddress. Truncate if - addressLength is smaller than the size of struct sockaddr_in */ - if(*fromAddrLen > (INT)sizeof(struct sockaddr_in)) - { - *fromAddrLen = sizeof(struct sockaddr_in); - } - memcpy(fromAddr, &peer4_address, (UINT)(*fromAddrLen)); - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - /* Update the Client address with socket family, remote host IPv6 address and port. */ - peer6_address.sin6_family = AF_INET6; - - if(bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0]); - peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1]); - peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2]); - peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_socket_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3]); - peer6_address.sin6_port = ntohs(bsd_socket_ptr -> nx_bsd_socket_peer_port); - } - else - { - peer6_address.sin6_addr._S6_un._S6_u32[0] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0]); - peer6_address.sin6_addr._S6_un._S6_u32[1] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1]); - peer6_address.sin6_addr._S6_un._S6_u32[2] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2]); - peer6_address.sin6_addr._S6_un._S6_u32[3] = ntohl(bsd_socket_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3]); - - /* Skip the port data for raw sockets. They do not use them. */ -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - if(!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - peer6_address.sin6_port = ntohs((USHORT)bsd_socket_ptr -> nx_bsd_socket_source_port); - } - - if((*fromAddrLen) > (INT)sizeof(peer6_address)) - { - *fromAddrLen = sizeof(peer6_address); - } - memcpy(fromAddr, &peer6_address, (UINT)(*fromAddrLen)); - - } - else -#endif /* !FEATURE_NX_IPV6 */ -#if defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) - { - if(*fromAddrLen >= (INT)sizeof(struct sockaddr_ll)) - { - struct sockaddr_ll *sockaddr = (struct sockaddr_ll*)fromAddr; - INT i; - sockaddr -> sll_family = AF_PACKET; - sockaddr -> sll_protocol = bsd_socket_ptr -> nx_bsd_socket_sll_protocol; - sockaddr -> sll_ifindex = bsd_socket_ptr -> nx_bsd_socket_sll_ifindex; - sockaddr -> sll_hatype = 0; - sockaddr -> sll_pkttype = 0; - sockaddr -> sll_halen = 6; - for(i = 0; i < 6; i++) - sockaddr -> sll_addr[i] = bsd_socket_ptr -> nx_bsd_socket_sll_addr[i]; - *fromAddrLen = sizeof(struct sockaddr_ll); - } - - } - else -#endif - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Error, IPv6 support is not enabled. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - } - - /* Successfully received a packet. Return bytes received. */ - return (INT)(bytes_received); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* soc_close PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function terminates communications on the supplied BSD socket. */ -/* The socket is disallowed for further sends and receives. Socket */ -/* resources such as socket memory are returned to the system. */ -/* */ -/* If a socket is enabled with the linger option, that will be used in */ -/* place of the default NX_BSD TIMEOUT for blocking sockets. Sockets */ -/* enabled for non blocking have their timeout set for zero. Note that */ -/* a zero wait option results in an immediate shutdown (e.g. send RST) */ -/* unless the NX_DISABLE_RESET_DISCONNECT is not enabled. */ -/* */ -/* For BSD applications enabled for disconnect complete notification */ -/* for TCP sockets, the socket will remain open until NetX notifies us */ -/* that the disconnect is complete. This allows the host BSD */ -/* application to perform asynchronous disconnects without having to */ -/* wait for the disconnect to complete. */ -/* */ -/* INPUT */ -/* */ -/* socketID */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* memset Clear memory */ -/* nx_tcp_socket_disconnect Disconnect a TCP Socket */ -/* nx_tcp_client_socket_unbind Unbind the socket */ -/* nx_tcp_server_socket_unaccept Unaccept the socket */ -/* nx_tcp_server_socket_unlisten Unlisten on a port */ -/* nx_tcp_socket_delete Deletes a TCP Socket */ -/* nx_udp_socket_unbind Unbind a UDP Socket */ -/* nx_udp_socket_delete Deletes a UDP Socket */ -/* tx_block_release Release block for socket */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT soc_close(INT sockID) -{ - -NX_BSD_SOCKET *bsd_socket_ptr; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -NX_PACKET *packet_ptr; -NX_PACKET *next_packet_ptr; -ULONG timeout; -INT i; -UINT counter; -INT delete_socket; -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -INT protocol; -UINT index; -#endif - - /* Check for a valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error. */ - set_errno(EBADF); - - /* Error, invalid socket ID. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Set up a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Get the protection mutex. */ - tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Is the socket already in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* No; If the NetX socket associated with this BSD socket been deleted, this is ok. */ - if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket && !bsd_socket_ptr -> nx_bsd_socket_udp_socket) - { - - /* Yes, no further action possible. Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return NX_SOC_OK; - } - - /* Otherwise, it is an error if socket not in use anymore. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set NetX socket pointers. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; - - /* There is. Flush the queue of all packets. */ - packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; - /* Setup packet pointer to the beginning of the queue. */ - while(packet_ptr) - { - next_packet_ptr = packet_ptr -> nx_packet_queue_next; - - /* Mark it as allocated so it will be released. */ - packet_ptr -> nx_packet_queue_next = (NX_PACKET *) NX_PACKET_ALLOCATED; - - nx_packet_release(packet_ptr); - - /* Move to the next packet */ - packet_ptr = next_packet_ptr; - } - - bsd_socket_ptr -> nx_bsd_socket_received_packet = NX_NULL; - bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = NX_NULL; - bsd_socket_ptr -> nx_bsd_socket_received_byte_count = 0; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 0; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max = 0; - - /* Now delete the underlying TCP or UDP socket. */ - - /* Is this a TCP socket? */ - if (tcp_socket_ptr) - { - - /* If the socket has not been closed, disconnect it. This would be the case - if NetX already closed the socket e.g. a RST packet received before the - host application called this function. */ - if (tcp_socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) - { - - /* Disconnect the socket. */ - - /* If the disconnect takes more than the timeout option, NetX marks the socket as "closed" - or puts it back to "listen" state. The default value is 1 to emulate an immediate - socket closure without sending a RST packet. */ - timeout = NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT; - - /* Release the mutex while disconnecting. */ - tx_mutex_put(nx_bsd_protection_ptr); - - nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); - - tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Verify that the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* The socket is no longer in use. */ - - /* Set the socket error code. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - /* Make sure the socket is unbound, not accepting connections and not bound to a listening port. */ - if(tcp_socket_ptr -> nx_tcp_socket_port) - { - - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT) - { - nx_tcp_client_socket_unbind(tcp_socket_ptr); - } - else - { - nx_tcp_server_socket_unaccept(tcp_socket_ptr); - } - - } - - /* Now we can delete the NetX TCP socket. */ - nx_tcp_socket_delete(tcp_socket_ptr); - - /* Clear the TCP socket structure. */ - memset((VOID *) tcp_socket_ptr, 0, sizeof(NX_TCP_SOCKET)); - - /* Release the NetX TCP socket. */ - tx_block_release((VOID *) tcp_socket_ptr); - - /* If this is the master server socket, we need to unaccept the - associated secondary socket. */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) - { - - INT sec_soc_id = (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id; - - if(sec_soc_id < NX_BSD_MAX_SOCKETS) - { - - /* Find whether or not this is the only master socket that is connected to this - secondary socket. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - if(i == sockID) - continue; - - if((nx_bsd_socket_array[i].nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && - (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && - (nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id == sec_soc_id)) - { - break; - } - } - - if(i == NX_BSD_MAX_SOCKETS) - { - - /* Unaccept and unlisten on the socket/port */ - /* nx_tcp_server_socket_unaccept(tcp_socket_ptr); */ - /* nx_tcp_server_socket_unlisten(nx_bsd_default_ip, tcp_socket_ptr -> nx_tcp_socket_port); */ - - /* Release the secondary socket if there are no more master sockets associated - with this secondary socket. */ - - tcp_socket_ptr = nx_bsd_socket_array[sec_soc_id].nx_bsd_socket_tcp_socket; - - /* If the secondary socket has not been closed, disconnect it. This would be the case - if NetX already closed the master socket. */ - if (tcp_socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) - { - - /* Disconnect the socket. */ - - /* If the disconnect takes more than the timeout option, NetX marks the socket as "closed" - or puts it back to "listen" state. The default value is 1 to emulate an immediate - socket closure without sending a RST packet. */ - timeout = NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT; - - /* Release the mutex while disconnecting. */ - tx_mutex_put(nx_bsd_protection_ptr); - - nx_tcp_socket_disconnect(tcp_socket_ptr, timeout); - - tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Verify that the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* The socket is no longer in use. */ - - /* Set the socket error code. */ - set_errno(EBADF); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - - /* Unaccept on the secondary socket. */ - nx_tcp_server_socket_unaccept(tcp_socket_ptr); - nx_tcp_server_socket_unlisten(nx_bsd_default_ip, tcp_socket_ptr -> nx_tcp_socket_port); - nx_tcp_socket_delete(tcp_socket_ptr); - - memset((VOID*)tcp_socket_ptr, 0, sizeof(NX_TCP_SOCKET)); - tx_block_release((VOID*)tcp_socket_ptr); - memset((VOID*)&(nx_bsd_socket_array[sec_soc_id]), 0, sizeof(NX_BSD_SOCKET)); - } - } - } - - /* Finally Clear the BSD socket structure. */ - memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return */ - return(NX_SOC_OK); - - } - else if (udp_socket_ptr) - { - - /* A UDP socket needs to be closed. */ - - /* Check whether this is the last BSD socket attached to the NX_UDP_SOCKET */ - counter = (UINT)udp_socket_ptr -> nx_udp_socket_reserved_ptr; - - delete_socket = NX_TRUE; - /* Decrease the counter value. */ - if(counter & 0xFFFF0000) - { - - counter = ((counter & 0xFFFF0000) - 0x00010000 + (counter & 0x0000FFFF)) & 0xFFFFFFFF; - - udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID*)counter; - - if(counter & 0xFFFF0000) - { - - /* Do not delete this socket. */ - delete_socket = NX_FALSE; - - /* If the underlying NX_UDP_SOCKET points to this UDP socket, we need to - reassign a BSD socket to the NX UDP socket. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - if((nx_bsd_socket_array[i].nx_bsd_socket_udp_socket == udp_socket_ptr) && - (i != sockID)) - { - - counter = (counter & 0xFFFF0000) + (UINT)i; - udp_socket_ptr -> nx_udp_socket_reserved_ptr = (VOID*)counter; - break; - } - } - - if(i == NX_BSD_MAX_SOCKETS) - { - delete_socket = NX_TRUE; - } - } - } - - if(delete_socket == NX_TRUE) - { - - if(udp_socket_ptr -> nx_udp_socket_bound_next) - { - nx_udp_socket_unbind(udp_socket_ptr); - } - - /* Socket successfully unbound. Now delete the UDP socket. */ - nx_udp_socket_delete(udp_socket_ptr); - - /* Clear the UDP socket block. */ - memset((VOID *) udp_socket_ptr, 0, sizeof(NX_UDP_SOCKET)); - - /* Release the NetX UDP socket memory. */ - tx_block_release((VOID *) udp_socket_ptr); - } - else - { - /* Remove this bsd udp socket from the list. */ - (bsd_socket_ptr -> nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr -> nx_bsd_socket_previous; - (bsd_socket_ptr -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr -> nx_bsd_socket_next; - } - - /* Clear the BSD socket block. */ - memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - else if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) - { - - /* There is no native NetX Duo raw socket to delete or - port to unbind. So just release the BSD socket memory. */ - - /* Remove this socket from the list. */ - protocol = bsd_socket_ptr -> nx_bsd_socket_protocol; - - /* Calculate the hash index in the raw socket protocol table. */ - index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); - - /* Determine if this is the only socket on this list. */ - if(bsd_socket_ptr -> nx_bsd_socket_next == bsd_socket_ptr) - { - /* Yes, this is the only socket on the list. */ - - /* Clear the list head pointer. */ - nx_bsd_socket_raw_protocol_table[index] = NX_NULL; - } - else - { - /* Remove this bsd udp socket from the list. */ - (bsd_socket_ptr -> nx_bsd_socket_next) -> nx_bsd_socket_previous = bsd_socket_ptr -> nx_bsd_socket_previous; - (bsd_socket_ptr -> nx_bsd_socket_previous) -> nx_bsd_socket_next = bsd_socket_ptr -> nx_bsd_socket_next; - - /* Determine if the head of the list points to the socket being removed. - If so, we need to move the head pointer. */ - if(nx_bsd_socket_raw_protocol_table[index] == bsd_socket_ptr) - { - /* Yes, we need to move the list head pointer. */ - nx_bsd_socket_raw_protocol_table[index] = bsd_socket_ptr -> nx_bsd_socket_next; - } - } - - /* Clear the BSD socket block. */ - memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ -#if defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) - else if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) - { - /* There is no native NetX Duo raw socket to delete or - port to unbind. So just release the BSD socket memory. */ - - /* Clear the BSD socket block. */ - memset((VOID *) bsd_socket_ptr, 0, sizeof(NX_BSD_SOCKET)); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(NX_SOC_OK); - } - -#endif /* defined(NX_BSD_RAW_PPPOE_SUPPORT) || defined(NX_BSD_RAW_SUPPORT) */ - - - - - /* Unknown socket type or invalid socket. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - - - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* fcntl PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs the requested operation on the file (e.g. */ -/* socket) descriptor set. This implementation supports only the set */ -/* or get flag, and only sets (or clears) the non blocking option. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* flag_type File description request */ -/* f_options Option(s) to set on the */ -/* specified file (socket) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_ERROR Errors with request */ -/* (file descriptor flags) File descriptor flags */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT fcntl(INT sockID, UINT flag_type, UINT f_options) -{ - -NX_BSD_SOCKET *bsd_socket_ptr; - - /* Check for invalid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* Return error status. */ - return NX_SOC_ERROR; - } - - /* Normalize the socket ID to our array. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Build pointer to BSD socket structure. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - if(flag_type == F_SETFL) - { - /* Set the FD flag. */ - bsd_socket_ptr -> nx_bsd_file_descriptor_flags = (INT)f_options; - - - /* Are there flags to clear? */ - if ((f_options & O_NONBLOCK) == 0) - { - /* Disable the socket for non blocking. */ - bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); - } - else - { - /* Enable the socket for non blocking. */ - bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; - } - - /* All done. Return 0 */ - return(0); - } - else if(flag_type == F_GETFL) - { - return(bsd_socket_ptr -> nx_bsd_file_descriptor_flags); - } - /* Flag_type is not the one we support */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - /* Return error status. */ - return NX_SOC_ERROR; - - - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* ioctl PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function carries out a socket IO service specified by the */ -/* command. */ -/* */ -/* INPUT */ -/* */ -/* sockID Socket (must be connected). */ -/* command IO command for ioctl function */ -/* result data returned (value) */ -/* */ -/* OUTPUT */ -/* */ -/* Number of bytes received If success */ -/* NX_SOC_ERROR (-1) Error during socket opration */ -/* NX_SOC_OK (0) Successful completion */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_bytes_available Retreive number of bytes on */ -/* the specified TCP socket */ -/* nx_udp_socket_bytes_available Retreive number of bytes on */ -/* the specified UDP socket */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT ioctl(INT sockID, INT command, INT *result) -{ - -NX_BSD_SOCKET *bsd_socket_ptr; -NX_TCP_SOCKET *tcp_socket_ptr; -NX_UDP_SOCKET *udp_socket_ptr; -UINT status; - - - /* Check that the supplied socket ID is valid. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Error, invalid socket ID. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Error getting the protection mutex. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set a pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Pick up the associated NetX socket pointers. */ - tcp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_tcp_socket; - udp_socket_ptr = bsd_socket_ptr -> nx_bsd_socket_udp_socket; - - /* Handle the command. */ - switch (command) - { - - case FIONREAD: - { - - /* Check NULL pointer. */ - if(result == NX_NULL) - { - tx_mutex_put(nx_bsd_protection_ptr); - - set_errno(EFAULT); - - /* Error, invalid address. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - - /* Determine which socket pointer to use. */ - if (tcp_socket_ptr) - { - - /* Extract the number of bytes on the TCP receive queue. */ - status = nx_tcp_socket_bytes_available(tcp_socket_ptr, (ULONG *)result); - - if (status != NX_SUCCESS) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Error in the native NetX call. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - else if (udp_socket_ptr) - { - - /* Extract the number of bytes on the UDP receive queue. */ - *result = (INT)(bsd_socket_ptr -> nx_bsd_socket_received_byte_count); - } - - break; - } - - case FIONBIO: - { - - /* Check NULL pointer. */ - if(result == NX_NULL) - { - tx_mutex_put(nx_bsd_protection_ptr); - - set_errno(EFAULT); - - /* Error, invalid address. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return(NX_SOC_ERROR); - } - - if(*result == NX_FALSE) - { - - /* Disable the socket for non blocking. */ - bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); - - /* Update the file descriptor with the non blocking bit. */ - bsd_socket_ptr -> nx_bsd_file_descriptor_flags &= ~O_NONBLOCK; - } - else - { - - /* Enable the socket for non blocking. */ - bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; - - /* Update the file descriptor with the non blocking bit. */ - bsd_socket_ptr -> nx_bsd_file_descriptor_flags |= O_NONBLOCK; - } - - break; - } - - default: - - /* Unhandled command; ignore */ - break; - } - - tx_mutex_put(nx_bsd_protection_ptr); - - return NX_SOC_OK; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_ntoa PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IP address to a string and returns a */ -/* pointer to the string. The caller is recommended to copy the */ -/* contents of the buffer to local memory since this function and */ -/* internal buffer can be reused. */ -/* */ -/* INPUT */ -/* */ -/* address_to_convert Struct holding IP address. */ -/* */ -/* OUTPUT */ -/* */ -/* char * Pointer to converted string */ -/* 0x0 Error during conversion */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get mutex protection */ -/* bsd_number_convert Convert integer to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -CHAR *inet_ntoa(struct in_addr address_to_convert) -{ -UINT status; - - /* Because we are using global buffer space to write out the string, get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - if (status != NX_SUCCESS) - { - return NX_NULL; - } - - inet_ntoa_internal(&address_to_convert, nx_bsd_url_buffer, NX_BSD_URL_BUFSIZE); - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return the start of the string buffer. */ - return nx_bsd_url_buffer; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* bsd_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an integer to a string. */ -/* */ -/* INPUT */ -/* */ -/* number Number to convert */ -/* string Pointer to string buffer */ -/* buffer_len Size of the string buffer */ -/* base the base of the number, */ -/* 2,8,10,16 */ -/* */ -/* OUTPUT */ -/* */ -/* size Size of string buffer */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT bsd_number_convert(UINT number, CHAR *string, ULONG buffer_len, UINT base) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < buffer_len) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string[j] = string[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % base; - - /* Update the input number. */ - number = number / base; - - /* Store the new digit in ASCII form. */ - if(digit < 10) - string[0] = (CHAR) (digit + 0x30); - else - string[0] = (CHAR) (digit + 0x57); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Make the string NULL terminated. */ - string[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_aton PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts hexadecimal characters into an ASCII IP */ -/* address representation. */ -/* */ -/* INPUT */ -/* */ -/* address_buffer_ptr String holding the IP address */ -/* addr Struct to store the IP address*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful conversion */ -/* NX_SOC_ERROR Error during conversion */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_isdigit Indicate char is a number */ -/* isspace Indicate char is a space */ -/* islower Indicate char is lowercase */ -/* htonl Convert to network byte order */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT inet_aton(const CHAR *address_buffer_ptr, struct in_addr *addr) -{ -ULONG value; -INT base = 10, ip_address_index; -UCHAR tempchar; -const UCHAR *buffer_ptr; -UINT ip_address_number[4]; /* Four discreet numbers in IP address representation. */ -UINT *ip_number_ptr; /* IP address as equivalent ULONG value. */ -UINT dot_flag; - - /* Set local variables. */ - buffer_ptr = (const UCHAR *) address_buffer_ptr; - ip_number_ptr = ip_address_number; - - tempchar = *buffer_ptr; - - /* Check for an invalid first character. */ - if (nx_bsd_isdigit(tempchar)== NX_FALSE) - { - return (0); - } - - dot_flag = 1; - - /* Parse the rest of the characters from the input number. */ - do - { - - /* Initialize the (next) extracted IP address number to zero. */ - value = 0; - - if(dot_flag== 1) - { - /* Initialize the numeric base to decimal unless we determine hex or octal. */ - base = 10; - - /* Determine which number base the input number buffer is. */ - if (*buffer_ptr == '0') - { - /* Get the next character. */ - buffer_ptr++; - - /* A leading 0 followed by an 'x' indicates this is hexidecimal. */ - if ((*buffer_ptr== 'x') || (*buffer_ptr == 'X')) - { - base = 16; - - /* Move ahead one character past the leading '0x' */ - buffer_ptr++; - } - else - { - /* This is octal. */ - base = 8; - buffer_ptr--; - } - } - } - - tempchar = *buffer_ptr; - - /* Parse characters making up the next word. */ - while (*buffer_ptr != '\0') - { - /* Check if the next character is a decimal or octal digit. */ - if (nx_bsd_isdigit(tempchar)) - { - - dot_flag = 0; - - /* Convert the tempchar character to a number. Multiply the existing - number by the base (8 or 10) and this digit to the sum. */ - value = (value * (ULONG)base) + (ULONG)(tempchar - '0'); - - /* Advance the IP address pointer to the next character. */ - buffer_ptr++; - - /* Get the next character. */ - tempchar = *buffer_ptr; - } - /* Else check if we are expecting a hexidecimal number. */ - else if (nx_bsd_isxdigit(tempchar)) - { - /* We are; Verify the base is 16. */ - if(base == 16) - { - - /* It is. handle upper or lower case hex digit. */ - CHAR c = (CHAR)(nx_bsd_islower(tempchar) ? 'a' : 'A'); - - dot_flag = 0; - - /* Convert the hex character to a hex digit, multiply the existing word by shifting the bits, - and add this hex digit to the sum. */ - value = (value << 4) + (ULONG)(tempchar + 10 - c); - - buffer_ptr++; - - /* Get the next character. */ - tempchar = *buffer_ptr; - } - else - { - /* Not a valid hex character. */ - return (0); - } - } - else - { - /* We have reached a number separator or possibly end of the string. */ - break; - } - } - - /* At the end of the current word. Is this a separator character? */ - if (*buffer_ptr == '.') - { - - dot_flag = 1; - - /* Yes, check for an invalid number (cannot exceed 255 or 0xFF. */ - if (value > 0xff) - { - return (0); - } - - /* Check that the pointer to the last extracted number does not exceed the array holding the IP address numbers. */ - if (ip_number_ptr >= (ip_address_number + 3)) - { - return (0); - } - - /* Copy the computed value into the IP address number buffer. */ - *ip_number_ptr = value; - - /* Move the pointer to where we will store the next number extracted. */ - ip_number_ptr++; - - /* Move to the next character in the IP address string. */ - buffer_ptr++; - } - /* Check for non digit or seperator character indicating (maybe) end of the buffer. */ - else - break; - - } while (1); - - /* If this is not a null terminating character, check for invalid trailing characters. */ - if (*buffer_ptr) - { - - if((*buffer_ptr != '\0') && (!nx_bsd_isspace(*buffer_ptr))) - { - - return (0); - } - } - - /* IP addresses are grouped as A, B, C, or D types. Determine which - type address we have by comparing the IP address value against...*/ - - /* Determine this by substracting the pointer to beginning of the whole - IP address number ip_number_ptr[4] against the pointer to the last extracted word, ip_address_number. */ - ip_address_index = ip_number_ptr - ip_address_number + 1; - - /* Check for an invalid array index (assume 'the array' is indexed 1-4). */ - if ((ip_address_index == 0) || (ip_address_index > 4)) - { - return (0); - } - - /* Sum each of the individual IP address numbers depending how many there were extracted. */ - - /* Most common input... */ - if (ip_address_index == 4) - { - INT i; - - /* Three separators parsed, so the format is a.b.c.d where c is 8 bits */ - - /* Check for a computed sum greater than can be contained in 8 bits. */ - if (value > 0xff) - return (0); - - /* 'Add' the last extracted number by prepending the three other bytes onto the total value. */ - for (i = 0; i<=2; i++) - { - value |= ip_address_number[i] << (24 - (i*8)); - } - } - /* Most common input... */ - else if (ip_address_index == 1) - { - - /* We are done, this address contained one 32 bit word (no separators). */ - } - /* Less common input... */ - else if (ip_address_index == 2) - { - /* One separator, so the format is a.b where b is 24 bits */ - - /* Check for a computed sum greater than can be contained in 24 bits. */ - if (value > 0xffffff) - return (0); - - /* 'Add' the last extracted number by prepending the most significant byte onto the total value. */ - value |= (ip_address_number[0] << 24); - } - else if (ip_address_index == 3) - { - /* Two separators parsed, so the format is a.b.c where c is 16 bits */ - INT i; - - /* Check for a computed sum greater than can be contained in 16 bits. */ - if (value > 0xffff) - return (0); - - /* 'Add' the last extracted number by prepending the two most significant bytes onto the total value. */ - for (i = 0; i<=1; i++) - { - value |= ip_address_number[i] << (24 - (i*8)); - } - } - - /* Check if a return pointer for the address data is supplied. */ - if (addr) - { - - /* Convert the IP address data to network byte order and return the data. */ - addr->s_addr = htonl(value); - } - - return (1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_addr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IP address string to a number. If it */ -/* detects an error in the conversion it returns a zero address. */ -/* */ -/* INPUT */ -/* */ -/* buffer IP address text buffer */ -/* address Converted address number */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful conversion */ -/* NX_SOC_ERROR Error during conversion */ -/* */ -/* CALLS */ -/* */ -/* inet_aton Indicate char is a space */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -in_addr_t inet_addr(const CHAR *buffer) -{ - -struct in_addr ip_address; -UINT status; - - status = (UINT)inet_aton(buffer, &ip_address); - - if (status == 0) - { - return (0xFFFFFFFF); - } - - return(ip_address.s_addr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* getsockopt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the status of the specified socket option in */ -/* the current BSD socket session. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* option_level Category of option (SOCKET) */ -/* option_name Socket option ID */ -/* option_value Pointer to option value */ -/* option_value Pointer to size of value */ -/* */ -/* OUTPUT */ -/* */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLS */ -/* */ -/* NX_SOC_OK Request processed successfully*/ -/* NX_SOC_ERROR Errors with request */ -/* (option data) Pointer to requested data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT getsockopt(INT sockID, INT option_level, INT option_name, VOID *option_value, INT *option_length) -{ - -TX_INTERRUPT_SAVE_AREA - -INT status; -NX_BSD_SOCKET *bsd_socket_ptr; -struct sock_errno *so_errno; -struct sock_keepalive *so_keepalive; -struct sock_reuseaddr *so_reuseaddr; -struct timeval *so_rcvtimeval; -struct sock_winsize *soc_window_size; -ULONG ticks; - - - /* Check for valid socket ID/descriptor. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check for invalid input. */ - if((option_value == NX_NULL) || (option_length == NX_NULL)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - if (option_level == IPPROTO_IP) - { - - if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) - { - - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - else if(option_level == SOL_SOCKET) - { - - if((option_name > SO_MAX) || (option_name < SO_MIN)) - { - - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - else - { - - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Get the protection mutex. */ - status = (INT)tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Setup pointer to socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - status = NX_SOC_OK; - switch (option_name) - { - - case SO_ERROR: - { - - /* If a valid option pointer was supplied, verify it points to a valid data size. */ - if (*option_length < (INT)sizeof(so_errno -> error)) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - so_errno = (struct sock_errno *)option_value; - - TX_DISABLE - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - so_errno -> error = bsd_socket_ptr -> nx_bsd_socket_error_code; - - /* Now clear the error code. */ - bsd_socket_ptr -> nx_bsd_socket_error_code = 0; - - /* Clear the error flag. The application is expected to close the socket at this point.*/ - bsd_socket_ptr -> nx_bsd_socket_status_flags = bsd_socket_ptr -> nx_bsd_socket_status_flags & (ULONG)(~NX_BSD_SOCKET_ERROR); - } - else - so_errno -> error = 0; - TX_RESTORE - - /* Set the actual size of the data returned. */ - *option_length = sizeof(struct sock_errno); - - } - - break; - - case SO_KEEPALIVE: - - /* Determine if NetX Duo supports keepalive. */ - - /* Check to make sure the size arguement is sufficient if supplied. */ - if (*option_length < (INT)sizeof(so_keepalive -> keepalive_enabled)) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - so_keepalive = (struct sock_keepalive *)option_value; -#ifndef NX_ENABLE_TCP_KEEPALIVE - so_keepalive -> keepalive_enabled = NX_FALSE; -#else - so_keepalive -> keepalive_enabled = (INT)(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled); -#endif /* NX_ENABLE_TCP_KEEPALIVE */ - *option_length = sizeof(struct sock_keepalive); - - break; - - case SO_RCVTIMEO: - - /* Check if the receive time out is set. */ - if (bsd_socket_ptr -> nx_bsd_option_receive_timeout == 0) - { - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - - } - - so_rcvtimeval = (struct timeval *)option_value; - - ticks = bsd_socket_ptr -> nx_bsd_option_receive_timeout; - - - so_rcvtimeval -> tv_usec = (suseconds_t)(ticks * NX_MICROSECOND_PER_CPU_TICK) % 1000000; - so_rcvtimeval -> tv_sec = (time_t)((ticks * NX_MICROSECOND_PER_CPU_TICK) / 1000000); - *option_length = sizeof(so_rcvtimeval); - - break; - - case SO_RCVBUF: - - soc_window_size = (struct 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); - - break; - - case SO_REUSEADDR: - - /* Check to make sure the size arguement is sufficient if supplied. */ - if (*option_length < (INT)sizeof(so_reuseaddr -> reuseaddr_enabled)) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - so_reuseaddr= (struct sock_reuseaddr *)option_value; - so_reuseaddr -> reuseaddr_enabled = bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; - *option_length = sizeof(struct sock_reuseaddr); - - break; - - case IP_MULTICAST_TTL: - - /* Validate the option length. */ - if(*option_length != sizeof(UCHAR)) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Verify that the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Make sure socket is UDP type. */ - if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) - { - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - 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); - break; - - default: - - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - /* Unsupported or unknown option. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* setsockopt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables the specified socket option in the current BSD*/ -/* socket session to the specified setting. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* option_level Category of option (SOCKET) */ -/* option_name Socket option ID */ -/* option_value Pointer to option value */ -/* option_length Size of option value data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK Request processed successfully*/ -/* NX_SOC_ERROR Errors with request */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT setsockopt(INT sockID, INT option_level, INT option_name, const VOID *option_value, INT option_length) -{ -UINT reuse_enabled; -NX_BSD_SOCKET *bsd_socket_ptr; -ULONG window_size; -ULONG timer_ticks; -struct timeval *time_val; -#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || !defined(NX_DISABLE_IPV4) -INT i; -#endif /* defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || !defined(NX_DISABLE_IPV4) */ -#ifndef NX_DISABLE_IPV4 -struct ip_mreq *mreq; -UINT mcast_interface; -UINT status; -#endif /* NX_DISABLE_IPV4 */ - - - /* Check for valid socket ID. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Error, invalid socket ID. */ - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check for invalid paremters. */ - if((option_value == NX_NULL) || (option_length == 0)) - { - - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - if (option_level == IPPROTO_IP) - { - - if((option_name <= SO_MAX) || (option_name > IP_OPTION_MAX)) - { - - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - else if(option_level == SOL_SOCKET) - { - - if((option_name > SO_MAX) || - (option_name < SO_MIN)) - { - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - } - else - { - /* Error, one or more invalid arguments. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Set up pointer to the BSD socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Set the socket option status. */ - switch (option_name) - { - - case SO_BROADCAST: - - /* This is the default behavior of NetX. All sockets have this capability. */ - break; - - case SO_KEEPALIVE: - - /* Only available to TCP BSD sockets. */ - if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - - /* Verify TCP keep alive is built into the NetX library or return an error. */ -#ifndef NX_ENABLE_TCP_KEEPALIVE - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; -#else - /* Determine if NetX Duo supports keepalive. */ - - /* Update the BSD socket with this attribute. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled = - (UINT)(((struct sock_keepalive *)option_value) -> keepalive_enabled); - - if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled == NX_TRUE) - { - - /* Set the keep alive timeout for this socket with the NetX configurable keep alive timeout. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL; - } - else - { - - /* Clear the socket keep alive timeout. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_timeout = 0; - } -#endif /* NX_ENABLE_TCP_KEEPALIVE */ - } - else - { - /* Not a TCP socket. */ - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - break; - - case SO_LINGER: - - /* The Linger socket option is not supported in NetX Duo BSD. */ - - return NX_NOT_ENABLED; - - case SO_SNDTIMEO: - - time_val = (struct timeval *)option_value; - - /* Calculate ticks for the ThreadX Timer. */ - timer_ticks = (ULONG)(time_val -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(time_val -> tv_sec) * NX_IP_PERIODIC_RATE; - - bsd_socket_ptr -> nx_bsd_option_send_timeout = timer_ticks; - - break; - - case SO_RCVTIMEO: - - time_val = (struct timeval *)option_value; - - /* Calculate ticks for the ThreadX Timer. */ - timer_ticks = (ULONG)(time_val -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(time_val -> tv_sec) * NX_IP_PERIODIC_RATE; - - bsd_socket_ptr -> nx_bsd_option_receive_timeout = timer_ticks; - - break; - - case SO_RCVBUF: - - /* Only available to TCP sockets. */ - if (!bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - - window_size = (ULONG)(((struct sock_winsize *)option_value) -> winsize); - -#ifdef NX_ENABLE_TCP_WINDOW_SCALING - - - /* If Window scaling feature is enabled, record this user-specified window size. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum = window_size; -#else - /* Otherwise the windows size limit is applied. */ - if(window_size > 65535) - window_size = 65535; - -#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ - - /* Setup the sliding window information. */ - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_default = window_size; - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_current = window_size; - - break; - - case SO_REUSEADDR: - - reuse_enabled = (UINT)(((struct sock_reuseaddr *)option_value) -> reuseaddr_enabled); - - if(reuse_enabled) - bsd_socket_ptr -> nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; - else - bsd_socket_ptr -> nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR); - - break; - - - case TCP_NODELAY: - - /* This is the default behavior of NetX. All sockets have this attribute. */ - - break; - - case IP_MULTICAST_TTL: - - /* Validate the option length. */ - if(option_length != sizeof(UCHAR)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Verify that the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Make sure socket is UDP type. */ - if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - /* Set the TTL value. */ - bsd_socket_ptr -> nx_bsd_socket_udp_socket -> nx_udp_socket_time_to_live = *(UCHAR*)option_value; - break; - - - case IP_RAW_RX_NO_HEADER: - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - i = *(INT*)option_value; - - if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && - ((bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) || (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6))) - { - - if(i) - { - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_RX_NO_HDR; - } - else - { - - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_RX_NO_HDR); - } - } - else -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - { - - set_errno(EINVAL); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return NX_SOC_ERROR; - } -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - break; -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - case IP_RAW_IPV6_HDRINCL: - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - i = *(INT*)option_value; - - /* Is this an IPv6 socket? */ - if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && - (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6)) - { - - /* Should the No Header feature be enabled (NX_TRUE)? */ - if(i) - { - - /* Yes, set the flag for no header. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_TX_HDR_INCLUDE; - } - else - { - - /* No, clear the flag for no header. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_TX_HDR_INCLUDE); - } - } - else -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - { - - set_errno(EINVAL); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return NX_SOC_ERROR; - } -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - break; -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - -#ifndef NX_DISABLE_IPV4 - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - - /* Validate the option length */ - if(option_length != sizeof(struct ip_mreq)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - mreq = (struct ip_mreq*)option_value; - - /* Make sure the multicast group address is valid. */ - if((mreq -> imr_multiaddr.s_addr & ntohl(NX_IP_CLASS_D_TYPE)) != ntohl(NX_IP_CLASS_D_TYPE)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Verify that the socket is still valid. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Make sure socket is UDP type. */ - if(bsd_socket_ptr -> nx_bsd_socket_udp_socket == NX_NULL) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOPROTOOPT); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Validate that the interface is one of the local IPv4 interfaces. */ - /* We allow imr_interface being zero to indicate the primary interface. */ - mcast_interface = NX_MAX_IP_INTERFACES; - - if(mreq -> imr_interface.s_addr == INADDR_ANY) - { - mcast_interface = 0; - } - else - { - - /* Set the socket error if extended socket options enabled. */ - UINT addr; - - /* Convert the local interface value to host byte order. */ - addr = ntohl(mreq -> imr_interface.s_addr); - - /* Search through the interface table for a matching one. */ - for(i = 0; i < NX_MAX_IP_INTERFACES; i++) - { - - if(addr == nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_ip_address) - { - - mcast_interface = (UINT)i; - break; - } - } - } - - if(mcast_interface == NX_MAX_IP_INTERFACES) - { - - /* Did not find a matching interface. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - if(option_name == IP_ADD_MEMBERSHIP) - { - - /* Make sure the IGMP feature is enabled. */ - if(nx_bsd_default_ip -> nx_ip_igmp_packet_receive == NX_NULL) - { - nx_igmp_enable(nx_bsd_default_ip); - } - - /* Join the group. */ - status = nx_igmp_multicast_interface_join(nx_bsd_default_ip, ntohl(mreq -> imr_multiaddr.s_addr), mcast_interface); - } - else - { - - /* Leave group */ - status = nx_igmp_multicast_leave(nx_bsd_default_ip, ntohl(mreq -> imr_multiaddr.s_addr)); - } - - if(status != NX_SUCCESS) - { - - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - break; -#endif /* NX_DISABLE_IPV4 */ - - case IP_HDRINCL: - -#if defined(NX_ENABLE_IP_RAW_PACKET_FILTER) && !defined(NX_DISABLE_IPV4) - i = *(INT*)option_value; - /* First verify that raw socket processing is enabled on the IP instance and that this is - an IPv4 thread. */ - if((bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) && - (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET)) - { - - /* Is the option being enabled (NX_TRUE)? */ - if(i) - { - - /* Yes, set the flag bit indicating BSD will append the IP header. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_TX_HDR_INCLUDE; - } - else - { - - /* No, clear the flag bit indicating IP task will append the IP header. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_TX_HDR_INCLUDE); - } - } - else -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - { - - set_errno(EINVAL); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - - return NX_SOC_ERROR; - } - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - break; -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - default: - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return an error status. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return NX_SOC_ERROR; - } - - /* Socket option successfully updated. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* getsockname PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the socket's primary interface address and */ -/* port. For NetX Duo environments, it returns the address at address */ -/* index 1 into the IP address table; this is where the primary */ -/* interface global IP address is normally located. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* localAddress sockaddr struct to return */ -/* the local address */ -/* addressLength Number of bytes in sockAddr */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT getsockname(INT sockID, struct sockaddr *localAddress, INT *addressLength) -{ - -#ifndef NX_DISABLE_IPV4 -struct sockaddr_in soc_struct; -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 -struct sockaddr_in6 soc6_struct; -#endif -UINT status; -NX_BSD_SOCKET *bsd_socket_ptr; - - - /* Check whether supplied socket ID is valid. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if((localAddress == NX_NULL) || (addressLength == NX_NULL) || (*addressLength == 0)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Setup pointer to socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND)) - { - /* This socket is not bound yet. Just return. - According to the spec, if the socket is not bound, the value stored in - localAddress is unspecified. */ - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Success! */ - return(NX_SOC_OK); - } - -#ifndef NX_DISABLE_IPV4 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - { - soc_struct.sin_addr.s_addr = INADDR_ANY; - } - else if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) - { - - set_errno(EINVAL); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - else - { - NX_INTERFACE* local_if = (NX_INTERFACE*)(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface); - soc_struct.sin_addr.s_addr = htonl(local_if -> nx_interface_ip_address); - } - soc_struct.sin_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_local_port); - - soc_struct.sin_family = AF_INET; - - if((*addressLength) > (INT)sizeof(struct sockaddr_in)) - { - *addressLength = sizeof(struct sockaddr_in); - } - memcpy(localAddress, &soc_struct, (UINT)(*addressLength)); - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - - if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - { - soc6_struct.sin6_addr._S6_un._S6_u32[0] = 0; - soc6_struct.sin6_addr._S6_un._S6_u32[1] = 0; - soc6_struct.sin6_addr._S6_un._S6_u32[2] = 0; - soc6_struct.sin6_addr._S6_un._S6_u32[3] = 0; - } - else if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == 0) - { - - set_errno(EINVAL); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - else - { - NXD_IPV6_ADDRESS* local_v6if = (NXD_IPV6_ADDRESS*)(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface); - - soc6_struct.sin6_addr._S6_un._S6_u32[0] = htonl(local_v6if -> nxd_ipv6_address[0]); - soc6_struct.sin6_addr._S6_un._S6_u32[1] = htonl(local_v6if -> nxd_ipv6_address[1]); - soc6_struct.sin6_addr._S6_un._S6_u32[2] = htonl(local_v6if -> nxd_ipv6_address[2]); - soc6_struct.sin6_addr._S6_un._S6_u32[3] = htonl(local_v6if -> nxd_ipv6_address[3]); - } - - soc6_struct.sin6_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_local_port); - - soc6_struct.sin6_family = AF_INET6; - - if((*addressLength) > (INT)sizeof(struct sockaddr_in6)) - { - *addressLength = sizeof(struct sockaddr_in6); - } - memcpy(localAddress, &soc6_struct, (UINT)(*addressLength)); - - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - set_errno(EPROTONOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Success! */ - return(NX_SOC_OK); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* getpeername PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the socket's remote address and port. */ -/* */ -/* INPUT */ -/* */ -/* sockID socket descriptor */ -/* localAddress sockaddr struct to return */ -/* the remote address */ -/* addressLength Number of bytes in sockAddr */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK (0) On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT getpeername(INT sockID, struct sockaddr *remoteAddress, INT *addressLength) -{ - -UINT status; -NX_BSD_SOCKET *bsd_socket_ptr; -#ifndef NX_DISABLE_IPV4 -struct sockaddr_in *soc_struct_ptr = NX_NULL; -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 -struct sockaddr_in6 *soc6_struct_ptr = NX_NULL; -#endif - - - /* Check whether supplied socket ID is valid. */ - if ((sockID < NX_BSD_SOCKFD_START) || (sockID >= (NX_BSD_SOCKFD_START + NX_BSD_MAX_SOCKETS))) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Error, invalid socket ID. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - /* Normalize the socket ID. */ - sockID = sockID - NX_BSD_SOCKFD_START; - - /* Check the remote address and length pointers. */ - if((remoteAddress == NX_NULL) ||(addressLength == NX_NULL)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Error getting the protection mutex. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(ERROR); - } - - /* Setup pointer to socket. */ - bsd_socket_ptr = &nx_bsd_socket_array[sockID]; - -#ifndef NX_DISABLE_IPV4 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - /* This is an IPv4 only socket. */ - - /* Now validate the size of remoteAddress structure. */ - if(*addressLength < (INT)sizeof(struct sockaddr_in)) - { - - /* User supplied buffer is too small .*/ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if socket enabled with extended BSD features. */ - set_errno(ESOCKTNOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - soc_struct_ptr = (struct sockaddr_in*)remoteAddress; - *addressLength = sizeof(struct sockaddr_in); - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - /* IPv6 socket */ - - /* Now validate the size of remoteAddress structure. */ - if(*addressLength < (INT)sizeof(struct sockaddr_in6)) - { - - /* User supplied buffer is too small .*/ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if socket enabled with extended BSD features. */ - set_errno(ESOCKTNOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - soc6_struct_ptr = (struct sockaddr_in6*)remoteAddress; - *addressLength = sizeof(struct sockaddr_in6); - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Not a valid address family. */ - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if socket enabled with extended BSD features. */ - set_errno(ESOCKTNOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - /* Is the socket still in use? */ - if (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Error, socket not in use anymore. */ - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - /* Check whether TCP or UDP */ - if (bsd_socket_ptr -> nx_bsd_socket_tcp_socket) - { - -#ifndef NX_DISABLE_IPV4 - /* TCP Socket. Determine socket family type. */ - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - - soc_struct_ptr -> sin_family = AF_INET; - soc_struct_ptr -> sin_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); - soc_struct_ptr -> sin_addr.s_addr = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v4); - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - - soc6_struct_ptr -> sin6_family = AF_INET6; - soc6_struct_ptr -> sin6_port = htons((USHORT)bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_port); - soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[0] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[0]); - soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[1] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[1]); - soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[2] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[2]); - soc6_struct_ptr -> sin6_addr._S6_un._S6_u32[3] = htonl(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip.nxd_ip_address.v6[3]); - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error if extended options enabled. */ - set_errno(EBADF); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - - } - } - else if (bsd_socket_ptr -> nx_bsd_socket_udp_socket) - { - -#ifndef NX_DISABLE_IPV4 - /* UDP Socket. Get Peer Name doesn't apply to UDP sockets. Only fill in AF family information.*/ - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) - { - soc_struct_ptr -> sin_family = AF_INET; - soc_struct_ptr -> sin_port = 0; - soc_struct_ptr -> sin_addr.s_addr = 0; - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET6) - { - soc6_struct_ptr -> sin6_family = AF_INET6; - soc6_struct_ptr -> sin6_port = 0; - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if socket enabled with extended BSD features. */ - set_errno(ESOCKTNOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - - } - } - else - { - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Set the socket error, if socket enabled with extended BSD features. */ - set_errno(ESOCKTNOSUPPORT); - - /* Return error. */ - NX_BSD_ERROR(ERROR, __LINE__); - return(ERROR); - } - - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Success! */ - return(NX_SOC_OK); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* select PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows for sockets to be checked for incoming packets.*/ -/* nfds should be one greater than value of the largest valued socket */ -/* descriptor in any of the lists. If you don't wish to calculate this,*/ -/* use FD_SETSIZE instead.For small numbers of sockets,select() will be*/ -/* less efficient if FD_SETSIZE is passed.If the bit corresponding to */ -/* a socket in an fd_set is set,that socket will be checked for the */ -/* condition the fd_set corresponds to.If the condition they are */ -/* checked for is true, they will still be set to true when select() */ -/* returns (otherwise they will be set to false). */ -/* Note that the sets are modified by select():thus they must be reset */ -/* between each call to the function. */ -/* */ -/* fd_sets can be manipulated using the following macros or functions: */ -/* */ -/* FD_SET(fd, fdset) Sets socket fd in fdset to true. */ -/* FD_CLR(fd, fdset) Sets socket fd in fdset to false. */ -/* FD_ISSET(fd, fdset)Returns true if socket fd is set to true in fdset*/ -/* FD_ZERO(fdset) Sets all the sockets in fdset to false. */ -/* */ -/* If the input timeout is NULL, select() blocks until one of the */ -/* sockets receives a packet. If the timeout is non-NULL, select waits */ -/* for the specified time and returns regardless if any socket has */ -/* received a packet. Otherwise as soon as a socket receives a packet */ -/* this function will return immediately. */ -/* */ -/* To use select() in non-blocking mode call it with a non-null timeout*/ -/* input but set tv_sec and tv_usec to zero, in Unix fashion. */ -/* */ -/* select() returns the number of sockets for which the specified */ -/* conditions are true. If it encounters an error, it will return -1. */ -/* */ -/* NOTE: ****** When select returns NX_SOC_ERROR it won't update */ -/* the readfds descriptor. */ -/* */ -/* INPUT */ -/* */ -/* nfds Maximum socket descriptor # */ -/* fd_set *readFDs List of read ready sockets */ -/* fd_set *writeFDs List of write ready sockets */ -/* fd_set *exceptFDs List of exceptions */ -/* struct timeval *timeOut */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS No descriptors read */ -/* (successful completion) */ -/* status Number of descriptors read */ -/* (< 0 if error occurred) */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* nx_tcp_socket_receive Receive TCP packet */ -/* nx_udp_source_extract Extract source IP and port */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* tx_thread_preemption_change Disable/restore preemption */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT select(INT nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) -{ - -INT i; -UINT status; -NX_BSD_SOCKET_SUSPEND suspend_request; -NX_PACKET *packet_ptr; -fd_set readfds_found; -fd_set writefds_found; -fd_set exceptfds_found; -INT readfds_left; -INT writefds_left; -INT exceptfds_left; -ULONG ticks; -UINT original_threshold; -TX_THREAD *current_thread_ptr; -INT ret; - - - /* Check for valid input parameters. */ - if ((readfds == NX_NULL) && (writefds == NX_NULL) && (exceptfds == NX_NULL) && (timeout == NX_NULL)) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Check the maximum number of file descriptors. */ - if((nfds < (NX_BSD_SOCKFD_START + 1)) || (nfds >= (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START + 1))) - { - - /* Set the socket error */ - set_errno(EBADF); - - /* Return an error. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Clear the read and the write selector set. */ - FD_ZERO(&readfds_found); - FD_ZERO(&writefds_found); - FD_ZERO(&exceptfds_found); - - if(readfds) - readfds_left = readfds -> fd_count; - else - readfds_left = 0; - - if(writefds) - { - - writefds_left = writefds -> fd_count; - } - else - { - - writefds_left = 0; - } - - if(exceptfds) - { - - exceptfds_left = exceptfds -> fd_count; - } - else - { - - exceptfds_left = 0; - } - - /* Compute the timeout for the suspension if a timeout value was supplied. */ - if (timeout != NX_NULL) - { - - /* Calculate ticks for the ThreadX Timer. */ - ticks = (ULONG)(timeout -> tv_usec)/NX_MICROSECOND_PER_CPU_TICK + (ULONG)(timeout -> tv_sec) * NX_IP_PERIODIC_RATE; - } - else - { - - /* If no timeout input, set the wait to 'forever.' */ - ticks = TX_WAIT_FOREVER; - } - - /* Get the protection mutex. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Set the socket error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Loop through the BSD sockets to see if the read ready request can be satisfied. */ - for (i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) - { - - if((readfds == NX_NULL) || (readfds_left == 0)) - break; - - /* Is this socket selected for read? */ - if (FD_ISSET((i + NX_BSD_SOCKFD_START), readfds)) - { - - /* Yes, decrement the number of read selectors left to search for. */ - readfds_left--; - - /* Is this BSD socket in use? */ - if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* There is; add this socket to the read ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - - /* Check to see if there is a disconnection request pending. */ - else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_DISCONNECTION_REQUEST) - { - - /* There is; add this socket to the read ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - - /* Check to see if there is a receive packet pending. */ - else if (nx_bsd_socket_array[i].nx_bsd_socket_received_packet) - { - - /* Therer is; add this socket to the read ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - /* Is this a TCP socket? */ - else if (nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket) - { - /* Check if this is a master socket and if its associated secondary socket - is connected. If it is, the master socket should be considered readable. */ - if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) - { - - if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) - { - - /* If the secondary socket does not exist, try to allocate one. */ - if(nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id >= NX_BSD_MAX_SOCKETS) - { - - /* This secondary socket is not avaialble yet. This could happen if the - previous accept call fails to allocate a new secondary socket. */ - ret = nx_bsd_tcp_create_listen_socket(i, 0); - - if(ret < 0) - { - - /* Mark the FD set so the application could be notified. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - } - - if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) - { - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - } - } - else if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) - { - - /* Yes; attempt to perform a non-blocking read. */ - status = nx_tcp_socket_receive(nx_bsd_socket_array[i].nx_bsd_socket_tcp_socket, &packet_ptr, TX_NO_WAIT); - - /* Check for success. */ - if (status == NX_SUCCESS) - { - - /* Save the received packet in the TCP BSD socket packet pointer. */ - nx_bsd_socket_array[i].nx_bsd_socket_received_packet = packet_ptr; - - /* Reset the packet offset. */ - nx_bsd_socket_array[i].nx_bsd_socket_received_packet_offset = 0; - - /* Increase the received count. */ - nx_bsd_socket_array[i].nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - nx_bsd_socket_array[i].nx_bsd_socket_received_packet_count++; - - /* Add this socket to the read ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - } - } -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - /* Is this a raw socket? */ - else if (nx_bsd_socket_array[i].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) - { - - /* Check the raw receive queue (by definition has a zero wait option (no suspension)). */ - status = nx_bsd_raw_packet_receive(&nx_bsd_socket_array[i], &packet_ptr); - - /* Determine if we have a packet. */ - if ((status == NX_SUCCESS) && (packet_ptr)) - { - - /* Get the sender IP address from the raw packet. */ - status = nx_bsd_raw_packet_info_extract(packet_ptr, &(nx_bsd_socket_array[i].nx_bsd_socket_source_ip_address), NX_NULL); - - /* Save the received packet in the BSD socket packet pointer. */ - nx_bsd_socket_array[i].nx_bsd_socket_received_packet = packet_ptr; - - /* Reset the packet offset. */ - nx_bsd_socket_array[i].nx_bsd_socket_received_packet_offset = 0; - - /* Add this socket to the read ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &readfds_found); - } - } -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - } - } - /* Loop through the BSD sockets to see if the write ready request can be satisfied. */ - for(i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) - { - - if((writefds == NX_NULL) || (writefds_left == 0)) - break; - - /* Is this socket selected for write? */ - if (FD_ISSET(i + NX_BSD_SOCKFD_START, writefds)) - { - - /* Yes, decrement the number of read selectors left to search for. */ - writefds_left--; - - /* Is this BSD socket in use? */ - if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - /* Yes, add this socket to the write ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); - } - - /* Check to see if there is a connection request pending. */ - else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_REQUEST) - { - - /* Yes, add this socket to the write ready list. */ - FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); - } - - /* Check to see if there is an error.*/ - else if (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - - FD_SET(i + NX_BSD_SOCKFD_START, &writefds_found); - } - } - } - - /* Loop through the BSD sockets to see if the exception request can be satisfied. */ - for(i = 0; i < (nfds - NX_BSD_SOCKFD_START); i++) - { - - if((exceptfds == NX_NULL) || (exceptfds_left == 0)) - break; - - /* Is this socket selected for exceptions? */ - if (FD_ISSET(i + NX_BSD_SOCKFD_START, exceptfds)) - { - - /* Yes, decrement the number of read selectors left to search for. */ - exceptfds_left--; - - /* Is this BSD socket in use? */ - if (!(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - FD_SET(i + NX_BSD_SOCKFD_START, &exceptfds_found); - } - - /* Check to see if there is an error.*/ - else if(nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ERROR) - { - - FD_SET(i + NX_BSD_SOCKFD_START, &exceptfds_found); - } - } - } - - /* Now determine if we have found anything that satisfies the select request. */ - if (readfds_found.fd_count || writefds_found.fd_count || exceptfds_found.fd_count) - { - - /* Yes, return what we have and we're done. */ - - /* Copy over the requested read ready fds. */ - if(readfds) - *readfds = readfds_found; - - if(writefds) - *writefds = writefds_found; - - if(exceptfds) - *exceptfds = exceptfds_found; - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - /* Return the number of fds found. */ - return(readfds_found.fd_count + writefds_found.fd_count + exceptfds_found.fd_count); - } - - /* Otherwise, nothing is ready to be read at this point. */ - - /* Pickup the current thread. */ - current_thread_ptr = tx_thread_identify(); - - /* Save the fd requests in the local suspension structure. This will be used by the receive notify routines to - wakeup threads on the select. */ - suspend_request.nx_bsd_socket_suspend_actual_flags = 0; - - if(readfds) - suspend_request.nx_bsd_socket_suspend_read_fd_set = *readfds; - else - FD_ZERO(&suspend_request.nx_bsd_socket_suspend_read_fd_set); - - if(writefds) - suspend_request.nx_bsd_socket_suspend_write_fd_set = *writefds; - else - FD_ZERO(&suspend_request.nx_bsd_socket_suspend_write_fd_set); - - if(exceptfds) - suspend_request.nx_bsd_socket_suspend_exception_fd_set = *exceptfds; - else - FD_ZERO(&suspend_request.nx_bsd_socket_suspend_exception_fd_set); - - /* Temporarily disable preemption. */ - tx_thread_preemption_change(current_thread_ptr, 0, &original_threshold); - - /* Release the protection mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - status = tx_event_flags_get(&nx_bsd_events, NX_BSD_SELECT_EVENT, TX_OR_CLEAR, (ULONG *) &suspend_request, ticks); - - /* Restore original preemption threshold. */ - tx_thread_preemption_change(current_thread_ptr, original_threshold, &original_threshold); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* If we got here, we received no packets. */ - - /* TX_NO_EVENT implies an immediate return from the flag get call. - This happens if the wait option is set to zero. */ - if (status == TX_NO_EVENTS) - { - - /* Determine if the effected sockets are non blocking (zero ticks for the wait option). */ - if (ticks == 0) - set_errno(EWOULDBLOCK); - else - set_errno(ETIMEDOUT); - - /* Do not handle as an error; just a timeout so return 0. */ - return(0); - } - else - { - - /* Actual error. */ - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - /* Error getting the protection mutex. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - else - { - - /* Otherwise, a receive event has been found. Simply copy the receive events. */ - if(readfds) - *readfds = suspend_request.nx_bsd_socket_suspend_read_fd_set; - if(writefds) - *writefds = suspend_request.nx_bsd_socket_suspend_write_fd_set; - if(exceptfds) - *exceptfds = suspend_request.nx_bsd_socket_suspend_exception_fd_set; - - /* Return the number of fds. */ - return(suspend_request.nx_bsd_socket_suspend_read_fd_set.fd_count + - suspend_request.nx_bsd_socket_suspend_write_fd_set.fd_count + - suspend_request.nx_bsd_socket_suspend_exception_fd_set.fd_count); - } - - -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the NetX callback function for TCP Socket receive operation */ -/* This function resumes all the threads suspended on the socket. */ -/* */ -/* INPUT */ -/* */ -/* *socket_ptr Pointer to the socket which */ -/* received the data packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_tcp_receive_notify(NX_TCP_SOCKET *socket_ptr) -{ -UINT bsd_socket_index; - - /* Figure out what BSD socket this is. */ - bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Determine if this is a good index into the BSD socket array. */ - if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) - { - - /* Bad socket index... simply return! */ - return; - } - - /* Now check if the socket may have been released (e.g. socket closed) while - waiting for the mutex. */ - if( socket_ptr -> nx_tcp_socket_id == 0 ) - { - - return; - } - - /* Check the suspended socket list for one ready to receive or send packets. */ - nx_bsd_select_wakeup(bsd_socket_index, FDSET_READ); - - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_establish_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the NetX callback function for TCP Server Socket listen. */ -/* This function resumes all the threads suspended on the socket. */ -/* */ -/* INPUT */ -/* */ -/* *socket_ptr Pointer to the socket which */ -/* Received the data packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT -static VOID nx_bsd_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr) -{ -UINT bsd_socket_index; -UINT master_socket_index; - - /* Figure out what BSD socket this is. */ - bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Determine if this is a good index into the BSD socket array. */ - if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) - { - - /* Bad socket index... simply return! */ - return; - } - - /* Initialize the master socket index to an invalid value so we can check if it was actually used - later. */ - master_socket_index = NX_BSD_MAX_SOCKETS; - - /* Mark the socket as connected, and also clear the EINPROGRESS flag */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; - - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; - - /* Reset the listen-enabled flag. */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_LISTEN); - - /* Mark the socket is bound. */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_BOUND; - -#ifndef NX_DISABLE_IPV4 - /* Find out the local address this socket is connected on. */ - if(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_family == AF_INET) - { - /* IPv4 case */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_local_bind_interface = (ULONG)socket_ptr -> nx_tcp_socket_connect_interface; - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_family == AF_INET6) - { - /* IPv6 */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_local_bind_interface = (ULONG)socket_ptr -> nx_tcp_socket_ipv6_addr; - } -#endif - /* Determine if the BSD socket is server socket. */ - - - /* Is this a secondary socket? */ - if (nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) - { - - /* Yes, get the master socket. */ - master_socket_index = (UINT)(nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id); - - /* Mark the server socket as also connected. */ - nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTED; - - nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_REQUEST; - - /* Check on connect requests for all server sockets for this master socket. */ - nx_bsd_select_wakeup(master_socket_index, FDSET_READ); - } - else - { - /* This is a client socket. */ - nx_bsd_select_wakeup(bsd_socket_index, FDSET_WRITE); - } -} -#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_socket_disconnect_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the NetX callback function for TCP Socket disconnect. */ -/* This function resumes all the BSD threads suspended on the socket. */ -/* */ -/* INPUT */ -/* */ -/* *socket_ptr Pointer to the socket which */ -/* received the data packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_tcp_socket_disconnect_notify(NX_TCP_SOCKET *socket_ptr) -{ - -UINT bsd_socket_index; -UINT master_socket_index; -NX_BSD_SOCKET *bsd_socket_ptr; -UINT status; - - - /* Figure out what BSD socket this is. */ - bsd_socket_index = (UINT) socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Determine if this is a good index into the BSD socket array. */ - if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) - { - /* No good! */ - return; - } - - bsd_socket_ptr = &nx_bsd_socket_array[bsd_socket_index]; - - /* If the socket already received a disconnect request, no need to do anything here. */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_DISCONNECTION_REQUEST) - { - return; - } - - /* Mark this socket as having a disconnect request pending. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_DISCONNECTION_REQUEST; - - /* Is the socket trying to make a connection? */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTION_INPROGRESS) - { - - /* Yes, clear the INPROGRESS flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_CONNECTION_INPROGRESS); - - /* If this is secondary server socket, there is no need to wake up the select call. */ - if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET) - { - - - /* Instead the socket needs to be cleaned up and to perform a relisten. */ - if(!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED)) - { - - /* Turn off the disconnection_request flag. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_DISCONNECTION_REQUEST); - - nx_tcp_server_socket_unaccept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - - /* Check if a listen request is queued up for this socket. */ - nx_bsd_tcp_pending_connection(bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - - status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port, - bsd_socket_ptr -> nx_bsd_socket_tcp_socket); - - /* Force the socket into SYN_RECEIVED state */ - nx_tcp_server_socket_accept(bsd_socket_ptr -> nx_bsd_socket_tcp_socket, NX_NO_WAIT); - - if(status == NX_CONNECTION_PENDING) - { - - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; - } - else if(status != NX_SUCCESS) - { - - /* Failed the relisten on the secondary socket. Set the error code on the - master socket, and wake it up. */ - - master_socket_index = (UINT)(bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id; - - nx_bsd_socket_array[master_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - nx_bsd_set_error_code(&nx_bsd_socket_array[master_socket_index], status); - - nx_bsd_select_wakeup(master_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); - } - } - - } - else - { - - /* Set error code. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - bsd_socket_ptr -> nx_bsd_socket_error_code = ECONNREFUSED; - - /* Wake up the select on both read and write FDsets. */ - nx_bsd_select_wakeup(bsd_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); - } - } - else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) - { - - /* Wake up the select on both read and write FDsets. */ - nx_bsd_select_wakeup(bsd_socket_index, (FDSET_READ | FDSET_WRITE | FDSET_EXCEPTION)); - } - else - { - - /* In this case, connection reaches maximum retries or is refused by peer. */ - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ERROR; - bsd_socket_ptr -> nx_bsd_socket_error_code = ENOTCONN; - } - -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_udp_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the NetX callback function for UDP Socket receive */ -/* operation. */ -/* */ -/* INPUT */ -/* */ -/* *socket_ptr Pointer to the socket which */ -/* Received the data packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* nx_udp_socket_receive Receive UDP packet */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - -UINT bsd_socket_index; -NX_PACKET *packet_ptr; -NX_UDP_SOCKET *udp_socket_ptr; - - - /* Figure out what BSD socket this is. */ - bsd_socket_index = ((UINT) socket_ptr -> nx_udp_socket_reserved_ptr) & 0x0000FFFF; - - /* Determine if this is a good index into the BSD socket array. */ - if (bsd_socket_index >= NX_BSD_MAX_SOCKETS) - { - return; - } - - udp_socket_ptr = nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_udp_socket; - - if (nx_udp_socket_receive(udp_socket_ptr, &packet_ptr, NX_NO_WAIT)) - { - return; - } - - nx_bsd_udp_packet_received((INT)bsd_socket_index, packet_ptr); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* FD_SET PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a fd to the set. */ -/* */ -/* INPUT */ -/* */ -/* fd fd to add. */ -/* fd_set *fdset fd set. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID FD_SET(INT fd, fd_set *fdset) -{ - -UINT index; - - - /* Check the FD size. */ - if (fd >= NX_BSD_SOCKFD_START) - { - - /* Normalize the fd. */ - fd = fd - NX_BSD_SOCKFD_START; - - /* Now make sure it isn't too big. */ - if (fd < NX_BSD_MAX_SOCKETS) - { - - /* Calculate the index into the bit map. */ - index = (UINT)fd/32; - - /* Now calculate the bit position. */ - fd = fd % 32; - - /* Is the bit already set? */ - if ((fdset -> fd_array[index] & (((ULONG) 1) << fd)) == 0) - { - - /* No, set the bit. */ - fdset -> fd_array[index] = fdset -> fd_array[index] | (((ULONG) 1) << fd); - - /* Increment the counter. */ - fdset -> fd_count++; - } - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* FD_CLR PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes a fd from a fd set. */ -/* */ -/* INPUT */ -/* */ -/* fd fd to remove. */ -/* fd_set *fdset fd set. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID FD_CLR(INT fd, fd_set *fdset) -{ - -UINT index; - - - /* Check the FD size. */ - if (fd >= NX_BSD_SOCKFD_START) - { - - /* Normalize the fd. */ - fd = fd - NX_BSD_SOCKFD_START; - - /* Now make sure it isn't too big. */ - if ((fd < NX_BSD_MAX_SOCKETS) && (fdset -> fd_count)) - { - - /* Calculate the index into the bit map. */ - index = (UINT)fd/32; - - /* Now calculate the bit position. */ - fd = fd % 32; - - /* Determine if the bit is set. */ - if (fdset -> fd_array[index] & (((ULONG) 1) << fd)) - { - - /* Yes, clear the bit. */ - fdset -> fd_array[index] = fdset -> fd_array[index] & ~(((ULONG) 1) << fd); - - /* Decrement the counter. */ - fdset -> fd_count--; - } - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* FD_ISSET PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function tests to see if a fd is in the set. */ -/* */ -/* INPUT */ -/* */ -/* fd fd to add. */ -/* fd_set *fdset fd set. */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE If fd is found in the set. */ -/* NX_FALSE If fd is not there in the set.*/ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT FD_ISSET(INT fd, fd_set *fdset) -{ - -UINT index; - - - /* Check the FD size. */ - if (fd >= NX_BSD_SOCKFD_START) - { - - /* Normalize the fd. */ - fd = fd - NX_BSD_SOCKFD_START; - - /* Now make sure it isn't too big. */ - if (fd < NX_BSD_MAX_SOCKETS) - { - - /* Calculate the index into the bit map. */ - index = (UINT)fd/32; - - /* Now calculate the bit position. */ - fd = fd % 32; - - /* Finally, see if the bit is set. */ - if (fdset -> fd_array[index] & (((ULONG) 1) << fd)) - { - - /* Yes, return true! */ - return(NX_TRUE); - } - } - } - - /* Otherwise, return false. */ - return(NX_FALSE); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* FD_ZERO PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears a fd set. */ -/* */ -/* INPUT */ -/* */ -/* fd_set *fdset fd set to clear. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID FD_ZERO(fd_set *fdset) -{ - -INT i; - - - /* Clear the count. */ - fdset -> fd_count = 0; - - /* Loop to clear the fd set. */ - for (i = 0; i < (NX_BSD_MAX_SOCKETS+31)/32; i++) - { - /* Clear an entry in the array. */ - fdset -> fd_array[i] = 0; - } -} - - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_raw_packet_filter PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives raw packets from NetX Duo and determines if */ -/* BSD will consume the packet (store on the BSD socket raw receive */ -/* queue) or if the packet is available to NetX Duo (not consumed). */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr NetX Duo IP instance */ -/* protocol Received packet protocol */ -/* packet_ptr Pointer to the received packet */ -/* */ -/* OUTPUT */ -/* */ -/* 0 Raw filter consumed the packet*/ -/* 1 Raw filter did not consume */ -/* packet. Allow the caller to*/ -/* process this packet */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_raw_receive_notify Notify threads waiting to */ -/* receive a raw packet */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_raw_packet_filter(NX_IP *ip_ptr, ULONG protocol, NX_PACKET *packet_ptr) -{ - -UINT index; -NX_BSD_SOCKET * bsd_socket_ptr; - - /* Calculate the hash index in the raw socket protocol table. */ - index = (UINT) ((protocol + (protocol >> 8)) & NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK); - - /* Search the bound sockets in this index for particular protocol. */ - bsd_socket_ptr = nx_bsd_socket_raw_protocol_table[index]; - - do - { - /* Determine if the protocol is matched. */ - if ((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && - (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET ) && - (bsd_socket_ptr -> nx_bsd_socket_protocol == protocol)) - { - - /* This packet protocol matches the BSD socket. */ - /* Make sure the queue_next is zero'ed out. */ - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Add the packet to the BSD socket raw packet receive queue. - Are there any packets on this queue yet? */ - if (bsd_socket_ptr -> nx_bsd_socket_received_packet == NX_NULL) - { - - /* No, this will be the only one. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet = packet_ptr; - bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; - - - /* Set the packet count. */ - bsd_socket_ptr -> nx_bsd_socket_received_byte_count = packet_ptr -> nx_packet_length; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 1; - } - else - { - /* Yes; add this packet to the end of the queue. */ - - /* Check if the queue is currently full. */ - if (bsd_socket_ptr -> nx_bsd_socket_received_byte_count_max && - (bsd_socket_ptr -> nx_bsd_socket_received_byte_count >= - bsd_socket_ptr -> nx_bsd_socket_received_byte_count_max)) - { - - /* Release the packet here, and tell NetX Duo the packet is 'consumed'. */ - nx_packet_release(packet_ptr); - - return 0; - } - - /* Drop the packet if the receive queue exceeds max depth.*/ - if(bsd_socket_ptr -> nx_bsd_socket_received_packet_count >= - bsd_socket_ptr -> nx_bsd_socket_received_packet_count_max) - { - /* Release the packet here, and tell NetX Duo the packet is 'consumed'. */ - nx_packet_release(packet_ptr); - - return 0; - } - - /* Add this packet to the end of the BSD raw receive queue. */ - (bsd_socket_ptr -> nx_bsd_socket_received_packet_tail) -> nx_packet_queue_next = packet_ptr; - bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; - - - /* Update our packet count. */ - bsd_socket_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count++; - } - - /* Notify any suspended threads waiting on this receive event. */ - nx_bsd_raw_receive_notify(ip_ptr, (UINT)(bsd_socket_ptr -> nx_bsd_socket_id)); - - return 0; - } - - }while(bsd_socket_ptr != nx_bsd_socket_raw_protocol_table[index]); - - /* Was a BSD socket with this protocol found? */ - if (bsd_socket_ptr == nx_bsd_socket_raw_protocol_table[index]) - { - /* No, let NetX Duo know it can discard the packet. */ - return 1; - } - - return(NX_SUCCESS); -} - -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_raw_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the NetX Duo callback function for raw socket receive */ -/* operation. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr NetX Duo IP instance */ -/* bsd_socket_index Index of the raw socket which */ -/* received the data packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Clear a socket ready list */ -/* FD_ISSET Check a socket is ready */ -/* FD_SET Set a socket to check */ -/* tx_event_flags_get Get events */ -/* tx_mutex_get Get protection */ -/* tx_mutex_put Release protection */ -/* tx_thread_identify Get current thread pointer */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID nx_bsd_raw_receive_notify(NX_IP *ip_ptr, UINT bsd_socket_index) -{ - NX_PARAMETER_NOT_USED(ip_ptr); - - nx_bsd_select_wakeup(bsd_socket_index, FDSET_READ); - -} - -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_raw_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves a packet from the BSD raw socket receive */ -/* queue. */ -/* */ -/* INPUT */ -/* */ -/* bsd_socket_ptr BSD raw socket */ -/* packet_ptr Pointer to retrieved packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Packet successfully retrieved */ -/* NX_NO_PACKET No packet on receive queue */ -/* NX_NOT_ENABLED Not enabled for raw packets */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* select Checks for receive packets */ -/* recv Checks the specified socket for */ -/* received packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT nx_bsd_raw_packet_receive(NX_BSD_SOCKET *bsd_socket_ptr, NX_PACKET **packet_ptr) -{ - - - /* Sanity check. Check this is indeed a raw socket. */ - if (!(bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET)) - { - /* Set the socket error. */ - set_errno(EPROTOTYPE); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_NOT_ENABLED); - } - - /* Verify this socket is enabled for raw packet processing. */ - if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_RAW_SOCKET) - { - - /* Are there any packets on the socket raw receive queue? */ - if (bsd_socket_ptr -> nx_bsd_socket_received_packet != NX_NULL) - { - - /* Yes, return a pointer to the packet at the top of the queue. */ - *packet_ptr = bsd_socket_ptr -> nx_bsd_socket_received_packet; - - /* Update the packet count. */ - bsd_socket_ptr -> nx_bsd_socket_received_byte_count -= (*packet_ptr) -> nx_packet_length; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count--; - - - /* Remove this packet from the receive queue and update queue packet pointers. */ - bsd_socket_ptr -> nx_bsd_socket_received_packet = (*packet_ptr) -> nx_packet_queue_next; - - /* If this was the last packet, set the tail pointer to NULL. */ - if (bsd_socket_ptr -> nx_bsd_socket_received_packet == NX_NULL) - { - bsd_socket_ptr -> nx_bsd_socket_received_packet_tail = NX_NULL; - bsd_socket_ptr -> nx_bsd_socket_received_byte_count = 0; - bsd_socket_ptr -> nx_bsd_socket_received_packet_count = 0; - } - } - else - { - - /* No packets on the queue. Return the NetX Duo status. This is an internal call, so no BSD socket error to report. */ - return NX_NO_PACKET; - } - } - else - { - return NX_NOT_ENABLED; - } - - return NX_SUCCESS; -} - -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_raw_packet_info_extract PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the source IP address and interface index */ -/* from the received packet. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to received raw packet*/ -/* address Pointer to sender IP address */ -/* interface_index Pointer to network index */ -/* packet received on */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* COPY_IPV6_ADDRESS Copy IPv6 address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT nx_bsd_raw_packet_info_extract(NX_PACKET *packet_ptr, NXD_ADDRESS *address, UINT *interface_index) -{ - -NX_INTERFACE *if_ptr = NX_NULL; - - -#ifndef NX_DISABLE_IPV4 - /* Determine what IP version the packet is. */ - if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) - { - - NX_IPV4_HEADER *ip_header_ptr; - - /* Set a pointer to the IPv4 header. */ - ip_header_ptr = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER)); - - /* Fill in the IP address information. */ - address -> nxd_ip_version = NX_IP_VERSION_V4; - address -> nxd_ip_address.v4 = ip_header_ptr -> nx_ip_header_source_ip; - - /* Pick up the packet interface. */ - if_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) - { - - NX_IPV6_HEADER *ipv6_header_ptr; - - ipv6_header_ptr = (NX_IPV6_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV6_HEADER)); - - /* Fill in the IPv6 address information. */ - address -> nxd_ip_version = NX_IP_VERSION_V6; - - /* Copy the IPv6 address. */ - address -> nxd_ip_address.v6[0] = ipv6_header_ptr -> nx_ip_header_source_ip[0]; - address -> nxd_ip_address.v6[1] = ipv6_header_ptr -> nx_ip_header_source_ip[1]; - address -> nxd_ip_address.v6[2] = ipv6_header_ptr -> nx_ip_header_source_ip[2]; - address -> nxd_ip_address.v6[3] = ipv6_header_ptr -> nx_ip_header_source_ip[3]; - - /* Pick up the packet interface. */ - if_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; - } -#endif - - /* The last piece of information is the packet interface. If the return pointer is NULL we are done! */ - if(interface_index == NX_NULL) - return(NX_SUCCESS); - - /* Search for interface index number. Initialize interface value as - invalid (0xFFFFFFFF). Once we find valid interface, we will update - the returned value. */ - *interface_index = 0xFFFFFFFF; - - if(if_ptr == NX_NULL) - { - /* No interface attached. Done here, and return success. */ - return(NX_SUCCESS); - } - - /* Compute the index by difference of the packet's interface from the primary interface, and dividing by the size. */ - *interface_index = if_ptr -> nx_interface_index; - - return(NX_SUCCESS); -} - -#endif /* NX_ENABLE_IP_RAW_PACKET_FILTER */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_set_socket_timed_wait_callback PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when a BSD TCP socket has closed. If the */ -/* BSD socket associated with the TCP socket is not enabled for */ -/* REUSEADDR, this function will put the BSD socket in the TIMED WAIT */ -/* state. */ -/* */ -/* When this time out expires, the BSD socket is removed from the TIME */ -/* WAIT State and available to the host application. */ -/* */ -/* Note: only sockets not enabled with REUSEADDR are placed in the WAIT*/ -/* STATE. All other BSD sockets are immediately available upon closing.*/ -/* */ -/* INPUT */ -/* */ -/* tcp_socket_ptr TCP socket state being closed */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_identify Identify socket owning thread */ -/* tx_mutex_get Obtain BSD mutex protection */ -/* tx_mutex_put Release BSD mutex protection */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID nx_bsd_socket_timed_wait_callback(NX_TCP_SOCKET *tcp_socket_ptr) -{ - NX_PARAMETER_NOT_USED(tcp_socket_ptr); - - /* Logic has been removed elsewhere but for compatibility with - NetX we leave this function stub. */ - - return; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_packet_data_extract_offset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies data from a NetX packet (or packet chain) into */ -/* the supplied user buffer. */ -/* */ -/* This basically defines the data extract service in the BSD source */ -/* code if it is not provided in the NetX or NetX Duo library already. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to the source packet */ -/* buffer_start Pointer to destination data area */ -/* buffer_length Size in bytes */ -/* bytes_copied Number of bytes copied */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifdef NX_BSD_INCLUDE_DATA_EXTRACT_OFFSET -UINT nx_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, ULONG buffer_length, ULONG *bytes_copied) -{ - -ULONG remaining_bytes; -UCHAR *source_ptr; -UCHAR *destination_ptr; -ULONG offset_bytes; -#ifndef NX_DISABLE_PACKET_CHAIN -ULONG packet_fragment_length; -#endif -ULONG bytes_to_copy; -NX_PACKET *working_packet_ptr; - - working_packet_ptr = packet_ptr; - - /* Check for an invalid offset or packet length. */ - if(offset >= working_packet_ptr -> nx_packet_length) - { - /* Note: A zero offset with a packet of zero length is ok. */ - if ((offset == 0) && (working_packet_ptr -> nx_packet_length == 0)) - { - *bytes_copied = 0; - return(NX_SUCCESS); - } - - /* Otherwise, this is an invalid offset or packet length. */ - return(NX_PACKET_OFFSET_ERROR); - } - - /* Initialize the source pointer to NULL. */ - source_ptr = NX_NULL; - - /* Traverse packet chain to offset. */ - offset_bytes = offset; -#ifndef NX_DISABLE_PACKET_CHAIN - while (working_packet_ptr) - { - packet_fragment_length = (working_packet_ptr -> nx_packet_append_ptr - working_packet_ptr -> nx_packet_prepend_ptr) ; - - /* Determine if we are at the offset location fragment in the packet chain */ - if (packet_fragment_length > offset_bytes) - { - /* Setup loop to copy from this packet. */ - source_ptr = working_packet_ptr -> nx_packet_prepend_ptr + offset_bytes; - - /* Yes, get out of this loop. */ - break; - } - - /* Decrement the remaining offset bytes*/ - offset_bytes = offset_bytes - packet_fragment_length ; - - /* Move to next packet. */ - working_packet_ptr = working_packet_ptr -> nx_packet_next; - } -#else /* NX_DISABLE_PACKET_CHAIN */ - - /* Setup loop to copy from this packet. */ - source_ptr = working_packet_ptr -> nx_packet_prepend_ptr + offset_bytes; - -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Check for a valid source pointer. */ - if (source_ptr == NX_NULL) - return(NX_PACKET_OFFSET_ERROR); - - /* Setup the destination pointer. */ - destination_ptr = buffer_start; - bytes_to_copy = (packet_ptr->nx_packet_length - offset); - - /* Pickup the amount of bytes to copy. */ - if( bytes_to_copy < buffer_length) - { - *bytes_copied = bytes_to_copy; /* the amount of bytes returned to the caller */ - remaining_bytes = bytes_to_copy; /* for use in the copy loop */ - } - else - { - *bytes_copied = buffer_length; - remaining_bytes = buffer_length; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Loop to copy bytes from packet(s). */ - while (working_packet_ptr && remaining_bytes) - { -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Calculate bytes to copy. */ - bytes_to_copy = working_packet_ptr -> nx_packet_append_ptr - source_ptr; - if(remaining_bytes < bytes_to_copy) - bytes_to_copy = remaining_bytes; - - /* Copy data from this packet. */ - memcpy(destination_ptr, source_ptr, bytes_to_copy); - - /* Update the pointers. */ - destination_ptr += bytes_to_copy; - remaining_bytes -= bytes_to_copy; - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Move to next packet. */ - working_packet_ptr = working_packet_ptr -> nx_packet_next; - - /* Check for a next packet. */ - if (working_packet_ptr) - { - - /* Setup new source pointer. */ - source_ptr = working_packet_ptr -> nx_packet_prepend_ptr; - } - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Return successful completion. */ - return(NX_SUCCESS); - -} -#endif /* NX_BSD_INCLUDE_DATA_EXTRACT_OFFSET */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the nx_bsd_socket_wait_timer expires. */ -/* It signals the BSD thread task to check and decrement the time */ -/* remaining on all sockets suspended in the wait state. */ -/* */ -/* INPUT */ -/* */ -/* info Timer thread data (not used) */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Sets the WAIT event in the BSD */ -/* event group */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifdef NX_BSD_TIMEOUT_PROCESS_IN_TIMER -VOID nx_bsd_timer_entry(ULONG info) -{ - nx_bsd_timeout_process(); -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_socket_set_inherited_settings PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function applies the socket options of the specified parent */ -/* (master) socket to the specified child (secondary) socket, if BSD */ -/* extended socket options are enabled. If they are not, this function */ -/* has no effect. */ -/* */ -/* INPUT */ -/* */ -/* master_sock_id Source of socket options */ -/* secondary_sock_id Socket inheriting options */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT nx_bsd_socket_set_inherited_settings(UINT master_sock_id, UINT secondary_sock_id) -{ - - /* Update the secondary socket options from the master socket. */ - if(nx_bsd_socket_array[master_sock_id].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING; - else - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING); - - if(nx_bsd_socket_array[master_sock_id].nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR) - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags |= NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR; - else - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_option_flags &= (ULONG)(~NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR); - -#ifdef NX_ENABLE_TCP_WINDOW_SCALING - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum = - nx_bsd_socket_array[master_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_rx_window_maximum; -#endif - - - /* Does this version of NetX Duo support TCP keep alive? */ - /* Is NetX Duo currently enabled for TCP keep alive? */ -#ifdef NX_ENABLE_TCP_KEEPALIVE - - nx_bsd_socket_array[secondary_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled = - nx_bsd_socket_array[master_sock_id].nx_bsd_socket_tcp_socket -> nx_tcp_socket_keepalive_enabled; - -#endif /* NX_ENABLE_TCP_KEEPALIVE */ - - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_isspace PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if the input character is white space */ -/* (ascii characters 0x09 - 0x0D or space (0x20). */ -/* */ -/* INPUT */ -/* */ -/* c Input character to examine */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Input character is white space */ -/* NX_FALSE Input character not white space*/ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_isspace(UCHAR c) -{ - - /* Check for horizontal, vertical tabs, carriage return or formfeed characters. */ - if ((c >= 0x09) && (c <= 0x0D)) - { - return NX_TRUE; - } - /* Check for a single space character*/ - else if (c == 20) - { - return NX_TRUE; - } - else - /* Not a white space character. */ - return NX_FALSE; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_islower PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if the input character is lower case */ -/* alphabetic character. */ -/* */ -/* INPUT */ -/* */ -/* c Input character to examine */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Input character is lower case */ -/* NX_FALSE Input character not lower case */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_islower(UCHAR c) -{ - - /* Check if characters is any character 'a' through 'z'. */ - if ((c >= 0x61) && (c <= 0x7A)) - { - - return NX_TRUE; - } - else - return NX_FALSE; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_isdigit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if the input character is a digit (0-9) */ -/* Does not include hex digits, (see nx_bsd_isxdigit). */ -/* */ -/* INPUT */ -/* */ -/* c Input character to examine */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Input character is a digit */ -/* NX_FALSE Input character not a digit */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_isdigit(UCHAR c) -{ - - /* Is the character any digit between 0 and 9? */ - if ((c >= 0x30) && (c <= 0x39)) - { - return NX_TRUE; - } - else - return NX_FALSE; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_isxdigit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if the input character is a digit (0-9) */ -/* or hex digit (A - F, or a-f). For decimal digits, see */ -/* nx_bsd_isdigit. */ -/* */ -/* INPUT */ -/* */ -/* c Input character to examine */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Input character is hex digit */ -/* NX_FALSE Input character not hex digit */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_isxdigit(UCHAR c) -{ - - /* Is the character any digit between 0 - 9? */ - if ((c >= 0x30) && (c <= 0x39)) - { - return NX_TRUE; - } - - /* Or is the character any base 16 digit A-F? */ - if ((c >= 0x41) && (c <= 0x46)) - { - return NX_TRUE; - } - - /* Lastly, check if character is any base 16 digit a-f? */ - if ((c >= 0x61) && (c <= 0x66)) - { - return NX_TRUE; - } - else - return NX_FALSE; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* set_errno PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the error on the current socket (thread) for */ -/* sockets enabled with BSD extended socket options. For sockets not */ -/* enabled with extended features, this function has no effect. */ -/* */ -/* INPUT */ -/* */ -/* tx_errno Socket error status code */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID set_errno(INT tx_errno) -{ - -TX_INTERRUPT_SAVE_AREA -TX_THREAD *current_thread_ptr; - - - TX_DISABLE - - current_thread_ptr = tx_thread_identify(); - current_thread_ptr -> bsd_errno = tx_errno; - - TX_RESTORE - - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* get_errno PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the error on the current socket (thread) for*/ -/* sockets enabled with BSD extended socket options. For sockets not */ -/* enabled with extended features, this function has no effect. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* Socket error status code */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT _nxd_get_errno() -{ - -TX_INTERRUPT_SAVE_AREA -INT val; -TX_THREAD *current_thread_ptr; - - - TX_DISABLE - - current_thread_ptr = tx_thread_identify(); - val = current_thread_ptr -> bsd_errno; - - TX_RESTORE - - return (val); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_select_wakeup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks the suspend list for a given socket being */ -/* readable or writeable. */ -/* */ -/* INPUT */ -/* */ -/* sock_id BSD socket ID */ -/* fd_sets The FD set to check */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* FD_ZERO Zeros out an FD Set */ -/* FD_SET Set a socket in the FDSET */ -/* TX_DISABLE Disable Interrupt */ -/* TX_RESTORE Enable Interrupt */ -/* tx_event_flags_set Set an event flag */ -/* */ -/* CALLED BY */ -/* */ -/* nx_bsd_timeout_process */ -/* nx_bsd_tcp_receive_notify */ -/* nx_bsd_tcp_establish_notify */ -/* nx_bsd_tcp_socket_disconnect_notify */ -/* nx_bsd_raw_receive_notify */ -/* nx_bsd_udp_packet_received */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_select_wakeup(UINT sock_id, UINT fd_sets) -{ -TX_INTERRUPT_SAVE_AREA -fd_set local_fd; -TX_THREAD *suspended_thread; -ULONG suspended_count; -ULONG original_suspended_count; -NX_BSD_SOCKET_SUSPEND *suspend_info; - - - /* At this point the thread should NOT own the IP mutex, and it must own the - BSD mutex. */ - - - FD_ZERO(&local_fd); - FD_SET((INT)sock_id + NX_BSD_SOCKFD_START, &local_fd); - - /* Disable interrupts temporarily. */ - TX_DISABLE - - /* Setup the head pointer and the count. */ - suspended_thread = nx_bsd_events.tx_event_flags_group_suspension_list; - suspended_count = nx_bsd_events.tx_event_flags_group_suspended_count; - - /* Save the original suspended count. */ - original_suspended_count = suspended_count; - - /* Loop to examine all threads suspended on select via the BSD event flag group. */ - while (suspended_count--) - { - - /* Determine if this thread is suspended on select. */ - if (suspended_thread -> tx_thread_suspend_info == NX_BSD_SELECT_EVENT) - { - - /* Yes, this thread is suspended on select. */ - - /* Pickup a pointer to its select suspend structure. */ - suspend_info = (NX_BSD_SOCKET_SUSPEND *) suspended_thread -> tx_thread_additional_suspend_info; - - /* Now determine if this thread was waiting for this socket. */ - if ((fd_sets & FDSET_READ) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set))) - { - - /* Copy the local fd over so that the return shows the receive socket. */ - suspend_info -> nx_bsd_socket_suspend_read_fd_set = local_fd; - - /* Adjust the suspension type so that the event flag set below will wakeup the thread - selecting. */ - suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; - } - - /* Now determine if this thread was waiting for this socket. */ - if ((fd_sets & FDSET_WRITE) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set))) - { - - /* Copy the local fd over so that the return shows the receive socket. */ - suspend_info -> nx_bsd_socket_suspend_write_fd_set = local_fd; - - /* Adjust the suspension type so that the event flag set below will wakeup the thread - selecting. */ - suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; - } - - /* Now determine if this thread was waiting for this socket. */ - if ((fd_sets & FDSET_EXCEPTION) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set))) - { - - /* Copy the local fd over so that the return shows the receive socket. */ - suspend_info -> nx_bsd_socket_suspend_exception_fd_set = local_fd; - - /* Adjust the suspension type so that the event flag set below will wakeup the thread - selecting. */ - suspended_thread -> tx_thread_suspend_info = NX_BSD_RECEIVE_EVENT; - } - - /* Clear FD that is not set. */ - if (suspended_thread -> tx_thread_suspend_info == NX_BSD_RECEIVE_EVENT) - { - if (!(fd_sets & FDSET_READ) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set))) - { - - /* Clear read FD. */ - FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_read_fd_set); - } - - if (!(fd_sets & FDSET_WRITE) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set))) - { - - /* Clear write FD. */ - FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_write_fd_set); - } - - if (!(fd_sets & FDSET_EXCEPTION) && (FD_ISSET((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set))) - { - - /* Clear exception FD. */ - FD_CLR((INT)sock_id + NX_BSD_SOCKFD_START, &suspend_info -> nx_bsd_socket_suspend_exception_fd_set); - } - } - } - - /* Now move to the next event. */ - suspended_thread = suspended_thread -> tx_thread_suspended_next; - - /* Restore interrupts. */ - TX_RESTORE - - /* Disable interrupts again. */ - TX_DISABLE - - /* Determine if something changes on the suspension list... this could have happened if there - was a timeout or a wait abort on the thread. */ - if (original_suspended_count != nx_bsd_events.tx_event_flags_group_suspended_count) - { - - /* Something changed, so simply restart the search. */ - - /* Setup the head pointer and the count. */ - suspended_thread = nx_bsd_events.tx_event_flags_group_suspension_list; - suspended_count = nx_bsd_events.tx_event_flags_group_suspended_count; - - /* Save the original suspended count. */ - original_suspended_count = suspended_count; - } - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */ - tx_event_flags_set(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR); - - return; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_set_error_code PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is sets the BSD error code based on NetX Duo API return code */ -/* */ -/* INPUT */ -/* */ -/* bsd_socket_ptr Pointer to the BSD socket */ -/* status_code NetX Duo API return code */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* set_errno Sets the BSD errno */ -/* */ -/* CALLED BY */ -/* */ -/* connect */ -/* bind */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_set_error_code(NX_BSD_SOCKET *bsd_socket_ptr, UINT status_code) -{ - switch(status_code) - { - case NX_NOT_CLOSED: - /* TCP connection is not closed state. */ - set_errno(EISCONN); - break; - - case NX_PTR_ERROR: - case NX_INVALID_PORT: - /* Invalid arguement. */ - set_errno(EINVAL); - break; - - case NX_MAX_LISTEN: - set_errno(ENOBUFS); - break; - - case NX_PORT_UNAVAILABLE: - case NX_NO_FREE_PORTS: - set_errno(EADDRNOTAVAIL); - break; - - case NX_ALREADY_BOUND: - set_errno(EINVAL); - break; - - case NX_WAIT_ABORTED: - set_errno(ETIMEDOUT); - break; - - case NX_NOT_CONNECTED: - /* NX TCP connect service may return NX_NOT_CONNECTED if the timeout is WAIT_FOREVER. */ - set_errno(ECONNREFUSED); - break; - - case NX_IN_PROGRESS: - /* The NetX "in progress" status is the equivalent of the non blocking BSD socket waiting - to connect. This can only happen if timeout is NX_NO_WAIT.*/ - if (bsd_socket_ptr -> nx_bsd_socket_option_flags & NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING) - { - bsd_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; - set_errno(EINPROGRESS); - } - else - set_errno(EINTR); - break; - - case NX_INVALID_INTERFACE: - case NX_IP_ADDRESS_ERROR: - set_errno(ENETUNREACH); - break; - - case NX_NOT_ENABLED: - set_errno(EPROTONOSUPPORT); - break; - - case NX_NOT_BOUND: - case NX_DUPLICATE_LISTEN: - default: - set_errno(EINVAL); - break; - } - - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_udp_packet_received PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is executed as part of the UDP packet receive callback */ -/* function. */ -/* */ -/* This routine puts an incoming UDP packet into the appropriate */ -/* UDP BSD socket, taking into consideration that multiple BSD sockets */ -/* may be mapped to the same NetX Duo UDP socket. */ -/* */ -/* INPUT */ -/* */ -/* sockID The BSD socket descriptor */ -/* packet_ptr The incoming UDP packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release a packet that is not */ -/* received by any sockets. */ -/* nx_bsd_select_wakeup Wake up any asychronous */ -/* receive call */ -/* */ -/* CALLED BY */ -/* */ -/* nx_bsd_udp_receive_notify */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_udp_packet_received(INT sockID, NX_PACKET *packet_ptr) -{ - -NX_BSD_SOCKET *bsd_ptr; -ULONG addr_family; -NX_BSD_SOCKET *exact_match = NX_NULL; -NX_BSD_SOCKET *receiver_match = NX_NULL; -NX_BSD_SOCKET *wildcard_match = NX_NULL; -NX_INTERFACE *interface_ptr; - - - bsd_ptr = &nx_bsd_socket_array[sockID]; - -#ifndef NX_DISABLE_IPV4 - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) - { - addr_family = AF_INET; - interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) - { - addr_family = AF_INET6; - interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; - } - else -#endif /* FEATURE_NX_IPV6 */ - { - - /* Invalid version. Release the packet and return. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Start the search for the BSD socket we received this packet on from current input socket ID. */ - bsd_ptr = &nx_bsd_socket_array[sockID]; - - do - { - /* Skip the sockets with different address family. */ - if(bsd_ptr -> nx_bsd_socket_family == addr_family) - { - /* bsd_ptr points to a related UDP socket. */ - if(bsd_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - { - wildcard_match = bsd_ptr; - } - else if(((ULONG)(interface_ptr) == bsd_ptr -> nx_bsd_socket_local_bind_interface) || - ((ULONG)(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr) == bsd_ptr -> nx_bsd_socket_local_bind_interface)) - { - - receiver_match = bsd_ptr; - } - else - { - - /* Does not match the local interface. Move to the next entry. */ - bsd_ptr = bsd_ptr -> nx_bsd_socket_next; - continue; - } - - /* At this point this socket is either a wildcard match or a receiver match. */ - - /* If the socket is connected, we check for sender's address match. */ - if(bsd_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) - { - - nxd_udp_source_extract(packet_ptr, - &bsd_ptr -> nx_bsd_socket_source_ip_address, - (UINT *)&bsd_ptr -> nx_bsd_socket_source_port); - -#ifndef NX_DISABLE_IPV4 - if(bsd_ptr -> nx_bsd_socket_family == AF_INET) - { - - /* Now we can check for an exact match based on sender IP address and port. */ - if((bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v4 == - bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v4) && - (bsd_ptr -> nx_bsd_socket_source_port == - bsd_ptr -> nx_bsd_socket_peer_port)) - { - exact_match = bsd_ptr; - } - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(bsd_ptr -> nx_bsd_socket_family == AF_INET6) - { - - /* Now we can check for an exact match based on sender IP address and port. */ - if((bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[0] == - bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[0]) && - (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[1] == - bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[1]) && - (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[2] == - bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[2]) && - (bsd_ptr -> nx_bsd_socket_source_ip_address.nxd_ip_address.v6[3] == - bsd_ptr -> nx_bsd_socket_peer_ip.nxd_ip_address.v6[3]) && - (bsd_ptr -> nx_bsd_socket_source_port == - bsd_ptr -> nx_bsd_socket_peer_port)) - { - - exact_match = bsd_ptr; - } - } -#endif - - if(exact_match != NX_NULL) - break; - - if(receiver_match != NX_NULL) - receiver_match = NX_NULL; - - if(wildcard_match != NX_NULL) - wildcard_match = NX_NULL; - } - } - - /* Move to the next entry. */ - bsd_ptr = bsd_ptr -> nx_bsd_socket_next; - - }while(bsd_ptr != &nx_bsd_socket_array[sockID]); - - /* Let bsd_ptr point to the matched socket. */ - if(exact_match != NX_NULL) - bsd_ptr = exact_match; - else if(receiver_match != NX_NULL) - bsd_ptr = receiver_match; - else if(wildcard_match != NX_NULL) - bsd_ptr = wildcard_match; - else - { - /* This packet is not for any of the BSD sockets. Release the packet and we are done. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Move the packet to the socket internal receive queue. */ - - if(bsd_ptr -> nx_bsd_socket_received_byte_count_max && - (bsd_ptr -> nx_bsd_socket_received_byte_count >= bsd_ptr -> nx_bsd_socket_received_byte_count_max)) - { - - /* Receive buffer is full. Release the packet and return. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Drop the packet if the receive queue exceeds max depth.*/ - if(bsd_ptr -> nx_bsd_socket_received_packet_count >= - bsd_ptr -> nx_bsd_socket_received_packet_count_max) - { - - /* Receive buffer is full. Release the packet and return. */ - nx_packet_release(packet_ptr); - - return; - } - if(bsd_ptr -> nx_bsd_socket_received_packet) - { - bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; - } - else - { - - bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; - } - - bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - bsd_ptr -> nx_bsd_socket_received_packet_count++; - - nx_bsd_select_wakeup((UINT)(bsd_ptr -> nx_bsd_socket_id), FDSET_READ); - - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_syn_received_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if the socket has a connection request. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Socket receiving the packet */ -/* packet_ptr Pointer to the received packet */ -/* */ -/* OUTPUT */ -/* */ -/* 0 Not a valid match */ -/* 1 Valid match found */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT nx_bsd_tcp_syn_received_notify(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr) -{ - -UINT bsd_socket_index; -INT i; -INT sockID_find; -ULONG addr_family; -INT search_index; -INT receiver_match = NX_BSD_MAX_SOCKETS; -INT wildcard_match = NX_BSD_MAX_SOCKETS; -NX_BSD_SOCKET *bsd_socket_ptr; -NX_INTERFACE *interface_ptr; - - - bsd_socket_index = (UINT)socket_ptr -> nx_tcp_socket_reserved_ptr; - - if(bsd_socket_index >= NX_BSD_MAX_SOCKETS) - { - - /* Bad socket index... simply return! */ - return(NX_FALSE); - } - - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; - -#ifndef NX_DISABLE_IPV4 - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) - { - addr_family = AF_INET; - } - else -#endif /* NX_DISABLE_IPV4 */ - { - addr_family = AF_INET6; - } - - /* Start the search at the position of the input socket. */ - search_index = (INT)bsd_socket_index; - - /* Get the packet interface. */ -#ifdef FEATURE_NX_IPV6 - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) -#endif /* FEATURE_NX_IPV6 */ - interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; -#ifdef FEATURE_NX_IPV6 - else if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) - interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; - else - return (NX_FALSE); -#endif /* FEATURE_NX_IPV6 */ - - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - bsd_socket_ptr = &nx_bsd_socket_array[search_index]; - - /* Skip the unrelated sockets. */ - if((bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && - (bsd_socket_ptr -> nx_bsd_socket_family == addr_family) && - ((bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CONNECTED) == 0) && - (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && - (bsd_socket_ptr -> nx_bsd_socket_local_port == socket_ptr -> nx_tcp_socket_port) && - (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE)) - { - - if(bsd_socket_ptr -> nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) - { - - wildcard_match = search_index; - } - else if(((ULONG)(interface_ptr) == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface) || - ((ULONG)(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr) == bsd_socket_ptr -> nx_bsd_socket_local_bind_interface)) - { - - receiver_match = search_index; - - /* Found a receiver match, which is a tighter match than the wildcard match. - So we can get out of the loop. */ - break; - } - } - - /* Move to the next entry. */ - search_index++; - - if(search_index >= NX_BSD_MAX_SOCKETS) - search_index = 0; - } - - if(receiver_match != NX_BSD_MAX_SOCKETS) - sockID_find = receiver_match; - else if(wildcard_match != NX_BSD_MAX_SOCKETS) - sockID_find = wildcard_match; - else - { - - /* No match found. Simply return .*/ - return(NX_FALSE); - } - - /* Found the listening master socket. Update the master socket ID of the input socket. */ - nx_bsd_socket_array[bsd_socket_index].nx_bsd_socket_union_id.nx_bsd_socket_master_socket_id = sockID_find; - - return(NX_TRUE); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_create_listen_socket PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine sets up the input socket as a listen socket. */ -/* */ -/* INPUT */ -/* */ -/* master_sockid Index to the master socket */ -/* backlog Size of the socket listen queue*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SOC_OK Successfully set up socket */ -/* NX_SOC_ERROR Error setting up the socket */ -/* */ -/* CALLS */ -/* */ -/* socket Allocate a BSD socket */ -/* nx_bsd_socket_set_inherited_settings Apply master socket options */ -/* nx_tcp_server_socket_listen Enable the socket to listen **/ -/* nx_tcp_server_socket_accept Wait for connection request */ -/* nx_tcp_server_socket_relisten Reset the socket to listen */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT nx_bsd_tcp_create_listen_socket(INT master_sockid, INT backlog) -{ - -INT i; -UINT status; -UINT local_port; -NX_BSD_SOCKET *master_socket_ptr = &nx_bsd_socket_array[master_sockid]; -NX_BSD_SOCKET *bsd_secondary_socket; -NX_BSD_SOCKET *bsd_socket_ptr; -NX_TCP_SOCKET *sec_socket_ptr; -INT secondary_sockID = NX_BSD_MAX_SOCKETS; - - - /* This is called from BSD internal code so the BSD mutex is obtained. */ - - /* Search through the sockets to find a master socket that is listening on the same port. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - /* Skip the entry if it is not master socket */ - if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) == 0) - continue; - - /* Skip the current master socket. */ - if(i == master_sockid) - continue; - - /* Skip the entry if it is not TCP */ - if(nx_bsd_socket_array[i].nx_bsd_socket_protocol != NX_PROTOCOL_TCP) - continue; - - /* Skip the entry if the the secondary socket id field is not valid. */ - if(nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id == NX_BSD_MAX_SOCKETS) - continue; - - /* Check if another master socket is listening on the same port. */ - if((nx_bsd_socket_array[i].nx_bsd_socket_local_port == master_socket_ptr -> nx_bsd_socket_local_port) && - (nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id - != (master_socket_ptr -> nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id)) && - (nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN)) - { - - /* This one is. Point to the same secondary socket. */ - (master_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = - nx_bsd_socket_array[i].nx_bsd_socket_union_id.nx_bsd_socket_secondary_socket_id; - master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; - master_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); - master_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; - master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; - - return(NX_SOC_OK); - } - } - - /* Did not find an existing master socket for listening. */ - - /* Check for a valid backlog. */ - if(backlog) - { - - /* Check backlog argument is within limits. */ - if (backlog > NX_BSD_MAX_LISTEN_BACKLOG) - { - - /* Error, invalid backlog. */ - /* Set the socket error if extended socket options enabled. */ - set_errno(ENOBUFS); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - } - - /* Now create a dedicated secondary socket to listen for next client connection. */ - secondary_sockID = socket((INT)(master_socket_ptr -> nx_bsd_socket_family), SOCK_STREAM, IPPROTO_TCP); - - /* Determine if there was an error. */ - if (secondary_sockID == NX_SOC_ERROR) - { - - /* Secondary socket create failed. Note: The socket thread error is set in socket(). */ - set_errno(ENOMEM); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Adjust the secondary socket ID. */ - secondary_sockID = secondary_sockID - NX_BSD_SOCKFD_START; - - /* The master server socket will never connect to a client! For each successful - client connection there will be a new secondary server socket and - each such socket is associated with this master server socket. This is - the difference between NetX and BSD sockets. The NetX listen() service is used - with this secondary server socket. */ - - /* Set a pointer to the secondary socket. */ - bsd_secondary_socket = &nx_bsd_socket_array[secondary_sockID]; - - /* Apply the master socket options to the secondary socket. */ - nx_bsd_socket_set_inherited_settings((UINT)master_sockid, (UINT)secondary_sockID); - - local_port = master_socket_ptr -> nx_bsd_socket_local_port; - - /* Invalidate the secondary master socket ID. */ - (bsd_secondary_socket -> nx_bsd_socket_union_id).nx_bsd_socket_master_socket_id = NX_BSD_MAX_SOCKETS; - - /* Now call listen for the secondary server socket. */ - if(backlog) - status = nx_tcp_server_socket_listen(nx_bsd_default_ip, local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket, (UINT)backlog, NX_NULL); - else - { - - /* Since a zero backlog is specified, this secondary socket needs to share with another master socket. */ - bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_port = local_port; - - /* Check if a listen request is queued up for this socket. */ - nx_bsd_tcp_pending_connection(local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket); - - status = nx_tcp_server_socket_relisten(nx_bsd_default_ip, local_port, bsd_secondary_socket -> nx_bsd_socket_tcp_socket); - } - - /* Check for an error. */ - if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - - /* Error, listen or relisten failed. */ - - /* Set the socket error depending on the NetX error status returned. */ - nx_bsd_set_error_code(master_socket_ptr, status); - - /* Return error code. */ - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Now mark this as a master server socket listening to client connections. */ - master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; - master_socket_ptr -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET); - master_socket_ptr -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_client_type = NX_FALSE; - master_socket_ptr -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_MASTER_SOCKET; - - /* This is a master socket. So we use the nx_bsd_socket_master_socket_id field to - record the secondary socket that is doing the real listen/accept work. */ - (master_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = secondary_sockID; - - /* Mark the secondary server socket as assigned to this master server socket. */ - bsd_secondary_socket -> nx_bsd_socket_status_flags &= (ULONG)(~NX_BSD_SOCKET_ACCEPTING); - bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET; - bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_ENABLE_LISTEN; - bsd_secondary_socket -> nx_bsd_socket_local_port = (USHORT)local_port; - - /* If the master server socket is marked as non-blocking, we need to - start the NetX accept process here. */ - - sec_socket_ptr = bsd_secondary_socket -> nx_bsd_socket_tcp_socket; - - /* Allow accept from remote. */ - nx_tcp_server_socket_accept(sec_socket_ptr, 0); - - /* Set the master socket of other BSD TCP sockets that bind to the same port to the same secondary socket. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - - bsd_socket_ptr = &nx_bsd_socket_array[i]; - - if((bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) && - (!(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_CLIENT)) && - (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_SERVER_MASTER_SOCKET) && - (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_ENABLE_LISTEN) && - (bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_BOUND) && - (bsd_socket_ptr -> nx_bsd_socket_local_port == local_port)) - { - - (bsd_socket_ptr -> nx_bsd_socket_union_id).nx_bsd_socket_secondary_socket_id = secondary_sockID; - } - } - - /* Check the relisten/listen status. */ - if(status == NX_CONNECTION_PENDING) - { - - /* Set the connection pending flag. */ - bsd_secondary_socket -> nx_bsd_socket_status_flags |= NX_BSD_SOCKET_CONNECTION_INPROGRESS; - - } - - return(NX_SOC_OK); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_tcp_pending_connection PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine checks if the BSD TCP socket has a listen request */ -/* queued up on in the specified port. */ -/* */ -/* INPUT */ -/* */ -/* local_port Listening port */ -/* socket_ptr Socket to check */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_tcp_syn_received_notify Match connection request */ -/* (packet) to input socket */ -/* nx_packet_receive Release packet to packet pool */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID nx_bsd_tcp_pending_connection(UINT local_port, NX_TCP_SOCKET *socket_ptr) -{ - -struct NX_TCP_LISTEN_STRUCT *listen_ptr; -NX_PACKET *packet_ptr; -NX_TCP_HEADER *tcp_header_ptr; -UINT ret; - - - listen_ptr = nx_bsd_default_ip -> nx_ip_tcp_active_listen_requests; - - if(listen_ptr) - { - - do - { - - if((listen_ptr -> nx_tcp_listen_port == local_port) && - (listen_ptr -> nx_tcp_listen_queue_current)) - { - - do - { - - packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; - - tcp_header_ptr = (NX_TCP_HEADER*)packet_ptr -> nx_packet_prepend_ptr; - - if(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) - { - - ret = nx_bsd_tcp_syn_received_notify(socket_ptr, packet_ptr); - - /* Yes. We are done. */ - if(ret == NX_TRUE) - { - - return; - } - - listen_ptr -> nx_tcp_listen_queue_head = packet_ptr -> nx_packet_queue_next; - - if(packet_ptr == listen_ptr -> nx_tcp_listen_queue_tail) - { - listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; - } - - listen_ptr -> nx_tcp_listen_queue_current--; - - nx_packet_release(packet_ptr); - - } - } while(listen_ptr -> nx_tcp_listen_queue_head); - } - - listen_ptr = listen_ptr -> nx_tcp_listen_next; - - }while(listen_ptr != nx_bsd_default_ip -> nx_ip_tcp_active_listen_requests); - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_find_interface_by_source_addr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the interface index value of a given IPv4 or */ -/* IPv6 source address. */ -/* */ -/* INPUT */ -/* */ -/* addr_family Address Family */ -/* ip_addr Pointer to an array of IPv4 */ -/* or IPv6 address */ -/* */ -/* OUTPUT */ -/* */ -/* Index value */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* nx_bsd_send_internal */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT nx_bsd_find_interface_by_source_addr(UINT addr_family, ULONG* ip_addr) -{ -INT i; -#ifndef NX_DISABLE_IPV4 -ULONG ipv4_addr; -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 -ULONG ipv6_addr[4]; -#endif - -#ifndef NX_DISABLE_IPV4 - if(addr_family == AF_INET) - { - ipv4_addr = *ip_addr; - NX_CHANGE_ULONG_ENDIAN(ipv4_addr); - - for(i = 0; i < NX_MAX_IP_INTERFACES; i++) - { - if((nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_valid) && - (nx_bsd_default_ip -> nx_ip_interface[i].nx_interface_ip_address == ipv4_addr)) - return i; - } - } -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if(addr_family == AF_INET6) - { - ipv6_addr[0] = *(ip_addr); - ipv6_addr[1] = *(ip_addr + 1); - ipv6_addr[2] = *(ip_addr + 2); - ipv6_addr[3] = *(ip_addr + 3); - NX_IPV6_ADDRESS_CHANGE_ENDIAN(ipv6_addr); - - for(i = 0; i < NX_MAX_IPV6_ADDRESSES; i++) - { - - if((nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address_valid) && - (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address_attached -> nx_interface_valid) && - (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[0] == ipv6_addr[0]) && - (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[1] == ipv6_addr[1]) && - (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[2] == ipv6_addr[2]) && - (nx_bsd_default_ip -> nx_ipv6_address[i].nxd_ipv6_address[3] == ipv6_addr[3])) - return i; - } - } -#endif - - return((INT)(NX_BSD_LOCAL_IF_INADDR_ANY)); - -} - - -#ifndef NX_DISABLE_IPV4 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_bsd_ipv4_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes the IP header checksum and updates that into */ -/* the ip header ,which is assumed to be already prepended in the */ -/* input packet buffer, and forwards it to the driver directly. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet to send */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ip_checksum_compute Compute IP checksum */ -/* (_nx_arp_entry_allocate) ARP entry allocate service */ -/* (_nx_arp_packet_send) Send an ARP packet */ -/* _nx_ip_packet_deferred_receive Receive loopback packet */ -/* _nx_packet_copy Copy packet to input packet */ -/* _nx_packet_transmit_release Release transmit packet */ -/* (nx_ip_fragment_processing) Fragment processing */ -/* (ip_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* nx_bsd_send_internal */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_bsd_ipv4_packet_send(NX_PACKET *packet_ptr) -{ - -TX_INTERRUPT_SAVE_AREA -NX_IP_DRIVER driver_request; -NX_IPV4_HEADER *ip_header_ptr; -#ifndef NX_DISABLE_IP_TX_CHECKSUM -ULONG checksum; -ULONG val; -#endif -UINT index; -NX_ARP *arp_ptr; -NX_PACKET *last_packet; -NX_PACKET *remove_packet; -UINT queued_count; -NX_PACKET *packet_copy; -ULONG network_mask; -ULONG network; -NX_IP * ip_ptr; -ULONG destination_ip; - - ip_ptr = nx_bsd_default_ip; -#ifndef NX_DISABLE_IP_INFO - - /* Increment the total send requests counter. */ - ip_ptr -> nx_ip_total_packet_send_requests++; -#endif - - - /* Setup the IP header pointer. */ - ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; - - destination_ip = ip_header_ptr -> nx_ip_header_destination_ip; - - /* Swap the destination address to host byte order.*/ - NX_CHANGE_ULONG_ENDIAN(destination_ip); - -#ifndef NX_DISABLE_IP_TX_CHECKSUM - checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4, - /* Length is the size of IP header, including options */ - (UINT)((*(UCHAR*)ip_header_ptr & 0xf) << 2), - /* IPv4 header checksum does not use src/dest addresses */ - NULL, NULL); - - val = (ULONG)(~checksum); - val = val & NX_LOWER_16_MASK; - - /* Convert to network byte order. */ - NX_CHANGE_ULONG_ENDIAN(val); - - /* Now store the checksum in the IP header. */ - ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val; - -#endif - - /* Determine if physical mapping is needed by the link driver. */ - if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_address_mapping_needed ) - { - - - network_mask = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network_mask; - network = packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_network; - - /* Determine whether or not the destination address is out of this local network. */ - if (((destination_ip & network_mask) != network) || - ((destination_ip & ~network_mask) == ~network_mask) || - (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)) - { - - /* We have an out-of-network destination IP address, check for a variety - of out-of-network destinations. */ - - /* Determine if an IP limited or directed broadcast is requested. */ - if ((destination_ip == NX_IP_LIMITED_BROADCAST) || - (((destination_ip & network_mask) == network) && - ((destination_ip & ~network_mask) == ~network_mask))) - { - - /* Build the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_BROADCAST; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_physical_address_msw = 0xFFFFUL; - driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFFUL; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) - { - - /* Fragmentation is needed, call the fragment routine if available. */ - if (ip_ptr -> nx_ip_fragment_processing) - { - - /* Call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - } - - /* In either case, this packet send is complete, just return. */ - return; - } -#endif - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Broadcast packet. */ - (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); - - return; - } - - /* Determine if we have a loopback address. */ - else if ((((destination_ip >= NX_IP_LOOPBACK_FIRST) && - (destination_ip <= NX_IP_LOOPBACK_LAST))) || - (destination_ip == ip_ptr -> nx_ip_interface[0].nx_interface_ip_address)) - { - - /* Yes, we have an internal loopback address. */ - - /* Copy the packet so it can be enqueued properly by the receive - processing. */ - if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Send the packet to this IP's receive processing like it came in from the - driver. */ - _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); - } -#ifndef NX_DISABLE_IP_INFO - else - { - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - } -#endif - - /* Release the transmit packet. */ - _nx_packet_transmit_release(packet_ptr); - return; - } - - /* Determine if we have a class D multicast address. */ - else if ((destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) - { - - /* Yes, we have a class D multicast address. Derive the physical mapping from - the class D address. */ - driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER; - driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (destination_ip & NX_IP_MULTICAST_MASK); - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - - /* Determine if the group address has been joined in this IP instance. */ - index = 0; - while (index < NX_MAX_MULTICAST_GROUPS) - { - - /* Determine if the destination address matches the requested address. */ - if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_join_list == destination_ip) - { - - /* Yes, break the loop! */ - break; - } - - /* Increment the join list index. */ - index++; - } - - /* Determine if the group was joined by this IP instance. */ - if (index < NX_MAX_MULTICAST_GROUPS) - { - - /* Determine if the group has loopback enabled. */ - if (ip_ptr -> nx_ipv4_multicast_entry[index].nx_ipv4_multicast_loopback_enable) - { - - /* Yes, loopback is enabled! */ - - /* Copy the packet so we can send it via loopback. */ - if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Packet copy was successful. Send the packet to this IP's receive processing like it came in from the - driver. */ - _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); - } -#ifndef NX_DISABLE_IP_INFO - else - { - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - } -#endif - } - } - - /* Build the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) - { - - /* Fragmentation is needed, call the fragment routine if available. */ - if (ip_ptr -> nx_ip_fragment_processing) - { - - /* Call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - } - - /* In either case, this packet send is complete, just return. */ - return; - } -#endif - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Send the IP packet out on the network via the attached driver. */ - (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); - - /* Return to caller. */ - return; - } - - /* Use default gateway. */ - else - { - - /* We have an out-of-network destination IP address, check to see if a - Gateway IP address has been specified. */ - if (ip_ptr -> nx_ip_gateway_address) - { - - /* Remap the destination IP address to the Gateway IP address. The ARP - processing below will handle getting the physical address for the - Gateway. */ - destination_ip = ip_ptr -> nx_ip_gateway_address; - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the number of no route errors. */ - ip_ptr -> nx_ip_transmit_no_route_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - - /* In either case, this packet send is complete, just return. */ - return; - } - } - } - - /* Yes, look into the ARP Routing Table to derive the physical address. */ - - /* Calculate the hash index for the destination IP address. */ - index = (UINT) ((destination_ip + (destination_ip >> 8)) & NX_ARP_TABLE_MASK); - - /* Disable interrupts temporarily. */ - TX_DISABLE - - /* Determine if there is an entry for this IP address. */ - arp_ptr = ip_ptr -> nx_ip_arp_table[index]; - - /* Determine if this arp entry matches the destination IP address. */ - if ((arp_ptr) && (arp_ptr -> nx_arp_ip_address == destination_ip)) - { - - /* Yes, we have an existing ARP mapping entry. */ - - /* Determine if there is a physical address. */ - if (arp_ptr -> nx_arp_physical_address_msw | arp_ptr -> nx_arp_physical_address_lsw) - { - - /* Yes, we have a physical mapping. Copy the physical address into the driver - request structure. */ - driver_request.nx_ip_driver_physical_address_msw = arp_ptr -> nx_arp_physical_address_msw; - driver_request.nx_ip_driver_physical_address_lsw = arp_ptr -> nx_arp_physical_address_lsw; - - /* Restore interrupts. */ - TX_RESTORE - - /* Build the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) - { - - /* Fragmentation is needed, call the fragment routine if available. */ - if (ip_ptr -> nx_ip_fragment_processing) - { - - /* Call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - } - - /* In either case, this packet send is complete, just return. */ - return; - } -#endif - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Send the IP packet out on the network via the attached driver. */ - (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); - - /* Return to caller. */ - return; - } - else - { - - /* Ensure the current packet's queue next pointer to NULL. */ - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Determine if the queue is empty. */ - if (arp_ptr -> nx_arp_packets_waiting == NX_NULL) - { - - /* Yes, we have an empty ARP packet queue. Simply place the - packet at the head of the list. */ - arp_ptr -> nx_arp_packets_waiting = packet_ptr; - - /* Restore interrupts. */ - TX_RESTORE - } - else - { - - /* Determine how many packets are on the ARP entry's packet - queue and remember the last packet in the queue. We know - there is at least one on the queue and another that is - going to be queued. */ - last_packet = arp_ptr -> nx_arp_packets_waiting; - queued_count = 0; - while (last_packet -> nx_packet_queue_next) - { - - /* Increment the queued count. */ - queued_count++; - - /* Move to the next packet in the queue. */ - last_packet = last_packet -> nx_packet_queue_next; - } - - /* Place the packet at the end of the list. */ - last_packet -> nx_packet_queue_next = packet_ptr; - - /* Default the remove packet pointer to NULL. */ - remove_packet = NX_NULL; - - /* Determine if the packets queued has exceeded the queue - depth. */ - if (queued_count >= NX_ARP_MAX_QUEUE_DEPTH) - { - - /* Save the packet pointer at the head of the list. */ - remove_packet = arp_ptr -> nx_arp_packets_waiting; - - /* Remove the packet from the ARP queue. */ - arp_ptr -> nx_arp_packets_waiting = remove_packet -> nx_packet_queue_next; - - /* Clear the remove packet queue next pointer. */ - remove_packet -> nx_packet_queue_next = NX_NULL; - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Determine if there is a packet to remove. */ - if (remove_packet) - { - - /* Yes, the packet queue depth for this ARP entry was exceeded - so release the packet that was removed from the queue. */ - _nx_packet_transmit_release(remove_packet); - } - } - - /* Return to caller. */ - return; - } - } - else - { - - /* At this point, we need to search the ARP list for a match for the - destination IP. */ - - /* First, restore interrupts. */ - TX_RESTORE - - /* Pickup the first ARP entry. */ - arp_ptr = ip_ptr -> nx_ip_arp_table[index]; - - /* Loop to look for an ARP match. */ - while (arp_ptr) - { - - /* Check for an IP match. */ - if (arp_ptr -> nx_arp_ip_address == destination_ip) - { - - /* Yes, we found a match. Get out of the loop! */ - break; - } - - /* Move to the next active ARP entry. */ - arp_ptr = arp_ptr -> nx_arp_active_next; - - /* Determine if we are at the end of the ARP list. */ - if (arp_ptr == ip_ptr -> nx_ip_arp_table[index]) - { - /* Clear the ARP pointer. */ - arp_ptr = NX_NULL; - break; - } - } - - /* Determine if we actually found a matching ARP entry. */ - if (arp_ptr) - { - - /* Yes, we found an ARP entry. Now check and see if - it has an actual physical address. */ - if (arp_ptr -> nx_arp_physical_address_msw | arp_ptr -> nx_arp_physical_address_lsw) - { - - /* Yes, we have a physical mapping. Copy the physical address into the driver - request structure. */ - driver_request.nx_ip_driver_physical_address_msw = arp_ptr -> nx_arp_physical_address_msw; - driver_request.nx_ip_driver_physical_address_lsw = arp_ptr -> nx_arp_physical_address_lsw; - - /* Disable interrupts. */ - TX_DISABLE - - /* Move this ARP entry to the head of the list. */ - ip_ptr -> nx_ip_arp_table[index] = arp_ptr; - - /* Restore interrupts. */ - TX_RESTORE - - /* Build the driver request message. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) - { - - /* Fragmentation is needed, call the fragment routine if available. */ - if (ip_ptr -> nx_ip_fragment_processing) - { - - /* Call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - } - - /* In either case, this packet send is complete, just return. */ - return; - } -#endif - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Send the IP packet out on the network via the attached driver. */ - (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); - - /* Return to caller. */ - return; - } - else - { - - /* We don't have physical mapping. */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Ensure the current packet's queue next pointer to NULL. */ - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Determine if the queue is empty. */ - if (arp_ptr -> nx_arp_packets_waiting == NX_NULL) - { - - /* Yes, we have an empty ARP packet queue. Simply place the - packet at the head of the list. */ - arp_ptr -> nx_arp_packets_waiting = packet_ptr; - - /* Restore interrupts. */ - TX_RESTORE - } - else - { - - - /* Determine how many packets are on the ARP entry's packet - queue and remember the last packet in the queue. We know - there is at least one on the queue and another that is - going to be queued. */ - last_packet = arp_ptr -> nx_arp_packets_waiting; - queued_count = 0; - while (last_packet -> nx_packet_queue_next) - { - - /* Increment the queued count. */ - queued_count++; - - /* Move to the next packet in the queue. */ - last_packet = last_packet -> nx_packet_queue_next; - } - - /* Place the packet at the end of the list. */ - last_packet -> nx_packet_queue_next = packet_ptr; - - /* Default the remove packet pointer to NULL. */ - remove_packet = NX_NULL; - - /* Determine if the packets queued has exceeded the queue - depth. */ - if (queued_count >= NX_ARP_MAX_QUEUE_DEPTH) - { - - /* Save the packet pointer at the head of the list. */ - remove_packet = arp_ptr -> nx_arp_packets_waiting; - - /* Remove the packet from the ARP queue. */ - arp_ptr -> nx_arp_packets_waiting = remove_packet -> nx_packet_queue_next; - - /* Clear the remove packet queue next pointer. */ - remove_packet -> nx_packet_queue_next = NX_NULL; - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Determine if there is a packet to remove. */ - if (remove_packet) - { - - /* Yes, the packet queue depth for this ARP entry was exceeded - so release the packet that was removed from the queue. */ - _nx_packet_transmit_release(remove_packet); - } - } - - /* Return to caller. */ - return; - } - } - else - { - - /* No ARP entry was found. We need to allocate a new ARP entry, populate it, and - initiate an ARP request to get the specific physical mapping. */ - - /* Allocate a new ARP entry. */ - if ((!ip_ptr -> nx_ip_arp_allocate) || - ((ip_ptr -> nx_ip_arp_allocate)(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]), NX_FALSE))) - { - - /* Error, release the protection and the packet. */ - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - - /* Release the packet. */ - _nx_packet_transmit_release(packet_ptr); - - /* Just return! */ - return; - } - - /* Otherwise, setup a pointer to the new ARP entry. */ - arp_ptr = (ip_ptr -> nx_ip_arp_table[index]) -> nx_arp_active_previous; - - /* Setup the IP address and clear the physical mapping. */ - arp_ptr -> nx_arp_ip_address = destination_ip; - arp_ptr -> nx_arp_physical_address_msw = 0; - arp_ptr -> nx_arp_physical_address_lsw = 0; - arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE; - arp_ptr -> nx_arp_retries = 0; - arp_ptr -> nx_arp_ip_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - - /* Ensure the queue next pointer is NULL for the packet before it - is placed on the ARP waiting queue. */ - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Queue the packet for output. */ - arp_ptr -> nx_arp_packets_waiting = packet_ptr; - - /* Call ARP send to send an ARP request. */ - (ip_ptr -> nx_ip_arp_packet_send)(ip_ptr, destination_ip, packet_ptr -> nx_packet_address.nx_packet_interface_ptr); - return; - } - } - } - else - { - - /* This IP instance does not require any IP-to-physical mapping. */ - - /* Determine if we have a loopback address. */ - if ((((destination_ip >= NX_IP_LOOPBACK_FIRST) && - (destination_ip <= NX_IP_LOOPBACK_LAST))) || - (destination_ip == packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_address)) - { - - /* Yes, we have an internal loopback address. */ - - /* Copy the packet so it can be enqueued properly by the receive - processing. */ - if (_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); -#endif - - /* Send the packet to this IP's receive processing like it came in from the - driver. */ - _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); - } -#ifndef NX_DISABLE_IP_INFO - else - { - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; - } -#endif - - /* Release the transmit packet. */ - _nx_packet_transmit_release(packet_ptr); - return; - } - - /* Build the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_ip_mtu_size) - { - - /* Fragmentation is needed, call the fragment routine if available. */ - if (ip_ptr -> nx_ip_fragment_processing) - { - - /* Call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - } - else - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - - /* Just release the packet. */ - _nx_packet_transmit_release(packet_ptr); - } - - /* In either case, this packet send is complete, just return. */ - return; - } -#endif - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV4_HEADER); - -#endif - - /* No mapping driver. Just send the packet out! */ - (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_link_driver_entry) (&driver_request); - } -} -#endif /*NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_bsd_ipv6_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function forwards the input packet directly to the appropriate */ -/* link driver. The caller needs to fill in the correct */ -/* source and destination addresses into the packet source and */ -/* destination address. The caller also makes sure that the packet */ -/* interface address is valid (not in tentative state), and source */ -/* address is not unspecified e.g. NULL. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet to send */ -/* src_addr Pointer to source address */ -/* dest_addr Pointer to dest address */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_packet_transmit_release Release transmit packet */ -/* _nx_nd_cache_add_entry Add new entry to ND Cache */ -/* IPv6_Address_Type Find IPv6 address type */ -/* _nx_packet_copy Packet copy */ -/* _nx_ip_packet_deferred_receive Places received packets in */ -/* deferred packet queue */ -/* _nx_icmpv6_send_ns Send neighbor solicitation */ -/* _nxd_ipv6_search_onlink Find onlink match */ -/* _nx_ipv6_fragment_processing Fragment processing */ -/* (ip_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* nx_bsd_send_internal */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_bsd_ipv6_packet_send(NX_PACKET *packet_ptr, ULONG *src_addr, ULONG *dest_addr) -{ - -UINT status; -ULONG address_type; -NX_IP_DRIVER driver_request; -NX_PACKET *remove_packet; -NX_PACKET *packet_copy; -UINT same_address; -NX_INTERFACE *if_ptr; -#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY -NX_IPV6_HEADER *ip_header_ptr; -#endif -NX_IPV6_DESTINATION_ENTRY *dest_entry_ptr; -#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY -UINT next_hop_path_mtu; -NX_IPV6_DESTINATION_ENTRY *next_hop_dest_entry_ptr; -#endif -NX_IP *ip_ptr; - - ip_ptr = nx_bsd_default_ip; -#ifndef NX_DISABLE_IP_INFO - - /* Increment the total send requests counter. */ - ip_ptr -> nx_ip_total_packet_send_requests++; -#endif - - if_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached; - - - /* If the interface IP address is not valid (in DAD state), only ICMP is allowed */ - if(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID) - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP invalid packet error. */ - ip_ptr -> nx_ip_invalid_transmit_packets++; -#endif - - /* Release the packet. */ - _nx_packet_transmit_release(packet_ptr); - - /* Return... nothing more can be done! */ - return; - } - -#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY - /* Build the IP header. */ - ip_header_ptr = (NX_IPV6_HEADER*)packet_ptr -> nx_packet_prepend_ptr; -#endif - - /* Check if the host is sending itself a packet. */ - same_address = (UINT)CHECK_IPV6_ADDRESSES_SAME(dest_addr, src_addr); - - /* If it is, consider this a loopback address. */ - if (same_address == 1) - { - - address_type = IPV6_ADDRESS_LOOPBACK; - } - else - { - - /* Otherwise check if this packet sending to a known loopback address. */ - address_type = IPv6_Address_Type(dest_addr); - } - - /* Handle the internal loopback case. */ - if(address_type == IPV6_ADDRESS_LOOPBACK) - { - - if(_nx_packet_copy(packet_ptr, &packet_copy, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT) == NX_SUCCESS) - { -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); -#endif - - /* Send the packet to this IP's receive processing like it came in from the driver. */ - _nx_ip_packet_deferred_receive(ip_ptr, packet_copy); - } -#ifndef NX_DISABLE_IP_INFO - else - { - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - } -#endif - /* Release the transmit packet. */ - _nx_packet_transmit_release(packet_ptr); - return; - - } - - /* Is this packet a multicast ? */ - if((dest_addr[0] & 0xFF000000) == 0xFF000000) - { - - - /* Set up the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_physical_address_msw = 0x00003333; - driver_request.nx_ip_driver_physical_address_lsw = dest_addr[3]; - driver_request.nx_ip_driver_interface = if_ptr; - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); -#endif - - /* Check if fragmentation is enabled. */ -#ifndef NX_DISABLE_FRAGMENTATION - - /* It is; is path MTU enabled? */ -#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY - - /* It is. We will check the path MTU for the packet destination to - determine if we need to fragment the packet. */ - - /* Get a pointer to the packet IP header. */ - ip_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_prepend_ptr; - - /* Lookup the multicast destination in the destination table. */ - status = _nx_icmpv6_dest_table_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &dest_entry_ptr, 0, 0); - - /* Did we find it in the table? */ - if ((status == NX_SUCCESS) && (dest_entry_ptr != NX_NULL)) - { - - /* Yes; Check the destination path MTU if fragmentation is needed. */ - if ((dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu > 0) && (packet_ptr -> nx_packet_length > - dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu)) - { - - /* Yes we must fragment the payload. */ - _nx_ipv6_fragment_process(&driver_request, dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu); - - /* This packet send is complete, just return. */ - return; - } - - /* Packet should drop through and be checked against the IP mtu. */ - } - -#endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */ - - - /* Does the packet payload exceed our IP instance MTU? */ - if (packet_ptr -> nx_packet_length > if_ptr -> nx_interface_ip_mtu_size) - { - /* Yes; ok to fragment the packet payload. */ - _nx_ipv6_fragment_process(&driver_request, if_ptr -> nx_interface_ip_mtu_size); - - /* This packet send is complete, just return. */ - return; - } - - /* Packet will go out unfragmented. */ - -#endif /* NX_DISABLE_FRAGMENTATION */ - - - /* Send the IP packet out on the network via the attached driver. */ - (if_ptr -> nx_interface_link_driver_entry) (&driver_request); - - /* Return to caller. */ - return; - } - - /* Determine if physical mapping is needed by this link driver. */ - if( if_ptr && if_ptr -> nx_interface_address_mapping_needed ) - { - - /* Obtain MAC address */ - ND_CACHE_ENTRY *NDCacheEntry = NX_NULL; - ULONG next_hop_address[4]; - - SET_UNSPECIFIED_ADDRESS(next_hop_address); - - /* Lookup the packet destination in the destination table. */ - status = _nx_icmpv6_dest_table_find(ip_ptr, dest_addr, &dest_entry_ptr, 0, 0); - - /* Was a matching entry found? */ - if(status != NX_SUCCESS) - { - - /* No; If the packet is either onlink or there is no default router, - just copy the packet destination address to the 'next hop' address. */ - - if(_nxd_ipv6_search_onlink(ip_ptr, dest_addr)) - { - COPY_IPV6_ADDRESS(dest_addr, next_hop_address); - - /* Add the next_hop in destination table. */ - status = _nx_icmpv6_dest_table_add(ip_ptr, dest_addr, &dest_entry_ptr, - next_hop_address, if_ptr -> nx_interface_ip_mtu_size, - NX_WAIT_FOREVER, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr); - - /* Get the NDCacheEntry. */ - if(status == NX_SUCCESS) - NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; - } - - /* Check whether or not we have a default router. */ - else if(_nxd_ipv6_router_lookup(ip_ptr, if_ptr, next_hop_address, (VOID**)&NDCacheEntry) == NX_SUCCESS) - { - /* Add the next_hop in destination table. */ - status = _nx_icmpv6_dest_table_add(ip_ptr, dest_addr, &dest_entry_ptr, - next_hop_address, if_ptr -> nx_interface_ip_mtu_size, - NX_WAIT_FOREVER, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr); - - /* If the default router did not has a reachable ND_CACHE_ENTRY. Get the NDCacheEntry. */ - if(!NDCacheEntry) - NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; - } - - /* Can not find next_hop or the destination table add failed. */ - if(status || ((next_hop_address[0] == 0) && (next_hop_address[1] == 0) && (next_hop_address[2] == 0) && (next_hop_address[3] == 0))) - { - - /* Release the packet. */ - _nx_packet_release(packet_ptr); - - /* Can't send it. */ - return; - } - - } - - /* Find a valid destination cache, set the nd cache and next hop address. */ - else - { - - /* Check the NDCacheEntry is valid. */ - if(dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry -> nx_nd_cache_nd_status == ND_CACHE_STATE_INVALID) - { - if(_nx_nd_cache_add_entry(ip_ptr, dest_addr, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr, &dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry)) - { - /* Release the packet. */ - _nx_packet_release(packet_ptr); - - /* Can't send it. */ - return; - } - - } - - /* Get the destination and next hop address. */ - NDCacheEntry = dest_entry_ptr -> nx_ipv6_destination_entry_nd_entry; - COPY_IPV6_ADDRESS(dest_entry_ptr -> nx_ipv6_destination_entry_next_hop, next_hop_address); - } - - /* According RFC2461 ch 7.3.3, as long as the entry is valid and not in INCOMPLETE state, - the IP layer should use the cached link layer address. */ - if((NDCacheEntry -> nx_nd_cache_nd_status >= ND_CACHE_STATE_REACHABLE) && - (NDCacheEntry -> nx_nd_cache_nd_status <= ND_CACHE_STATE_PROBE)) - { - - UCHAR *mac_addr; - - mac_addr = NDCacheEntry -> nx_nd_cache_mac_addr; - - /* Assume we find the mac */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_physical_address_msw = (ULONG)((mac_addr[0] << 8) | mac_addr[1]); - driver_request.nx_ip_driver_physical_address_lsw = - (ULONG)((mac_addr[2] << 24) | (mac_addr[3] << 16) | (mac_addr[4] << 8) | mac_addr[5]); - driver_request.nx_ip_driver_interface = if_ptr; - -#ifndef NX_DISABLE_FRAGMENTATION - - /* If the packet size is bigger than MTU, NetX Duo is enabled to fragment - the packet payload. */ - - /* Check if path MTU Discovery is enabled first. */ - -#ifdef NX_ENABLE_IPV6_PATH_MTU_DISCOVERY - - /* It is. To know if we need to fragment this packet we need the path MTU for the packet - destination. */ - - /* If this destination has a non null next hop, we need to ascertain the next hop MTU. */ - - /* Get the path MTU for the actual destination. */ - next_hop_path_mtu = dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu; - - - /* Find the next hop in the destination table. */ - status = _nx_icmpv6_dest_table_find(ip_ptr, next_hop_address, &next_hop_dest_entry_ptr, 0, 0); - - if (status == NX_SUCCESS) - { - - /* Now compare the destination path MTU with the next hop path MTU*/ - if ((next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu > 0) && - (next_hop_path_mtu > next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu)) - { - - /* Update the path mtu to reflect the next hop route. */ - next_hop_path_mtu = next_hop_dest_entry_ptr -> nx_ipv6_destination_entry_path_mtu; - } - } - - /* Yes; Check the destination path MTU if fragmentation is needed. */ - if ((next_hop_path_mtu > 0) && - (packet_ptr -> nx_packet_length > next_hop_path_mtu)) - { - - /* Yes we must fragment the payload. */ - _nx_ipv6_fragment_process(&driver_request, next_hop_path_mtu); - - /* This packet send is complete, just return. */ - return; - } -#endif /* NX_ENABLE_IPV6_PATH_MTU_DISCOVERY */ - - /* Send packet unfragmented. */ - - /* If we didn't find anything in the destination table, let the packet drop through. NetX Duo - will check our IP instance MTU if fragmentation is needed before sending. */ - - - /* Does the packet payload exceed our IP instance MTU? */ - if (packet_ptr -> nx_packet_length > if_ptr -> nx_interface_ip_mtu_size) - { - /* Yes; ok to fragment the packet payload. */ - _nx_ipv6_fragment_process(&driver_request, if_ptr -> nx_interface_ip_mtu_size); - - /* This packet send is complete, just return. */ - return; - } - - /* The packet requires no fragmentation. Proceed with sending the packet. */ - -#endif /* NX_DISABLE_FRAGMENTATION */ - - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER); -#endif - - /* Send the IP packet out on the network via the attached driver. */ - (if_ptr -> nx_interface_link_driver_entry) (&driver_request); - - /* If the entry is in STALE state, move it to DELAY state. */ - if(NDCacheEntry -> nx_nd_cache_nd_status == ND_CACHE_STATE_STALE) - { - NDCacheEntry -> nx_nd_cache_nd_status = ND_CACHE_STATE_DELAY; - - /* Start the Delay first probe timer */ - NDCacheEntry -> nx_nd_cache_timer_tick = NX_DELAY_FIRST_PROBE_TIME; - - } - - /* Return to caller. */ - return; - } - - /* No MAC address was found in our cache table. Start the Neighbor Discovery (ND) - process to get it. */ - - /* Ensure the current packet's queue next pointer to NULL */ - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Determine if the queue is empty. */ - if(NDCacheEntry -> nx_nd_cache_packet_waiting_head == NX_NULL) - { - /* ICMPv6 is enabled */ - if(ip_ptr -> nx_ip_icmpv6_packet_process) - { - - /* Queue up this packet */ - NDCacheEntry -> nx_nd_cache_packet_waiting_head = packet_ptr; - NDCacheEntry -> nx_nd_cache_packet_waiting_tail = packet_ptr; - NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length = 1; - - /* Set the outgoing address and interface to the cache entry. */ - NDCacheEntry -> nx_nd_cache_outgoing_address = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr; - NDCacheEntry -> nx_nd_cache_interface_ptr = if_ptr; - - /* Is this a new entry? */ - if(NDCacheEntry -> nx_nd_cache_nd_status == ND_CACHE_STATE_CREATED) - { - - /* Start Neighbor discovery process by advancing to the incomplete state. */ - NDCacheEntry -> nx_nd_cache_nd_status = ND_CACHE_STATE_INCOMPLETE; - } - - _nx_icmpv6_send_ns(ip_ptr, next_hop_address, - 1, packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr, 0, NX_NULL); - - NDCacheEntry -> nx_nd_cache_num_solicit = NX_MAX_MULTICAST_SOLICIT - 1; - NDCacheEntry -> nx_nd_cache_timer_tick = ip_ptr -> nx_ipv6_retrans_timer_ticks; - - } - else - { - - _nx_packet_transmit_release(packet_ptr); -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - } - return; - } - - /* The ND process already started. Simply queue up this packet */ - NDCacheEntry -> nx_nd_cache_packet_waiting_tail -> nx_packet_queue_next = packet_ptr; - NDCacheEntry -> nx_nd_cache_packet_waiting_tail = packet_ptr; - NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length++; - - /* Check if the number of packets enqueued exceeds the allowed number. */ - if(NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length > NX_ND_MAX_QUEUE_DEPTH) - { - - /* Yes, so delete the first packet. */ - remove_packet = NDCacheEntry -> nx_nd_cache_packet_waiting_head; - - NDCacheEntry -> nx_nd_cache_packet_waiting_head = remove_packet -> nx_packet_queue_next; - - /* Update the queued packet count for this cache entry. */ - NDCacheEntry -> nx_nd_cache_packet_waiting_queue_length--; - - _nx_packet_transmit_release(remove_packet); -#ifndef NX_DISABLE_IP_INFO - /* Increment the IP transmit resource error count. */ - ip_ptr -> nx_ip_transmit_resource_errors++; - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - } - - return; - } - - /* For now do nothing. Just release the packet */ - _nx_packet_release(packet_ptr); -} - -#endif /* FEATURE_NX_IPV6 */ - -#if defined(FEATURE_NX_IPV6) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_bsd_swap_ipv6_extension_headers PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs endian swap operations on the IPv6 */ -/* extension headers. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet */ -/* header_type Type of the first extension */ -/* header */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* NX_CHANGE_USHORT_ENDIAN Swap endian-ness on 16-bit */ -/* integer. */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo BSD Layer Source Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_bsd_swap_ipv6_extension_headers(NX_PACKET *packet_ptr, UCHAR header_type) -{ -UCHAR *scan_ptr; -ULONG remaining_bytes; -ULONG header_length = 40; -NX_IPV6_HEADER_OPTION *option; - - - remaining_bytes = (ULONG)packet_ptr -> nx_packet_prepend_ptr - (ULONG)packet_ptr -> nx_packet_ip_header; - - scan_ptr = packet_ptr -> nx_packet_ip_header; - - remaining_bytes -= header_length; - scan_ptr += header_length; - - while(remaining_bytes) - { - option = (NX_IPV6_HEADER_OPTION*)scan_ptr; - switch(header_type) - { - case NX_PROTOCOL_NEXT_HEADER_HOP_BY_HOP: - - break; - - case NX_PROTOCOL_NEXT_HEADER_DESTINATION: - - break; - - case NX_PROTOCOL_NEXT_HEADER_ROUTING: - break; - - - case NX_PROTOCOL_NEXT_HEADER_FRAGMENT: - NX_CHANGE_USHORT_ENDIAN(((NX_IPV6_HEADER_FRAGMENT_OPTION *)scan_ptr) -> nx_ipv6_header_fragment_option_offset_flag); - break; - - default: - - break; - } - - header_type = option -> nx_ipv6_header_option_next_header; - - if(header_type == NX_PROTOCOL_NEXT_HEADER_AUTHENTICATION) - header_length = (ULONG)((option -> nx_ipv6_header_option_ext_length << 2) + 2); - else - header_length = (ULONG)((option -> nx_ipv6_header_option_ext_length + 1) << 3); - - - remaining_bytes -= header_length; - scan_ptr += header_length; - } -} -#endif /* defined(FEATURE_NX_IPV6) && defined(NX_ENABLE_IP_RAW_PACKET_FILTER) */ -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_pppoe_internal_sendto PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends raw PPPOE packet to driver directly. */ -/* */ -/* INPUT */ -/* */ -/* bsd_socket_ptr Pointer to bsd socket */ -/* msg Message to send */ -/* msgLength Length of message */ -/* flags Flags */ -/* destAddr Pointer to destination address*/ -/* destAddrLen Length of destination address */ -/* */ -/* OUTPUT */ -/* */ -/* msgLength On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_append Append data to the packet */ -/* nx_packet_release Release the packet on error */ -/* tx_mutex_get Obtain exclusive access to */ -/* tx_mutex_put Release exclusive access */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT nx_bsd_pppoe_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, INT flags, struct sockaddr* destAddr, INT destAddrLen) -{ -UINT if_index; -struct sockaddr_ll *destAddr_ll; -#if 0 -ULONG src_mac_msw; -ULONG src_mac_lsw; -#endif -NX_IP_DRIVER driver_request; -UINT status; -NX_PACKET *packet_ptr = NX_NULL; - - NX_PARAMETER_NOT_USED(bsd_socket_ptr); - NX_PARAMETER_NOT_USED(flags); - - /* Validate the parameters. */ - if(destAddr == NX_NULL) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(destAddr -> sa_family != AF_PACKET) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(destAddrLen != sizeof(struct sockaddr_ll)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - destAddr_ll = (struct sockaddr_ll*)destAddr; - - if((destAddr_ll -> sll_protocol != ETHERTYPE_PPPOE_SESS) && (destAddr_ll -> sll_protocol != ETHERTYPE_PPPOE_DISC)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Validate the interface ID */ - if_index = (UINT)(destAddr_ll -> sll_ifindex); - if(if_index >= NX_MAX_IP_INTERFACES) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid == 0) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - -#if 0 - /* Pickup the source MAC address */ - src_mac_msw = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_physical_address_msw; - src_mac_lsw = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_physical_address_lsw; -#endif - - - - /* Validate the packet length */ - if(msgLength > (INT)(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_mtu_size + 14)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* FIXME: If the socket is non-blocking, Timeout value should be set to 0 */ - status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - - - /* Now copy the data into the NetX packet. */ - status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, NX_NO_WAIT); - - /* Was the data copy successful? */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - /* Now ready to transmit this packet. */ - driver_request.nx_ip_driver_ptr = nx_bsd_default_ip; - if(destAddr_ll -> sll_protocol == ETHERTYPE_PPPOE_SESS) - driver_request.nx_ip_driver_command = NX_LINK_PACKET_PPPOE_SESS_SEND; - else - driver_request.nx_ip_driver_command = NX_LINK_PACKET_PPPOE_DISC_SEND; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = &nx_bsd_default_ip -> nx_ip_interface[if_index]; - - /* Obtain the BSD lock. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - (driver_request.nx_ip_driver_interface -> nx_interface_link_driver_entry)(&driver_request); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(msgLength); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_bsd_pppoe_packet_received PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives raw PPPOE packet from driver directly. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to received packet */ -/* frame_type Type of frame */ -/* interface_id Interface ID */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_select_wakeup Wake up any asychronous */ -/* receive call */ -/* nx_packet_release Release the packet on error */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_bsd_pppoe_packet_received(NX_PACKET *packet_ptr, UINT frame_type, UINT interface_id) -{ - -UINT i; -UINT sockid = NX_BSD_MAX_SOCKETS; -UINT create_id = 0xFFFFFFFF; -NX_BSD_SOCKET *bsd_ptr; - - NX_PARAMETER_NOT_USED(interface_id); - - /* Find the socket with the lowest create-ID. Put the packet into the socket's recevie queue. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && - /* - (nx_bsd_socket_array[i].nx_bsd_raw_socket_enabled == NX_TRUE) && - */ - (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_PACKET) && - (nx_bsd_socket_array[i].nx_bsd_socket_protocol == frame_type)) - { - if(nx_bsd_socket_array[i].nx_bsd_socket_create_id < create_id) - { - sockid = i; - create_id = nx_bsd_socket_array[i].nx_bsd_socket_create_id; - } - } - } - if(sockid == NX_BSD_MAX_SOCKETS) - { - /* No BSD sockets are avaialble for this frame type. */ - nx_packet_release(packet_ptr); - return(NX_SUCCESS); - } - /* Now we need to put the packet into the socket. */ - bsd_ptr = &nx_bsd_socket_array[sockid]; - - /* Drop the packet if the receive queue exceeds max depth. */ - if(bsd_ptr -> nx_bsd_socket_received_packet_count >= - bsd_ptr -> nx_bsd_socket_received_packet_count_max) - { - nx_packet_release(packet_ptr); - return(NX_SUCCESS); - } - - if(bsd_ptr -> nx_bsd_socket_received_packet) - { - bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; - } - else - { - bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; - } - - bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - bsd_ptr -> nx_bsd_socket_received_packet_count ++; - - nx_bsd_select_wakeup(sockid, FDSET_READ); - - return 0; -} -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - -#ifdef NX_BSD_RAW_SUPPORT - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_bsd_hardware_internal_sendto PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends raw packet to driver directly. */ -/* */ -/* INPUT */ -/* */ -/* bsd_socket_ptr Pointer to bsd socket */ -/* msg Message to send */ -/* msgLength Length of message */ -/* flags Flags */ -/* destAddr Pointer to destination address*/ -/* destAddrLen Length of destination address */ -/* */ -/* OUTPUT */ -/* */ -/* msgLength On success */ -/* NX_SOC_ERROR (-1) On failure */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_append Append data to the packet */ -/* nx_packet_release Release the packet on error */ -/* tx_mutex_get Obtain exclusive access to */ -/* tx_mutex_put Release exclusive access */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT _nx_bsd_hardware_internal_sendto(NX_BSD_SOCKET *bsd_socket_ptr, CHAR *msg, INT msgLength, INT flags, struct sockaddr* destAddr, INT destAddrLen) -{ -UINT if_index; -struct sockaddr_ll *destAddr_ll; -UINT status; -NX_PACKET *packet_ptr = NX_NULL; - - NX_PARAMETER_NOT_USED(bsd_socket_ptr); - NX_PARAMETER_NOT_USED(flags); - - /* Validate the parameters. */ - if(destAddr == NX_NULL) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(destAddr -> sa_family != AF_PACKET) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(destAddrLen != sizeof(struct sockaddr_ll)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - destAddr_ll = (struct sockaddr_ll*)destAddr; - - /* Validate the interface ID */ - if_index = (UINT)(destAddr_ll -> sll_ifindex); - if(if_index >= NX_MAX_IP_INTERFACES) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - if(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_valid == 0) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - /* Validate the packet length */ - if(msgLength > (INT)(nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_ip_mtu_size + 18)) - { - /* Set the socket error if extended socket options enabled. */ - set_errno(EINVAL); - - NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - status = nx_packet_allocate(nx_bsd_default_packet_pool, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - - /* Set IP interface. */ - packet_ptr -> nx_packet_ip_interface = &nx_bsd_default_ip -> nx_ip_interface[if_index]; - - /* Now copy the data into the NetX packet. */ - status = nx_packet_data_append(packet_ptr, (VOID *) msg, (ULONG)msgLength, nx_bsd_default_packet_pool, NX_NO_WAIT); - - /* Was the data copy successful? */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error. */ - set_errno(ENOBUFS); - - /* Return an error status.*/ - NX_BSD_ERROR(status, __LINE__); - return(NX_SOC_ERROR); - } - -#if defined(__PRODUCT_NETXDUO__) && defined(NX_ENABLE_INTERFACE_CAPABILITY) - packet_ptr -> nx_packet_interface_capability_flag = nx_bsd_default_ip -> nx_ip_interface[if_index].nx_interface_capability_flag; -#endif /* defined(__PRODUCT_NETXDUO__) && defined(NX_ENABLE_INTERFACE_CAPABILITY) */ - - /* Obtain the BSD lock. */ - status = tx_mutex_get(nx_bsd_protection_ptr, NX_BSD_TIMEOUT); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Set the socket error if extended socket options enabled. */ - set_errno(EACCES); - - /* Return an error. */ - NX_BSD_ERROR(NX_BSD_MUTEX_ERROR, __LINE__); - return(NX_SOC_ERROR); - } - - _nx_driver_hardware_packet_send(packet_ptr); - - /* Release the mutex. */ - tx_mutex_put(nx_bsd_protection_ptr); - - return(msgLength); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_bsd_hardware_packet_received PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives raw packet from driver directly. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to received packet */ -/* consumed Return packet consumed or not */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_select_wakeup Wake up any asychronous */ -/* receive call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_bsd_hardware_packet_received(NX_PACKET *packet_ptr, UCHAR *consumed) -{ - -UINT i; -UINT sockid = NX_BSD_MAX_SOCKETS; -NX_BSD_SOCKET *bsd_ptr; - - /* Initialize the consumed to be false. */ - *consumed = NX_FALSE; - - /* Find the socket with the matching interface. Put the packet into the socket's recevie queue. */ - for(i = 0; i < NX_BSD_MAX_SOCKETS; i++) - { - if((nx_bsd_socket_array[i].nx_bsd_socket_status_flags & NX_BSD_SOCKET_IN_USE) && - (nx_bsd_socket_array[i].nx_bsd_socket_family == AF_PACKET) && - ((nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == NX_BSD_LOCAL_IF_INADDR_ANY) || - (nx_bsd_socket_array[i].nx_bsd_socket_local_bind_interface == (ULONG)(packet_ptr -> nx_packet_ip_interface)))) - { - sockid = i; - } - } - if(sockid == NX_BSD_MAX_SOCKETS) - { - /* No BSD sockets are avaialble for this frame type. */ - return; - } - /* Now we need to put the packet into the socket. */ - bsd_ptr = &nx_bsd_socket_array[sockid]; - - /* Drop the packet if the receive queue exceeds max depth. */ - if(bsd_ptr -> nx_bsd_socket_received_packet_count >= - bsd_ptr -> nx_bsd_socket_received_packet_count_max) - { - return; - } - -#ifndef NX_DISABLE_BSD_RAW_PACKET_DUPLICATE - /* Duplicate the packet. */ - if (nx_packet_copy(packet_ptr, &packet_ptr, nx_bsd_default_packet_pool, NX_NO_WAIT) != NX_SUCCESS) - { - return; - } -#else - /* Consume the packet. IP layer will not see it. */ - *consumed = NX_TRUE; -#endif /* NX_DISABLE_BSD_RAW_PACKET_DUPLICATE */ - - if(bsd_ptr -> nx_bsd_socket_received_packet) - { - bsd_ptr -> nx_bsd_socket_received_packet_tail -> nx_packet_queue_next = packet_ptr; - } - else - { - bsd_ptr -> nx_bsd_socket_received_packet = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_packet_offset = 0; - } - - bsd_ptr -> nx_bsd_socket_received_packet_tail = packet_ptr; - bsd_ptr -> nx_bsd_socket_received_byte_count += packet_ptr -> nx_packet_length; - bsd_ptr -> nx_bsd_socket_received_packet_count ++; - - nx_bsd_select_wakeup(sockid, FDSET_READ); - - return; -} -#endif /* NX_BSD_RAW_SUPPORT */ - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_pton PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IP address from presentation to numeric. */ -/* */ -/* INPUT */ -/* */ -/* af Either AF_INET or AF_INET6 */ -/* src A pointer pointing to the */ -/* presentation of IP address */ -/* dst A pointer pointing to the */ -/* destination memory */ -/* */ -/* OUTPUT */ -/* */ -/* status 1 OK */ -/* 0 invalid presentation */ -/* -1 error */ -/* */ -/* CALLS */ -/* */ -/* inet_aton Convert IPv4 address from */ -/* presentation to numeric */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT inet_pton(INT af, const CHAR *src, VOID *dst) -{ -CHAR ch; -USHORT value; -/* A number used to convert a character in '0123456789abcdefABCDEF' to a number. */ -UINT minuend; -/* A counter used to recoder the number of digits between 2 colons. */ -UINT digit_counter; - -UCHAR *colon_location; -/* A pointer used to traverse the destination memory. */ -UCHAR *dst_cur_ptr; -/* A pointer to the end of the destination memory. */ -UCHAR *dst_end_ptr; -ULONG *dst_long_ptr; - -const CHAR *ipv4_addr_start = src; -UINT n, i; - -struct in_addr ipv4_addr; - - if(af == AF_INET) - { - /* Convert IPv4 address from presentation to numeric. */ - if(inet_aton(src, &ipv4_addr)) - { - /* Copy the IPv4 address to the destination. */ - *((ULONG *)dst) = ipv4_addr.s_addr; - return 1; - } - return 0; - } - else if(af == AF_INET6) - { - /* If : is at the beginning, the next value must be : .*/ - if(*src == ':') - if(*src++ != ':') - return 0; - - /* Initialization. */ - value = 0; - digit_counter = 0; - colon_location = NX_NULL; - dst_cur_ptr = dst; - /* Calculate the end of the destination memory. */ - dst_end_ptr = (UCHAR*)dst + 15; - /* Clear the destination memory. */ - memset(dst_cur_ptr, 0, 16); - - while(*src != 0) - { - /* Get the current character. */ - ch = *src++; - - /* Judge which minuend to use. - * '0' - 48 == 0 - * 'a' - 87 == 10 - * 'A' - 55 == 10 - */ - minuend = 0; - if(ch >= '0' && ch <= '9') - minuend = 48; - else if(ch >= 'a' && ch <= 'f') - minuend = 87; - else if(ch >= 'A' && ch <= 'F') - minuend = 55; - - /* if minuend is not 0, then ch is character in "0123456789abcdefABCDEF" */ - if(minuend) - { - /* Convert the character to number. */ - value = (USHORT)(value << 4); - value = (USHORT)(value | ((UINT)ch - minuend)); - - /* The max number of digits between 2 colons is 4. */ - if(++digit_counter > 4) - return 0; - - continue; - } - - if(ch == ':') - { - ipv4_addr_start = src; - - /* Is there a digit before the colon? */ - if(!digit_counter) - { - /* There is no digit before the colon. */ - - /* If there are 2 "::", Invalid Presentation Format. - * IF there is a ":::", Invalid Presention Format. */ - if(colon_location) - return 0; - - /* Record the colon location. */ - colon_location = dst_cur_ptr; - continue; - } - else if(*src == '\0') - { - /* The colon is at the end of src, Invalid Presention Format. */ - return 0; - } - - if(dst_cur_ptr + 1 > dst_end_ptr) - { - /* Invalid Presentation Format. */ - return 0; - } - - /* Store the value to the dst memory. */ - *(dst_cur_ptr++) = (UCHAR) (value >> 8) & 0xff; - *(dst_cur_ptr++) = (UCHAR) (value) & 0xff; - - /* Reset the value and digit counter. */ - digit_counter = 0; - value = 0; - - continue; - - } - else if(ch == '.') - { - /* Process the dotted-decimal string in IPv4-mapped IPv6 address and IPv4-compatible IPv6 address. */ - - if(dst_cur_ptr + 3 > dst_end_ptr) - { - /* Invalid Presentation Format. */ - return 0; - } - - /* Convert the ipv4 address from presentation to numeric. */ - if(inet_aton(ipv4_addr_start, &ipv4_addr)) - { - - /* Make sure the result is in network byte order. */ - ipv4_addr.s_addr = ntohl(ipv4_addr.s_addr); - NX_CHANGE_ULONG_ENDIAN(ipv4_addr.s_addr); - - /* Store the value to the dst memory. */ - *(ULONG *)dst_cur_ptr = ipv4_addr.s_addr; - - dst_cur_ptr += 4; - digit_counter = 0; - - break; - } - else - return 0; - - - } - else - { - return 0; - } - } - - if(digit_counter) - { - - /* Invalid Presentation Format. */ - if(dst_cur_ptr + 1 > dst_end_ptr) - return 0; - - /* Store the value to the dst memory. */ - *(dst_cur_ptr++) = (UCHAR) (value >> 8) & 0xff; - *(dst_cur_ptr++) = (UCHAR) (value) & 0xff; - - } - - if(colon_location) - { - /* There is a :: in the IPv6 address presentation. */ - - /* Calculate how many octets should be moved to the end of the dst memory. */ - n = (UINT)(dst_cur_ptr - colon_location); - - if(dst_cur_ptr == dst_end_ptr) - return 0; - - /* Move the data to the end of dst memory. - * ----------- ----------- - * |aabb0000000| ----> |aa0000000bb| - * ----------- ----------- - */ - for(i = 1; i <=n; i++) - { - *(dst_end_ptr--) = colon_location[n - i]; - colon_location[n-i] = 0; - } - - dst_cur_ptr = dst_end_ptr + 1; - } - - if(dst_cur_ptr != (dst_end_ptr + 1)) - return 0; - - dst_long_ptr = (ULONG *)dst; - - /* First convert it to host byte order. */ - NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[0]); - NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[1]); - NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[2]); - NX_CHANGE_ULONG_ENDIAN(dst_long_ptr[3]); - - /* Convert it to network byte order by BSD macros. */ - dst_long_ptr[0] = htonl(dst_long_ptr[0]); - dst_long_ptr[1] = htonl(dst_long_ptr[1]); - dst_long_ptr[2] = htonl(dst_long_ptr[2]); - dst_long_ptr[3] = htonl(dst_long_ptr[3]); - return 1; - } - else - { - /* Error. */ - return -1; - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_ntop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IP address from numeric to presentation. */ -/* */ -/* INPUT */ -/* */ -/* af Either AF_INET or AF_INET6 */ -/* src A void pointer pointing to */ -/* network byte order IP address*/ -/* dst A char pointer pointing to */ -/* the destination buffer */ -/* size The size of the destination */ -/* buffer */ -/* */ -/* OUTPUT */ -/* */ -/* dst The destination buffer */ -/* */ -/* CALLS */ -/* */ -/* inet_ntoa_internal Convert IPv4 address from */ -/* numeric to presentation */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -const CHAR *inet_ntop(INT af, const VOID *src, CHAR *dst, socklen_t size) -{ - -INT shorthand_index; -INT shorthand_len; -INT current_index; -INT current_len; - -INT i; -INT index; -UINT rt_size; - - - if(af == AF_INET) - { - /* Convert IPv4 address from numeric to presentation. */ - if(inet_ntoa_internal(src, dst, size)) - return dst; - else - return NX_NULL; - } - else if(af == AF_INET6) - { - USHORT temp[8]; - temp[0] = (USHORT)(ntohl(*((ULONG *)src)) >> 16); - temp[1] = (USHORT)(ntohl(*((ULONG *)src)) & 0xFFFF); - temp[2] = (USHORT)(ntohl(*(((ULONG *)src) + 1)) >> 16); - temp[3] = (USHORT)(ntohl(*(((ULONG *)src) + 1)) & 0xFFFF); - temp[4] = (USHORT)(ntohl(*(((ULONG *)src) + 2)) >> 16); - temp[5] = (USHORT)(ntohl(*(((ULONG *)src) + 2)) & 0xFFFF); - temp[6] = (USHORT)(ntohl(*(((ULONG *)src) + 3)) >> 16); - temp[7] = (USHORT)(ntohl(*(((ULONG *)src) + 3)) & 0xFFFF); - - /* Initialization. */ - shorthand_index = -1; - shorthand_len = 0; - current_index = -1; - current_len = 0; - - /* Find the longest 0x00 in src for :: - * 16 * 8 == 128 */ - for(i = 0; i < 8; i++) - { - if(temp[i] == 0) - { - if(current_index == -1) - { - /* Record the index of 0x00, Initialize the length to 1. */ - current_index = i; - current_len = 1; - } - else - { - current_len++; - } - } - else - { - /* Not 0x00 . */ - - if(current_index != -1) - { - /* Not equal -1, means there is record of 0x00s . */ - - if(shorthand_index == -1 || current_len > shorthand_len) - { - /* Record the longest 0x00s. */ - shorthand_index = current_index; - shorthand_len = current_len; - } - - /* Reset the index. */ - current_index = -1; - } - - } - } - - - if(current_len > shorthand_len) - { - /* Record the longest 0x00s. */ - shorthand_index = current_index; - shorthand_len = current_len; - } - - /* If length is less than 2, no need for shorthand. */ - if(shorthand_len < 2) - { - shorthand_index = -1; - } - - index = 0; - /* Format the result. */ - for(i = 0; i < 8; i++) - { - /* Is i in the range of :: */ - if((shorthand_index != -1) && - (i >= shorthand_index) && - (i < (shorthand_index + shorthand_len))) - { - if(i == shorthand_index) - { - /* Check if there is enough memory to store a character. */ - if((size - (ULONG)index) < 1) - return NX_NULL; - - dst[index++] = ':'; - } - continue; - } - - if(i != 0) - { - /* Check if there is enough memory to store a character. */ - if((size - (ULONG)index) < 1) - return NX_NULL; - - dst[index++] = ':'; - } - - /* Does this address contain IPv4 address. */ - if(i == 6 && shorthand_index == 0 && - (shorthand_len == 6 || /* IPv4-mapped IPv6 address -----> ::1.2.3.4 */ - (shorthand_len == 5 && temp[5] == 0xffff))) /* IPv4-compatible IPv6 address -----> ::ffff:1.2.3.4 */ - { - /* Convert ipv4 address to string. 12 == 16 - 4*/ - rt_size = (UINT)inet_ntoa_internal((UCHAR*)src + 12, &dst[index], size - (ULONG)index); - - /* Check the return size, 0 means error. */ - if(rt_size) - index += (INT)rt_size; - else - return NX_NULL; - } - - /* Convert hex number to string */ - rt_size = bsd_number_convert(temp[i], &dst[index], size - (ULONG)index, 16); - if(!rt_size) - return NX_NULL; - - /* Increment the index. */ - index += (INT)rt_size; - - } - - /* Is there a trailing : */ - if((shorthand_index != -1) && (shorthand_index + shorthand_len == 8)) - { - /* Check if there is enough memory to store a character. */ - if((size - (ULONG)index) < 1) - return NX_NULL; - - dst[index++] = ':'; - - } - - /* Check if there is enough memory to store a character. */ - if((size - (ULONG)index) < 1) - return NX_NULL; - - dst[index] = '\0'; - - return dst; - } - else - { - return NX_NULL; - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* inet_ntoa_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IPv4 address to a string and returns the */ -/* size of the string. */ -/* */ -/* INPUT */ -/* */ -/* src A void pointer pointing to */ -/* IPv4 address */ -/* dst A char pointer pointing to */ -/* the destination buffer */ -/* dst_size The size of the destination */ -/* buffer */ -/* */ -/* OUTPUT */ -/* */ -/* index The size of the IPv4 address */ -/* string */ -/* */ -/* CALLS */ -/* */ -/* memset Set the memory to 0 */ -/* bsd_number_convert Convert a number to string */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo BSD Layer Source Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -static INT inet_ntoa_internal(const VOID *src, CHAR *dst, ULONG dst_size) -{ -ULONG temp; -UINT size; -UINT index = 0; - - - /* Set a local pointer to move up the buffer. */ - temp = ntohl(*((ULONG *)src)); - - memset(dst, 0, dst_size); - - /* Convert the first number to a string. */ - size = bsd_number_convert((temp >> 24), &dst[0], dst_size - index, 10); - - if(!size) - return 0; - - /* Move up the index and buffer pointer. */ - index += size; - - /* Check the rest of the dst buffer. */ - if((dst_size - index) < 1) - return 0; - - /* Add the decimal. */ - dst[index++] = '.'; - - /* And repeat three more times...*/ - size = bsd_number_convert((temp >> 16) & 0xff, &dst[index], dst_size - index, 10); - - if(!size) - return 0; - - index += size; - - if((dst_size - index) < 1) - return 0; - - dst[index++] = '.'; - - size = bsd_number_convert((temp >> 8) & 0xff, &dst[index], dst_size - index, 10); - - if(!size) - return 0; - - index += size; - - if((dst_size - index) < 1) - return 0; - - dst[index++] = '.'; - - size = bsd_number_convert(temp & 0xff, &dst[index], dst_size - index, 10); - - if(!size) - return 0; - - index += size; - - if((dst_size - index) < 1) - return 0; - - dst[index++] = '\0'; - - /* Return the size of the dst string. */ - return((INT)(index)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* getaddrinfo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns one or more addrinfo structures according to */ -/* the specified node and service. */ -/* */ -/* INPUT */ -/* */ -/* node Node is either a hostname or */ -/* an address string(dotted- */ -/* decimal for IPv4 or a hex */ -/* string for IPv6). */ -/* service Service is either a service */ -/* name or a decimal port number*/ -/* string. */ -/* hints Hints is either a null pointer*/ -/* or a pointer to an addrinfo */ -/* structure that the caller */ -/* fills in with hints about the*/ -/* types of information the */ -/* caller wants returned. */ -/* res Pointer to the returned */ -/* addrinfo list. */ -/* */ -/* OUTPUT */ -/* */ -/* status 0 if OK, nonzero on errors */ -/* */ -/* CALLS */ -/* */ -/* bsd_string_to_number Convert a string to a number */ -/* htons Host byte order to network */ -/* byte order */ -/* memcmp Memory compare */ -/* inet_pton Convert IP address from */ -/* presentation to numeric */ -/* tx_block_allocate Allocate memory for address or*/ -/* addrinfo */ -/* memset Set the memory to 0 */ -/* freeaddrinfo Release addrinfo memory */ -/* nx_dns_ipv4_address_by_name_get Get ipv4 addr by name via dns */ -/* nxd_dns_ipv6_address_by_name_get Get ipv6 addr by name via dns */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT getaddrinfo(const CHAR *node, const CHAR *service, const struct addrinfo *hints, struct addrinfo **res) -{ - -UINT status; -#ifdef NX_BSD_ENABLE_DNS -UINT status2; -#endif -UINT pton_flag; -UINT port; -UINT i, j; -INT addr_family; -UINT ipv4_addr_count = 0; -UINT ipv6_addr_count = 0; -UINT match_service_count; -UINT match_service_socktype[3]; -UINT match_service_protocol[3]; -struct addrinfo *addrinfo_cur_ptr = NX_NULL; -struct addrinfo *addrinfo_head_ptr = NX_NULL; -struct addrinfo *addrinfo_tail_ptr = NX_NULL; -struct sockaddr *sockaddr_ptr = NX_NULL; -UCHAR *cname_buffer = NX_NULL; - -/* When hints is a null pointer, use the default value below. */ -static struct addrinfo default_hints = {0, AF_UNSPEC, 0, 0, 0, NX_NULL, NX_NULL, NX_NULL}; - - - - /* if node and service are null return an error, invalid input. */ - if((node == NX_NULL) && (service == NX_NULL)) - return EAI_NONAME; - - if(hints) - { - - /* Check if the address family is valid. */ - if((hints -> ai_family != AF_INET) && - (hints -> ai_family != AF_INET6) && - (hints -> ai_family != AF_UNSPEC)) - return EAI_FAMILY; - - /* Check if the socket type is valid. */ - if((hints -> ai_socktype != SOCK_DGRAM) && - (hints -> ai_socktype != SOCK_STREAM) && - (hints -> ai_socktype != 0)) - return EAI_SOCKTYPE; - - /* If socktype and protocol are both specified, check if they are meaningful. */ - if((hints -> ai_socktype != 0) && (hints -> ai_protocol != 0)) - { - if(((hints -> ai_socktype == SOCK_STREAM) && (hints -> ai_protocol != IPPROTO_TCP)) || - ((hints -> ai_socktype == SOCK_DGRAM) && (hints -> ai_protocol != IPPROTO_UDP)) || - ((hints -> ai_socktype == SOCK_RAW) && (hints -> ai_protocol != IPPROTO_RAW))) - return EAI_SOCKTYPE; - } - - } - else - { - hints = &default_hints; - } - - /* Sock type specified? */ - if(hints -> ai_socktype == 0) - { - - /* No; is protocol specified? */ - if(hints -> ai_protocol == 0) - { - - /* No, protocol is not specified. */ - - /* Set default socktype and protocol. */ - match_service_count = 3; - match_service_socktype[0] = SOCK_STREAM; - match_service_protocol[0] = IPPROTO_TCP; - match_service_socktype[1] = SOCK_DGRAM; - match_service_protocol[1] = IPPROTO_UDP; - match_service_socktype[2] = SOCK_RAW; - match_service_protocol[2] = 0; - } - else - { - - /* protocol is specified. */ - match_service_count = 1; - match_service_protocol[0] = (UINT)(hints -> ai_protocol); - - /* Set default socktype according to protocol. */ - if(hints -> ai_protocol == IPPROTO_TCP) - match_service_socktype[0] = SOCK_STREAM; - else if(hints -> ai_protocol == IPPROTO_UDP) - match_service_socktype[0] = SOCK_DGRAM; - } - } - else - { - - /* Socktype is specified. */ - match_service_count = 1; - match_service_socktype[0] = (UINT)(hints -> ai_socktype); - - if(hints -> ai_protocol == 0) - { - - /* Protocol is not specified. */ - - /* Set default protocol according to socktype. */ - if(hints -> ai_socktype == SOCK_STREAM) - match_service_protocol[0] = IPPROTO_TCP; - else if(hints -> ai_socktype == SOCK_DGRAM) - match_service_protocol[0] = IPPROTO_UDP; - else if(hints -> ai_socktype == SOCK_RAW) - match_service_protocol[0] = 0; - } - else - { - - /* Protocol is specififed. */ - match_service_protocol[0] = (UINT)(hints -> ai_protocol); - } - } - - if(service) - { - - /* Service is not null. */ - if(bsd_string_to_number(service, &port) != NX_SOC_ERROR) - { - - /* Service is a decimal port number string, and has been converted to a numeric port successfully. */ - - /* Convert port from host byte order to network byte order. */ - port = htons(port); - } - else - { - - /* Service is an address name, not a decimal port number string. */ - - /* Check if numeric service flag is set. If so this is an invalid string. */ - if(hints -> ai_flags & AI_NUMERICSERV) - return EAI_NONAME; - - match_service_count = 0; - - /* Look for a match of name, protocol and socket type for a match in the service list. */ - for(i = 0; i < _nx_bsd_serv_list_len; i++) - { - - /* Check if there is a match. */ - if(!memcmp(_nx_bsd_serv_list_ptr[i].service_name, service, _nx_bsd_string_length((CHAR *)service)) && - ((_nx_bsd_serv_list_ptr[i].service_socktype == hints -> ai_socktype) ||(hints -> ai_socktype == 0)) && - ((_nx_bsd_serv_list_ptr[i].service_protocol == hints -> ai_protocol) ||(hints -> ai_protocol == 0))) - { - match_service_socktype[match_service_count] = (UINT)(_nx_bsd_serv_list_ptr[i].service_socktype); - match_service_protocol[match_service_count++] = (UINT)(_nx_bsd_serv_list_ptr[i].service_protocol); - - /* Convert host byte order to network byte order. */ - port = htons(_nx_bsd_serv_list_ptr[i].service_port); - } - } - - /* Service is not available. */ - if(match_service_count == 0) - return EAI_SERVICE; - } - } - else - { - - /* Convert host byte order to network byte order. */ - port = htons(0); - } - - if(node) - { - - /* Node is not null. */ - - /* Determine the address family. */ - addr_family = AF_INET; - - for(i = 0; i < _nx_bsd_string_length((CHAR *)node); i++) - { - if(node[i] == ':') - { - /* There is a colon, so it is an IPv6 address. */ - addr_family = AF_INET6; - break; - } - } - - /* Initialize to 0, default to pton failing. */ - pton_flag = 0; - - if(addr_family == AF_INET) - { - - /* Convert node from a string presentation to a numeric address. */ - if(inet_pton(addr_family, node, &(nx_bsd_ipv4_addr_buffer[0])) == 1) - { - /* pton has successful completion. */ - pton_flag = 1; - - /* Check if the address and the specified family match. */ - if((hints -> ai_family != AF_INET) && (hints -> ai_family != AF_UNSPEC)) - return EAI_ADDRFAMILY; - - NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv4_addr_buffer[0]); - ipv4_addr_count = 1; - } - } - else - { - - /* Convert node from a string presentation to a numeric address. */ - if(inet_pton(addr_family, node, &(nx_bsd_ipv6_addr_buffer[0])) == 1) - { - /* pton completed successfully. */ - pton_flag = 1; - - /* Check is the address and the specified family matches. */ - if((hints -> ai_family != AF_INET6) && (hints -> ai_family != AF_UNSPEC)) - return EAI_ADDRFAMILY; - - NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[0]); - NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[1]); - NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[2]); - NX_CHANGE_ULONG_ENDIAN(nx_bsd_ipv6_addr_buffer[3]); - ipv6_addr_count = 1; - } - } - - if(pton_flag == 1) - { - - /* pton completed successfull. Host (node) is an address string. */ - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - /* DNS supports extended services including Canonical name queries. */ - if((hints -> ai_flags & AI_CANONNAME) && !(hints -> ai_flags & AI_NUMERICHOST)) - { - - /* Allocate a block for canonical name. */ - status = tx_block_allocate(&nx_bsd_cname_block_pool, (VOID *) &cname_buffer, NX_BSD_TIMEOUT); - - /* Check for error status. */ - if (status != TX_SUCCESS) - { - /* Set the error. */ - set_errno(ENOMEM); - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Return memory allocation error. */ - return(EAI_MEMORY); - } - - memcpy(cname_buffer, node, _nx_bsd_string_length((CHAR *)node)); - - } -#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ - - } - else - { - - /* Presentation to numeric format fails, node may be a hostname, not a numeric IP address. */ - - /* Check if numeric host flag is set. */ - if(hints -> ai_flags & AI_NUMERICHOST) - return EAI_NONAME; - -#ifdef NX_BSD_ENABLE_DNS - if(hints -> ai_family == AF_INET) - { - - /* Get IPv4 address by hostname. */ - status = nx_dns_ipv4_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv4_addr_buffer[0], - NX_BSD_IPV4_ADDR_PER_HOST * 4, &ipv4_addr_count, NX_BSD_TIMEOUT); - - if(status != NX_SUCCESS) - { - - /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation where the specified - network host exists but does not have any network addresses defined. It would be better to return EAI_FAIL - for DNS FAIL, and EAI_NODATA for the latter situation. */ - return EAI_FAIL; - } - } - else if(hints -> ai_family == AF_INET6) - { - - /* Get IPv6 address by hostname. */ - status = nxd_dns_ipv6_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv6_addr_buffer[0], - NX_BSD_IPV6_ADDR_PER_HOST * 16, &ipv6_addr_count, NX_BSD_TIMEOUT); - - if(status != NX_SUCCESS) - { - /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation where the specified - network host exists but does not have any network addresses defined. It would be better to return EAI_FAIL - for DNS FAIL, and EAI_NODATA for the latter situation. */ - return EAI_FAIL; - } - } - else - { - - /* Address family is not specified. Query for both IPv4 and IPv6 address. */ - - /* Get IPv4 address by hostname. */ - status = nx_dns_ipv4_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv4_addr_buffer[0], - NX_BSD_IPV4_ADDR_PER_HOST * 4, &ipv4_addr_count, NX_BSD_TIMEOUT); - - /* Get IPv6 address by hostname. */ - status2 = nxd_dns_ipv6_address_by_name_get(_nx_dns_instance_ptr, (UCHAR *)node, &nx_bsd_ipv6_addr_buffer[0], - NX_BSD_IPV6_ADDR_PER_HOST * 16, &ipv6_addr_count, NX_BSD_TIMEOUT); - - if((status != NX_SUCCESS) && status2 != NX_SUCCESS) - { - /* Just return EAI_FAIL, because we can't discriminate between DNS FAIL and the situation that the specified - network host exists, but does not have any network addresses defined. It would be better to return EAI_FAIL - for DNS FAIL, and EAI_NODATA for the latter situation. */ - return EAI_FAIL; - } - } - - if(hints -> ai_flags & AI_CANONNAME) - { - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - /* Allocate a block for canonical name. */ - status = tx_block_allocate(&nx_bsd_cname_block_pool, (VOID *) &cname_buffer, NX_BSD_TIMEOUT); - - /* Check for error status. */ - if (status != TX_SUCCESS) - { - /* Set the error. */ - set_errno(ENOMEM); - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Return memory allocation error. */ - return(EAI_MEMORY); - } - - status = nx_dns_cname_get(_nx_dns_instance_ptr, (UCHAR *)node, cname_buffer, - nx_bsd_cname_block_pool.tx_block_pool_block_size, NX_BSD_TIMEOUT); - if(status != NX_SUCCESS) - { - memcpy(cname_buffer, node, _nx_bsd_string_length((CHAR *)node)); - } - -#else - cname_buffer = (UCHAR *)node; -#endif - } -#else - return EAI_FAIL; -#endif - - } - } - else - { - - /* Node is null. */ - if(hints -> ai_flags & AI_PASSIVE) - { - /* The caller wiil use the socket for a passive open. */ - - nx_bsd_ipv4_addr_buffer[0] = INADDR_ANY; - - nx_bsd_ipv6_addr_buffer[0] = 0; - nx_bsd_ipv6_addr_buffer[1] = 0; - nx_bsd_ipv6_addr_buffer[2] = 0; - nx_bsd_ipv6_addr_buffer[3] = 0; - } - else - { - - /* Localhost address. */ - nx_bsd_ipv4_addr_buffer[0] = 0x7F000001; - - nx_bsd_ipv6_addr_buffer[0] = 0; - nx_bsd_ipv6_addr_buffer[1] = 0; - nx_bsd_ipv6_addr_buffer[2] = 0; - nx_bsd_ipv6_addr_buffer[3] = 1; - } - - if (hints -> ai_family != AF_INET6) - { - ipv4_addr_count = 1; - } - ipv6_addr_count = 1; - } - - - for(i = 0; i < ipv4_addr_count + ipv6_addr_count; i++) - { - - /* Allocate a block for ipv4 address. */ - status = tx_block_allocate(&nx_bsd_addrinfo_block_pool, (VOID *) &sockaddr_ptr, NX_BSD_TIMEOUT); - - /* Check for error status. */ - if (status != TX_SUCCESS) - { - - /* Set the error. */ - set_errno(ENOMEM); - - /* If head is not null, free the memory. */ - if(addrinfo_head_ptr) - freeaddrinfo(addrinfo_head_ptr); - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - if(hints -> ai_flags & AI_CANONNAME) - tx_block_release((VOID *)cname_buffer); -#endif - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Return memory allocation error. */ - return(EAI_MEMORY); - } - - /* Clear the memory. */ - memset((VOID*)sockaddr_ptr, 0, sizeof(struct addrinfo)); - - if(i < ipv4_addr_count) - { - - /* Process IPv4 address. */ - ((struct sockaddr_in*)sockaddr_ptr) -> sin_family = AF_INET; - ((struct sockaddr_in*)sockaddr_ptr) -> sin_port = (USHORT)port; - ((struct sockaddr_in*)sockaddr_ptr) -> sin_addr.s_addr = nx_bsd_ipv4_addr_buffer[i]; - - NX_CHANGE_ULONG_ENDIAN(((struct sockaddr_in*)sockaddr_ptr) -> sin_addr.s_addr); - } - else - { - - /* Process IPv6 address. */ - ((struct sockaddr_in6*)sockaddr_ptr) -> sin6_family = AF_INET6; - ((struct sockaddr_in6*)sockaddr_ptr) -> sin6_port = (USHORT)port; - memcpy(&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr), &nx_bsd_ipv6_addr_buffer[(i - ipv4_addr_count)*4], 16); - - NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[0])); - NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[1])); - NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[2])); - NX_CHANGE_ULONG_ENDIAN(*(ULONG*)&(((struct sockaddr_in6*)sockaddr_ptr) -> sin6_addr.s6_addr32[3])); - - } - - for(j = 0; j < match_service_count; j++) - { - - /* Allocate a block from the addrinfo block pool. */ - status = tx_block_allocate(&nx_bsd_addrinfo_block_pool, (VOID *) &addrinfo_cur_ptr, NX_BSD_TIMEOUT); - - /* Check for error status. */ - if (status != TX_SUCCESS) - { - - /* Set the error. */ - set_errno(ENOMEM); - - /* If head is not null, free the memory. */ - if(addrinfo_head_ptr) - freeaddrinfo(addrinfo_head_ptr); - - tx_block_release((VOID *)sockaddr_ptr); - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - if(hints -> ai_flags & AI_CANONNAME) - tx_block_release((VOID *)cname_buffer); -#endif - - /* Error getting NetX socket memory. */ - NX_BSD_ERROR(NX_BSD_BLOCK_POOL_ERROR, __LINE__); - - /* Return memory allocation error. */ - return(EAI_MEMORY); - } - - /* Clear the socket memory. */ - memset((VOID*)addrinfo_cur_ptr, 0, sizeof(struct addrinfo)); - - if(i < ipv4_addr_count) - { - - /* IPv4 */ - addrinfo_cur_ptr -> ai_family = AF_INET; - addrinfo_cur_ptr -> ai_addrlen = sizeof(struct sockaddr_in); - } - else - { - - /* IPv6 */ - addrinfo_cur_ptr -> ai_family = AF_INET6; - addrinfo_cur_ptr -> ai_addrlen = sizeof(struct sockaddr_in6); - } - - addrinfo_cur_ptr -> ai_socktype = (INT)(match_service_socktype[j]); - addrinfo_cur_ptr -> ai_protocol = (INT)(match_service_protocol[j]); - addrinfo_cur_ptr -> ai_addr = sockaddr_ptr; - if((i == 0) && (j == 0) && (hints -> ai_flags & AI_CANONNAME)) - addrinfo_cur_ptr -> ai_canonname = (CHAR *)cname_buffer; - else - addrinfo_cur_ptr -> ai_canonname = NX_NULL; - addrinfo_cur_ptr -> ai_next = NX_NULL; - - /* Make a list. */ - if(addrinfo_head_ptr == NX_NULL) - addrinfo_head_ptr = addrinfo_cur_ptr; - else - addrinfo_tail_ptr -> ai_next = addrinfo_cur_ptr; - - addrinfo_tail_ptr = addrinfo_cur_ptr; - - } - } - - *res = addrinfo_head_ptr; - - return 0; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* freeaddrinfo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function releases the memory allocated by getaddrinfo. */ -/* */ -/* INPUT */ -/* */ -/* res Pointer to a addrinfo struct */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_block_release Release socket memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID freeaddrinfo(struct addrinfo *res) -{ - -struct addrinfo *next_addrinfo; -struct sockaddr *ai_addr_ptr = NX_NULL; -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -CHAR *ai_canonname_ptr = NX_NULL; -#endif - - while(res) - { -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - if((res -> ai_canonname) && - (res -> ai_canonname != ai_canonname_ptr)) - { - - /* Release the CNAME memory. */ - tx_block_release((VOID *)res -> ai_canonname); - - ai_canonname_ptr = res -> ai_canonname; - } -#endif - if((res -> ai_addr) && - (res -> ai_addr != ai_addr_ptr)) - { - - /* Release the address memory. */ - tx_block_release((VOID *)res -> ai_addr); - - ai_addr_ptr = res -> ai_addr; - } - - /* Move next. */ - next_addrinfo = res -> ai_next; - - /* Release the addrinfo memory. */ - tx_block_release((VOID *)res); - - res = next_addrinfo; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* bsd_string_to_number PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts string to number. */ -/* */ -/* INPUT */ -/* */ -/* string Pointer to a string */ -/* number Pointer to a number */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* nx_bsd_isdigit Indicate char is a number */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static INT bsd_string_to_number(const CHAR *string, UINT *number) -{ - - /* Initialize the numbet to zero. */ - *number = 0; - - while(*string != '\0') - { - - /* Check if the current character is a digit character. */ - if(!nx_bsd_isdigit((UCHAR)(*string))) - return NX_SOC_ERROR; - - *number = (*number * 10) + (UINT)(*string - 0x30); - - string++; - } - - return NX_SOC_OK; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* getnameinfo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a socket address to a corresponding host and */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* sa Pointer to a generic socket */ -/* address structure */ -/* salen Length of sa structure */ -/* host Pointer to caller-allocated */ -/* buffer for hostname */ -/* hostlen Host buffer size */ -/* serv Pointer to caller-allocated */ -/* buffer for service name */ -/* servlen Service buffer size */ -/* */ -/* OUTPUT */ -/* */ -/* status 0 if OK, nonzero on errors */ -/* */ -/* CALLS */ -/* */ -/* nx_dns_host_by_address_get Get hostname by IPv4 address */ -/* nxd_dns_host_by_address_get Get hostname by IPv6 address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) -{ - -UINT i = 0; -/* Flag used to identify whether host/service is numeric, 0 no, 1 yes. */ -UINT numeric_flag; -USHORT *temp; -#ifdef NX_BSD_ENABLE_DNS -UINT status; -#ifdef FEATURE_NX_IPV6 -NXD_ADDRESS nxd_ipv6_addr; -#endif -#endif -const CHAR *rt_ptr; - - if(!sa) - { - - /* sa is NULL. */ - return EAI_FAMILY; - } - else - { - if((sa -> sa_family != AF_INET) && - (sa -> sa_family != AF_INET6)) - { - - /* sa isn't NULL, but family type is invalid. */ - return EAI_FAMILY; - } - else if((sa -> sa_family == AF_INET && salen != sizeof(struct sockaddr_in)) || - (sa -> sa_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))) - { - - /* Address length is invalid. */ - return EAI_FAMILY; - } - } - - /* Both host and service null are invalid */ - if((host == NX_NULL) && (serv == NX_NULL) && ((flags & NI_NAMEREQD) == 0)) - return EAI_NONAME; - - if(serv && servlen > 0) - { - numeric_flag = 1; - - /* If NUMERICSERV bit is set, set to 1. */ - if(flags & NI_NUMERICSERV) - { - numeric_flag = 1; - } - else if(flags & NI_DGRAM) - { - /* Socket type must be SOCK_DGRAM. */ - - for(i = 0; i < _nx_bsd_serv_list_len; i++) - { - temp = (USHORT *)(sa -> sa_data); - if((_nx_bsd_serv_list_ptr[i].service_port == *temp) && - (_nx_bsd_serv_list_ptr[i].service_socktype == SOCK_DGRAM)) - { - - /* Found a matched service, set numeric flag to 0. */ - numeric_flag = 0; - break; - } - } - } - else - { - - /* Socket type is SOCK_STREAM. */ - for(i = 0; i < _nx_bsd_serv_list_len; i++) - { - temp = (USHORT *)(sa -> sa_data); - if((_nx_bsd_serv_list_ptr[i].service_port == *temp) && - (_nx_bsd_serv_list_ptr[i].service_socktype == SOCK_STREAM)) - { - - /* Found a matched service, set numeric flag to 0. */ - numeric_flag = 0; - break; - } - } - } - - if(numeric_flag) - { - - /* Service is numeric, copy the service port. Then convert host byte order to network byte order. */ - temp = (USHORT *)(sa -> sa_data); - if(bsd_number_convert(htons(*temp), (CHAR *)serv, servlen, 10) == 0) - return EAI_OVERFLOW; - } - else - { - - /* Service isn't numeric, copy the service name. */ - if(_nx_bsd_string_length(_nx_bsd_serv_list_ptr[i].service_name) > servlen) - return EAI_OVERFLOW; - - memcpy(serv, _nx_bsd_serv_list_ptr[i].service_name, - _nx_bsd_string_length(_nx_bsd_serv_list_ptr[i].service_name)); - } - } - - if(host && hostlen > 0) - { - numeric_flag = 1; - - /* If NUMERIC bit is set, set flag to 1. */ - if(flags & NI_NUMERICHOST) - numeric_flag = 1; - else - { - -#ifdef NX_BSD_ENABLE_DNS - if(sa -> sa_family == AF_INET) - { - -#ifndef NX_DISABLE_IPV4 - /* Get host name by IPv4 address via DNS. */ - status = nx_dns_host_by_address_get(_nx_dns_instance_ptr, ntohl(((struct sockaddr_in *)sa) -> sin_addr.s_addr), - (UCHAR *)host, hostlen, NX_BSD_TIMEOUT); -#else - status = NX_DNS_NO_SERVER; -#endif /* NX_DISABLE_IPV4 */ - } - else - { -#ifdef FEATURE_NX_IPV6 - /* copy data from sockaddr structure to NXD_ADDRESS structure. */ - nxd_ipv6_addr.nxd_ip_version = NX_IP_VERSION_V6; - nxd_ipv6_addr.nxd_ip_address.v6[0] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[0]); - nxd_ipv6_addr.nxd_ip_address.v6[1] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[1]); - nxd_ipv6_addr.nxd_ip_address.v6[2] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[2]); - nxd_ipv6_addr.nxd_ip_address.v6[3] = ntohl(((struct sockaddr_in6 *)sa) -> sin6_addr.s6_addr32[3]); - - /* Get host name by IPv6 address via DNS. */ - status = nxd_dns_host_by_address_get(_nx_dns_instance_ptr, &nxd_ipv6_addr, - (UCHAR *) host, hostlen, NX_BSD_TIMEOUT); -#else - status = NX_DNS_NO_SERVER; -#endif - } - - - if(status == NX_DNS_SIZE_ERROR) - return EAI_OVERFLOW; - else if(status != NX_SUCCESS) - { - - /* DNS query fails. */ - if(flags & NI_NAMEREQD) - return EAI_NONAME; - } - else - { - - /* DNS query succeeds. */ - numeric_flag = 0; - } -#else - if(flags & NI_NAMEREQD) - return EAI_NONAME; -#endif - } - - if(numeric_flag) - { - - /* Host must be numeric string. Convert IP address from numeric to presentation. */ - if(sa -> sa_family == AF_INET) - rt_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)sa) -> sin_addr, (CHAR *)host, hostlen); - else - rt_ptr = inet_ntop(AF_INET6, &((struct sockaddr_in6*)sa) -> sin6_addr, (CHAR *)host, hostlen); - - if(!rt_ptr) - return EAI_OVERFLOW; - } - - } - - return 0; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_bsd_set_service_list PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function lets user set the service list used by getaddrinfo */ -/* */ -/* INPUT */ -/* */ -/* serv_list_ptr Pointer to a service list */ -/* serv_list_len Service list length */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID nx_bsd_set_service_list(struct NX_BSD_SERVICE_LIST *serv_list_ptr, ULONG serv_list_len) -{ - _nx_bsd_serv_list_ptr = serv_list_ptr; - _nx_bsd_serv_list_len = serv_list_len; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_bsd_string_length PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the length of string. */ -/* */ -/* INPUT */ -/* */ -/* string Pointer to a string */ -/* */ -/* OUTPUT */ -/* */ -/* ULONG String length */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo BSD Layer Source Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_bsd_string_length(CHAR * string) -{ -int length = 0; - - while(*string != '\0') - { - length++; - string++; - } - - return((ULONG)length); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_bsd_fast_periodic_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles BSD system clock. When the timer expires, the */ -/* BSD system clock is updated and then default IP fast periodic entry */ -/* routine is invoked. */ -/* */ -/* INPUT */ -/* */ -/* id Argument of default timer entry*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* None */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_bsd_fast_periodic_timer_entry(ULONG id) -{ - - /* Update the BSD system clock. */ - nx_bsd_system_clock += nx_bsd_timer_rate; - - /* Call default IP fast periodic timer entry. */ - nx_bsd_ip_fast_periodic_timer_entry(id); -} diff --git a/protocol_handlers/BSD/nxd_bsd.h b/protocol_handlers/BSD/nxd_bsd.h deleted file mode 100644 index 0495cdde..00000000 --- a/protocol_handlers/BSD/nxd_bsd.h +++ /dev/null @@ -1,883 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** BSD 4.3 Socket API Compatible Interface to NetX Duo */ -/** */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* BSD DEFINITIONS RELEASE */ -/* */ -/* nxd_bsd.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the constants, structures, etc... needed to */ -/* implement the BSD 4.3 Socket API Compatible Interface to NetX Duo. */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_BSD_H -#define NXD_BSD_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "time.h" - -/* Bring in the necessary NetX include file. */ -#include "nx_api.h" - - -/* Define the print error macro for reporting source line number. - -#define NX_BSD_PRINT_ERRORS -*/ - -/* Defined, raw pppoe feature is enabled. */ -/* -#define NX_BSD_RAW_PPPOE_SUPPORT -*/ - -/* Defined, raw feature is enabled. */ -/* -#define NX_BSD_RAW_SUPPORT -*/ - -/* Defined, raw packet is not duplicated. Then NetX will not handle packets such as ARP. */ -/* -#define NX_DISABLE_BSD_RAW_PACKET_DUPLICATE -*/ - -#if defined(NX_BSD_RAW_SUPPORT) && defined(NX_BSD_RAW_PPPOE_SUPPORT) -#error "Raw feature conflicts with raw PPPoE feature" -#endif /* defined(NX_BSD_RAW_SUPPORT) && defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - -/* Defined, getaddrinfo is able to get address by name/cname. getnameinfo is able to get name by address. */ -/* -#define NX_BSD_ENABLE_DNS -*/ - - -/* - Define the BSD socket timeout process to execute in the timer context. - If this option is not defined, application needs to create stack space for the BSD timeout process - thread, and passes the stack to the BSD layer through the bsd_initialize() call. In this configuration, - the BSD timeout process is all done in the BSD timeout process thread context. - - User may choose to define NX_BSD_TIMEOUT_PROCESS_IN_TIMER, so the BSD timeout process is executed in the - ThreadX timer object context. This configuration could eliminate an extra thread (and associated stack - space.) The following parameters passed into bsd_initialize are ignored: - * bsd_thread_stack_area - * bsd_thread_stack_size - * bsd_thread_priority - However system designer needs to be aware of the following if the BSD timeout process is - executed in ThreadX timer context: - * The amount of BSD socket processing may slow down the ThreadX timer; - * If the timer is executed in ISR context (ThreadX library is built with TX_TIMER_PROCESS_IN_ISR), - the BSD timeout process is now executing in the ISR context; - - By default NX_BSD_TIMEOUT_PROCESS_IN_TIMER is NOT defined. -*/ -/* #define NX_BSD_TIMEOUT_PROCESS_IN_TIMER */ - -/* Define configuration constants for the BSD compatibility layer. Note that these can be overridden via -D or a #define somewhere else. */ - -#ifndef NX_BSD_TCP_WINDOW -#define NX_BSD_TCP_WINDOW 65535 /* 64k is typical window size for 100Mb ethernet. */ -#endif - -#ifndef NX_BSD_SOCKFD_START -#define NX_BSD_SOCKFD_START 32 /* Logical FD starting value. */ -#endif - -#ifndef NX_BSD_MAX_SOCKETS -#define NX_BSD_MAX_SOCKETS 32 /* Maximum number of total sockets available in the BSD layer. Note */ -#endif /* NOTE: Must be multiple of 32! */ - -#ifndef NX_BSD_MAX_LISTEN_BACKLOG -#define NX_BSD_MAX_LISTEN_BACKLOG 5 /* Maximum listen backlog. */ -#endif - -#ifndef NX_MICROSECOND_PER_CPU_TICK -#define NX_MICROSECOND_PER_CPU_TICK (1000000/NX_IP_PERIODIC_RATE) /* Number of microseconds per timer interrupt, default 10ms. */ -#endif -#ifndef NX_BSD_TIMEOUT -#define NX_BSD_TIMEOUT (20*NX_IP_PERIODIC_RATE) - /* By default all internal NetX calls wait and block for 20 seconds. */ -#endif - - -#ifndef NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT -#define NX_BSD_TCP_SOCKET_DISCONNECT_TIMEOUT 1 /* Timeout in timer ticks for internal NetX to disconnect the socket. - The default value of 1 tick is so NetX BSD emulates native BSD - socket and performs an immediate socket close without sending an RST - packet. */ -#endif - -/* Define configurable options for BSD extended options. */ - - -#ifndef NX_BSD_TIMER_RATE -#define NX_BSD_TIMER_RATE (1 * NX_IP_PERIODIC_RATE) /* Rate at which BSD timer runs. */ -#endif - - -/* Define BSD events */ - -#define NX_BSD_RECEIVE_EVENT ((ULONG) 0x00000001) /* Event flag to signal a receive packet event */ -#define NX_BSD_SELECT_EVENT ((ULONG) 0x00008000) /* Event flag to signal a thread is waiting in select */ -#define NX_BSD_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flag */ -#define NX_BSD_CONNECT_EVENT ((ULONG) 0x00000002) -#define NX_BSD_LINGER_EVENT ((ULONG) 0x00000004) /* Event flag to signal a timed linger state has expired on a socket */ -#define NX_BSD_TIMED_WAIT_EVENT ((ULONG) 0x00000008) /* Event flag to signal a timed wait state has expired on a socket */ -#define NX_BSD_TIMER_EVENT ((ULONG) 0x00000010) /* Event flag to singal a BSD 1 sec timer */ - -/* For compatibility undefine the fd_set. Then define the FD set size. */ - -#ifdef fd_set -#undef fd_set -#endif - -#ifdef FD_SETSIZE -#undef FD_SETSIZE /* May be different in other header files e.g 64 in GNU types.h file */ -#define FD_SETSIZE (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START) /* Number of sockets to select on - same is max sockets! */ -#else -#define FD_SETSIZE (NX_BSD_MAX_SOCKETS + NX_BSD_SOCKFD_START) /* Number of sockets to select on - same is max sockets! */ -#endif - - -/* Define some BSD protocol constants. */ - -#define SOCK_STREAM 1 /* TCP Socket */ -#define SOCK_DGRAM 2 /* UDP Socket */ -#define SOCK_RAW 3 /* Raw socket */ -#define IPPROTO_TCP 6 /* TCP Socket */ -#define IPPROTO_UDP 17 /* TCP Socket */ -#define IPPROTO_RAW 255 /* Raw Socket */ - -/* Define supported flags for 'send' and 'recv'. */ -#define MSG_PEEK 0x02 /* Peek incoming message */ -#define MSG_DONTWAIT 0x40 /* Nonblocking IO */ - -/* Address families. */ - -#define AF_UNSPEC 0 /* Unspecified. */ -#define AF_NS 1 /* Local to host (pipes, portals). */ -#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) */ - -/* Protocol families, same as address families. */ -#define PF_INET AF_INET -#define PF_INET6 AF_INET6 -#define PF_PACKET AF_PACKET -#define ETH_P_ALL 3 - -#define INADDR_ANY 0 -#define NX_BSD_LOCAL_IF_INADDR_ANY 0xFFFFFFFF -/* Define API error codes. */ - -#define NX_SOC_ERROR -1 /* Failure. */ -#ifndef ERROR -#define ERROR NX_SOC_ERROR -#endif -#define NX_SOC_OK 0 /* Success. */ -#ifndef OK -#define OK NX_SOC_OK -#endif -#define NX_BSD_BLOCK_POOL_ERROR 1 -#define NX_BSD_MUTEX_ERROR 2 -#define NX_BSD_THREAD_ERROR 4 -#define NX_BSD_EVENT_ERROR 7 -#define NX_BSD_ENVIRONMENT_ERROR 8 - -#ifndef NX_PACKET_OFFSET_ERROR -#define NX_PACKET_OFFSET_ERROR 0x53 -#endif - -/* The Netx API does not require Host to Network conversion or vice versa. The following macro's are provided for source compatibility reasons only. */ - -#ifndef htons -#define htons(a) a -#endif -#ifndef htonl -#define htonl(a) a -#endif -#ifndef ntohs -#define ntohs(a) a -#endif -#ifndef ntohl -#define ntohl(a) a -#endif - -/* Define error handling macro. */ - -#ifdef NX_BSD_PRINT_ERRORS -#define NX_BSD_ERROR(status, line) printf(" NX BSD debug error message:, NX status: %x source line: %i \n", status, line) -#else -#define NX_BSD_ERROR(status, line) -#endif - - -/* Define file descriptor operation flags. */ - -/* Note: FIONREAD is hardware dependant. The default is for i386 processor. */ -#ifndef FIONREAD -#define FIONREAD 0x541B /* Read bytes available for the ioctl() command */ -#endif - -#define F_GETFL 3 /* Get file descriptors */ -#define F_SETFL 4 /* Set a subset of file descriptors (e.g. O_NONBlOCK */ -#define O_NONBLOCK 0x4000 /* Option to enable non blocking on a file (e.g. socket) */ - -#ifndef FIONBIO -#define FIONBIO 0x5421 /* Enables socket non blocking option for the ioctl() command */ -#endif - - -/* Define the minimal TCP socket listen backlog value. */ -#ifndef NX_BSD_TCP_LISTEN_MIN_BACKLOG -#define NX_BSD_TCP_LISTEN_MIN_BACKLOG 1 -#endif - -/* Define the maximum number of packets that can be queued on a UDP socket or RAW socket. */ -#ifndef NX_BSD_SOCKET_QUEUE_MAX -#define NX_BSD_SOCKET_QUEUE_MAX 5 -#endif - -/* Define the constants that determine how big the hash table is for raw socket Protocol. The - value must be a power of two, so subtracting one gives us the mask. */ - -#ifndef NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE -#define NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE 32 -#endif /* NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE */ - -#define NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_MASK (NX_BSD_SOCKET_RAW_PROTOCOL_TABLE_SIZE-1) - -/* Define additional BSD socket errors. */ - -/* From errno-base.h in /usr/include/asm-generic; */ -#define EPERM 1 /* Operation not permitted */ -#define E_MIN 1 /* Minimum Socket/IO error */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ - -/* From errno.h in /usr/include/asm-generic; */ - -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ -#define EDEADLOCK EDEADLK -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ -#define ECANCELED 125 /* Operation Canceled */ -#define ENOKEY 126 /* Required key not available */ -#define EKEYEXPIRED 127 /* Key has expired */ -#define EKEYREVOKED 128 /* Key has been revoked */ -#define EKEYREJECTED 129 /* Key was rejected by service */ -#define EOWNERDEAD 130 /* Owner died - for robust mutexes*/ -#define ENOTRECOVERABLE 131 /* State not recoverable */ -#define ERFKILL 132 /* Operation not possible due to RF-kill */ - - -/* List of BSD sock options from socket.h in /usr/include/asm/socket.h and asm-generic/socket.h. - Note: not all of these are implemented in NetX Duo Extended socket options. - - The first set of socket options take the socket level (category) SOL_SOCKET. */ - -#define SOL_SOCKET 1 /* Define the socket option category. */ -#define IPPROTO_IP 2 /* Define the IP option category. */ -#define SO_MIN 1 /* Minimum Socket option ID */ -#define SO_DEBUG 1 /* Debugging information is being recorded.*/ -#define SO_REUSEADDR 2 /* Enable reuse of local addresses in the time wait state */ -#define SO_TYPE 3 /* Socket type */ -#define SO_ERROR 4 /* Socket error status */ -#define SO_DONTROUTE 5 /* Bypass normal routing */ -#define SO_BROADCAST 6 /* Transmission of broadcast messages is supported.*/ -#define SO_SNDBUF 7 /* Enable setting trasnmit buffer size */ -#define SO_RCVBUF 8 /* Enable setting receive buffer size */ -#define SO_KEEPALIVE 9 /* Connections are kept alive with periodic messages */ -#define SO_OOBINLINE 10 /* Out-of-band data is transmitted in line */ -#define SO_NO_CHECK 11 /* Disable UDP checksum */ -#define SO_PRIORITY 12 /* Set the protocol-defined priority for all packets to be sent on this socket */ -#define SO_LINGER 13 /* Socket lingers on close pending remaining send/receive packets. */ -#define SO_BSDCOMPAT 14 /* Enable BSD bug-to-bug compatibility */ -#define SO_REUSEPORT 15 /* Rebind a port already in use */ - -#ifndef SO_PASSCRED /* Used for passing credentials. Not currently in use. */ -#define SO_PASSCRED 16 /* Enable passing local user credentials */ -#define SO_PEERCRED 17 /* Obtain the process, user and group ids of the other end of the socket connection */ -#define SO_RCVLOWAT 18 /* Enable receive "low water mark" */ -#define SO_SNDLOWAT 19 /* Enable send "low water mark" */ -#define SO_RCVTIMEO 20 /* Enable receive timeout */ -#define SO_SNDTIMEO 21 /* Enable send timeout */ -#endif /* SO_PASSCRED */ -#define SO_SNDBUFFORCE 22 /* Enable setting trasnmit buffer size overriding user limit (admin privelege) */ -#define SO_RCVBUFFORCE 23 /* Enable setting trasnmit buffer size overriding user limit (admin privelege) */ -#define SO_MAX SO_RCVBUFFORCE /* Maximum Socket option ID */ - -/* This second set of socket options take the socket level (category) IPPROTO_IP. */ - -#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. */ -#define IP_BLOCK_SOURCE 30 /* Block multicast from certain source. */ -#define IP_UNBLOCK_SOURCE 31 /* Unblock multicast from certain source. */ -#define IP_ADD_MEMBERSHIP 32 /* Join IPv4 multicast membership */ -#define IP_DROP_MEMBERSHIP 33 /* Leave IPv4 multicast membership */ -#define IP_HDRINCL 34 /* Raw socket IPv4 header included. */ -#define IP_RAW_RX_NO_HEADER 35 /* NetX proprietary socket option that does not include - IPv4/IPv6 header (and extension headers) on received raw sockets.*/ -#define IP_RAW_IPV6_HDRINCL 36 /* Transmitted buffer over IPv6 socket contains IPv6 header. */ -#define IP_OPTION_MAX IP_RAW_IPV6_HDRINCL - - - -/* - * User-settable options (used with setsockopt). - */ -#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -#define TCP_MAXSEG 0x02 /* set maximum segment size */ -#define TCP_NOPUSH 0x04 /* don't push last block of write */ -#define TCP_NOOPT 0x08 /* don't use TCP options */ - - -/* Define data types used in structure timeval. */ - -typedef LONG suseconds_t; - -struct timeval -{ - time_t tv_sec; /* Seconds */ - suseconds_t tv_usec; /* Microseconds */ -}; - -struct sockaddr_storage -{ - USHORT ss_len; - USHORT ss_family; -}; - -struct sockaddr -{ - USHORT sa_family; /* Address family (e.g. , AF_INET). */ - UCHAR sa_data[14]; /* Protocol- specific address information. */ -}; - -struct in6_addr -{ - union - { - UCHAR _S6_u8[16]; - ULONG _S6_u32[4]; - } _S6_un; -}; - -#define s6_addr _S6_un._S6_u8 -#define s6_addr32 _S6_un._S6_u32 - -struct sockaddr_in6 -{ - USHORT sin6_family; /* AF_INET6 */ - USHORT sin6_port; /* Transport layer port. */ - ULONG sin6_flowinfo; /* IPv6 flow information. */ - struct in6_addr sin6_addr; /* IPv6 address. */ - ULONG sin6_scope_id; /* set of interafces for a scope. */ - -}; - -/* Internet address (a structure for historical reasons). */ - -struct in_addr -{ - ULONG s_addr; /* Internet address (32 bits). */ -}; - -typedef ULONG in_addr_t; -typedef ULONG socklen_t; - - - -/* Socket address, Internet style. */ - -struct sockaddr_in -{ - USHORT sin_family; /* Internet Protocol (AF_INET). */ - USHORT sin_port; /* Address port (16 bits). */ - struct in_addr sin_addr; /* Internet address (32 bits). */ - CHAR sin_zero[8]; /* Not used. */ -}; - - - -typedef struct FD_SET_STRUCT /* The select socket array manager. */ -{ - INT fd_count; /* How many are SET? */ - ULONG fd_array[(NX_BSD_MAX_SOCKETS + 31)/32]; /* Bit map of SOCKET Descriptors. */ -} fd_set; - - - -typedef struct NX_BSD_SOCKET_SUSPEND_STRUCT -{ - ULONG nx_bsd_socket_suspend_actual_flags; - fd_set nx_bsd_socket_suspend_read_fd_set; - fd_set nx_bsd_socket_suspend_write_fd_set; - fd_set nx_bsd_socket_suspend_exception_fd_set; - -} NX_BSD_SOCKET_SUSPEND; - - -struct ip_mreq -{ - struct in_addr imr_multiaddr; /* The IPv4 multicast address to join. */ - struct in_addr imr_interface; /* The interface to use for this group. */ -}; - - -/* Define additional BSD data structures for supporting socket options. */ - -struct sock_errno -{ - INT error; /* default = 0; */ -}; - -struct linger -{ - INT l_onoff; /* 0 = disabled; 1 = enabled; default = 0;*/ - INT l_linger; /* linger time in seconds; default = 0;*/ -}; - -struct sock_keepalive -{ - INT keepalive_enabled; /* 0 = disabled; 1 = enabled; default = 0;*/ -}; - -struct sock_reuseaddr -{ - INT reuseaddr_enabled; /* 0 = disabled; 1 = enabled; default = 1; */ -}; - -struct sock_winsize -{ - INT winsize; /* receive window size for TCP sockets ; */ -}; - -/* Define an union struct for master ID and secondary ID used in NX_BSD_SOCKET_STRUCT. */ -union UNION_ID -{ - INT nx_bsd_socket_master_socket_id; - INT nx_bsd_socket_secondary_socket_id; -}; - - -struct addrinfo -{ - INT ai_flags; - INT ai_family; - INT ai_socktype; - INT ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - CHAR *ai_canonname; - struct addrinfo *ai_next; -}; - -struct NX_BSD_SERVICE_LIST -{ - CHAR *service_name; - USHORT service_port; - INT service_socktype; - INT service_protocol; -}; - -/* Define the Errors return by getaddrinfo. */ - -/* The specified host doesn't have addresses in the specified address family. */ -#define EAI_ADDRFAMILY 40 -/* Name server temporary failure. */ -#define EAI_AGAIN 41 -/* hints.si_flags contains invalid flag. */ -#define EAI_BADFLAGS 42 -/* DNS fail. */ -#define EAI_FAIL 43 -/* Invalid address family. */ -#define EAI_FAMILY 44 -/* memory failure. */ -#define EAI_MEMORY 45 -/* host exsits, but doesn't have address in specified family. */ -#define EAI_NODATA 46 -#define EAI_NONAME 47 -/* service not available for the specified socket type. */ -#define EAI_SERVICE 48 -#define EAI_OVERFLOW 49 -/* invalid socktype. */ -#define EAI_SOCKTYPE 50 -#define EAI_SYSTEM 51 - - -/* Define ai_flags value. */ -#define AI_PASSIVE 0x0001 -/* request CNAME. */ -#define AI_CANONNAME 0x0002 -/* host must be a address string. */ -#define AI_NUMERICHOST 0x0004 -/* service must be a port string. */ -#define AI_NUMERICSERV 0x0008 -#define AI_V4MAPPED 0x0010 -#define AI_ALL 0x0020 -#define AI_ADDRCONFIG 0x0040 - -/* Return numeric string for hostname. */ -#define NI_NUMERICHOST 0x0001 -/* Return numeric string for service name. */ -#define NI_NUMERICSERV 0x0002 -/* Return only hostname portion of FQDN. */ -#define NI_NOFQDN 0x0004 -/* Return error if name can't be resolved from address. */ -#define NI_NAMEREQD 0x0008 -/* Datagram service. */ -#define NI_DGRAM 0x0010 - - -/* Defines maximum IPv4 addresses for getaddrinfo. */ -#ifndef NX_BSD_IPV4_ADDR_MAX_NUM -#define NX_BSD_IPV4_ADDR_MAX_NUM 5 -#endif /* NX_BSD_IPV4_ADDR_MAX_NUM */ - -/* Defines maximum IPv6 addresses for getaddrinfo. */ -#ifndef NX_BSD_IPV6_ADDR_MAX_NUM -#define NX_BSD_IPV6_ADDR_MAX_NUM 5 -#endif /* NX_BSD_IPV6_ADDR_MAX_NUM */ - -/* Defines maximum IPv4 addresses stored from DNS. */ -#ifndef NX_BSD_IPV4_ADDR_PER_HOST -#define NX_BSD_IPV4_ADDR_PER_HOST 5 -#endif /* NX_BSD_IPV4_ADDR_PER_HOST */ - -/* Defines maximum IPv6 addresses stored from DNS. */ -#ifndef NX_BSD_IPV6_ADDR_PER_HOST -#define NX_BSD_IPV6_ADDR_PER_HOST 2 -#endif /* NX_BSD_IPV6_ADDR_PER_HOST */ - -/* Define the BSD socket status bits. */ -#define NX_BSD_SOCKET_CONNECTION_INPROGRESS 1 -#define NX_BSD_SOCKET_ERROR (1 << 1) -#define NX_BSD_SOCKET_CONNECTED (1 << 2) -/* Disconnected from the stack. */ -#define NX_BSD_SOCKET_DISCONNECT_FROM_STACK (1 << 3) -#define NX_BSD_SOCKET_SERVER_MASTER_SOCKET (1 << 4) -#define NX_BSD_SOCKET_SERVER_SECONDARY_SOCKET (1 << 5) -#define NX_BSD_SOCKET_TX_HDR_INCLUDE (1 << 6) -#define NX_BSD_SOCKET_RX_NO_HDR (1 << 7) -#define NX_BSD_SOCKET_IN_USE (1 << 8) -#define NX_BSD_SOCKET_CLIENT (1 << 9) -#define NX_BSD_SOCKET_ENABLE_LISTEN (1 << 10) -#define NX_BSD_SOCKET_BOUND (1 << 11) -#define NX_BSD_SOCKET_ACCEPTING (1 << 12) -#define NX_BSD_SOCKET_CONNECTION_REQUEST (1 << 13) -#define NX_BSD_SOCKET_DISCONNECTION_REQUEST (1 << 14) - -/* Define the BSD socket options bits. */ -#define NX_BSD_SOCKET_ENABLE_RAW_SOCKET 1 -#define NX_BSD_SOCKET_ENABLE_OPTION_LINGER (1 << 1) -#define NX_BSD_SOCKET_ENABLE_OPTION_REUSEADDR (1 << 2) -#define NX_BSD_SOCKET_ENABLE_OPTION_NON_BLOCKING (1 << 3) - -/* Define the internal management structure for the BSD layer. */ - -typedef struct NX_BSD_SOCKET_STRUCT -{ - NX_TCP_SOCKET *nx_bsd_socket_tcp_socket; - NX_UDP_SOCKET *nx_bsd_socket_udp_socket; - ULONG nx_bsd_socket_family; - /* Store the protocol number. For example TCP is 6, UDP is 17. For raw socket - it is the protocol it wishes to receive. */ - USHORT nx_bsd_socket_protocol; - TX_THREAD *nx_bsd_socket_busy; - union UNION_ID nx_bsd_socket_union_id; - NX_PACKET* nx_bsd_socket_received_packet; - NX_PACKET* nx_bsd_socket_received_packet_tail; - UINT nx_bsd_socket_received_byte_count; - UINT nx_bsd_socket_received_byte_count_max; - UINT nx_bsd_socket_received_packet_count; - UINT nx_bsd_socket_received_packet_count_max; - ULONG nx_bsd_socket_received_packet_offset; - INT nx_bsd_socket_source_port; - ULONG nx_bsd_socket_local_bind_interface; - UINT nx_bsd_socket_local_bind_interface_index; - NXD_ADDRESS nx_bsd_socket_source_ip_address; - NXD_ADDRESS nx_bsd_socket_peer_ip; - - /* For TCP/UDP, the local port is the port number this socket receives on. - For raw socket this field is not used. */ - USHORT nx_bsd_socket_local_port; - USHORT nx_bsd_socket_peer_port; - INT nx_bsd_option_linger_time; - UINT nx_bsd_option_linger_time_closed; - UINT nx_bsd_option_linger_start_close; - UINT nx_bsd_socket_time_wait_remaining; - ULONG nx_bsd_option_receive_timeout; - ULONG nx_bsd_option_send_timeout; - INT nx_bsd_file_descriptor_flags; - ULONG nx_bsd_socket_status_flags; - ULONG nx_bsd_socket_option_flags; - int nx_bsd_socket_error_code; - - struct NX_BSD_SOCKET_STRUCT - *nx_bsd_socket_next; - struct NX_BSD_SOCKET_STRUCT - *nx_bsd_socket_previous; - - INT nx_bsd_socket_id; -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - UINT nx_bsd_socket_create_id; -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) - UCHAR nx_bsd_socket_sll_addr[6]; - USHORT nx_bsd_socket_sll_protocol; - INT nx_bsd_socket_sll_ifindex; -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - -} NX_BSD_SOCKET; - - -/* Define the BSD function prototypes for use by the application. */ - -INT accept(INT sockID, struct sockaddr *ClientAddress, INT *addressLength); -INT bsd_initialize(NX_IP *default_ip, NX_PACKET_POOL *default_pool, CHAR *bsd_thread_stack_area, ULONG bsd_thread_stack_size, UINT bsd_thread_priority); -INT bind(INT sockID, struct sockaddr *localAddress, INT addressLength); -INT connect(INT sockID, struct sockaddr *remoteAddress, INT addressLength); -INT getpeername(INT sockID, struct sockaddr *remoteAddress, INT *addressLength); -INT getsockname(INT sockID, struct sockaddr *localAddress, INT *addressLength); -INT ioctl(INT sockID, INT command, INT *result); -in_addr_t inet_addr(const CHAR *buffer); -CHAR *inet_ntoa(struct in_addr address_to_convert); -INT inet_aton(const CHAR *cp_arg, struct in_addr *addr); -INT inet_pton(INT af, const CHAR *src, VOID *dst); -const CHAR *inet_ntop(INT af, const VOID *src, CHAR *dst, socklen_t size); -INT listen(INT sockID, INT backlog); -#ifdef NX_ENABLE_IP_RAW_PACKET_FILTER -UINT nx_bsd_raw_packet_receive(NX_BSD_SOCKET *bsd_socket_ptr, NX_PACKET **packet_ptr); -UINT nx_bsd_raw_packet_info_extract(NX_PACKET *packet_ptr, NXD_ADDRESS *nxd_address, UINT *interface_index); -VOID nx_bsd_raw_receive_notify(NX_IP *ip_ptr, UINT bsd_socket_index); -#endif -UINT nx_bsd_socket_set_inherited_settings(UINT master_sock_id, UINT secondary_sock_id); -INT recvfrom(INT sockID, CHAR *buffer, INT buffersize, INT flags,struct sockaddr *fromAddr, INT *fromAddrLen); -INT recv(INT sockID, VOID *rcvBuffer, INT bufferLength, INT flags); -INT sendto(INT sockID, CHAR *msg, INT msgLength, INT flags, struct sockaddr *destAddr, INT destAddrLen); -INT send(INT sockID, const CHAR *msg, INT msgLength, INT flags); -INT select(INT nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); -INT soc_close( INT sockID); -INT socket(INT protocolFamily, INT type, INT protocol); -INT fcntl(INT sock_ID, UINT flag_type, UINT f_options); -INT getsockopt(INT sockID, INT option_level, INT option_name, VOID *option_value, INT *option_length); -INT setsockopt(INT sockID, INT option_level, INT option_name, const VOID *option_value, INT option_length); -INT getaddrinfo(const CHAR *node, const CHAR *service, const struct addrinfo *hints, struct addrinfo **res); -VOID freeaddrinfo(struct addrinfo *res); -INT getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); -VOID nx_bsd_set_service_list(struct NX_BSD_SERVICE_LIST *serv_list_ptr, ULONG serv_list_len); - -#undef FD_SET -#undef FD_CLR -#undef FD_ISSET -#undef FD_ZERO - -VOID FD_SET(INT fd, fd_set *fdset); -VOID FD_CLR(INT fd, fd_set *fdset); -INT FD_ISSET(INT fd, fd_set *fdset); -VOID FD_ZERO(fd_set *fdset); -VOID set_errno(INT tx_errno); -int _nxd_get_errno(VOID); -#define errno (_nxd_get_errno()) - -#ifdef NX_BSD_RAW_PPPOE_SUPPORT - -#define ETHERTYPE_PPPOE_DISC 0x8863 /* PPPoE Discovery protocol type */ -#define ETHERTYPE_PPPOE_SESS 0x8864 /* PPPoE Session Protocol type */ - -#define NX_LINK_PACKET_PPPOE_SESS_SEND ETHERTYPE_PPPOE_SESS -#define NX_LINK_PACKET_PPPOE_DISC_SEND ETHERTYPE_PPPOE_DISC - - -UINT _nx_bsd_pppoe_packet_received(NX_PACKET *packet_ptr, UINT frame_type, UINT interface_id); -#endif /* NX_BSD_RAW_PPPOE_SUPPORT */ - -#if defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) -/* Link Layer Socket Addressing */ -struct sockaddr_ll -{ - USHORT sll_family; /* Address Family. Must be AF_PACKET */ - USHORT sll_protocol; /* LL frame type */ - INT sll_ifindex; /* Interface Index. */ - USHORT sll_hatype; /* Header type */ - UCHAR sll_pkttype; /* Packet type */ - UCHAR sll_halen; /* Length of address */ - UCHAR sll_addr[8]; /* Physical layer address */ -}; -#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ - -#ifdef NX_BSD_RAW_SUPPORT -extern UINT _nx_driver_hardware_packet_send(NX_PACKET *packet_ptr); /* Send hardware packet. */ -extern VOID (*_nx_driver_hardware_packet_received_callback)(NX_PACKET *packet_ptr, UCHAR *consumed);/* Callback function pointer when packet is received. */ -#endif /* NX_BSD_RAW_SUPPORT */ - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_BSD_H */ - diff --git a/protocol_handlers/CMakeLists.txt b/protocol_handlers/CMakeLists.txt deleted file mode 100644 index 8a7e8aa2..00000000 --- a/protocol_handlers/CMakeLists.txt +++ /dev/null @@ -1,70 +0,0 @@ -# Each protocol handler is listed below. If you want -# to disable some / all of these, comment out the block(s) in question - -set(SOURCES - # {{BEGIN_TARGET_SOURCES}} - ${CMAKE_CURRENT_LIST_DIR}/auto_ip/nx_auto_ip.c - # ${CMAKE_CURRENT_LIST_DIR}/BSD/nxd_bsd.c - ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcpv6_client.c - ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcpv6_server.c - ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcp_client.c - ${CMAKE_CURRENT_LIST_DIR}/dhcp/nxd_dhcp_server.c - ${CMAKE_CURRENT_LIST_DIR}/dns/nxd_dns.c - ${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_client.c - ${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_server.c - ${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_client.c - ${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_server.c - ${CMAKE_CURRENT_LIST_DIR}/mdns/nxd_mdns.c - ${CMAKE_CURRENT_LIST_DIR}/mqtt/nxd_mqtt_client.c - ${CMAKE_CURRENT_LIST_DIR}/nat/nx_nat.c - ${CMAKE_CURRENT_LIST_DIR}/pop3/nxd_pop3_client.c - ${CMAKE_CURRENT_LIST_DIR}/ppp/nx_ppp.c - ${CMAKE_CURRENT_LIST_DIR}/pppoe/nx_pppoe_client.c - ${CMAKE_CURRENT_LIST_DIR}/pppoe/nx_pppoe_server.c - ${CMAKE_CURRENT_LIST_DIR}/smtp/nxd_smtp_client.c - ${CMAKE_CURRENT_LIST_DIR}/snmp/nxd_snmp.c - ${CMAKE_CURRENT_LIST_DIR}/snmp/nx_des.c - ${CMAKE_CURRENT_LIST_DIR}/snmp/nx_sha1.c - ${CMAKE_CURRENT_LIST_DIR}/sntp/nxd_sntp_client.c - ${CMAKE_CURRENT_LIST_DIR}/telnet/nxd_telnet_client.c - ${CMAKE_CURRENT_LIST_DIR}/telnet/nxd_telnet_server.c - ${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_client.c - ${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_server.c - ${CMAKE_CURRENT_LIST_DIR}/web/nx_tcpserver.c - ${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_client.c - ${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_server.c - # {{END_TARGET_SOURCES}} -) - -# Remove the file server files if the user doesn't want them -if(NOT NXD_ENABLE_FILE_SERVERS) - list(REMOVE_ITEM SOURCES - "${CMAKE_CURRENT_LIST_DIR}/web/nx_web_http_server.c" - "${CMAKE_CURRENT_LIST_DIR}/http/nxd_http_server.c" - "${CMAKE_CURRENT_LIST_DIR}/ftp/nxd_ftp_server.c" - "${CMAKE_CURRENT_LIST_DIR}/tftp/nxd_tftp_server.c" - ) -endif() - -target_sources(${PROJECT_NAME} PRIVATE ${SOURCES}) - -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_LIST_DIR}/auto_ip - ${CMAKE_CURRENT_LIST_DIR}/BSD - ${CMAKE_CURRENT_LIST_DIR}/dhcp - ${CMAKE_CURRENT_LIST_DIR}/dns - ${CMAKE_CURRENT_LIST_DIR}/ftp - ${CMAKE_CURRENT_LIST_DIR}/http - ${CMAKE_CURRENT_LIST_DIR}/mdns - ${CMAKE_CURRENT_LIST_DIR}/mqtt - ${CMAKE_CURRENT_LIST_DIR}/nat - ${CMAKE_CURRENT_LIST_DIR}/pop3 - ${CMAKE_CURRENT_LIST_DIR}/ppp - ${CMAKE_CURRENT_LIST_DIR}/pppoe - ${CMAKE_CURRENT_LIST_DIR}/smtp - ${CMAKE_CURRENT_LIST_DIR}/snmp - ${CMAKE_CURRENT_LIST_DIR}/sntp - ${CMAKE_CURRENT_LIST_DIR}/telnet - ${CMAKE_CURRENT_LIST_DIR}/tftp - ${CMAKE_CURRENT_LIST_DIR}/web -) diff --git a/protocol_handlers/auto_ip/nx_auto_ip.c b/protocol_handlers/auto_ip/nx_auto_ip.c deleted file mode 100644 index 5f0cdcb3..00000000 --- a/protocol_handlers/auto_ip/nx_auto_ip.c +++ /dev/null @@ -1,1223 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** AutoIP (AutoIP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_AUTO_IP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -#ifndef TX_DISABLE_ERROR_CHECKING -#define TX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_ip.h" -#include "nx_arp.h" -#include "tx_thread.h" -#include "tx_timer.h" -#include "nx_auto_ip.h" - -/* Keep the AutoIP instance for callback notify. */ -static NX_AUTO_IP *_nx_auto_ip_ptr; - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the AutoIP create function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* name Pointer to AutoIP name */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to start of stack */ -/* stack_size Size of stack in bytes */ -/* priority Priority of AutoIP thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_create AutoIP create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id == NX_AUTO_IP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual AutoIP create routine. */ - status = _nx_auto_ip_create(auto_ip_ptr, name, ip_ptr, stack_ptr, stack_size, priority); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an AutoIP instance for the associated IP */ -/* instance. There must be only one AutoIP instance per IP instance. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* name Pointer to AutoIP name */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to start of stack */ -/* stack_size Size of stack in bytes */ -/* priority Priority of AutoIP thread */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_create Create AutoIP thread */ -/* tx_event_flags_create Create event flags group */ -/* tx_event_flags_delete Delete event flags group */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority) -{ - -UINT status; - - - /* Initialize the AutoIP control block to zero. */ - memset((void *) auto_ip_ptr, 0, sizeof(NX_AUTO_IP)); - - /* Create the AutoIP event flags. */ - status = tx_event_flags_create(&(auto_ip_ptr -> nx_auto_ip_conflict_event), "NetX AutoIP Collision Event"); - - /* Determine if successful. */ - if (status) - { - - /* No, return an error. */ - return(NX_AUTO_IP_ERROR); - } - - /* Create the AutoIP processing thread. */ - status = tx_thread_create(&(auto_ip_ptr -> nx_auto_ip_thread), "NetX AutoIP", _nx_auto_ip_thread_entry, (ULONG) auto_ip_ptr, - stack_ptr, stack_size, priority, priority, 1, TX_DONT_START); - - /* Determine if the thread creation was successful. */ - if (status) - { - - /* Delete the event flags. */ - tx_event_flags_delete(&(auto_ip_ptr -> nx_auto_ip_conflict_event)); - - /* No, return an error. */ - return(NX_AUTO_IP_ERROR); - } - - /* Save the IP pointer and interface fields. */ - auto_ip_ptr -> nx_auto_ip_ip_ptr = ip_ptr; - - /* Default the auto IP interface to the primary interface. */ - auto_ip_ptr -> nx_ip_interface_index = 0; - - /* Save the AutoIP name. */ - auto_ip_ptr -> nx_auto_ip_name = name; - - /* Update the AutoIP structure ID. */ - auto_ip_ptr -> nx_auto_ip_id = NX_AUTO_IP_ID; - - /* Keep the AutoIP instance for callback notify. */ - _nx_auto_ip_ptr = auto_ip_ptr; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking services for the set interface*/ -/* index service. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* interface_index Index into IP interface table */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - status = _nx_auto_ip_set_interface(auto_ip_ptr, interface_index); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the index for the interface on the local host */ -/* needing auto IP to set the address. The default value is zero */ -/* (primary interface). */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* interface_index Index into IP interface table */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index) -{ - - /* Determine if a local IP address was successfully setup. */ - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - /* Bad interface index. */ - return(NX_AUTO_IP_BAD_INTERFACE_INDEX); - } - - - /* Set the index to the specified value. */ - auto_ip_ptr -> nx_ip_interface_index = interface_index; - - /* Return successful outcome. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_get_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the AutoIP get address function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* local_ip_address Destination for local IP addr */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_get_address AutoIP get address function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID) || (local_ip_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual AutoIP get address routine. */ - status = _nx_auto_ip_get_address(auto_ip_ptr, local_ip_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_get_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the local IP address resolved by the AutoIP */ -/* protocol. If there is no valid local IP address this routine */ -/* returns an error and an IP address of all zeros. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* local_ip_address Destination for local IP addr */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address) -{ - -ULONG host_ip_address; -NX_IP *ip_ptr; - - - /* Set local variables for convenience. */ - ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; - host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; - - /* Determine if a local IP address was successfully setup. */ - if (auto_ip_ptr -> nx_auto_ip_current_local_address == host_ip_address) - { - - /* Yes, a local IP address is setup. */ - *local_ip_address = auto_ip_ptr -> nx_auto_ip_current_local_address; - - /* Return success! */ - return(NX_SUCCESS); - } - else - { - - /* No, a local IP address has not been setup. Clear the return value. */ - *local_ip_address = 0; - - /* Return an error. */ - return(NX_AUTO_IP_NO_LOCAL); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the AutoIP start function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_start AutoIP start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual AutoIP start routine. */ - status = _nx_auto_ip_start(auto_ip_ptr, starting_local_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the AutoIP thread of a previously created */ -/* AutoIP instance. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* starting_local_address Starting local IP address, */ -/* only IP addresses from */ -/* 169.254.1.0 through */ -/* 169.254.254.255 are valid,*/ -/* where a value of 0 implies*/ -/* a random generated value */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_resume Resume AutoIP thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address) -{ - - - /* First, start the local IP address to that supplied. */ - auto_ip_ptr -> nx_auto_ip_current_local_address = starting_local_address; - - /* Set the restart flag. */ - auto_ip_ptr -> nx_auto_ip_restart_flag = NX_TRUE; - - /* Set the event flags to ensure AutoIP thread wakes up. */ - tx_event_flags_set(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR); - - /* Resume the AutoIP thread. */ - tx_thread_resume(&(auto_ip_ptr -> nx_auto_ip_thread)); - - /* Return status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the AutoIP stop function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_stop AutoIP stop function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual AutoIP stop routine. */ - status = _nx_auto_ip_stop(auto_ip_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops the AutoIP thread of a previously created and */ -/* started AutoIP instance. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend AutoIP thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr) -{ - -UINT status; - - - /* Suspend the AutoIP thread. */ - status = tx_thread_suspend(&(auto_ip_ptr -> nx_auto_ip_thread)); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_auto_ip_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the AutoIP delete function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_delete AutoIP delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((auto_ip_ptr == NX_NULL) || (auto_ip_ptr -> nx_auto_ip_id != NX_AUTO_IP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual AutoIP delete routine. */ - status = _nx_auto_ip_delete(auto_ip_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the previously created and stopped AutoIP */ -/* AutoIP instance. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* Completion Status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_delete Delete event flags */ -/* tx_thread_delete Delete AutoIP thread */ -/* tx_thread_terminate Terminate AutoIP thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr) -{ - -NX_IP *ip_ptr; - - - /* First, set the ID to show it is invalid. */ - auto_ip_ptr -> nx_auto_ip_id = 0; - - /* Pickup the IP pointer. */ - ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; - - /* Get IP mutex so IP conflict notification can be setup. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Clear the handler to avoid conflict notification callbacks. */ - ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_conflict_notify_handler = NX_NULL; - ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_probe_address = 0; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Terminate the AutoIP thread. */ - tx_thread_terminate(&(auto_ip_ptr -> nx_auto_ip_thread)); - - /* Delete the AutoIP thread. */ - tx_thread_delete(&(auto_ip_ptr -> nx_auto_ip_thread)); - - /* Delete the AutoIP event flags. */ - tx_event_flags_delete(&(auto_ip_ptr -> nx_auto_ip_conflict_event)); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry point of the AutoIP thread. All AutoIP */ -/* actions are coordinated by this thread. */ -/* */ -/* INPUT */ -/* */ -/* auto_ip_ptr Pointer to AutoIP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_auto_ip_arp_packet_send Send AutoIP probe and */ -/* announce ARP messages */ -/* nx_ip_interface_address_set Set interface address */ -/* nx_ip_interface_status_check Get interface status */ -/* tx_event_flags_get Get event flags */ -/* tx_mutex_get Get IP protection */ -/* tx_mutex_put Put IP protection */ -/* tx_thread_sleep Thread sleep */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_auto_ip_thread_entry(ULONG auto_ip_ptr_info) -{ - -NX_AUTO_IP *auto_ip_ptr; -NX_IP *ip_ptr; -UINT i, status; -ULONG addresses; -ULONG conflict; -ULONG temp; -ULONG delay; -ULONG hw_address_lsw; -ULONG host_ip_address; - - - /* Pickup the AutoIP pointer. */ - auto_ip_ptr = (NX_AUTO_IP *) auto_ip_ptr_info; - - /* Pickup the associated IP pointer. */ - ip_ptr = auto_ip_ptr -> nx_auto_ip_ip_ptr; - - /* Wait for the IP instance to be initialized before proceeding. This will ensure the - MAC address is valid before a random local IP address is generated. */ - nx_ip_interface_status_check(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, NX_IP_LINK_ENABLED, &temp, NX_WAIT_FOREVER); - - /* Set LSW of hardware address */ - hw_address_lsw = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_physical_address_lsw; - - /* Setup the conflict flag to false. */ - conflict = NX_FALSE; - - /* Loop forever inside the AutoIP thread! */ - while(1) - { - - /* Probe for local IP address use! */ - - /* Update the local variable in case anything has changed. */ - host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; - - /* Wait until the IP address is non-zero. The only way this can be non-zero is - if the application has changed it or it was resolved by the DHCP protocol. */ - while (host_ip_address) - { - - /* Sleep for the maximum probe period. */ - tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MAX); - - /* Get the IP address from the IP task and see if it has changed from non zero. */ - host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; - } - - /* Determine if the restart flag is set. */ - if (auto_ip_ptr -> nx_auto_ip_restart_flag) - { - - /* Clear the restart flag. */ - auto_ip_ptr -> nx_auto_ip_restart_flag = NX_FALSE; - - /* Reset the conflict count. */ - auto_ip_ptr -> nx_auto_ip_conflict_count = 0; - - /* Clear the conflict flag, since we might have an new starting local IP address. */ - conflict = NX_FALSE; - } - - /* Determine if a conflict condition is present. This flag is set at various places - below. */ - if (conflict) - { - - /* Yes, a conflict was detected. */ - - /* Increment the conflict count. */ - auto_ip_ptr -> nx_auto_ip_conflict_count++; - - /* Determine if we have reached the maximum number of conflicts. */ - if (auto_ip_ptr -> nx_auto_ip_conflict_count > NX_AUTO_IP_MAX_CONFLICTS) - { - - /* Yes, we have had excessive conflicts... we must now add extra delay. */ - tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_RATE_LIMIT_INTERVAL); - } - - /* Clear the the local IP address in order to generate another random one. */ - auto_ip_ptr -> nx_auto_ip_current_local_address = 0; - - /* Clear the conflict flag. */ - conflict = NX_FALSE; - } - - /* Determine if a starting local IP address needs to be derived. */ - if (auto_ip_ptr -> nx_auto_ip_current_local_address == 0) - { - - /* Yes, the starting local IP address must be derived. */ - - /* Get pseudo random value with LSW of MAC address. */ - temp = ((ULONG) NX_RAND()) + hw_address_lsw; - - /* Determine the address range of local IP addresses. */ - addresses = NX_AUTO_IP_END_ADDRESS - NX_AUTO_IP_START_ADDRESS; - - /* Make sure that the random number fits within this range. */ - temp = temp % addresses; - - /* Now create a starting local IP address. */ - auto_ip_ptr -> nx_auto_ip_current_local_address = NX_AUTO_IP_START_ADDRESS + temp; - } - - /* Register with NetX for ARP conflict detection for this local IP address. */ - - /* Get IP mutex so ARP notification can be setup. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Finally, setup the handler to indicate the we want collision notification. */ - ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_conflict_notify_handler = _nx_auto_ip_conflict; - - /* Clear any outstanding events. */ - tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, TX_NO_WAIT); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Calculate the delay time. */ - delay = (ULONG)NX_RAND() % (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_WAIT); - - /* Sleep for a small period of time. */ - tx_thread_sleep(delay); - - /* Loop to probe for the specified local IP address. */ - for (i = 0; i < NX_AUTO_IP_PROBE_NUM; i++) - { - - /* Increment the total probe count. */ - auto_ip_ptr -> nx_auto_ip_probe_count++; - - /* Send the ARP probe. */ - _nx_arp_probe_send(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, auto_ip_ptr -> nx_auto_ip_current_local_address); - - /* Calculate the delay time. */ - delay = ((ULONG) NX_RAND()) % (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MAX); - - /* Determine if this is less than the minimum. */ - if (delay < (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MIN)) - { - - /* Set the delay to the minimum. */ - delay = (NX_IP_PERIODIC_RATE * NX_AUTO_IP_PROBE_MIN); - } - - /* Delay by waiting for conflict events before sending the next ARP probe. This event is - set by the conflict callback function when an ARP entry is received that matches - the registered address. */ - status = tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, delay); - - /* Determine if conflict was detected. */ - if (status == NX_SUCCESS) - { - - /* Yes, a conflict is present. */ - - /* Set the conflict flag and get out of the loop. */ - conflict = NX_TRUE; - break; - } - - /* Update the local variable in case anything has changed. */ - host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; - - /* Check for a restart or an IP address change. */ - if (host_ip_address || (auto_ip_ptr -> nx_auto_ip_restart_flag)) - break; - } - - /* Determine if there was a conflict. If so, continue at the top of the loop. */ - if (conflict) - { - -#ifdef NX_AUTO_IP_DEBUG - printf("AutoIP %s, CONFLICT for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); -#endif - continue; - } - - /* Check for a restart or an IP address change. */ - if (host_ip_address || (auto_ip_ptr -> nx_auto_ip_restart_flag)) - continue; - - /* At this point, the local IP address has been successfully probed via ARP messages without - any collisions. It is now time to go into an announce phase to indicate local IP address - is ours! */ - -#ifdef NX_AUTO_IP_DEBUG - printf("AutoIP %s, RESOLVED for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); -#endif - - /* Set the NetX IP address. */ - nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, auto_ip_ptr -> nx_auto_ip_current_local_address, 0xFFFF0000); - - /* Delay before announcing: NX_AUTO_IP_ANNOUNCE_WAIT. */ - tx_thread_sleep(NX_IP_PERIODIC_RATE * NX_AUTO_IP_ANNOUNCE_WAIT); - - /* It is now time to go into an announce phase to indicate local IP address is ours! */ - for (i = 0; i < NX_AUTO_IP_ANNOUNCE_NUM; i++) - { - - /* Increment the total announcement count. */ - auto_ip_ptr -> nx_auto_ip_announce_count++; - - /* Send the ARP announcement. */ - _nx_arp_announce_send(ip_ptr, auto_ip_ptr -> nx_ip_interface_index); - - /* Calculate the delay time. */ - delay = (NX_IP_PERIODIC_RATE * NX_AUTO_IP_ANNOUNCE_INTERVAL); - - /* Delay by waiting for conflict events before sending the next ARP announcement. This event is - set by the conflict callback function when an ARP entry is received that matches - the registered address. */ - status = tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, delay); - - /* Determine if conflict was detected. */ - if (status == NX_SUCCESS) - { - - /* Yes, a conflict is present. */ - - /* Set the conflict flag and get out of the loop. */ - conflict = NX_TRUE; - break; - } - } - - /* Determine if there was a conflict. If so, continue at the top of the loop. */ - if (conflict) - { - -#ifdef NX_AUTO_IP_DEBUG - printf("AutoIP %s, CONFLICT for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); -#endif - - /* Conflict, clear the IP address. */ - nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, 0, 0); - - continue; - } - - /* Now, wait infinitely for another conflict situation. */ - tx_event_flags_get(&(auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR_CLEAR, &temp, TX_WAIT_FOREVER); - - /* Update the local variable in case anything has changed. */ - host_ip_address = ip_ptr -> nx_ip_interface[auto_ip_ptr -> nx_ip_interface_index].nx_interface_ip_address; - - /* Determine if a conflict is present. */ - - /* If we get here a late conflict is present. */ - if (auto_ip_ptr -> nx_auto_ip_current_local_address == host_ip_address) - { - - /* Increment the total defend count. */ - auto_ip_ptr -> nx_auto_ip_defend_count++; - -#ifdef NX_AUTO_IP_DEBUG - printf("AutoIP %s, DEFEND for: %d,%d,%d,%d\n", auto_ip_ptr -> nx_auto_ip_name, - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 24), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 16 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address >> 8 & 0xFF), - (auto_ip_ptr -> nx_auto_ip_current_local_address & 0xFF)); -#endif - - /* No defense currently, just clear the IP address once a late collision is detected - and start over. */ - nx_ip_interface_address_set(ip_ptr, auto_ip_ptr -> nx_ip_interface_index, 0, 0); - - /* Set the conflict flag. */ - conflict = NX_TRUE; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_auto_ip_conflict PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the AutoIP instance that a conflict was */ -/* detected by the NetX ARP receive packet handling routine. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr IP instance pointer */ -/* interface_index IP Interface Index */ -/* ip_address IP Address to bind to */ -/* physical_msw Physical address MSW */ -/* physical_lsw Physical address LSW */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_auto_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw) -{ - - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(interface_index); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(physical_msw); - NX_PARAMETER_NOT_USED(physical_lsw); - - /* Set the event flags to indicate that a collision was detected by NetX ARP processing. */ - tx_event_flags_set(&(_nx_auto_ip_ptr -> nx_auto_ip_conflict_event), 0x1, TX_OR); -} -#endif /* NX_DISABLE_IPV4 */ diff --git a/protocol_handlers/auto_ip/nx_auto_ip.h b/protocol_handlers/auto_ip/nx_auto_ip.h deleted file mode 100644 index e5de5ea0..00000000 --- a/protocol_handlers/auto_ip/nx_auto_ip.h +++ /dev/null @@ -1,215 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** AutoIP (AutoIP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_auto_ip.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX AutoIP Protocol (AutoIP) component, */ -/* including all data types and external references. It is assumed */ -/* that nx_api.h and nx_port.h have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_AUTO_IP_H -#define NX_AUTO_IP_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -/* Define the AutoIP ID that is used to mark the AutoIP structure as created. */ - -#define NX_AUTO_IP_ID 0x4155544FUL - - -/* Define the timing and retry constants for AutoIP. */ - -#ifndef NX_AUTO_IP_PROBE_WAIT -#define NX_AUTO_IP_PROBE_WAIT 1 -#endif - -#ifndef NX_AUTO_IP_PROBE_NUM -#define NX_AUTO_IP_PROBE_NUM 3 -#endif - -#ifndef NX_AUTO_IP_PROBE_MIN -#define NX_AUTO_IP_PROBE_MIN 1 -#endif - -#ifndef NX_AUTO_IP_PROBE_MAX -#define NX_AUTO_IP_PROBE_MAX 2 -#endif - -#ifndef NX_AUTO_IP_MAX_CONFLICTS -#define NX_AUTO_IP_MAX_CONFLICTS 10 -#endif - -#ifndef NX_AUTO_IP_RATE_LIMIT_INTERVAL -#define NX_AUTO_IP_RATE_LIMIT_INTERVAL 60 -#endif - -#ifndef NX_AUTO_IP_ANNOUNCE_WAIT -#define NX_AUTO_IP_ANNOUNCE_WAIT 2 -#endif - -#ifndef NX_AUTO_IP_ANNOUNCE_NUM -#define NX_AUTO_IP_ANNOUNCE_NUM 2 -#endif - -#ifndef NX_AUTO_IP_ANNOUNCE_INTERVAL -#define NX_AUTO_IP_ANNOUNCE_INTERVAL 2 -#endif - -#ifndef NX_AUTO_IP_DEFEND_INTERVAL -#define NX_AUTO_IP_DEFEND_INTERVAL 10 -#endif - - -/* Define the starting and ending local IP addresses. */ - -#define NX_AUTO_IP_START_ADDRESS IP_ADDRESS(169,254,1,0) -#define NX_AUTO_IP_END_ADDRESS IP_ADDRESS(169,254,254,255) - - -/* Define error codes from AutoIP API. */ - -#define NX_AUTO_IP_ERROR 0xA00 -#define NX_AUTO_IP_NO_LOCAL 0xA01 -#define NX_AUTO_IP_BAD_INTERFACE_INDEX 0xA02 - - -/* Define the AutoIP structure that holds all the information necessary for this AutoIP - instance. */ - -typedef struct NX_AUTO_IP_STRUCT -{ - ULONG nx_auto_ip_id; - CHAR *nx_auto_ip_name; - NX_IP *nx_auto_ip_ip_ptr; - UINT nx_ip_interface_index; - ULONG nx_auto_ip_current_local_address; - ULONG nx_auto_ip_restart_flag; - ULONG nx_auto_ip_conflict_count; - ULONG nx_auto_ip_probe_count; - ULONG nx_auto_ip_announce_count; - ULONG nx_auto_ip_defend_count; - TX_EVENT_FLAGS_GROUP nx_auto_ip_conflict_event; - TX_THREAD nx_auto_ip_thread; -} NX_AUTO_IP; - - -#ifndef NX_AUTO_IP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map AutoIP API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_auto_ip_create _nx_auto_ip_create -#define nx_auto_ip_get_address _nx_auto_ip_get_address -#define nx_auto_ip_set_interface _nx_auto_ip_set_interface -#define nx_auto_ip_start _nx_auto_ip_start -#define nx_auto_ip_stop _nx_auto_ip_stop -#define nx_auto_ip_delete _nx_auto_ip_delete - -#else - -/* Services with error checking. */ - -#define nx_auto_ip_create _nxe_auto_ip_create -#define nx_auto_ip_get_address _nxe_auto_ip_get_address -#define nx_auto_ip_set_interface _nxe_auto_ip_set_interface -#define nx_auto_ip_start _nxe_auto_ip_start -#define nx_auto_ip_stop _nxe_auto_ip_stop -#define nx_auto_ip_delete _nxe_auto_ip_delete - -#endif - -/* Define the prototypes accessible to the application software. */ - -UINT nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); -UINT nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); -UINT nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); -UINT nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); -UINT nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); - - -#else - -/* AutoIP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT _nx_auto_ip_create(NX_AUTO_IP *auto_ip_ptr, CHAR *name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT _nxe_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); -UINT _nx_auto_ip_get_address(NX_AUTO_IP *auto_ip_ptr, ULONG *local_ip_address); -UINT _nxe_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); -UINT _nx_auto_ip_set_interface(NX_AUTO_IP *auto_ip_ptr, UINT interface_index); -UINT _nxe_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); -UINT _nx_auto_ip_start(NX_AUTO_IP *auto_ip_ptr, ULONG starting_local_address); -UINT _nxe_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); -UINT _nx_auto_ip_stop(NX_AUTO_IP *auto_ip_ptr); -UINT _nxe_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); -UINT _nx_auto_ip_delete(NX_AUTO_IP *auto_ip_ptr); -VOID _nx_auto_ip_thread_entry(ULONG auto_ip_address); -VOID _nx_auto_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw); - -#endif - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_AUTO_IP_H */ - diff --git a/protocol_handlers/dhcp/nxd_dhcp_client.c b/protocol_handlers/dhcp/nxd_dhcp_client.c deleted file mode 100644 index 23ee2eba..00000000 --- a/protocol_handlers/dhcp/nxd_dhcp_client.c +++ /dev/null @@ -1,10109 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol (DHCP) Client */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_DHCP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_system.h" -#include "nx_ip.h" -#include "nx_arp.h" -#include "nxd_dhcp_client.h" -#include "tx_timer.h" - - -/* Define the DHCP Internal Function. */ -static VOID _nx_dhcp_thread_entry(ULONG ip_instance); -static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length); -static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length); -static UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index); -static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index); -static ULONG _nx_dhcp_update_timeout(ULONG timeout); -static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout); -static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length); -static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size); -static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value); -static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size); -static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type); -static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr); -static ULONG _nx_dhcp_add_randomize(ULONG timeout); -static VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); -static VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *dhcp_interface, NX_PACKET *packet_ptr); -static VOID _nx_dhcp_timeout_entry(ULONG dhcp); -static VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr); -static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record); - - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE -static VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT interface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw); -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - - -/* Define the Request string that specifies which options are to be added - to the DHCP Client discover request to the server. Additional options - (found in nx_dhcp.h) may be added after the last option. */ - -UCHAR _nx_dhcp_request_parameters[] = { NX_DHCP_OPTION_SUBNET_MASK, - NX_DHCP_OPTION_GATEWAYS, - NX_DHCP_OPTION_DNS_SVR}; - -#define NX_DHCP_REQUEST_PARAMETER_SIZE sizeof(_nx_dhcp_request_parameters) - -static struct NX_DHCP_STRUCT *_nx_dhcp_created_ptr; - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP create function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* ip_ptr Pointer to IP instance */ -/* name_ptr DHCP name pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_create Actual DHCP create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (dhcp_ptr == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Call actual DHCP create service. */ - status = _nx_dhcp_create(dhcp_ptr, ip_ptr, name_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the DHCP structure and associated IP */ -/* instance for DHCP operation. In doing so, it creates a packet */ -/* pool for DHCP messages, a UDP socket for communication with the */ -/* server, and a DHCP processing thread. */ -/* */ -/* The primary interface is automatically enabled for DHCP. To run */ -/* DHCP on a different interface, use the nx_dhcp_set_interface_index */ -/* service. To run DHCP on multiple interfaces, see */ -/* nx_dhcp_interface_enable and nx_dhcp_interface_start */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* ip_ptr Pointer to IP instance */ -/* name_ptr DHCP name pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_pool_create Create the DHCP packet pool */ -/* nx_packet_pool_delete Delete the DHCP packet pool */ -/* nx_udp_socket_create Create the DHCP UDP socket */ -/* nx_udp_socket_delete Delete the DHCP UDP socket */ -/* tx_mutex_create Create DHCP mutex */ -/* tx_mutex_delete Delete DHCP mutex */ -/* tx_thread_create Create DHCP processing thread */ -/* tx_timer_create Create DHCP timer */ -/* tx_timer_delete Delete DHCP timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr) -{ - -UINT status; -#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK -CHAR *temp_ptr; -UINT label_length = 0; -#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */ - - -#ifdef NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK - - /* Set the pointer. */ - temp_ptr = name_ptr; - - /* The total length of a domain name (host name) is restricted to 255 octets or less. */ - if (_nx_utility_string_length_check(temp_ptr, NX_NULL, 255)) - { - return (NX_DHCP_INVALID_NAME); - } - - /* The labels must follow the rules for ARPANET host names. They must - start with a letter, end with a letter or digit, and have as interior - characters only letters, digits, and hyphen. There are also some - restrictions on the length. Labels must be 63 characters or less. - RFC 1035, Section 2.3.1, Page8. */ - while (*temp_ptr) - { - - /* Is a dot? */ - if (*temp_ptr == '.') - { - - /* Current label is end. */ - - /* Labels must be 63 characters or less, and check the continuous dot '..' for host name. */ - if ((label_length == 0) || (label_length > 63)) - return (NX_DHCP_INVALID_NAME); - - /* End with a letter or digit. Only need to check the Hyphen '-' since - *(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */ - if (*(temp_ptr - 1) == '-') - return (NX_DHCP_INVALID_NAME); - - /* Continue the next lable. */ - label_length = 0; - } - else - { - - /* Update the lable length. */ - label_length++; - - /* Letter. */ - if((((*temp_ptr) | 0x20) >= 'a') && (((*temp_ptr) | 0x20) <= 'z')) - { - - /* Continue next character. */ - temp_ptr++; - continue; - } - - /* Start with a letter. */ - if (label_length == 1) - return (NX_DHCP_INVALID_NAME); - - /* Hyphen or Digits. */ - if ((*temp_ptr != '-') && - ((*temp_ptr < '0') || (*temp_ptr > '9'))) - return (NX_DHCP_INVALID_NAME); - } - - /* Continue next character. */ - temp_ptr++; - } - - /* Check again if the host name have not the 'dot' terminator. */ - if (*(temp_ptr - 1) != '.') - { - - /* Labels must be 63 characters or less. */ - if (label_length > 63) - return (NX_DHCP_INVALID_NAME); - - /* End with a letter or digit. Only need to check the Hyphen '-' since - *(temp_ptr - 1) must be Letter, Hyphen or Digits in 'else'. */ - if (*(temp_ptr - 1) == '-') - return (NX_DHCP_INVALID_NAME); - } -#endif /* NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK */ - - /* Initialize the DHCP control block to zero. */ - memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP)); - - /* Save the IP pointer. */ - dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr; - - /* Save the DHCP name. */ - dhcp_ptr -> nx_dhcp_name = name_ptr; - - /* If the host does not intend to supply their own packet pool, create one here. */ -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - - /* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets. - RFC 2131, Section 2, Page10. */ - if (NX_DHCP_PACKET_PAYLOAD < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM)) - { - - /* Invalid payload, return error status. */ - return(NX_DHCP_INVALID_PAYLOAD); - } - - /* Create the pool and check the status */ - status = nx_packet_pool_create(&dhcp_ptr -> nx_dhcp_pool, "NetX DHCP Client", NX_DHCP_PACKET_PAYLOAD, - dhcp_ptr -> nx_dhcp_pool_area, NX_DHCP_PACKET_POOL_SIZE); - - /* Determine if it was successful. */ - if (status != NX_SUCCESS) - { - - /* No, return error status. */ - return(status); - } - - /* Set an internal packet pool pointer to the newly created packet pool. */ - dhcp_ptr -> nx_dhcp_packet_pool_ptr = &dhcp_ptr -> nx_dhcp_pool; - -#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION - - /* Set the maximum DHCP message size. */ - dhcp_ptr -> nx_dhcp_max_dhcp_message_size = NX_DHCP_PACKET_PAYLOAD - NX_PHYSICAL_HEADER; -#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ - -#endif /* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL */ - - /* Create the Socket and check the status */ - status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Client", - NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH); - - /* Was the socket creation successful? */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* No, return error status. */ - return(status); - } - - - /* Set the UDP socket receive callback function. */ - status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_udp_receive_notify); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - } - - /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if - a client connection has gone silent and needs to be terminated. */ - status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_timer), "DHCP Client Timer", _nx_dhcp_timeout_entry, - (ULONG)(ALIGN_TYPE)dhcp_ptr, (NX_DHCP_TIME_INTERVAL), - (NX_DHCP_TIME_INTERVAL), TX_NO_ACTIVATE); - - NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_timer), dhcp_ptr) - - /* Determine if the semaphore creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* No, return error status. */ - return(status); - } - - /* Create the DHCP mutex. */ - status = tx_mutex_create(&(dhcp_ptr -> nx_dhcp_mutex), "NetX DHCP Client", TX_NO_INHERIT); - - /* Determine if the semaphore creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* Delete the timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); - - /* No, return error status. */ - return(status); - } - - /* Create the DHCP processing thread. */ - status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_thread), "NetX DHCP Client", _nx_dhcp_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, - dhcp_ptr -> nx_dhcp_thread_stack, NX_DHCP_THREAD_STACK_SIZE, - NX_DHCP_THREAD_PRIORITY, NX_DHCP_THREAD_PRIORITY, 1, TX_DONT_START); - - NX_THREAD_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_thread), dhcp_ptr) - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the mutex. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* Delete the timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); - - /* No, return error status. */ - return(status); - } - - /* Create a DHCP event flag group. . */ - status = tx_event_flags_create(&(dhcp_ptr -> nx_dhcp_events), (CHAR *)"DHCP Client Events"); - - /* Check for error. */ - if (status != TX_SUCCESS) - { - - /* Delete the thread. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Delete the mutex. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete the timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* No, return error status. */ - return(status); - } - - /* Update the dhcp structure ID. */ - dhcp_ptr -> nx_dhcp_id = NX_DHCP_ID; - - /* Save the DHCP instance. */ - _nx_dhcp_created_ptr = dhcp_ptr; - - /* Default enable DHCP on the primary interface (0). */ - _nx_dhcp_interface_enable(dhcp_ptr, 0); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_clear_broadcast_flag PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP set the clear broadcast */ -/* flag in DHCP Client messages service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* clear_flag Broadcast flag status */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_broadcast_flag Actual DHCP Client clear */ -/* broadcast flag service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag) -{ - -UINT status; - - /* Check for invalid input pointer. */ - if (dhcp_ptr == NX_NULL) - { - - return(NX_PTR_ERROR); - } - - /* Call actual DHCP clear flag service. */ - status = _nx_dhcp_clear_broadcast_flag(dhcp_ptr, clear_flag); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_clear_broadcast_flag PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service uses the clear_flag input to clear or set the broadcast*/ -/* in DHCP Client messages to the DHCP server. By default the broadcast*/ -/* flag is set. */ -/* */ -/* This function is intended for DHCP Clients whose DHCP messages are */ -/* routed through a relay agent (router) that will not accept DHCP */ -/* messages with broadcast replies requested. */ -/* */ -/* NX_TRUE broadcast flag is cleared for all messages */ -/* NX_FALSE broadcast flag set only if it normally would be */ -/* */ -/* The server reply will actually be broadcast when relayed by the */ -/* router using this strategy. */ -/* */ -/* If DHCP is enabled on multiple interfaces, this service will set the*/ -/* broadcast flag on all interfaces. To set this flag on a specific */ -/* interface, use the nx_dhcp_interface_clear_broadcast_flag. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* clear_flag Broadcast flag status */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag) -{ - -UINT i; - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Loop to set the broadcast flag for all interface record enabled. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) - { - - dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_clear_broadcast = clear_flag; - } - } - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_clear_broadcast_flag PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the interface specific clear */ -/* broadcast flag service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Network interface index */ -/* clear_flag Broadcast flag status */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_clear_broadcast_flag Actual DHCP Client clear */ -/* broadcast flag service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag) -{ - -UINT status; - - /* Check for invalid input pointer. */ - if (dhcp_ptr == NX_NULL) - { - - return(NX_PTR_ERROR); - } - - /* Check interface index. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Call actual DHCP clear flag service. */ - status = _nx_dhcp_interface_clear_broadcast_flag(dhcp_ptr, iface_index, clear_flag); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interace_clear_broadcast_flag PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service uses the clear_flag input to determine if the DHCP */ -/* Client on the specified network interface should clear the broadcast*/ -/* flag in its DHCP messages to the DHCP server (normally it sets the */ -/* broadcast flag. */ -/* */ -/* This is intended for DHCP Clients whose DHCP messages are routed */ -/* through arelay agent (router) that will not accept DHCP messages */ -/* withbroadcast replies requested. */ -/* */ -/* NX_TRUE broadcast flag is cleared for all messages */ -/* NX_FALSE broadcast flag set only if it normally would be */ -/* */ -/* The server reply will actually be broadcast when relayed by the */ -/* router using this strategy. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Network interface index */ -/* clear_flag Broadcast flag status */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_dhcp_interface_record_find Find Client record for input */ -/* DHCP interface */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Set or clear the option to request unicast/clear broadcast flag. */ - interface_record -> nx_dhcp_clear_broadcast = clear_flag; - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the set the DHCP Client */ -/* packet pool service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* packet_pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Packet pool successfully set */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_NOT_ENABLED DHCP client not enabled for */ -/* user create packet pool */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_packet_pool_set */ -/* Actual set packet pool service*/ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr) -{ - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - NX_PARAMETER_NOT_USED(dhcp_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - - /* Client not configured for the user creating the packet pool. Return an error status. */ - return NX_NOT_ENABLED; -#else - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dhcp_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - /* Check the packet payload size, DHCP Client must be prepared to receive a message of up to 576 octets. - RFC2131, Section2, Page10. */ - if (packet_pool_ptr -> nx_packet_pool_payload_size < (NX_PHYSICAL_HEADER + NX_DHCP_MINIMUM_IP_DATAGRAM)) - { - - /* Invalid payload, return error status. */ - return(NX_DHCP_INVALID_PAYLOAD); - } - - status = _nx_dhcp_packet_pool_set(dhcp_ptr, packet_pool_ptr); - - return status; -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DHCP Client packet pool by passing in a */ -/* packet pool pointer to packet pool already create. The */ -/* NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL must be set. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* packet_pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_NOT_ENABLED Setting DHCP Client packet */ -/* pool not enabled */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr) -{ - - - /* Determine if the DHCP Client is configured for accepting a packet pool pointer. */ -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - NX_PARAMETER_NOT_USED(dhcp_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - - /* No, return the error status. */ - return NX_NOT_ENABLED; -#else - - /* Set the Client packet pool to the supplied packet pool. */ - dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr; - -#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION - - /* Set the maximum DHCP message size. */ - dhcp_ptr -> nx_dhcp_max_dhcp_message_size = packet_pool_ptr -> nx_packet_pool_payload_size - NX_PHYSICAL_HEADER; -#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ - - return NX_SUCCESS; -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the reinitialize service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_reinitialize(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Call the actual reinitialize service. */ - status = _nx_dhcp_reinitialize(dhcp_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reinitializes all enabled DHCP interfaces for */ -/* restarting the DHCP client protocol. Network parameters in the DHCP*/ -/* Client and IP interface(s) are both cleared, and sets the DHCP state*/ -/* back to the not started state. */ -/* */ -/* To reinitialize the DHCP Client on a specific interface when */ -/* multiple interfaces are enabled for DHCP, use the */ -/* nx_dhcp_interface_reinitialize service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_reinitialize Reinitialize DHCP interface */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Loop to reinitalize the record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) - { - - /* Reinitialize the record. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the reinitialize service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Specify interface to init */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_INVALID_INTERFACE Index exceeds max interface */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_reinitialize Actual reinitialize service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual reinitialize service. */ - status = _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reinitializes the DHCP instance for restarting the */ -/* DHCP client state machine and re-running the DHCP protocol on the */ -/* specified interface. The IP address and other network parameters in*/ -/* the DHCP Client and in the IP interface are cleared. */ -/* */ -/* This function also sets the DHCP server IP address to the broadcast */ -/* address and sets the DHCP client state back to the INIT state. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Specify interface to init */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find Client record for input */ -/* DHCP interface */ -/* nx_ip_interface_address_set Clear IP inteface address of */ -/* the input DHCP interface */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* nx_ip_gateway_address_clear Clear the gateway address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; -ULONG ip_address; -ULONG network_mask; -ULONG gateway_address; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Check if have IP address. */ - if (interface_record -> nx_dhcp_ip_address) - { - - /* Get the IP address. */ - status = nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, &ip_address, &network_mask); - - /* Check if the IP address is set by DHCP. */ - if ((status == NX_SUCCESS) && (ip_address == interface_record -> nx_dhcp_ip_address)) - { - - /* Clear the IP address. */ - nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, 0, 0); - } - } - - /* Check if have gateway address. */ - if (interface_record -> nx_dhcp_gateway_address) - { - - /* Get the gateway address. */ - status = nx_ip_gateway_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, &gateway_address); - - /* Check status. */ - if ((status == NX_SUCCESS) && (gateway_address == interface_record -> nx_dhcp_gateway_address)) - { - - /* Clear the Gateway/Router IP address. */ - nx_ip_gateway_address_clear(dhcp_ptr -> nx_dhcp_ip_ptr); - } - } - - /* Initialize the client DHCP IP address with the NULL IP address. */ - interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS; - - /* Initialize the client DHCP server IP address. */ - interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS; - - /* Clear these DHCP Client network values too.*/ - interface_record -> nx_dhcp_gateway_address = NX_BOOTP_NO_ADDRESS; - interface_record -> nx_dhcp_network_mask = NX_BOOTP_NO_ADDRESS; - - /* Clear the flag to skip the discovery step. The host application must - call the nx_dhcp_request_ip_address to reset the flag and the requested IP address. */ - interface_record -> nx_dhcp_skip_discovery = NX_FALSE; - - /* Initialize renew and rebind timeout values to zero. */ - interface_record -> nx_dhcp_rebind_time = 0; - interface_record -> nx_dhcp_renewal_time = 0; - - /* Setup for infinite lease time request. */ - interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE; - - /* Reset the seconds field for starting the DHCP request process. */ - interface_record -> nx_dhcp_seconds = 0; - - /* Reset the timeout and retransmission interval. */ - interface_record -> nx_dhcp_timeout = 0; - interface_record -> nx_dhcp_rtr_interval = 0; - - /* Set the DHCP state to the initial state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_request_client_ip PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the client ip request */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_request_address Client's requested IP address */ -/* skip_discover_message Initialize Client state to */ -/* BOOT (skip discover message)*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message) -{ - -UINT status; - - - /* Check for an invalid DHCP pointer . */ - if (dhcp_ptr == NX_NULL) - { - - /* Return an error. */ - return(NX_PTR_ERROR); - } - - /* Determine that a nonzero IP address is entered. */ - if (client_request_address == NX_BOOTP_NO_ADDRESS) - { - - return NX_DHCP_INVALID_IP_REQUEST; - } - - /* Call actual request client IP service. */ - status = _nx_dhcp_request_client_ip(dhcp_ptr, client_request_address, skip_discover_message); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_request_client_ip PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the requested client IP address in DHCP Client */ -/* messages, and enables or disables the skip discovery option */ -/* based on the skip_discover_message input. */ -/* */ -/* If multiple interfaces are enabled for DHCP, this function sets the */ -/* requested Client IP on the first valid interface it finds. */ -/* */ -/* To set the requested Client IP for a specific interface, use the */ -/* nx_dhcp_interface_request_ip() service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_request_address Client's requested IP address */ -/* skip_discover_message To set DHCP Client flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_request_client_ip Interface specific request */ -/* IP service */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ - -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_request_address, UINT skip_discover_message) -{ - -UINT i; -UINT status; - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Set the request IP. */ - status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, - client_request_address, skip_discover_message); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_request_client_ip PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the request IP service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Index to apply parameter to */ -/* client_request_address Client's requested IP address */ -/* skip_discover_message To set DHCP Client flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - status = _nx_dhcp_interface_request_client_ip(dhcp_ptr, iface_index, client_request_address, skip_discover_message); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_request_client_ip PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the requested client IP address in the client */ -/* REQUEST message on the input interface. If the skip_discover_message*/ -/* flag is set, the DISCOVER message is skipped when the DHCP Client */ -/* (re))starts. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Index to apply parameter to */ -/* client_request_address Client's requested IP address */ -/* skip_discover_message To set DHCP Client flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find Client record for the */ -/* input interface */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_request_address, UINT skip_discover_message) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Use input IP address. */ - interface_record -> nx_dhcp_ip_address = client_request_address; - - /* Set the flag for skipping the discovery state. */ - interface_record -> nx_dhcp_skip_discovery = skip_discover_message; - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return success! */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP delete function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_delete Actual DHCP delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_delete(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP delete service. */ - status = _nx_dhcp_delete(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disables DHCP on all enabled interfaces, deletes the */ -/* DHCP instance and releases all of its resources. All DHCP and IP */ -/* interface IP addresses and the IP gateway are cleared on all */ -/* valid DHCP interfaces. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_dhcp_interface_disable Disable DHCP on interface */ -/* nx_packet_pool_delete Delete the DHCP packet pool */ -/* nx_udp_socket_delete Delete the DHCP UDP socket */ -/* tx_thread_suspend Suspend DHCP Thread */ -/* tx_thread_terminate Terminate DHCP thread */ -/* tx_mutex_delete Delete DHCP mutex */ -/* tx_event_flags_delete Delete DHCP flag group */ -/* tx_timer_deactivate Stop the DHCP timer */ -/* tx_timer_delete Delete the DHCP timer */ -/* tx_thread_delete Delete DHCP thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_delete(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Disable all the interfaces enabled for DHCP. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this interface (i) is enabled for DHCP. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Disable the interface record. */ - _nx_dhcp_interface_disable(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Terminate the DHCP processing thread. */ - tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Delete the DHCP processing thread. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Delete the DHCP event flags. */ - tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_events)); - - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); - - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Unbind the port. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - /* Delete the packet pool. */ - nx_packet_pool_delete(dhcp_ptr -> nx_dhcp_packet_pool_ptr); -#endif - - /* Get the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete the DHCP mutex. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Clear the dhcp structure ID. */ - dhcp_ptr -> nx_dhcp_id = 0; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_force_renew PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP force renew function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_force_renew Actual DHCP force renew */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_force_renew(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP force renew service. */ - status = _nx_dhcp_force_renew(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_force_renew PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function forces the DHCP processing thread to renew the lease */ -/* on all valid (DHCP enabled) interfaces. To force renew on a specific*/ -/* interface if multiple interfaces are enabled for DHCP, use the */ -/* nx_dhcp_interface_force_renew service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* nx_dhcp_interface_force_renew Force renew on DHCP interface */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_force_renew(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Force renew on this interface. */ - _nx_dhcp_interface_force_renew(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_force_renew PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function forces the DHCP processing thread to renew the lease */ -/* on the specified interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to force renew on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* nx_dhcp_interface_force_renew Actual force renew service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Call the actual reinitialize service. */ - status = _nx_dhcp_interface_force_renew(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_force_renew PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows the DHCP Client to force a renew on a */ -/* previously obtained lease on the input interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to force renew on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find record for the interface */ -/* _nx_dhcp_send_request_internal Send request to DHCP server */ -/* _nx_dhcp_update_renewal_timeout Update time left on renew lease*/ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index) -{ -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record for this interface. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return status. */ - return(status); - } - - /* Determine if DHCP is in the Bound state. */ - if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND) - { - - /* Since the Client is initiating RENEW ('force' renew'), set the state to RENEW. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; - - /* Send the renew request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Reset the renew time remaining (before transition to the REBIND state) and - the dhcp timeout for retransmission of RENEW request. */ - interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - else - { - - /* Return a not bound error code. */ - status = NX_DHCP_NOT_BOUND; - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_decline PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP decline function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_decline Actual DHCP decline function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_decline(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP release service. */ - status = _nx_dhcp_decline(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_decline PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function declines the IP address(es) assigned to the DHCP */ -/* Client on all valid interfaces. The DHCP Client state is set back */ -/* to the INIT state and DHCP is automatically restarted. */ -/* */ -/* To decline an IP address on a specific interface where multiple */ -/* interfaces are enabled for DHCP, use the */ -/* nx_dhcp_interface_decline service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_decline Interface specific decline */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_decline(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER);\ - - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Decline the address. */ - _nx_dhcp_interface_decline(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_decline PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the decline service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to decline IP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_decline Actual decline service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index) -{ -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual decline service. */ - status = _nx_dhcp_interface_decline(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_decline PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function declines the IP assigned to the input DHCP Client */ -/* interface. The DHCP Client state is set back to the INIT state and */ -/* DHCP is automatically restarted. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to decline IP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find record for the interface */ -/* _nx_dhcp_send_request_internal Send DHCP request */ -/* _nx_dhcp_interface_reinitialize Reset IP and DHCP Client */ -/* network parameters */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; -UINT original_state; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr ->nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Check the record state. */ - if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NOT_BOUND); - } - - /* Get the original state. */ - original_state = interface_record -> nx_dhcp_state; - - /* Send the decline DHCP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDECLINE); - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* Wait for some time before restarting the configuration process to avoid excessive network traffic in case of looping. RFC2131, Section3.1, Page17. */ - interface_record -> nx_dhcp_timeout = NX_DHCP_RESTART_WAIT; - - /* Set the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = 0; - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP release function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_release Actual DHCP release function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_release(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP release service. */ - status = _nx_dhcp_release(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function releases the IP previously assigned to this DHCP */ -/* instance on all interfaces enabled for DHCP. A subsequent call to */ -/* nx_dhcp_start initiates a new request to obtain an IP address. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_release Interface specific send */ -/* release request service */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_release(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Release the address. */ - _nx_dhcp_interface_release(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return. */ - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the release service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to release IP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_release Actual release service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual interface release service. */ - status = _nx_dhcp_interface_release(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function releases the IP previously assigned to this DHCP */ -/* interface. The DHCP state is returned back to the NOT STARTED state.*/ -/* A subsequent call to _nx_dhcp_interface_start will initiate a new */ -/* request to obtain an IP address. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to release IP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find record for the interface */ -/* _nx_dhcp_send_request_internal Send request to DHCP server */ -/* _nx_dhcp_interface_reinitialize Clear IP and DHCP network */ -/* parameters to restart DHCP */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT i; -UINT status, original_state; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); - } - - /* Determine if DHCP is in the Boot state. */ - if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return an error code. */ - return(NX_DHCP_NOT_BOUND); - } - - /* Get the original state. */ - original_state = interface_record -> nx_dhcp_state; - - /* Send the release DHCP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPRELEASE); - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - - /* Check if other interfaces are running DHCP. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) - { - - /* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX - resources need to stay activated. */ - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); - } - } - - /* Has DHCP stopped on all interfaces? */ - if (i == NX_DHCP_CLIENT_MAX_RECORDS) - { - - /* Yes, stop DHCP Thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Deactivate DHCP Timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Unbind UDP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP start function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_start Actual DHCP start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_start(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP start service. */ - status = _nx_dhcp_start(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts DHCP on all interfaces that are enabled for */ -/* DHCP. If no interfaces have previously been started on DHCP, this */ -/* function re/starts the DHCP CLient thread, binds the socket and */ -/* re/starts the timer. */ -/* */ -/* To start DHCP on a specific interface if multiple interfaces are */ -/* enabled for DHCP, use the nx_dhcp_interface_start service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCP_NO_INTERFACES_STARTED Unable to start any interfaces*/ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_start Interface specific start DHCP */ -/* Client service */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_start(NX_DHCP *dhcp_ptr) -{ - -UINT status; -UINT interfaces_started = 0; -UINT i; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Check all interfaces to find out which need to start the DHCP protocol. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) - { - - /* Start DHCP on this interface. */ - status = _nx_dhcp_interface_start(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - - /* Note, not all interfaces are enabled to run, so - status may not be successful. Skip to the next - interface. */ - - /* Check status. */ - if ((status == NX_SUCCESS) || (status == NX_DHCP_ALREADY_STARTED)) - { - interfaces_started++; - } - } - } - - /* Check if any interfaces started DHCP. */ - if (interfaces_started == 0) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Unable to start any interfaces. */ - return NX_DHCP_NO_INTERFACES_STARTED; - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the interface specific */ -/* DHCP start service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to start DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_start Actual interface start service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP interface start service. */ - status = _nx_dhcp_interface_start(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function 'starts' the specified interface. It finds the matching*/ -/* DHCP Client record for that interface and checks that the interface */ -/* has been enabled for DHCP (see nx_dhcp_interface_enable). It then */ -/* checks if any interfaces are running DHCP. If not it binds the DHCP */ -/* socket port, activates the DHCP timer, and resumes the DHCP Client */ -/* thread. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to start DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find the Client record for the*/ -/* specified interface */ -/* nx_udp_socket_bind Bind DHCP socket */ -/* nx_udp_socket_unbind Unbind DHCP socket */ -/* tx_thread_resume Initiate DHCP processing */ -/* tx_timer_activate Activate DHCP timer */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT i; -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); - } - - /* Check if DHCP is already started. */ - if (interface_record -> nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_ALREADY_STARTED); - } - - /* Check if other interface are working. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) - { - - /* Yes, other interface have started DHCP. */ - break; - } - } - - /* Check if any interfaces have started DHCP. */ - if (i == NX_DHCP_CLIENT_MAX_RECORDS) - { - - /* Bind the UDP socket to the DHCP Client port. */ - status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); - - /* Check for error */ - if (status != NX_SUCCESS) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Resume the DHCP processing thread. */ - status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Determine if the resume was successful. */ - if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED)) - { - - /* Error, unbind the DHCP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Activate DHCP Timer. */ - status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Determine if the resume was successful. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the DHCP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Start DHCP service for this interface record. */ - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the interface specific */ -/* DHCP enable interface service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to enable DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_add Actual interface enable service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Call actual DHCP interface enable service. */ - status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the specified interface as enabled to run DHCP. */ -/* It ensures all DHCP parameters are initialized to zero, and uses the */ -/* physical interface MAC address to set the unique Client ID used for */ -/* transactions with the DHCP server. */ -/* */ -/* By default the primary interface is enabled in nx_dhcp_create. An */ -/* interface must be enabled before DHCP can be started on it. */ -/* Thereafter, it is only necessary to call this function on an interface*/ -/* that has been disabled. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to enable DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCP_NO_RECORDS_AVAILABLE No more records available to */ -/* enable DHCP on an interface */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index) -{ -UINT i; -ULONG client_physical_lsw, client_physical_msw; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_TRUE) - { - - /* Check if the interface is already enabled. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_INTERFACE_ALREADY_ENABLED); - } - } - else - { - - /* Yes, we found an available record. */ - if (interface_record == NX_NULL) - interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; - } - } - - /* Check if we found an valid DHCP interface record. */ - if (interface_record == NX_NULL) - { - - /* No, release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_RECORDS_AVAILABLE); - } - - /* Set this record as valid. */ - interface_record -> nx_dhcp_record_valid = NX_TRUE; - - /* Set interface index. */ - interface_record -> nx_dhcp_interface_index = iface_index; - - /* Initialize the client DHCP IP address with the NULL IP address. */ - interface_record -> nx_dhcp_ip_address = NX_BOOTP_NO_ADDRESS; - - /* Initialize the client DHCP server IP address. */ - interface_record -> nx_dhcp_server_ip = NX_BOOTP_NO_ADDRESS; - - /* Initialize renew and rebind timeout values to zero. */ - interface_record -> nx_dhcp_rebind_time = 0; - interface_record -> nx_dhcp_renewal_time = 0; - - /* Setup for infinite lease time request. */ - interface_record -> nx_dhcp_lease_time = NX_DHCP_INFINITE_LEASE; - - /* Get the client MAC address from the device interface. */ - client_physical_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; - client_physical_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; - - /* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */ - interface_record -> nx_dhcp_xid = (ULONG)(client_physical_msw ^ client_physical_lsw ^ (ULONG)NX_RAND()); - - /* Clear the timeout. */ - interface_record -> nx_dhcp_timeout = 0; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the disable service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to disable DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_disable Actual disable service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index) -{ -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual delete service. */ - status = _nx_dhcp_interface_disable(dhcp_ptr, iface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disables the input interface to run DHCP. The DHCP */ -/* Client need not be in any state or DHCP to be started on this */ -/* interface to disable it. */ -/* */ -/* This function clears the DHCP and IP interface network parameters. */ -/* Before DHCP can be restarted on this interface, it must be enabled */ -/* by calling nx_dhcp_interface_enable. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to disable DHCP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find Client record for input */ -/* interface */ -/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */ -/* parameters */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Reinitalize the DHCP. This clears network values in DHCP and IP interfaces */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); - - /* Set the record as invalid. */ - interface_record -> nx_dhcp_record_valid = NX_FALSE; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_state_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP notify function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dchp_state_change_notify Application function to call */ -/* upon DHCP state change */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_state_change_notify Actual DHCP notify function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP notify service. */ - status = _nx_dhcp_state_change_notify(dhcp_ptr, dhcp_state_change_notify); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_state_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up an application notification function that is */ -/* called whenever a DHCP interface enters a new state. If a NULL */ -/* pointer is supplied, the notification is effectively cancelled. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dchp_state_change_notify Application function to call */ -/* upon DHCP state change */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)) -{ - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Setup the DHCP notify function. */ - dhcp_ptr -> nx_dhcp_state_change_callback = dhcp_state_change_notify; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_state_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the state change notify call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dhcp_state_interface_change_notify Application function to call */ -/* upon DHCP state change */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_state_change_notify Actual DHCP notify function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_interface_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)) -{ - -UINT status; - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - { - return(NX_PTR_ERROR); - } - - /* Call actual DHCP notify service. */ - status = _nx_dhcp_interface_state_change_notify(dhcp_ptr, dhcp_state_interface_change_notify); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_state_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up an application notification function that is */ -/* called whenever DHCP on the input interface enters a new state. If */ -/* NULL function pointer is supplied, the notification is cancelled. */ -/* The interface on which the DHCP state changed is indicated by the */ -/* iface_index input. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dchp_state_change_notify interface-specific callback */ -/* for DHCP state change */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)) -{ - - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Setup the DHCP notify function. */ - dhcp_ptr -> nx_dhcp_interface_state_change_callback = dhcp_interface_state_change_notify; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP stop function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_stop Actual DHCP stop function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_stop(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP stop service. */ - status = _nx_dhcp_stop(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function halts DHCP processing on all interfaces enabled for */ -/* DHCP. The Client state is reset to NOT STARTED, and if no */ -/* interfaces are currently running DHCP, this function suspends the */ -/* DHCP Client thread, and unbinds the DHCP socket port. */ -/* */ -/* To stop DHCP on a specific interface when multiple interfaces are */ -/* enabled for DHCP, use the nx_dhcp_interface_stop service. */ -/* */ -/* To restart DHCP Client on a stopped interface, the interface must */ -/* be reinitialized using either nx_dhcp_reinitialize() to reinitialize*/ -/* all enabled DHCP interfaces, or nx_dhcp_interface_reinitialize() for*/ -/* a specific interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_stop Interface specific DHCP stop */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_stop(NX_DHCP *dhcp_ptr) -{ - -UINT i; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Check all interfaces to find out which need to stop the DHCP protocol. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) - { - - /* Stop DHCP. */ - _nx_dhcp_interface_stop(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index); - } - } - - /* Stop DHCP Thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Deactivate DHCP Timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Ubind UDP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the interface specific */ -/* DHCP stop service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to stop DHCP */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_stop Actual interface stop service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT status; - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_dhcp_interface_stop(dhcp_ptr, iface_index); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops DHCP processing on the specified interface. It */ -/* sets the DHCP state to the unstarted status. If any state changes */ -/* occurred it calls the record state change callback. */ -/* */ -/* If DHCP is not started on any of the DHCP Client interfaces, this */ -/* function will suspend the thread, unbind the socket and stop the */ -/* timer. */ -/* */ -/* Note: before DHCP Client can be restarted on the interface, the */ -/* DHCP Client must be reinitialized by calling */ -/* nx_dhcp_interface_reinitialize(). */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to stop DHCP on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find record assigned to the */ -/* input interface */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT i; -UINT status; -UINT original_state; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Not found. Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Get the original state. */ - original_state = interface_record -> nx_dhcp_state; - - /* Determine if DHCP is started. */ - if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* DHCP is not started so it can't be stopped. */ - return(NX_DHCP_NOT_STARTED); - } - - /* Set the state to NX_DHCP_STATE_NOT_STARTED. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record->nx_dhcp_state); - } - } - - /* Check if other interfaces are running DHCP. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state != NX_DHCP_STATE_NOT_STARTED)) - { - - /* Yes, other interfaces have started DHCP. We can assume Netx and ThreadX - resources need to stay activated. */ - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_SUCCESS); - } - } - - /* Has DHCP stopped on all interfaces? */ - if (i == NX_DHCP_CLIENT_MAX_RECORDS) - { - - /* Yes, stop DHCP Thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Deactivate DHCP Timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Unbind UDP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_user_option_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP user option function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* option_request Option request */ -/* destination_ptr Pointer to return buffer */ -/* destination_size Size of return buffer (and */ -/* modified to reflect how */ -/* much information is in the */ -/* response) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_user_option_request Actual DHCP user option */ -/* function call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) || - (destination_ptr == NX_NULL) || (destination_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP user option request service. */ - status = _nx_dhcp_user_option_retrieve(dhcp_ptr, option_request, destination_ptr, destination_size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_user_option_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function searches the DHCP options buffer to obtain the */ -/* specified option. If successful, the option is placed in the */ -/* supplied destination string. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* option_request Option request */ -/* destination_ptr Pointer to return buffer */ -/* destination_size Size of return buffer (and */ -/* modified to reflect how */ -/* much information is in the */ -/* response) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interfaces enabled */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_user_option_retrieve */ -/* Search DHCP interface options */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) -{ - -UINT i; -UINT status; - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Retrieve the user option. */ - status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, - option_request, destination_ptr, destination_size); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_user_option_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP user option function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface index */ -/* option_request Option request */ -/* destination_ptr Pointer to return buffer */ -/* destination_size Size of return buffer (and */ -/* modified to reflect how */ -/* much information is in the */ -/* response) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_user_option_request Actual DHCP user option */ -/* function call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_ptr -> nx_dhcp_id != NX_DHCP_ID) || - (destination_ptr == NX_NULL) || (destination_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check interface index. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP interface user option request service. */ - status = _nx_dhcp_interface_user_option_retrieve(dhcp_ptr, iface_index, option_request, destination_ptr, destination_size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_user_option_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function searches the DHCP options buffer to obtain the */ -/* specified option. If successful, the option is placed in the */ -/* supplied destination string. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface index */ -/* option_request Option request */ -/* destination_ptr Pointer to return buffer */ -/* destination_size Size of return buffer (and */ -/* modified to reflect how */ -/* much information is in the */ -/* response) */ -/* */ -/* OUTPUT */ -/* */ -/* destination_size Size of returned option */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_search_buffer Search the buffer */ -/* _nx_dhcp_interface_record_find Find record of input interface*/ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size) -{ - -UCHAR *buffer_ptr; -UINT size; -UINT status; -UINT i; -ULONG *long_ptr; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Check state. */ - if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return an error. */ - return(NX_DHCP_NOT_BOUND); - } - - /* Setup a pointer to the previous buffer. */ - buffer_ptr = _nx_dhcp_search_buffer(interface_record -> nx_dhcp_options_buffer, - option_request, interface_record -> nx_dhcp_options_size); - - /* Determine if the option was found. */ - if (!buffer_ptr) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return an error. */ - return(NX_DHCP_PARSE_ERROR); - } - - /* Calculate the size of the option. */ - size = (UINT) *buffer_ptr; - - /* Determine if the destination is large enough. */ - if (size > *destination_size) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Server did not respond. */ - return(NX_DHCP_DEST_TO_SMALL); - } - - /* Skip the option size field. */ - buffer_ptr++; - - /* Check to see which option data is requested: */ - switch (option_request) - { - case NX_DHCP_OPTION_SUBNET_MASK: - case NX_DHCP_OPTION_TIME_OFFSET: - case NX_DHCP_OPTION_GATEWAYS: - case NX_DHCP_OPTION_TIMESVR: - case NX_DHCP_OPTION_DNS_SVR: - case NX_DHCP_OPTION_NTP_SVR: - case NX_DHCP_OPTION_DHCP_LEASE: - case NX_DHCP_OPTION_DHCP_SERVER: - case NX_DHCP_OPTION_RENEWAL: - case NX_DHCP_OPTION_REBIND: - { - - /* The length of these options must always be a multiple of 4 octets. */ - /* Store the value as host byte order. */ - long_ptr = (ULONG *) destination_ptr; - - /* Loop to set the long value. */ - for (i = 0; i < size;) - { - - /* Set the long value. */ - *long_ptr = _nx_dhcp_get_data(buffer_ptr + i, 4); - - /* Update the pointer. */ - long_ptr ++; - i += 4; - } - break; - } - default: - { - - /* Directly copy the data into destination buffer. */ - memcpy(destination_ptr, buffer_ptr, size); - break; - } - } - - /* Return the actual option size. */ - *destination_size = size; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_user_option_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the option convert service.*/ -/* */ -/* INPUT */ -/* */ -/* source_ptr Source of string area */ -/* */ -/* OUTPUT */ -/* */ -/* value Pointer to conversion value */ -/* NULL Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_user_option_convert Actual option convert service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -ULONG _nxe_dhcp_user_option_convert(UCHAR *source_ptr) -{ - -ULONG temp; - - /* Check for invalid input. */ - if (source_ptr == NX_NULL) - { - return NX_NULL; - } - - /* Pickup the ULONG. */ - temp = _nx_dhcp_user_option_convert(source_ptr); - - /* Return the ULONG. */ - return(temp); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_user_option_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the four bytes pointed to by the input */ -/* string pointer to an ULONG and returns the value. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Source of string area */ -/* */ -/* OUTPUT */ -/* */ -/* value Pointer to conversion value */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -ULONG _nx_dhcp_user_option_convert(UCHAR *source_ptr) -{ - -ULONG temp; - - - /* Pickup the ULONG. */ - temp = (((ULONG) *(source_ptr)) << 24) | - (((ULONG) *(source_ptr+1)) << 16) | - (((ULONG) *(source_ptr+2)) << 8) | - ((ULONG) *(source_ptr+3)); - - /* Return the ULONG. */ - return(temp); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_user_option_add_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the user option add */ -/* callback set service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dhcp_user_option_add Pointer to application's */ -/* option add function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_user_option_add_callback_set Actual user option callback */ -/* set service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, - UCHAR *user_option_ptr, UINT *user_option_length)) -{ - -UINT status; - - /* Check for invalid input. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_user_option_add == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Call actual DHCP user option callback set service. */ - status = _nx_dhcp_user_option_add_callback_set(dhcp_ptr, dhcp_user_option_add); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_user_option_add_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the user option add callback. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dhcp_user_option_add Pointer to application's */ -/* option add function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, - UCHAR *user_option_ptr, UINT *user_option_length)) -{ - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Set the callback. */ - dhcp_ptr -> nx_dhcp_user_option_add = dhcp_user_option_add; - - /* Release the mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_udp_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the IP thread task detects a UDP packet*/ -/* has been received on this socket. It allows the DHCP Client to make */ -/* a non blocking nx_udp_socket_receive call. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to DHCP socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event packet is received */ -/* */ -/* CALLED BY */ -/* */ -/* IP thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - - NX_PARAMETER_NOT_USED(socket_ptr); - - /* Set the data received event flag. */ - tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_RECEIVE_EVENT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the DHCP Client timer expires. It */ -/* loops through all valid interfaces that have started DHCP, and */ -/* updates their DHCP timeout. If an interface timeout has expired, it*/ -/* processes that interface depending on which DHCP state it is in. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set an event that timer expired*/ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX timer */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_timeout_entry(ULONG dhcp) -{ - -NX_DHCP *dhcp_ptr; - - - /* Setup DHCP pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP, dhcp) - - /* Set the data event flag. */ - tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_TIMER_EVENT, TX_OR); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the processing thread for the DHCP Client. */ -/* Its processing consists of executing a while-forever loop that */ -/* checks for events (e.g. packet receive, timer expiration). For */ -/* received packets, some initial packet validation is done before */ -/* calling _nx_dhcp_packet_process. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_instance Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Check for events */ -/* _nx_udp_socket_receive Retrieve packet from socket */ -/* _nx_dhcp_interface_record_find Find record of this interface */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* _nx_dhcp_packet_process Process received packet */ -/* _nx_dhcp_timout_entry Process timer expiration */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_thread_entry(ULONG dhcp_instance) -{ - -NX_DHCP *dhcp_ptr; -NX_PACKET *packet_ptr; -ULONG events; -UINT status; -UINT iface_index; -UINT source_port; -ULONG source_ip_address; -UINT protocol; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - /* Setup the DHCP pointer. */ - NX_THREAD_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP, dhcp_instance) - - /* Obtain the DHCP mutex before processing an. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Enter the DHCP Client task loop. */ - do - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Wait for a DHCP client activity. */ - tx_event_flags_get(&(dhcp_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_ALL_EVENTS, - TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Obtain the DHCP mutex before processing an. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Check for DHCP data received event. */ - if (events & NX_DHCP_CLIENT_RECEIVE_EVENT) - { - - /* Loop to receive DHCP message. */ - while(1) - { - - /* Check for an incoming DHCP packet with non blocking option. */ - status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT); - - /* Check for packet receive errors. */ - if (status != NX_SUCCESS) - { - break; - } - - /* Find the source IP address, port, interface this packet is on. */ - status = nx_udp_packet_info_extract(packet_ptr, &source_ip_address, &protocol, &source_port, &iface_index); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - continue; - } - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the original packet . */ - nx_packet_release(packet_ptr); - continue; - } - - /* Process DHCP packet. */ - _nx_dhcp_packet_process(dhcp_ptr, interface_record, packet_ptr); - } - } - - /* Timer event. */ - if (events & NX_DHCP_CLIENT_TIMER_EVENT) - { - _nx_dhcp_timeout_process(dhcp_ptr); - } - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - - /* IP address conflict event. */ - if (events & NX_DHCP_CLIENT_CONFLICT_EVENT) - { - - /* Loop to check the interface. */ - for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++) - { - - /* Check the flag. */ - if (dhcp_ptr -> nx_dhcp_interface_conflict_flag == 0) - { - break; - } - - /* Check if IP address conflict for this interface. */ - if (dhcp_ptr -> nx_dhcp_interface_conflict_flag & ((UINT)(1 << iface_index))) - { - - /* Handle notice of address conflict event. Let the server know we - did not get assigned a unique IP address. */ - _nx_dhcp_interface_decline(dhcp_ptr, iface_index); - - /* Clear the flag. */ - dhcp_ptr -> nx_dhcp_interface_conflict_flag &= (UINT)(~(1 << iface_index)); - } - } - } -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - } while (1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the DHCP Client thread is notified of a*/ -/* receive event. If verifies the packet is intended for this host, */ -/* and checks the transaction ID from the Server to match its ID, */ -/* processing the packet based on DHCP state. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* interface_record Pointer to DHCP interface */ -/* packet_ptr Pointer to received packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_find_matching_record Find Client record matching */ -/* the packet interface */ -/* nx_packet_allocate Allocate new packet from DHCP */ -/* Client packet pool */ -/* nx_packet_release Release packet back to DHCP */ -/* Client packet pool */ -/* nx_packet_data_extract_offset Copy data to new packet buffer*/ -/* _nx_dhcp_get_option_value Get data for input option */ -/* _nx_dhcp_extract_information Extract basic info from packet*/ -/* _nx_dhcp_send_request_internal Send DHCP message */ -/* nx_ip_interface_address_set Set IP interface address */ -/* nx_ip_gateway_address_set Set IP gateway address */ -/* _nx_dhcp_interface_reinitialize Clear DHCP interface data */ -/* for restarting DHCP */ -/* */ -/* CALLED BY */ -/* */ -/* nx_dhcp_thread_entry DHCP Client thread entry fcn */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_packet_process(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, NX_PACKET *packet_ptr) -{ - -UINT status; -NX_PACKET *new_packet_ptr; -ULONG dhcp_type; -UCHAR *work_ptr; -ULONG bytes_copied; -UINT offset; -NX_IP *ip_ptr; -UINT iface_index; -ULONG packet_client_mac_msw, packet_client_mac_lsw; -ULONG dhcp_client_mac_msw, dhcp_client_mac_lsw; -UINT original_state; -UCHAR *buffer; -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE -ULONG probing_delay; -#endif - - /* Set the IP pointer and interface index. */ - ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; - iface_index = interface_record -> nx_dhcp_interface_index; - - /* Check for valid packet length. */ - if (packet_ptr -> nx_packet_length <= NX_BOOTP_OFFSET_OPTIONS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return; - } - - /* Copy the received packet (datagram) over to a packet from the DHCP Client pool and release - the packet back to receive packet pool as soon as possible. */ - status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Error allocating packet, return error status. */ - return; - } - - /* Verify the incoming packet does not exceed our DHCP Client packet payload. */ - if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < ((packet_ptr) -> nx_packet_length)) - { - - /* Release the newly allocated packet . */ - nx_packet_release(new_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Initialize the offset to the beginning of the packet buffer. */ - offset = 0; - status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, (packet_ptr) -> nx_packet_length, &bytes_copied); - - /* Check status. */ - if ((status != NX_SUCCESS) || (bytes_copied == 0)) - { - - /* Release the allocated packet we'll never send. */ - nx_packet_release(new_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Error extracting packet buffer, return error status. */ - return; - } - - /* Update the new packet with the bytes copied. For chained packets, this will reflect the total - 'datagram' length. */ - new_packet_ptr -> nx_packet_length = bytes_copied; - - - /* Now we can release the original packet. */ - nx_packet_release(packet_ptr); - - /* Set the interface index and MAC address. */ - dhcp_client_mac_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; - dhcp_client_mac_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; - - /* Set work_ptr. */ - work_ptr = new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_CLIENT_HW; - - /* Pickup the target MAC address in the DHCP message. */ - packet_client_mac_msw = (((ULONG)work_ptr[0]) << 8) | ((ULONG)work_ptr[1]); - packet_client_mac_lsw = (((ULONG)work_ptr[2]) << 24) | - (((ULONG)work_ptr[3]) << 16) | - (((ULONG)work_ptr[4]) << 8) | - ((ULONG)work_ptr[5]); - - /* Determine if the MAC address matches ours. */ - if ((packet_client_mac_msw != dhcp_client_mac_msw) || (packet_client_mac_lsw != dhcp_client_mac_lsw)) - { - - /* Release the allocated packet. */ - nx_packet_release(new_packet_ptr); - return; - } - - /* Check if XIDs match. */ - if (_nx_dhcp_get_data(new_packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_XID, 4) != interface_record -> nx_dhcp_xid) - { - - /* Release the original packet . */ - nx_packet_release(new_packet_ptr); - - /* Error with XID data, return error status. */ - return; - } - - /* Save the original state for the state change callback; after this point we will likely change it. */ - original_state = interface_record -> nx_dhcp_state; - - /* The action depends on the current state of the dhcp client. */ - switch (interface_record -> nx_dhcp_state) - { - - case NX_DHCP_STATE_SELECTING: - { - - /* Set up a buffer pointer. */ - buffer = new_packet_ptr -> nx_packet_prepend_ptr; - - /* Get what type of DHCP message it is. */ - status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr -> nx_packet_length); - - /* Determine if it is an Offer. */ - if ((status == NX_SUCCESS) && (dhcp_type == NX_DHCP_TYPE_DHCPOFFER)) - { - - /* Yes, a valid Offer is received! */ - - /* Increment the number of offers received. */ - interface_record -> nx_dhcp_offers_received++; - - /* Update the DHCP Client interface parameters (IP address, server IP, lease, renewal and rebind times */ - if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) - break; - - /* Send the DHCP Request to accept the offer. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Reset the initial timeout to NX_DHCP_MIN_RETRANS_TIMEOUT seconds */ - interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT; - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; - - /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); - - /* Check if the timeout is zero. */ - if (interface_record -> nx_dhcp_timeout == 0) - interface_record -> nx_dhcp_timeout = 1; - - /* Update the state to Requesting state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; - } - - /* Let the timeout processing handle retransmissions. We're done here */ - break; - } - - case NX_DHCP_STATE_REQUESTING: - { - -#ifdef NX_DHCP_ENABLE_BOOTP - - /* Initialize the value of dhcp type since we do not care for BOOTP. */ - dhcp_type = NX_DHCP_TYPE_DHCPACK; - - /* Also initialize status to success since we won't make the get option call. */ - status = NX_SUCCESS; -#endif - - /* Setup buffer pointer. */ - buffer = new_packet_ptr -> nx_packet_prepend_ptr; - -#ifndef NX_DHCP_ENABLE_BOOTP - /* There is a valid DHCP response, see if it is an ACK. */ - status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); -#endif - /* Proceed to processing the server response? */ - if (status == NX_SUCCESS) - { - - /* Yes, check and see if it is an ACK back to our previous request. */ - if (dhcp_type == NX_DHCP_TYPE_DHCPACK) - { - - /* Increment the number of ACKs received. */ - interface_record -> nx_dhcp_acks_received++; - - /* Either we got an ACK or we are using BOOTP. */ - - /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ - if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) - break; - - /* If the host is configured to send an ARP probe to verify Client address is - not in use, do so now. */ - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - - /* Change to the Address Probing state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_ADDRESS_PROBING; - - /* Initalize the time for probing. */ - probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_WAIT); - - /* Check the probing_delay for timer interval. */ - if (probing_delay) - interface_record -> nx_dhcp_timeout = probing_delay; - else - interface_record -> nx_dhcp_timeout = 1; - - /* Set the probing count. */ - interface_record -> nx_dhcp_probe_count = NX_DHCP_ARP_PROBE_NUM; - - /* Setup the handler to indicate the we want collision notification. */ - ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_conflict_notify_handler = _nx_dhcp_ip_conflict; - -#else /* NX_DHCP_CLIENT_SEND_ARP_PROBE not defined: */ - - nx_ip_interface_address_set(ip_ptr, iface_index, - interface_record -> nx_dhcp_ip_address, - interface_record -> nx_dhcp_network_mask); - - /* Check if the gateway address is valid. */ - if (interface_record -> nx_dhcp_gateway_address) - { - - /* Set the gateway address. */ - nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); - } - - /* No ARP probe performed. OK to change to the Bound state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; - -#ifdef NX_DHCP_ENABLE_BOOTP - /* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */ - interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER; -#else - /* Set the renewal time received from the server. */ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; -#endif /* NX_DHCP_ENABLE_BOOTP */ - -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE*/ - - break; - } - else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) - { - - /* Increment the number of NACKs received. */ - interface_record -> nx_dhcp_nacks_received++; - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); - - /* Restart DHCP service for this interface record. */ - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - - /* Check if the timeout is less than 1 second. */ - if (interface_record -> nx_dhcp_timeout < NX_IP_PERIODIC_RATE) - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - } - } - break; - } - - case NX_DHCP_STATE_BOUND: - { - - /* Silently discard all received packets in the BOUND state, RFC2131, Section 4.4 Figure 5 */ - - break; - } - - case NX_DHCP_STATE_RENEWING: - { - - /* Setup the buffer pointer. */ - buffer = new_packet_ptr -> nx_packet_prepend_ptr; - - /* Check the server response if it accepts are renewal. */ - status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); - - /* Was the option retrieved? */ - if (status == NX_SUCCESS) - { - - /* Yes, Check for an ACK. */ - if (dhcp_type == NX_DHCP_TYPE_DHCPACK) - { - - /* Increment the number of ACKs received. */ - interface_record -> nx_dhcp_acks_received++; - - /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ - if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) - break; - - /* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */ - nx_ip_interface_address_set(ip_ptr, iface_index, - interface_record -> nx_dhcp_ip_address, - interface_record -> nx_dhcp_network_mask); - - /* Check if the gateway address is valid. */ - if (interface_record -> nx_dhcp_gateway_address) - { - - /* Set the gateway address. */ - nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); - } - - /* Lease has been renewed, set the countdown timer back to the renewal time and go back - to the Bound state*/ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; - - /* Change the state back to bound. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; - - } - else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) - { - - /* Increment the number of NACKs received. */ - interface_record -> nx_dhcp_nacks_received++; - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); - - /* Restart DHCP service for this interface record. */ - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - } - } - break; - } - - case NX_DHCP_STATE_REBINDING: - { - - /* Setup buffer pointer. */ - buffer = new_packet_ptr -> nx_packet_prepend_ptr; - - /* There is a valid DHCP response, pickup the type of response. */ - status = _nx_dhcp_get_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, &dhcp_type, new_packet_ptr ->nx_packet_length); - - /* Valid response? */ - if (status == NX_SUCCESS) - { - - /* Is it an ACK response? */ - if (dhcp_type == NX_DHCP_TYPE_DHCPACK) - { - - /* Increment the number of ACKs received. */ - interface_record -> nx_dhcp_acks_received++; - - /* Update the parameters (IP address, server IP, lease, renewal and rebind times */ - if (_nx_dhcp_extract_information(dhcp_ptr, interface_record, buffer, new_packet_ptr -> nx_packet_length)) - break; - - /* Set the IP address and gateway address from the value extracted from the Server's DHCP response. */ - nx_ip_interface_address_set(ip_ptr, iface_index, - interface_record -> nx_dhcp_ip_address, - interface_record -> nx_dhcp_network_mask); - - /* Check if the gateway address is valid. */ - if (interface_record -> nx_dhcp_gateway_address) - { - - /* Set the gateway address. */ - nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); - } - - /* Lease has been renewed, set the countdown timer back to the renewal time and go back - to the Bound state. */ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; - - /* Change to bound state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; - } - else if (dhcp_type == NX_DHCP_TYPE_DHCPNACK) - { - - /* Increment the number of NACKs received. */ - interface_record -> nx_dhcp_nacks_received++; - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); - - /* Restart DHCP service for this interface record. */ - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - } - } - break; - } - - default: - break; - - } /* End of switch case */ - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_timeout_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is by the DHCP Client when it checks for a timer */ -/* expiration event. It checks all the DHCP interface records who have */ -/* started DHCP and updates the time remaining on their timeout. */ -/* If a timeout has expired, this function then processes it according */ -/* to the DHCP state it is in. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_send_request_internal Send a request to DHCP server */ -/* _nx_dhcp_update_timeout Reset the DHCP timeout */ -/* _nx_dhcp_add_randomize Modify timeout by random value*/ -/* _nx_dhcp_update_renewal_timeout Set the retransmission timeout*/ -/* _nx_arp_probe_send Send ARP probe for IP address */ -/* uniqueness if ARP probe */ -/* enabled */ -/* nx_ip_interface_address_set Set the IP interface address */ -/* nx_ip_gateway_address_set Set the IP gateway address */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_timeout_process(NX_DHCP *dhcp_ptr) -{ - -UINT i; -UINT original_state; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE -ULONG probing_delay; -NX_IP *ip_ptr; - - - /* Pickup the associated IP pointer. */ - ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; - -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - /* Update the timeout on both interfaces. Check what needs to be done - if a timeout expires, based on Client state. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if the DHCP Client is active on this interface. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE) - continue; - - /* Set the interface reocrd pointer. */ - interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; - - /* Update the count. */ - interface_record -> nx_dhcp_seconds ++; - - /* Check the timer. */ - if (interface_record -> nx_dhcp_timeout != 0) - { - - /* Apply the timer interval to the current DHCP Client timeout. */ - if (interface_record -> nx_dhcp_timeout > NX_DHCP_TIME_INTERVAL) - { - - /* Update the timeout. */ - interface_record -> nx_dhcp_timeout -= (ULONG)NX_DHCP_TIME_INTERVAL; - } - else - { - - /* The DHCP Client timeout has expired. */ - interface_record -> nx_dhcp_timeout = 0; - - /* Save the current state for state change callback. */ - original_state = interface_record -> nx_dhcp_state; - - /* Process according to what state the Client is in. */ - switch (interface_record -> nx_dhcp_state) - { - - case NX_DHCP_STATE_INIT: - { - - /* Reset the seconds field for starting the DHCP address acquistiion. */ - interface_record -> nx_dhcp_seconds = 0; - - /* Initial state when there is no address. Send a DHCPDISCOVER message - to find a DHCP server and switch to the SELECTING state. - Initial timeout is NX_DHCP_MIN_RETRANS_TIMEOUT seconds. */ -#ifndef NX_DHCP_ENABLE_BOOTP - /* Only if the DHCP Client is requesting an IP address and is configured to skip the Discovery message. */ - if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && - (interface_record -> nx_dhcp_skip_discovery)) - { - - /* Send out the DHCP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* And change to the Requesting state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; - } - else - { - - /* Send out the DHCP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER); - - /* And change to the Selecting state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_SELECTING; - } -#else - /* Send the BOOTP Request message. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); - - /* And change to the Requesting state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_REQUESTING; -#endif - - /* Check if the retransmission interval is zero. */ - if (interface_record -> nx_dhcp_rtr_interval == 0) - { - - /* Set the interval to min retransmission timeout. */ - interface_record -> nx_dhcp_rtr_interval = NX_DHCP_MIN_RETRANS_TIMEOUT; - } - else - { - - /* Record the retransmission interval for next retransmission. */ - interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); - } - - /* Update the timeout for next retransmission. */ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; - - /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); - - /* Check if the timeout is zero. */ - if (interface_record -> nx_dhcp_timeout == 0) - interface_record -> nx_dhcp_timeout = 1; - - break; - } - - case NX_DHCP_STATE_SELECTING: - { - -#ifndef NX_DHCP_ENABLE_BOOTP - /* Retransmit the Discover message. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPDISCOVER); -#else - /* Retransmit the BOOTP Request message. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); -#endif - - /* Update the retransmision interval. */ - interface_record -> nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); - - /* Update the timeout for next retransmission. */ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_rtr_interval; - - /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); - - /* Check if the timeout is zero. */ - if (interface_record -> nx_dhcp_timeout == 0) - interface_record -> nx_dhcp_timeout = 1; - - break; - } - - case NX_DHCP_STATE_REQUESTING: - { - -#ifndef NX_DHCP_ENABLE_BOOTP - /* Send a DHCP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); -#else - /* Send a BOOTP request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_BOOT_REQUEST); -#endif - - /* Update the retransmision interval. */ - interface_record->nx_dhcp_rtr_interval = _nx_dhcp_update_timeout(interface_record -> nx_dhcp_rtr_interval); - - /* Reset the timeout for next retransmision. */ - interface_record -> nx_dhcp_timeout = interface_record->nx_dhcp_rtr_interval; - - /* This will modify the timeout by up to +/- 1 second as recommended by RFC 2131, Section 4.1, Page 24. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_add_randomize(interface_record -> nx_dhcp_timeout); - - /* Check if the timeout is zero. */ - if (interface_record -> nx_dhcp_timeout == 0) - interface_record -> nx_dhcp_timeout = 1; - - break; - } - - case NX_DHCP_STATE_ADDRESS_PROBING: - { - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - - /* Send the ARP probe. */ - _nx_arp_probe_send(ip_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_ip_address); - - /* Decrease the probe count. */ - interface_record -> nx_dhcp_probe_count--; - - /* Check the probe count. */ - if (interface_record -> nx_dhcp_probe_count) - { - - /* Calculate the delay time. */ - probing_delay = (ULONG)NX_RAND() % (NX_DHCP_ARP_PROBE_MAX); - - /* Determine if this is less than the minimum. */ - if (probing_delay < NX_DHCP_ARP_PROBE_MIN) - { - - /* Set the delay to the minimum. */ - probing_delay = NX_DHCP_ARP_PROBE_MIN; - } - - /* Check the probing_delay for timer interval. */ - if (probing_delay) - interface_record -> nx_dhcp_timeout = probing_delay; - else - interface_record -> nx_dhcp_timeout = 1; - } - else - { - - /* No address conflict. */ - ip_ptr -> nx_ip_interface[interface_record -> nx_dhcp_interface_index].nx_interface_ip_conflict_notify_handler = NX_NULL; - - /* Set the IP address. */ - nx_ip_interface_address_set(ip_ptr, interface_record -> nx_dhcp_interface_index, - interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask); - - /* Check if the gateway address is valid. */ - if (interface_record -> nx_dhcp_gateway_address) - { - - /* Set the gateway address. */ - nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, interface_record -> nx_dhcp_gateway_address); - } - - /* Change to the Bound state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_BOUND; - - #ifdef NX_DHCP_ENABLE_BOOTP - /* BOOTP does not use timeouts. For the life of this DHCP Client application, keep the same IP address. */ - interface_record -> nx_dhcp_timeout = NX_WAIT_FOREVER; -#else - /* Set the renewal time received from the server. */ - interface_record -> nx_dhcp_timeout = interface_record -> nx_dhcp_renewal_time; -#endif /* NX_DHCP_ENABLE_BOOTP */ - } - -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - break; - } - - case NX_DHCP_STATE_BOUND: - { - - /* Reset the seconds field for starting the DHCP request process. */ - interface_record -> nx_dhcp_seconds = 0; - - /* The lease has timed out. Time to renew. */ - - /* And change to the Renewing state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; - - /* Send the renewal request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Set the time remaining based on RFC 2131 when T1 expires. */ - interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - - break; - } - - case NX_DHCP_STATE_RENEWING: - { - - /* Check if we have reached the end of the renewal time. */ - if (interface_record -> nx_dhcp_renewal_remain_time >= interface_record -> nx_dhcp_rtr_interval) - { - interface_record -> nx_dhcp_renewal_remain_time -= interface_record -> nx_dhcp_rtr_interval; - } - else - { - interface_record -> nx_dhcp_renewal_remain_time = 0; - } - - /* Update the timeout for renew retranmission. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); - - /* Check if we are at the limit on retransmission. */ - if (interface_record -> nx_dhcp_timeout == 0) - { - - /* And change to the Rebinding state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING; - - /* Send the rebind request. */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Calculate the rebind time based on the RFC 2131. */ - interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time; - - /* Calculate the timeout for the response. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - } - else - { - - /* Retransmit the Renewing message and wait again */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - } - - break; - } - - case NX_DHCP_STATE_REBINDING: - { - - /* No response yet, the response must have timed out, - update the timeout and check if we have reached the - end of the rebinding time. */ - if (interface_record -> nx_dhcp_rebind_remain_time >= interface_record -> nx_dhcp_rtr_interval) - { - interface_record -> nx_dhcp_rebind_remain_time -= interface_record -> nx_dhcp_rtr_interval; - } - else - { - interface_record -> nx_dhcp_rebind_remain_time = 0; - } - - /* Update the timeout for renew retranmission. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); - - /* Check if we are at the limit on retransmission. */ - if (interface_record -> nx_dhcp_timeout == 0) - { - - /* Timeout. Restart DHCP service for this interface record. */ - - /* Reinitialize DHCP. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, interface_record -> nx_dhcp_interface_index); - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - } - else - { - - /* Retransmit the Renewing message and wait again */ - _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, NX_DHCP_TYPE_DHCPREQUEST); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - } - break; - } - - default: - { - - break; - } - } - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - - } /* End of switch statement. */ - } - - } /* Try the next interface record. */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_send_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the DHCP client send */ -/* request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dhcp_message_type Type of DHCP message to send , */ -/* */ -/* OUTPUT */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_dhcp_send_request Actual send request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type) -{ - -UINT status; - - - /* Check for invalid input. */ - if (!dhcp_ptr || (dhcp_message_type == 0) || (dhcp_message_type > NX_DHCP_TYPE_DHCPFORCERENEW)) - { - return (NX_PTR_ERROR); - } - - /* Call the actual service and return completion status. */ - status = _nx_dhcp_send_request(dhcp_ptr, dhcp_message_type); - - return(status); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_send_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the specified request to the first DHCP enabled */ -/* interface found. To send a RELEASE or DECLINE message, use the */ -/* nx_dhcp_release/nx_dhcp_interface_release or nx_dhcp_decline/ */ -/* nx_dhcp_interface_decline respectively. */ -/* */ -/* To send a request on a specific DHCP interface if multiple */ -/* interfaces are DHCP enabled, use the */ -/* nx_dhcp_interface_send_request service. */ -/* */ -/* Note: Except for an INFORM REQUEST message, the application should */ -/* not need to send DHCP messages out independently of the DHCP Client */ -/* processing thread. It is not recommended to use this function once */ -/* the DHCP Client has started until it is BOUND. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* dhcp_message_type Type of DHCP message to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_send_request Send DHCP request to server */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type) -{ - -UINT status; -UINT i; - - /* Obtain the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Set the request on only the first (only) valid interface. */ - status = _nx_dhcp_interface_send_request(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, dhcp_message_type); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_send_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the send request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to send message on */ -/* dhcp_message_type DHCP messages to send: */ -/* NX_DHCP_TYPE_DHCPDECLINE */ -/* NX_DHCP_TYPE_DHCPRELEASE */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_send_request Actual send the DHCP request */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type) -{ - -UINT status; - - - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_dhcp_interface_send_request(dhcp_ptr, iface_index, dhcp_message_type); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_send_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows the host application to send a specific request*/ -/* on the specified interface. The interface must be enabled for DHCP. */ -/* */ -/* To send a RELEASE or DECLINE message on a specific interface, use */ -/* the nx_dhcp_interface_release or nx_dhcp_interface_decline */ -/* respectively. */ -/* */ -/* Note: Except for an INFORM REQUEST message, the application should */ -/* not need to send DHCP messages out independently of the DHCP Client */ -/* processing thread. It is not recommended to use this function once */ -/* the DHCP Client has started until it is BOUND. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to send message on */ -/* dhcp_message_type Type of DHCP message to send, */ -/* NX_DHCP_TYPE_DHCPDECLINE */ -/* NX_DHCP_TYPE_DHCPRELEASE */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCP_INVALID_MESSAGE Message type not allowed */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find Client record for the */ -/* specified interface */ -/* _nx_dhcp_send_request_internal Send the DHCP request */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); - } - - /* If the message is a RELEASE or DECLINE request, the host should call nx_dhcp_release - or nx_dhcp_decline respectively. */ - if ((dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE)) - { - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return NX_DHCP_INVALID_MESSAGE; - } - - /* The DHCP INFORM message is independent of the Client thread task activity. */ - if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM) - { - - /* Determine if DHCP is started. */ - if (dhcp_ptr -> nx_dhcp_interface_record[iface_index].nx_dhcp_state == NX_DHCP_STATE_NOT_STARTED) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* DHCP is not started so it should not 'send' a request to the server. */ - return(NX_DHCP_NOT_STARTED); - } - } - - - status = _nx_dhcp_send_request_internal(dhcp_ptr, interface_record, dhcp_message_type); - - /* Release the DHCP mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return status; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_send_request_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a DHCP request to the server. Any additional */ -/* options are appended to the request structure for certain types of */ -/* DHCP requests. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to send message on */ -/* dhcp_message_type Type of DHCP message to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a DHCP packet */ -/* nx_packet_release Release DHCP packet */ -/* nx_udp_socket_send Send DHCP packet */ -/* _nx_dhcp_store_data Write data into message */ -/* _nx_dhcp_add_option_value Add an option to the request */ -/* _nx_dhcp_add_option_string Add an option string to the */ -/* request */ -/* nx_udp_socket_interface_send Send packet out on interface */ -/* _nx_dhcp_client_send_with_zero_source_address */ -/* Send broadcast packet with */ -/* zero source IP address */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_interface_send_request Send request on specified */ -/* interface */ -/* _nx_dhcp_interface_force_renew Send Force Renew message */ -/* _nx_dhcp_interface_decline Send DECLINE message */ -/* _nx_dhcp_interface_release Send RELEASE message */ -/* _nx_dhcp_packet_process Process received packets */ -/* _nx_dhcp_timeout_process Process timer expirations */ -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -/* _nx_dhcp_resume Resume the DHCP Client thread */ -#endif -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_send_request_internal(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UINT dhcp_message_type) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer; -ULONG targetIP; -UINT status; -ULONG dhcp_client_mac_msw; -ULONG dhcp_client_mac_lsw; -UINT iface_index; -UINT index = 0; -UCHAR *user_option_ptr; -UINT user_option_length; -UINT name_length; - - - /* Set the interface idnex. */ - iface_index = interface_record -> nx_dhcp_interface_index; - - /* Allocate a DHCP packet. */ - status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Increment the DHCP internal error counter. */ - interface_record -> nx_dhcp_internal_errors++; - - /* Return status. */ - return(status); - } - - /* Set the interface index and MAC address. */ - dhcp_client_mac_msw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; - dhcp_client_mac_lsw = dhcp_ptr -> nx_dhcp_ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; - - /* Setup the buffer pointer. */ - buffer = packet_ptr -> nx_packet_prepend_ptr; - - /* Clear the buffer out... just in case. */ - memset((void *) buffer, 0, NX_BOOTP_OFFSET_END); - - /* Setup the standard BootP fields. */ - buffer[NX_BOOTP_OFFSET_OP] = NX_BOOTP_OP_REQUEST; - buffer[NX_BOOTP_OFFSET_HTYPE] = NX_BOOTP_TYPE_ETHERNET; - buffer[NX_BOOTP_OFFSET_HLEN] = NX_BOOTP_HLEN_ETHERNET; - buffer[NX_BOOTP_OFFSET_HOPS] = 0; - buffer[NX_BOOTP_OFFSET_SERVER_NM] = 0; - buffer[NX_BOOTP_OFFSET_BOOT_FILE] = 0; - - /* Setup the 'Xid' field. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_XID, 4, interface_record -> nx_dhcp_xid); - - /* Set the 'secs' field according to RFC2131, Secion4.4.1, Page37, Table5. */ - if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) - { - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, 0); - } - else - { - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SECS, 2, interface_record -> nx_dhcp_seconds); - } - - /* Set the broadcast flag according to RFC2131, Secion4.4.1, Page38, Table5. */ - - /* Set the broadcast flag to 0 for DHCP Decline and DHCP Release. */ - if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) || (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) - { - - /* Request the response be sent unicast. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST); - } - - /* Set the 'broadcast' flag according to user requirement for DHCP Discover, DHCP Request and DHCP Inform. */ - else if (interface_record -> nx_dhcp_clear_broadcast == NX_TRUE) - { - - /* Request the response be sent unicast. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_UNICAST); - } - else - { - - /* Request the response be sent broadcast. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_FLAGS, 1, NX_BOOTP_FLAGS_BROADCAST); - } - - /* RFC 2131 4.4.1: Do not set the Client IP ("ciaddr" field) address...*/ - if (dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM) - { - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, NX_BOOTP_NO_ADDRESS); - } - /* ...unless this is an INFORM REQUEST message. */ - else - { - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); - } - - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_YOUR_IP, 4, NX_BOOTP_NO_ADDRESS); - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, NX_BOOTP_NO_ADDRESS); - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_GATEWAY_IP, 4, NX_BOOTP_NO_ADDRESS); - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW, 2, dhcp_client_mac_msw); - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_mac_lsw); - -#ifndef NX_DHCP_ENABLE_BOOTP - /* Update the index. */ - index = NX_BOOTP_OFFSET_OPTIONS; - - /* A BOOTP Client should not request DHCP option data. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_VENDOR, 4, NX_BOOTP_MAGIC_COOKIE); - - /* Add the actual DHCP request. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_TYPE, NX_DHCP_OPTION_DHCP_TYPE_SIZE, dhcp_message_type, &index); -#endif - - /* Determine if any additional options need to be added relative to the DHCP message type. - RFC 2131, Table 5: Fields and options used by DHCP Clients. */ - switch (dhcp_message_type) - { - -#ifdef NX_DHCP_ENABLE_BOOTP - - case NX_DHCP_TYPE_BOOT_REQUEST: - - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_SERVER_IP, 4, interface_record -> nx_dhcp_server_ip); - - break; -#endif - - case NX_DHCP_TYPE_DHCPDISCOVER: - - - /* Determine if we have a valid IP address. */ - if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && - (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS)) - { - - /* Add a IP request option if we have a valid IP address */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, - interface_record -> nx_dhcp_ip_address, &index); - } - - /* Add an option request for an infinite lease. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index); - - /* Add the system name */ - if (dhcp_ptr -> nx_dhcp_name) - { - - /* Check name length. */ - if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) - { - nx_packet_release(packet_ptr); - return(NX_DHCP_INVALID_NAME); - } - - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, - (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); - } - - /* Add an option request for DHCP parameters (gateway, subnet mask, etc.). */ - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, NX_DHCP_REQUEST_PARAMETER_SIZE, _nx_dhcp_request_parameters, &index); - -#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION - - /* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept. - RFC2132, Section9.10, Page28. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index); -#endif - - /* Increment the number of Discovery messages sent. */ - interface_record -> nx_dhcp_discoveries_sent++; - break; - - case NX_DHCP_TYPE_DHCPREQUEST: - - /* Add the system name */ - if (dhcp_ptr -> nx_dhcp_name) - { - - /* Check name length. */ - if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) - { - nx_packet_release(packet_ptr); - return(NX_DHCP_INVALID_NAME); - } - - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); - } - - /* Determine if we have a valid IP address. Must not include if Renewing or Rebinding RCV 2131 4.3.2. */ - if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && - (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS) && - (interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) && - (interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING)) - { - - /* Add an IP request option if we have a valid IP address. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, - interface_record -> nx_dhcp_ip_address, &index); - } - - /* Add a request for an infinite lease if we haven't already set the timers. */ - if ((interface_record -> nx_dhcp_rebind_time == 0) || - (interface_record -> nx_dhcp_renewal_time == 0)) - { - - /* Add the infinite lease option. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_LEASE, NX_DHCP_OPTION_DHCP_LEASE_SIZE, NX_DHCP_INFINITE_LEASE, &index); - } - - /* Should add server ID if not renewing. */ - if ((interface_record -> nx_dhcp_state != NX_DHCP_STATE_RENEWING) && - (interface_record -> nx_dhcp_state != NX_DHCP_STATE_REBINDING) && - (interface_record -> nx_dhcp_server_ip != NX_BOOTP_BC_ADDRESS) - ) - { - - /* Add Server identifier option. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, - interface_record -> nx_dhcp_server_ip, &index); - } - else if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) || - (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)) - - { - - /* Ensure the renewal message fields are correct. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); - } - - /* Add the request for the DHCP parameters (gateway, subnet mask, etc.) if not renewing. */ - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, NX_DHCP_REQUEST_PARAMETER_SIZE, _nx_dhcp_request_parameters, &index); - -#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION - - /* Add an option to specify the maximum length DHCP message that DHCP Client is willing to accept. - RFC2132, Section9.10, Page28. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_MAX_DHCP_MESSAGE, 2, dhcp_ptr -> nx_dhcp_max_dhcp_message_size, &index); -#endif - - /* Increment the number of Request messages sent. */ - interface_record -> nx_dhcp_requests_sent++; - break; - - case NX_DHCP_TYPE_DHCPDECLINE: - - /* Does the Client have a nonzero requested address it is declining? */ - if ((interface_record -> nx_dhcp_ip_address != NX_BOOTP_NO_ADDRESS) && - (interface_record -> nx_dhcp_ip_address != NX_BOOTP_BC_ADDRESS)) - { - - /* Yes; add Request IP address option. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_IP_REQ, NX_DHCP_OPTION_DHCP_IP_REQ_SIZE, - interface_record -> nx_dhcp_ip_address, &index); - } - - /* Add Server identifier option. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, - interface_record -> nx_dhcp_server_ip, &index); - - break; - - case NX_DHCP_TYPE_DHCPRELEASE: - - /* Added the 'ciaddr', Indicate the IP address being released. */ - _nx_dhcp_store_data(buffer + NX_BOOTP_OFFSET_CLIENT_IP, 4, interface_record -> nx_dhcp_ip_address); - - /* Add Server identifier option. */ - _nx_dhcp_add_option_value(buffer, NX_DHCP_OPTION_DHCP_SERVER, NX_DHCP_OPTION_DHCP_SERVER_SIZE, - interface_record -> nx_dhcp_server_ip, &index); - - /* Increment the number of Release messages sent. */ - interface_record -> nx_dhcp_releases_sent++; - break; - - case NX_DHCP_TYPE_DHCPINFORM: - - /* Add the system name */ - if (dhcp_ptr -> nx_dhcp_name) - { - - /* Check name length. */ - if (_nx_utility_string_length_check(dhcp_ptr -> nx_dhcp_name, &name_length, 255)) - { - nx_packet_release(packet_ptr); - return(NX_DHCP_INVALID_NAME); - } - - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_HOST_NAME, name_length, (UCHAR *) dhcp_ptr -> nx_dhcp_name, &index); - } - - /* Add an option request for DHCP parameters (gateway, subnet mask, etc.). */ - _nx_dhcp_add_option_string(buffer, NX_DHCP_OPTION_DHCP_PARAMETERS, 1, &(interface_record -> nx_dhcp_user_option), &index); - - /* Increment the number of Inform messages sent. */ - interface_record -> nx_dhcp_informs_sent++; - - break; - - default: - break; - } - - /* Add any user supplied options to the buffer. */ - if (dhcp_ptr -> nx_dhcp_user_option_add) - { - - /* Set the pointer for adding user option. */ - user_option_ptr = buffer + index; - - /* Calculate the available length for user options. Minus 1 to add the END option. */ - user_option_length = (UINT)(packet_ptr -> nx_packet_data_end - user_option_ptr - 1); - - /* Add the specific DHCP option user wanted. */ - if (dhcp_ptr -> nx_dhcp_user_option_add(dhcp_ptr, iface_index, dhcp_message_type, user_option_ptr, &user_option_length) == NX_TRUE) - { - - /* Update the index to include the user options. */ - index += user_option_length; - } - else - { - - /* Invalid user options. Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_DHCP_UNKNOWN_OPTION); - } - } - - /* Setup the packet pointers. */ - packet_ptr -> nx_packet_length = NX_BOOTP_OFFSET_END; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_BOOTP_OFFSET_END; - -#ifndef NX_DHCP_ENABLE_BOOTP - - /* Added the END option. */ - *(buffer + index) = NX_DHCP_OPTION_END; - index ++; - - /* Check the option length. */ - if (index > NX_BOOTP_OFFSET_END) - { - packet_ptr -> nx_packet_length = index; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; - } -#endif - - /* Set the target address according to RFC2131, Section4.3.6, Page33, Table4 and Section4.4.4, Page40. - DHCP Request for renewing and DHCP Release message must be unicast. */ - if (((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING)) || - (dhcp_message_type == NX_DHCP_TYPE_DHCPRELEASE)) - { - - /* Use the current server's IP address. */ - targetIP = interface_record -> nx_dhcp_server_ip; - } - else - { - - /* Set the server target IP address to broadcast. */ - targetIP = NX_BOOTP_BC_ADDRESS; - } - - /* DHCP messages broadcast by a client prior to that client obtaining - its IP address must have the source address field in the IP header - set to 0. RFC2131, Section4.1, Page23. */ - if ((dhcp_message_type == NX_DHCP_TYPE_DHCPDISCOVER) || - ((dhcp_message_type == NX_DHCP_TYPE_DHCPREQUEST) && (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND))) - { - - /* Call function to send the special packet with zero source address.*/ - status = _nx_dhcp_client_send_with_zero_source_address(dhcp_ptr, iface_index, packet_ptr); - } - else - { - - /* Send the packet. */ - status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, targetIP, NX_DHCP_SERVER_UDP_PORT, iface_index); - } - - /* If an error is detected, release the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_send_with_zero_source_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds the UDP and IP header with zero source address,*/ -/* then sends the packet to the appropriate link driver. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to send message on */ -/* packet_ptr Pointer to packet to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* (ip_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_send_request_internal Send DHCP Request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_client_send_with_zero_source_address(NX_DHCP *dhcp_ptr, UINT iface_index, NX_PACKET *packet_ptr) -{ - -NX_IP *ip_ptr; -NX_UDP_SOCKET *socket_ptr; -NX_UDP_HEADER *udp_header_ptr; -NX_IPV4_HEADER *ip_header_ptr; -NX_INTERFACE *interface_ptr; -ULONG ip_src_addr, ip_dest_addr; -UINT compute_checksum; -ULONG checksum; -ULONG val; -NX_IP_DRIVER driver_request; - - /* Set up the pointer to the associated IP instance. */ - ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; - - /* Set up the pointer to the associated socket. */ - socket_ptr = &dhcp_ptr -> nx_dhcp_socket; - - /* Set up the pointer to the interface. */ - interface_ptr = &(ip_ptr -> nx_ip_interface[iface_index]); - packet_ptr -> nx_packet_ip_interface = interface_ptr; - - /* Set up the address. */ - ip_src_addr = NX_BOOTP_NO_ADDRESS; - ip_dest_addr = NX_BOOTP_BC_ADDRESS; - - /* Check the interface. */ - if ((!interface_ptr -> nx_interface_valid) || (!interface_ptr -> nx_interface_link_up)) - { - - /* None found; return the error status. */ - return(NX_INVALID_INTERFACE); - } - - /* Build UDP header. */ - - /* Prepend the UDP header to the packet. First, make room for the UDP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER); - - /* Set the correct IP version. */ - packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V4; - -#ifndef NX_DISABLE_UDP_INFO - /* Increment the total UDP packets sent count. */ - ip_ptr -> nx_ip_udp_packets_sent++; - - /* Increment the total UDP bytes sent. */ - ip_ptr -> nx_ip_udp_bytes_sent += packet_ptr -> nx_packet_length; - - /* Increment the total UDP packets sent count for this socket. */ - socket_ptr -> nx_udp_socket_packets_sent++; - - /* Increment the total UDP bytes sent for this socket. */ - socket_ptr -> nx_udp_socket_bytes_sent += packet_ptr -> nx_packet_length; -#endif - - /* Increase the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_UDP_HEADER); - - /* Setup the UDP header pointer. */ - udp_header_ptr = (NX_UDP_HEADER *) packet_ptr -> nx_packet_prepend_ptr; - - /* Build the first 32-bit word of the UDP header. */ - udp_header_ptr -> nx_udp_header_word_0 = (((ULONG)socket_ptr -> nx_udp_socket_port ) << NX_SHIFT_BY_16) | (ULONG) NX_DHCP_SERVER_UDP_PORT; - - /* Build the second 32-bit word of the UDP header. */ - udp_header_ptr -> nx_udp_header_word_1 = (packet_ptr -> nx_packet_length << NX_SHIFT_BY_16); - - /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will - swap the endian of the UDP header. */ - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - -#ifdef NX_DISABLE_UDP_TX_CHECKSUM - compute_checksum = 0; -#else /* NX_DISABLE_UDP_TX_CHECKSUM */ - compute_checksum = 1; -#endif /* NX_DISABLE_UDP_TX_CHECKSUM */ - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - if (compute_checksum) - { - /* Yes, we need to compute the UDP checksum. */ - checksum = _nx_ip_checksum_compute(packet_ptr, - NX_PROTOCOL_UDP, - (UINT)packet_ptr -> nx_packet_length, - &ip_src_addr, - &ip_dest_addr); - - checksum = ~checksum & NX_LOWER_16_MASK; - - /* If the computed checksum is zero, it will be transmitted as all ones. */ - /* RFC 768, page 2. */ - if (checksum == 0) - checksum = 0xFFFF; - - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; - - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - /* Set CHECKSUM flag so the driver would invoke the HW checksum. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Get mutex protection. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Build the IP header. */ - - /* Prepend the IP header to the packet. First, make room for the IP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 20; - - /* Increase the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 20; - - /* Setup the IP header pointer. */ - ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; - - /* Build the first 32-bit word of the IP header. */ - ip_header_ptr -> nx_ip_header_word_0 = (NX_IP_VERSION | socket_ptr -> nx_udp_socket_type_of_service | (0xFFFF & packet_ptr -> nx_packet_length)); - - /* Build the second 32-bit word of the IP header. */ - ip_header_ptr -> nx_ip_header_word_1 = (ip_ptr -> nx_ip_packet_id++ << NX_SHIFT_BY_16) | socket_ptr -> nx_udp_socket_fragment_enable; - - /* Build the third 32-bit word of the IP header. */ - ip_header_ptr -> nx_ip_header_word_2 = ((socket_ptr -> nx_udp_socket_time_to_live << NX_IP_TIME_TO_LIVE_SHIFT) | NX_IP_UDP); - - /* Place the source IP address in the IP header. */ - ip_header_ptr -> nx_ip_header_source_ip = ip_src_addr; - - /* Place the destination IP address in the IP header. */ - ip_header_ptr -> nx_ip_header_destination_ip = ip_dest_addr; - - /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will - swap the endian of the IP header. */ - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip); - -#ifdef NX_DISABLE_IP_TX_CHECKSUM - compute_checksum = 0; -#else /* NX_DISABLE_IP_TX_CHECKSUM */ - compute_checksum = 1; -#endif /* NX_DISABLE_IP_TX_CHECKSUM */ - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if (packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - if (compute_checksum) - { - checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4, 20, NULL, NULL); - - val = (ULONG)(~checksum); - val = val & NX_LOWER_16_MASK; - - /* Convert to network byte order. */ - NX_CHANGE_ULONG_ENDIAN(val); - - /* Now store the checksum in the IP header. */ - ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | val; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - -#ifdef NX_ENABLE_IP_PACKET_FILTER - /* Check if the IP packet filter is set. */ - if (ip_ptr -> nx_ip_packet_filter) - { - - /* Yes, call the IP packet filter routine. */ - if ((ip_ptr -> nx_ip_packet_filter((VOID *)(ip_header_ptr), NX_IP_PACKET_OUT)) != NX_SUCCESS) - { - - /* Release mutex protection. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Return a not successful status. */ - return(NX_NOT_SUCCESSFUL); - } - } -#endif /* NX_ENABLE_IP_PACKET_FILTER */ - - /* Build the driver request. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_ip_interface; - driver_request.nx_ip_driver_command = NX_LINK_PACKET_BROADCAST; - driver_request.nx_ip_driver_physical_address_msw = 0xFFFFUL; - driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFFUL; - - /* Determine if fragmentation is needed. */ - if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_mtu_size) - { - -#ifndef NX_DISABLE_FRAGMENTATION - /* Check the DF bit flag. */ - if ((ip_ptr -> nx_ip_fragment_processing) && (socket_ptr -> nx_udp_socket_fragment_enable != NX_DONT_FRAGMENT)) - { - - /* Fragmentation is needed, call the IP fragment processing routine. */ - (ip_ptr -> nx_ip_fragment_processing) (&driver_request); - - /* Release mutex protection. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Return a successful status. */ - return(NX_SUCCESS); - } - else -#endif /* NX_DISABLE_FRAGMENTATION */ - { - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP send packets dropped count. */ - ip_ptr -> nx_ip_send_packets_dropped++; -#endif - - /* Release mutex protection. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Return a not successful status. */ - return(NX_NOT_SUCCESSFUL); - } - } - -#ifndef NX_DISABLE_IP_INFO - - /* Increment the IP packet sent count. */ - ip_ptr -> nx_ip_total_packets_sent++; - - /* Increment the IP bytes sent count. */ - ip_ptr -> nx_ip_total_bytes_sent += packet_ptr -> nx_packet_length - 20; -#endif - - /* Broadcast packet. */ - (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); - - /* Release mutex protection. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_extract_information PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts important information from the server's */ -/* response DHCP message. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* interface_record Pointer to DHCP interface */ -/* dhcp_message Pointer to DHCP message */ -/* length Size of DHCP message buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_ip_address_set Set the DHCP IP address */ -/* nx_ip_gateway_address_set Set the Gateway address */ -/* _nx_dhcp_get_option_value Get DHCP option from buffer */ -/* _nx_dhcp_get_data Get data from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_packet_process Data received handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_extract_information(NX_DHCP *dhcp_ptr, NX_DHCP_INTERFACE_RECORD *interface_record, UCHAR *dhcp_message, UINT length) -{ - -ULONG value; - - - /* Extract the IP address. */ - value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_YOUR_IP, 4); - - /* Determine if it is valid. */ - if ((value != NX_BOOTP_NO_ADDRESS) && - (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || - ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || - ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) - { - - /* Store the IP address. */ - interface_record -> nx_dhcp_ip_address = value; - } - else - { - return(NX_DHCP_BAD_IP_ADDRESS); - } - - /* Determine if there is a subnet mask. Note a DHCP Server receiving a BOOTP request - may send DHCP option data for subnet masks as per RFC 1534 Section 2. */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_SUBNET_MASK, &value, length) == NX_SUCCESS) - { - - /* Make sure there is a valid IP address too. */ - if (value != NX_BOOTP_NO_ADDRESS) - { - - interface_record -> nx_dhcp_network_mask = value; - } - else - { - ULONG ip_address; - - /* No valid network mask info supplied; use the current network mask if any. Don't - care about current IP address for now. */ - nx_ip_interface_address_get(dhcp_ptr -> nx_dhcp_ip_ptr, - interface_record -> nx_dhcp_interface_index, - &ip_address, - &(interface_record -> nx_dhcp_network_mask)); - } - } - -#ifdef NX_DHCP_ENABLE_BOOTP - - /* Update the IP address. */ - value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_SERVER_IP, 4); - - /* Determine if it is valid. */ - if (value != NX_BOOTP_NO_ADDRESS) - { - - /* Store the IP address. */ - interface_record -> nx_dhcp_server_ip = value; - } - - /* Update the IP address. */ - value = _nx_dhcp_get_data(dhcp_message + NX_BOOTP_OFFSET_GATEWAY_IP, 4); - - /* Determine if it is valid. */ - if ((value != NX_BOOTP_NO_ADDRESS) && - (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || - ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || - ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) - { - - /* Store the gateway/Router IP address to the Client record. */ - interface_record -> nx_dhcp_gateway_address = value; - } - else - { - - /* The gateway may be sent as an option: See note above about BOOTP Clients - parsing DHCP option data. */ - - /* Determine if the IP gateway/router IP address is present. */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS) - { - - /* Determine if it is valid. */ - if ((value != NX_BOOTP_NO_ADDRESS) && - (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || - ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || - ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) - { - - /* Store the gateway/Router IP address to the Client record. */ - interface_record -> nx_dhcp_gateway_address = value; - } - else - { - return(NX_DHCP_BAD_IP_ADDRESS); - } - } - } - -#else - - /* NX_DHCP_ENABLE_BOOTP not defined */ - - /* Overwrite the server ID if there is a DHCP option for Server ID */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_SERVER, &value, length) == NX_SUCCESS) - { - - /* Determine if it is valid. */ - if ((value != NX_BOOTP_NO_ADDRESS) && - (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || - ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || - ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) - { - - /* Store the server IP address. */ - interface_record -> nx_dhcp_server_ip = value; - } - else - { - return(NX_DHCP_BAD_IP_ADDRESS); - } - } - - /* Get the lease time. */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_DHCP_LEASE, &value, length) == NX_SUCCESS) - { - - /* Check for an infinite lease. */ - if (value == 0xFFFFFFFF) - { - /* Store the 'infinite' lease time . */ - interface_record -> nx_dhcp_lease_time = value; - interface_record -> nx_dhcp_renewal_time = value; - interface_record -> nx_dhcp_rebind_time = value; - } - else - { - - /* Store the lease time in timer ticks. */ - interface_record -> nx_dhcp_lease_time = value * (ULONG)NX_IP_PERIODIC_RATE; - - /* Set the renew and rebind times. */ - interface_record -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_lease_time / 2; - interface_record -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_lease_time - (interface_record -> nx_dhcp_lease_time / 8); - } - } - - /* Overwrite the renew and rebind times with the specified values if the options are present. */ - if ((_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_RENEWAL, &value, length) == NX_SUCCESS) && - (value <= interface_record -> nx_dhcp_lease_time)) - { - - /* Check for an infinite lease. */ - if (value == 0xFFFFFFFF) - { - /* Set the 'infinite least time. */ - interface_record -> nx_dhcp_renewal_time = value; - } - else - { - - /* Store the renewal time in timer ticks */ - interface_record -> nx_dhcp_renewal_time = value * (ULONG)NX_IP_PERIODIC_RATE; - } - } - - /* Determine if there is a rebind time. */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_REBIND, &value, length) == NX_SUCCESS) - { - - /* Check for an infinite lease. */ - if (value == 0xFFFFFFFF) - { - - /* Set the 'infinite least time. */ - interface_record -> nx_dhcp_rebind_time = value; - } - else - { - - /* Convert to timer ticks. */ - value = value * (ULONG)NX_IP_PERIODIC_RATE; - - /* Sanity check*/ - if ((value <= interface_record -> nx_dhcp_lease_time) && - (value >= interface_record -> nx_dhcp_renewal_time)) - { - - /* Store the rebind time. */ - interface_record -> nx_dhcp_rebind_time = value; - } - } - } - - /* Determine if this is an ACK from a server response, which can only happen from a handful of states. */ - if ((interface_record -> nx_dhcp_state == NX_DHCP_STATE_REQUESTING) || - (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) || - (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING)) - { - - /* Determine if the IP gateway/router IP address is present. */ - if (_nx_dhcp_get_option_value(dhcp_message, NX_DHCP_OPTION_GATEWAYS, &value, length) == NX_SUCCESS) - { - - /* Determine if it is valid. */ - if ((value != NX_BOOTP_NO_ADDRESS) && - (((value & NX_IP_CLASS_A_MASK) == NX_IP_CLASS_A_TYPE) || - ((value & NX_IP_CLASS_B_MASK) == NX_IP_CLASS_B_TYPE) || - ((value & NX_IP_CLASS_C_MASK) == NX_IP_CLASS_C_TYPE))) - { - - /* Store the gateway/Router IP address to the Client record. */ - interface_record -> nx_dhcp_gateway_address = value; - } - else - { - return(NX_DHCP_BAD_IP_ADDRESS); - } - } - } - - /* Check the DHCP options size. */ - if ((length - NX_BOOTP_OFFSET_OPTIONS) > NX_DHCP_OPTIONS_BUFFER_SIZE) - interface_record -> nx_dhcp_options_size = NX_DHCP_OPTIONS_BUFFER_SIZE; - else - interface_record -> nx_dhcp_options_size = length - NX_BOOTP_OFFSET_OPTIONS; - - /* Copy the DHCP options into DHCP Client options buffer. */ - memcpy(interface_record -> nx_dhcp_options_buffer, - &dhcp_message[NX_BOOTP_OFFSET_OPTIONS], interface_record -> nx_dhcp_options_size); - -#endif /* NX_DHCP_ENABLE_BOOTP */ - - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_get_option_value PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function searches through a buffer containing a BootP message */ -/* for a DHCP option parameter and gets the value of that option if */ -/* it exists. The function is restricted to options that are less */ -/* than 4 octets (bytes) in size. */ -/* */ -/* INPUT */ -/* */ -/* bootp_message Pointer to option buffer */ -/* option Option requested */ -/* value Pointer to return value var */ -/* length Size of option buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_search_buffer Search the buffer */ -/* _nx_dhcp_get_data Get data from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_packet_process Data received handler */ -/* _nx_dhcp_extract_information Extract info from server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_get_option_value(UCHAR *bootp_message, UINT option, ULONG *value, UINT length) -{ - -UCHAR *data; -UCHAR *option_message; -UINT option_length; - - - /* Setup buffer pointer. */ - option_message = &bootp_message[NX_BOOTP_OFFSET_OPTIONS]; - option_length = length - NX_BOOTP_OFFSET_OPTIONS; - - /* Find the option. */ - if ((option != NX_DHCP_OPTION_PAD) && (option != NX_DHCP_OPTION_END)) - { - - /* Search the buffer for the option. */ - data = _nx_dhcp_search_buffer(option_message, option, option_length); - - /* Check to see if the option was found. */ - if (data != NX_NULL) - { - - /* Check for the proper size. */ - if (*data > 4) - { - - /* Check for the gateway option. */ - if (option == NX_DHCP_OPTION_GATEWAYS) - { - - /* Pickup the first gateway address. */ - *value = _nx_dhcp_get_data(data + 1, 4); - - /* For now, just disregard any additional gateway addresses. */ - return(NX_SUCCESS); - } - else - { - - /* Invalid size, return error. */ - return(NX_SIZE_ERROR); - } - } - else - { - - /* Get the actual value. */ - *value = _nx_dhcp_get_data(data + 1, *data); - return(NX_SUCCESS); - } - } - } - - /* Return an error if not found. */ - return(NX_OPTION_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_add_option_value PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine adds a DHCP vendor option value to the BootP message */ -/* in the supplied buffer. Adding the option includes adding the */ -/* option code, length and option data value. */ -/* */ -/* INPUT */ -/* */ -/* bootp_message Pointer to message buffer */ -/* option Option to add */ -/* value Value of Option to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_store_data Store data value */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_send_request_internal Send DHCP request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_add_option_value(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index) -{ - - - /* Store the option. */ - *(bootp_message + (*index)) = (UCHAR)option; - (*index) ++; - - /* Store the option size. */ - *(bootp_message + (*index)) = (UCHAR)size; - (*index) ++; - - /* Store the option value. */ - _nx_dhcp_store_data(bootp_message + (*index), size, value); - (*index) += size; - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_add_option_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine adds a DHCP option string to the BootP message in */ -/* supplied buffer. Adding the option includes adding the option */ -/* code, length and option string. */ -/* */ -/* INPUT */ -/* */ -/* bootp_message Pointer to message buffer */ -/* option Option to add */ -/* size Size of option string */ -/* value Option string pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_move_string Store option string */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_send_request_internal Internal DHCP message send */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_add_option_string(UCHAR *bootp_message, UINT option, UINT size, UCHAR *value, UINT *index) -{ - - /* Store the option. */ - *(bootp_message + (*index)) = (UCHAR)option; - (*index) ++; - - /* Store the option size. */ - *(bootp_message + (*index)) = (UCHAR)size; - (*index) ++; - - /* Store the option value. */ - _nx_dhcp_move_string(bootp_message + (*index), value, size); - (*index) += size; - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_add_randomize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine adds randomized variance to the input timeout up to */ -/* +/- one second. */ -/* */ -/* INPUT */ -/* */ -/* timeout Timeout to randomize */ -/* */ -/* OUTPUT */ -/* */ -/* ULONG Modified timeout value */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* nx_dhcp_process Process the current state of */ -/* the DHCP Client state machine*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dhcp_add_randomize(ULONG timeout) -{ - -ULONG adjustment; - - /* Uniform random number chosen from the range -1 to +1 second as recommended by RFC2131, Section4.1, Page24. */ - - /* Calculate random time adjustment in timer ticks from the range 0 to NX_IP_PERIODIC_RATE * 2. */ - adjustment = (ULONG)NX_RAND() % ((NX_IP_PERIODIC_RATE << 1) + 1); - - /* Check for adjustment. */ - if (adjustment < NX_IP_PERIODIC_RATE) - { - - /* Updated timeout, minus NX_IP_PERIODIC_RATE - adjustment. */ - - /* Check for timeout. */ - if (timeout > (NX_IP_PERIODIC_RATE - adjustment)) - timeout -= (ULONG)(NX_IP_PERIODIC_RATE - adjustment); - else - timeout = 0; - } - else - { - - /* Updated timeout, add adjustment- NX_IP_PERIODIC_RATE. */ - timeout += (ULONG)(adjustment - NX_IP_PERIODIC_RATE); - } - - return timeout; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_update_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCP timeout for retransmission. When the */ -/* current timeout expires, this function doubles the timeout, but */ -/* limits the timeout value to NX_DHCP_MAX_RETRANS_TIMEOUT (seconds). */ -/* */ -/* INPUT */ -/* */ -/* timeout The current Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* timeout The updated timeout */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_convert_delay_to_ticks Convert the delay to ticks */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_timeout_process Timer expiration handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dhcp_update_timeout(ULONG timeout) -{ - - /* Timed out, double the timeout, limited to NX_DHCP_MAX_RETRANS_TIMEOUT */ - if ((2 * timeout) >= NX_DHCP_MAX_RETRANS_TIMEOUT) - { - - /* Set the timeout as NX_DHCP_MAX_RETRANS_TIMEOUT. */ - timeout = NX_DHCP_MAX_RETRANS_TIMEOUT; - } - else - { - - /* Double timeout value. */ - timeout = timeout * 2; - } - - /* Return the sequence timeout. */ - return(timeout); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_update_renewal_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCP timeout when trying to renew a */ -/* lease according to the RFC. When the current period has timed out, */ -/* this function halves the timeout, limiting the minimum timeout */ -/* value to NX_DHCP_MIN_RENEW_TIMEOUT seconds. */ -/* */ -/* INPUT */ -/* */ -/* timeout The current Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* timeout Renewal time remaining */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_client_interface_update_time_remaining */ -/* Apply input time elapsed to */ -/* the DHCP Client record */ -/* _nx_dhcp_timeout_process Timer expiration handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dhcp_update_renewal_timeout(ULONG timeout) -{ - - /* check if the timeout is non zero */ - if (timeout != 0) - { - - /* Timed out, halve the timeout, limited to NX_DHCP_MIN_RENEW_TIMEOUT or - the remaining timeout if it is less than NX_DHCP_MIN_RENEW_TIMEOUT */ - if (timeout > NX_DHCP_MIN_RENEW_TIMEOUT) - { - - /* Timeout can still decrease, either - force it to the minimum or halve it */ - if (timeout > (2 * NX_DHCP_MIN_RENEW_TIMEOUT )) - { - - /* Halve timeout. */ - timeout = timeout / 2; - } - else - { - - /* set timeout to minimum. */ - timeout = NX_DHCP_MIN_RENEW_TIMEOUT ; - } - } - } - - /* Return the sequence timeout. */ - return(timeout); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_search_buffer PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine searches through a buffer containing a BootP message */ -/* for a DHCP option parameter and returns a pointer to the byte */ -/* containing the size of the data section of that option if it */ -/* exists. If the option cannot be found then function returns NULL. */ -/* If the option has no data (PAD and END) then the pointer is not */ -/* usable. */ -/* */ -/* INPUT */ -/* */ -/* option_message Pointer to option buffer area */ -/* option Option to search for */ -/* length Length of search buffer */ -/* */ -/* OUTPUT */ -/* */ -/* pointer Pointer to found option */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_get_option_value Get the value of an option */ -/* _nx_dhcp_get_option_data Get the string of an option */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UCHAR *_nx_dhcp_search_buffer(UCHAR *option_message, UINT option, UINT length) -{ - -UCHAR *data; -UINT i; -UINT size; - - /* Setup buffer pointer. */ - data = option_message; - i = 0; - - /* Search as long as there are valid options. */ - while (i < length - 1) - { - - /* Simply skip any padding */ - if (*data == NX_DHCP_OPTION_PAD) - { - - data++; - i++; - } - - /* On a match, return a pointer to the size. */ - else if (*data == option) - { - - size = *(data + 1); - - /* Check if the option data is in the packet. */ - if ((i + size + 1) > length) - return(NX_NULL); - - /* Return a pointer to the option size byte. */ - return(data + 1); - } - - /* Otherwise skip the option by adding the size to the pointer. */ - else - { - - size = *(++data); - - /* skip the data plus the size byte */ - data += size + 1; - i += size + 1; - } - } - - /* Return NULL to indicate the option was not found. */ - return(NX_NULL); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_get_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine gets a data value from a buffer, assuming the data is */ -/* stored in standard Network format (big endian). Up to 4 bytes of */ -/* data are used, if there are more than 4 bytes, only the lower 4 */ -/* bytes are returned. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* */ -/* OUTPUT */ -/* */ -/* value Data value retrieved */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_get_response Get response from server */ -/* _nx_dhcp_extract_information Extract server information */ -/* _nx_dhcp_get_option_value Retrieve option value */ -/* _nx_dhcp_update_address_list Update address list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dhcp_get_data(UCHAR *data, UINT size) -{ - -ULONG value = 0; - - - /* Process the data retrieval request. */ - while (size-- > 0) - { - - /* Build return value. */ - value = (value << 8) | *data++; - } - - /* Return value. */ - return(value); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_store_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores a data value in a buffer in standard Network */ -/* format (big endian) where the destination may be unaligned. Up to */ -/* 4 bytes of data are stored, if the size is larger than 4 bytes, the */ -/* remaining bytes are set to zero. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* value Value to store */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_send_request_internal Send DHCP request */ -/* _nx_dhcp_add_option_value Add a DHCP option */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_store_data(UCHAR *data, UINT size, ULONG value) -{ - - /* Make sure that data is left justified. */ - switch (size) - { - - case 1: - - value <<= 24; - break; - - case 2: - - value <<= 16; - break; - - case 3: - - value <<= 8; - break; - - default: - break; - } - - /* Store the value. */ - while (size-- > 0) - { - - *data = (UCHAR) ((value >> 24) & 0xff); - data++; - value <<= 8; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_move_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores a sequence of data bytes to a buffer. */ -/* */ -/* INPUT */ -/* */ -/* dest Pointer to destination buffer */ -/* source Pointer to source buffer */ -/* size Number of bytes to move */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_add_option_string Add option string */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_move_string(UCHAR *dest, UCHAR *source, UINT size) -{ - - /* Loop to copy all bytes. */ - while (size-- > 0) - { - - /* Copy a byte. */ - *dest++ = *source++; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_server_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the DHCP server get */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Client task */ -/* server_address Pointer to DHCP server address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_server_address_get Actual get DHCP IP server */ -/* address service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address) -{ - -UINT status ; - - - if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_dhcp_server_address_get(dhcp_ptr, server_address); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the DHCP Client's DHCP server IP address on */ -/* the first DHCP enabled interface found. */ -/* */ -/* Note that the caller should only call this service when the Client */ -/* is bound to an IP address from a DHCP server. See the */ -/* nx_dhcp_state_change_notify for notification of state changes. */ -/* */ -/* If multiple interfaces are enabled for DHCP, use */ -/* nx_dhcp_interface_server_address_get() to get the server IP address */ -/* on a specified interface. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Client task */ -/* server_address Pointer to DHCP server address*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_server_address_get Interface specific server IP */ -/* address get service */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address) -{ - -UINT i; -UINT status; - - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check the interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Get the server address of first valid record. */ - status = _nx_dhcp_interface_server_address_get(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, server_address); - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); - } - } - - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_interface_server_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the DHCP server get */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Client task */ -/* iface_index Interface of the Server */ -/* server_address Pointer to DHCP server address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_server_address_get Actual get server IP address */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address) -{ - -UINT status; - - if ((dhcp_ptr == NX_NULL) || (server_address == NX_NULL)) - { - return NX_PTR_ERROR; - } - - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual reinitialize service. */ - status = _nx_dhcp_interface_server_address_get(dhcp_ptr, iface_index, server_address); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_server_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the DHCP Client's DHCP server IP address on */ -/* the specified interface. */ -/* */ -/* Note that the caller should only call this service when the Client */ -/* is in the bound state. See nx_dhcp_state_change_notify for */ -/* notification when the Client state changes. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Client task */ -/* iface_index Interface of the DHCP server */ -/* server_address Pointer to DHCP server address */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCP_NOT_BOUND Client state not Bound */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_dhcp_interface_record_find Find record for the interface */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); - } - - /* Check the record state. */ - if (interface_record -> nx_dhcp_state >= NX_DHCP_STATE_BOUND) - { - - /* Set the server IP address from the DHCP Client instance. */ - *server_address = interface_record -> nx_dhcp_server_ip; - status = NX_SUCCESS; - } - else - status = NX_DHCP_NOT_BOUND; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return status; -} - - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_ip_conflict PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the DHCP instance that a conflict was */ -/* detected by the NetX ARP receive packet handling routine. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr IP instance pointer */ -/* iface_index IP Interface Index */ -/* ip_address IP Address to bind to */ -/* physical_msw Physical address MSW */ -/* physical_lsw Physical address LSW */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_ip_conflict(NX_IP *ip_ptr, UINT iface_index, ULONG ip_address, ULONG physical_msw, ULONG physical_lsw) -{ - - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(physical_msw); - NX_PARAMETER_NOT_USED(physical_lsw); - - /* Set the interface index. */ - _nx_dhcp_created_ptr -> nx_dhcp_interface_conflict_flag |= (UINT)(1 << iface_index); - - /* Set the address conflict event flag. */ - tx_event_flags_set(&(_nx_dhcp_created_ptr -> nx_dhcp_events), NX_DHCP_CLIENT_CONFLICT_EVENT, TX_OR); -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_set_interface_index PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function does error checking for the set interface index call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* interface_index Interface the DHCP Client task*/ -/* is associated with */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_set_interface_index Actual set interface index */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (dhcp_ptr == NX_NULL) - { - - return(NX_PTR_ERROR); - } - /* Check for invalid non pointer input. */ - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - return(NX_INVALID_INTERFACE); - } - - /* Call the actual set DHCP Client interface service */ - status = _nx_dhcp_set_interface_index(dhcp_ptr, interface_index); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_set_interface_index PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables DHCP on the specified interface. This function*/ -/* should be called before the DHCP Client is started. The intended use*/ -/* of this function is for DHCP to run on only one interface. To enable*/ -/* multiple interfaces for DHCP, use the nx_dhcp_interface_enable */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface to enable DHCP on */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_enable Enable DHCP on interface */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT iface_index) -{ - -UINT i; -UINT status; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), NX_WAIT_FOREVER); - - /* Invalidate all the interfaces enabled for DHCP. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Invalidate this interface. */ - dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid = NX_FALSE; - - /* Change the state. */ - dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state = NX_DHCP_STATE_NOT_STARTED; - } - - /* Enable DHCP on this interface. */ - status = _nx_dhcp_interface_enable(dhcp_ptr, iface_index); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_interface_record_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Find the Client record that is assigned to the input interface */ -/* index, and return a pointer to that record. The interface index must*/ -/* match the interface index of the Client record, and the interface */ -/* must be enabled for DHCP. If no matching records are found, an */ -/* error status is returned, and the interface record pointer is NULL. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* interface_index Interface to find */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_DHCP_INTERFACE_NOT_ENABLED No matching record found */ -/* */ -/* CALLS */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_interface_record_find(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_INTERFACE_RECORD **interface_record) -{ - -UINT i; - - /* Find which DHCP Client interface record is assigned the input interface. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if this record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid == NX_FALSE) - continue; - - /* Check if the interface index matches. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index == iface_index) - { - - /* Yes, we found the record. */ - *interface_record = &dhcp_ptr -> nx_dhcp_interface_record[i]; - - /* Return. */ - return (NX_SUCCESS); - } - } - - /* No matching record found. */ - return (NX_DHCP_INTERFACE_NOT_ENABLED); -} - - -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get DHCP Client record */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_record_ptr Pointer to memory to save */ -/* Client record to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status from */ -/* internal DHCP calls */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_create_record */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr) -{ - -UINT status; - - if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_dhcp_client_get_record(dhcp_ptr, client_record_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a DHCP Client record for restoring the Client */ -/* state between power cycles or idle (sleep) mode. It copies the */ -/* first DHCP enabled Client record found to the supplied client record*/ -/* pointer. If DHCP is enabled on multiple interfaces, use */ -/* nx_dhcp_client_interface_record_get to get a record of a specific */ -/* interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_record_ptr Pointer to Client record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCP_NO_INTERFACES_ENABLED No DHCP interface enabled */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_get_record Get record for specified index*/ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr) -{ - -UINT i; -UINT status; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check if the interface record is valid. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) && - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state >= NX_DHCP_STATE_BOUND)) - { - - /* Find a record of the current state of the DHCP CLient. */ - status = _nx_dhcp_client_interface_get_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, client_record_ptr); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_interface_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get DHCP Client */ -/* interface record service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface index */ -/* client_record_ptr Pointer to memory to save */ -/* Client record to */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_create_record */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Check interface index. */ - if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) - { - return NX_INVALID_INTERFACE; - } - - status = _nx_dhcp_client_interface_get_record(dhcp_ptr, iface_index, client_record_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_interface_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a DHCP Client record for restoring the Client */ -/* state between power cycles or idle (sleep) mode. It then copies the*/ -/* Client record to the supplied client record pointer. */ -/* */ -/* The DHCP Client state should be restored from a Client record saved */ -/* to memory (client_record_ptr). */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface index */ -/* client_record_ptr Pointer to memory to save */ -/* Client record to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCP_NOT_BOUND Client not Bound to address */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_interface_record_find Find interface record matching*/ -/* the input interface */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Check the state. */ - if (interface_record -> nx_dhcp_state < NX_DHCP_STATE_BOUND) - { - - /* The DHCP Client is not bound to an IP address. Cannot create a record for restoring Client - state if the Client not bound to an IP address. */ - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return NX_DHCP_NOT_BOUND; - } - - /* Clear memory before filling with data. */ - memset(client_record_ptr, 0, sizeof(NX_DHCP_CLIENT_RECORD)); - - /* Set the record. */ - client_record_ptr -> nx_dhcp_state = interface_record -> nx_dhcp_state; - client_record_ptr -> nx_dhcp_ip_address = interface_record -> nx_dhcp_ip_address; /* Server assigned IP Address */ - client_record_ptr -> nx_dhcp_network_mask = interface_record -> nx_dhcp_network_mask; /* Server assigned network mask */ - client_record_ptr -> nx_dhcp_gateway_address = interface_record -> nx_dhcp_gateway_address; - client_record_ptr -> nx_dhcp_server_ip = interface_record -> nx_dhcp_server_ip; - client_record_ptr -> nx_dhcp_timeout = interface_record -> nx_dhcp_timeout; - client_record_ptr -> nx_dhcp_lease_time = interface_record -> nx_dhcp_lease_time ; - client_record_ptr -> nx_dhcp_renewal_time = interface_record -> nx_dhcp_renewal_time; - client_record_ptr -> nx_dhcp_rebind_time = interface_record -> nx_dhcp_rebind_time; - client_record_ptr -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_renewal_remain_time; - client_record_ptr -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_rebind_remain_time; - client_record_ptr -> nx_dhcp_interface_index = interface_record -> nx_dhcp_interface_index; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the client restore service.*/ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed Time elapsed in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERRPR Invalid pointer input */ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_restore_record Actual restore record service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT status; - - - if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Note: zero time elapsed is an acceptable value. */ - - status = _nx_dhcp_client_restore_record(dhcp_ptr, client_record_ptr, time_elapsed); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCP Client state of the first DHCP */ -/* enabled interface found with the supplied DHCP Client record */ -/* pointed to by the client_record_ptr pointer. It then updates the */ -/* time out parameters of the DHCP Client with the time_elapsed */ -/* input (in timer ticks). */ -/* */ -/* If DHCP is enabled on multiple interfaces, use */ -/* nx_dhcp_client_interface_restore_record to restore a record to a */ -/* specific interface. */ -/* */ -/* This function is intended for restoring Client state between reboots*/ -/* and assumes the DHCP Client state was previously obtained and stored*/ -/* in non volatile memory before power down. */ -/* */ -/* Note: his should not be called in addition to _nx_dhcp_client_update*/ -/* _time_remaining. _nx_dhcp_client_restore_ calls that function, */ -/* so calling t_nx_dhcp_client_update_time_remaining separately would */ -/* effectively apply the time elapsed a second time. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCP_NO_INTERFACES_ENABLED No interfaces enabled for DHCP*/ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_restore_record */ -/* Interface specific restore */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT i; -UINT status; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Create a record of the current state of the DHCP Client. */ - status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, - client_record_ptr, time_elapsed); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_interface_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the client restore service.*/ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* iface_index Interface index */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERRPR Invalid pointer input */ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_restore_record */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dhcp_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Check interface index. */ - if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) - { - return NX_INVALID_INTERFACE; - } - - status = _nx_dhcp_client_interface_restore_record(dhcp_ptr, iface_index, client_record_ptr, time_elapsed); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_interface_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCP Client state with the input DHCP */ -/* Client record for the specified interface. It copies data from the */ -/* Client record to the interface racord, and updates the time out */ -/* parameters of the DHCP Client with the time_elapsed inpur (in timer */ -/* ticks). */ -/* */ -/* This function is intended for restoring Client state between reboots*/ -/* and assumes the DHCP Client record was previously obtained and */ -/* stored in non volatile memory before power down. */ -/* */ -/* Note: this should not be called in addition to */ -/* nx_dhcp_client_update_time_remaining. */ -/* nx_dhcp_client_interface_restore_record calls that function, so */ -/* calling nx_dhcp_client_update_time_remaining would apply the time */ -/* elapsed a second time. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_dhcp_interface_record_find Find client record for */ -/* specified interface */ -/* nx_ip_interface_address_set Set IP interface address */ -/* _nx_dhcp_client_update_time_remaining Update time remaining for time*/ -/* elapsed while powered down */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT status; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - interface_record -> nx_dhcp_state = client_record_ptr -> nx_dhcp_state; - interface_record -> nx_dhcp_gateway_address = client_record_ptr -> nx_dhcp_gateway_address; - interface_record -> nx_dhcp_server_ip = client_record_ptr -> nx_dhcp_server_ip; - interface_record -> nx_dhcp_timeout = client_record_ptr -> nx_dhcp_timeout; - interface_record -> nx_dhcp_lease_time = client_record_ptr -> nx_dhcp_lease_time ; - interface_record -> nx_dhcp_renewal_time = client_record_ptr -> nx_dhcp_renewal_time; - interface_record -> nx_dhcp_rebind_time = client_record_ptr -> nx_dhcp_rebind_time; - interface_record -> nx_dhcp_renewal_remain_time = client_record_ptr -> nx_dhcp_renewal_remain_time; - interface_record -> nx_dhcp_rebind_remain_time = client_record_ptr -> nx_dhcp_rebind_remain_time; - - /* Restore directly from the client record. */ - interface_record -> nx_dhcp_ip_address = client_record_ptr -> nx_dhcp_ip_address; - interface_record -> nx_dhcp_network_mask = client_record_ptr -> nx_dhcp_network_mask; - interface_record -> nx_dhcp_interface_index = iface_index; - - /* Update the IP instance with saved network parameters.*/ - status = nx_ip_interface_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, iface_index, interface_record -> nx_dhcp_ip_address, interface_record -> nx_dhcp_network_mask); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return status; - } - - /* Now apply the time elapsed to update the DHCP Client time remaining on its lease and current DHCP state. */ - status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, interface_record-> nx_dhcp_interface_index, time_elapsed); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_update_time_remaining PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the update time remaining */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_update_time_remaining Update DHCP timeout for time */ -/* elapsed while powered down */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed) -{ - -UINT status; - - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - status = _nx_dhcp_client_update_time_remaining(dhcp_ptr, time_elapsed); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_update_time_remaining PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function applies the input time_elapsed to the DHCP Client */ -/* time remaining and determines if a state change occurred meanwhile. */ -/* Note that time_elapsed is in timer ticks. */ -/* */ -/* There is no need to call this function if also calling */ -/* _nx_dhcp_client_restore_record which applies the elapsed time. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCP_NO_INTERFACES_ENABLED No interface enabled for DHCP */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_update_time_remaining */ -/* Apply the elapsed time to the */ -/* specified DHCP timeout */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_client_restore_record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed) -{ - -UINT i; -UINT status; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the DHCP interface record. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Create a record of the current state of the DHCP CLient. */ - status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index, time_elapsed); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(NX_DHCP_NO_INTERFACES_ENABLED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_client_interface_update_time_remaining PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the update time remaining */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_interface_update_time_remaining */ -/* Actual update time service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Check interface index. */ - if (iface_index >= NX_DHCP_CLIENT_MAX_RECORDS) - { - return NX_INVALID_INTERFACE; - } - - status = _nx_dhcp_client_interface_update_time_remaining(dhcp_ptr, iface_index, time_elapsed); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_client_interface_update_time_remaining PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function applies the input time_elapsed data to the DHCP Client*/ -/* state and determines what state it should be in (e.g. BOUND, */ -/* IP address. Note, time_elapsed is in timer ticks. If called from the*/ -/* application it is assumed the application device is sleeping, not */ -/* powering up. If the device is waking up from sleeping, it does not */ -/* need to restore the DHCP client state but only to update the time */ -/* elapsed. */ -/* */ -/* Therefore this should not be called in addition to */ -/* _nx_dhcp_client_restore_record. The restore record service handles */ -/* updating time remaining, such that calling this service would */ -/* effectively apply the time elapsed a second time. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_dhcp_update_renewal_timeout Update time remaining on lease*/ -/* _nx_dhcp_interface_record_find Find record for the interface */ -/* _nx_dhcp_interface_reinitialize Clear DHCP and IP network */ -/* parameters */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed) -{ - -UINT status; -UINT accrued_time_adjusted = 0; -UINT time_accrued; -UINT original_state; -NX_DHCP_INTERFACE_RECORD *interface_record = NX_NULL; - - - /* Obtain DHCP Client protection mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Find the interface record. */ - status = _nx_dhcp_interface_record_find(dhcp_ptr, iface_index, &interface_record); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Get the original state. */ - original_state = interface_record -> nx_dhcp_state; - - /* Compute the time since the lease was assigned before we suspended the Client. */ - if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_BOUND) - { - if (interface_record -> nx_dhcp_renewal_time >= interface_record -> nx_dhcp_timeout) - { - /* Since the Client is in a BOUND state, we know the timeout is less than T2 - or nx_dhcp_renew_time. */ - time_accrued = interface_record -> nx_dhcp_renewal_time - interface_record -> nx_dhcp_timeout; - } - else - { - /* Invalid DHCP timeout. If it is in the BOUND state, set to the renewal time. */ - time_accrued = interface_record -> nx_dhcp_renewal_time; - } - } - else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) - { - - /* Since the Client is in the RENEWING state, the total time on the lease is the - lease rebind time - the time out in the RENEW state: */ - time_accrued = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_remain_time; - - /* Note if dhcp_ptr -> nx_dhcp_rebind_time < dhcp_ptr -> nx_dhcp_renewal_remain_time, - the CLient either received invalid DHCP parameters or there is an internal error. - The renewal time should never exceed the rebind time. */ - } - else if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING) - { - - /* Since the Client is in the REBINDING state, the total time on the lease is the - lease time - the time remaining in the REBIND state: */ - time_accrued = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_remain_time; - - /* Note if dhcp_ptr -> nx_dhcp_lease_time < dhcp_ptr -> nx_dhcp_rebind_remain_time, - the CLient either received invalid DHCP parameters or there is an internal error. - The rebind time should never exceed the lease time. */ - } - else - { - /* Expired! */ - accrued_time_adjusted = 0xFFFFFFFF; - } - - /* Adjust the time accrued to include the interval while the Client was suspended. */ - if (accrued_time_adjusted != 0xFFFFFFFF) - { - accrued_time_adjusted = time_accrued + time_elapsed; - } - - /* Determine if the DHCP Client needs to renew. */ - if (accrued_time_adjusted < interface_record -> nx_dhcp_renewal_time) - { - - /* Not yet. Update the nx_dhcp_timeout for the time elapsed and we're done. */ - interface_record -> nx_dhcp_timeout -= time_elapsed; - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* We are done. Ok to resume the Client. */ - return NX_SUCCESS; - } - - /* Determine if the Client should renew. */ - else if (accrued_time_adjusted < interface_record -> nx_dhcp_rebind_time) - { - - /* Yes; it has not reached the expiration on the renew period. */ - - /* Check if it is already in the RENEW state. */ - if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_RENEWING) - { - - /* Yes it is, so do nothing. Let the Client continue renewing. */ - - /* Update the time remaining for the Client to renew its lease. */ - interface_record -> nx_dhcp_renewal_remain_time -= time_elapsed; - - /* Reset the timeout based on the updated time remaining to renew. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - } - else - { - - /* No it wasn't so update the Client for the RENEW state. */ - - /* Compute how many seconds into the renew period the Client is (total time on lease over and above - the time to start renewing. */ - if (accrued_time_adjusted == interface_record -> nx_dhcp_renewal_time) - { - - interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - interface_record -> nx_dhcp_renewal_time; - } - else - { - - interface_record -> nx_dhcp_renewal_remain_time = interface_record -> nx_dhcp_rebind_time - accrued_time_adjusted; - } - - /* Set the DHCP timeout for being in the RENEW phase. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_renewal_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - - /* And change to the Renewing state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_RENEWING; - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* We are done. Ok to resume the Client. */ - return NX_SUCCESS; - } - - /* Determine if it is time for the Client to rebind (e.g. check the lease has not completely expired). */ - else if (accrued_time_adjusted < interface_record -> nx_dhcp_lease_time) - { - - /* Check if it is already in the REBIND state. */ - if (interface_record -> nx_dhcp_state == NX_DHCP_STATE_REBINDING) - { - /* Yes it is, so do nothing. Let the Client complete its rebind task*/ - - /* Update the time remaining for the Client to rebind an IP address. */ - interface_record -> nx_dhcp_rebind_remain_time -= time_elapsed; - - /* Reset the timeout based on the updated time remaining to rebind. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - } - else - { - - /* No it wasn't so update the Client for the REBIND state. */ - - /* Compute how many seconds into the rebind period the Client is (total time on lease over and above - the time to start rebinding. */ - if (accrued_time_adjusted == interface_record -> nx_dhcp_rebind_time) - { - - interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - interface_record -> nx_dhcp_rebind_time; - } - else - { - - interface_record -> nx_dhcp_rebind_remain_time = interface_record -> nx_dhcp_lease_time - accrued_time_adjusted; - } - - /* Set the DHCP timeout for being in the RENEW phase. */ - interface_record -> nx_dhcp_timeout = _nx_dhcp_update_renewal_timeout(interface_record -> nx_dhcp_rebind_remain_time); - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - - /* Record the retransmission interval. */ - interface_record -> nx_dhcp_rtr_interval = interface_record -> nx_dhcp_timeout; - - /* And change to the Rebinding state. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_REBINDING; - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* We are done. Ok to resume the Client. */ - return NX_SUCCESS; - } - else - { - - /* Clear the existing DHCP Client network parameters for restarting in the INIT state. */ - _nx_dhcp_interface_reinitialize(dhcp_ptr, iface_index); - - /* Start the DHCP protocol again by setting the state back to INIT. */ - interface_record -> nx_dhcp_state = NX_DHCP_STATE_INIT; - - /* The client begins in INIT state and forms a DHCPDISCOVER message. - The client should wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. - RFC2131, Section4.4.1, Page36. */ - - /* Use the minimum value, Wait one second to begain in INIT state and forms a DHCP Discovery message. */ - interface_record -> nx_dhcp_timeout = NX_IP_PERIODIC_RATE; - interface_record -> nx_dhcp_rtr_interval = 0; - } - - /* Check if the state is changed. */ - if (original_state != interface_record -> nx_dhcp_state) - { - - /* Determine if the application has specified a routine for DHCP state change notification. */ - if (dhcp_ptr -> nx_dhcp_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_state); - } - - /* Determine if the application has specified a routine for DHCP interface state change notification. */ - if (dhcp_ptr -> nx_dhcp_interface_state_change_callback) - { - - /* Yes, call the application's state change notify function with the new state. */ - (dhcp_ptr -> nx_dhcp_interface_state_change_callback)(dhcp_ptr, interface_record -> nx_dhcp_interface_index, interface_record -> nx_dhcp_state); - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr->nx_dhcp_mutex)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the Client resume service.*/ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_resume Actual Client resume service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_resume(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - status = _nx_dhcp_resume(dhcp_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resumes the DHCP Client thread and timer. It then */ -/* checks the state on all DHCP enabled interfaces if renewing or */ -/* rebinding. If so it sends a REQUEST to the DHCP server. */ -/* */ -/* The DHCP Client application can then call the */ -/* nx_dhcp_client_udpate_remaining_time() service to update the time */ -/* remaining on the client lease, before calling nx_dhcp_resume. */ -/* */ -/* This function does not change the Client state, lease timeout or */ -/* time remaining on the current lease. It requires the */ -/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* NX_DHCP_ALREADY_STARTED DHCP Client thread started */ -/* status NetX or ThreadX completion */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_send_request_internal Send message to DHCP server */ -/* nx_udp_socket_bind Bind UDP socket to port */ -/* tx_thread_resume Resume the DHCP Client thread */ -/* tx_mutex_get Obtain mutex protection */ -/* tx_mutex_put Release mutex protectiob */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_resume(NX_DHCP *dhcp_ptr) -{ - -UINT i; -UINT status; -NX_IP *ip_ptr; -ULONG client_physical_msw; -ULONG client_physical_lsw; -UINT iface_index; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Resume the DHCP processing thread. */ - status = tx_thread_resume(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Determine if the resume was successful. */ - if ((status != TX_SUCCESS) && (status != TX_SUSPEND_LIFTED)) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Active the timer. */ - status = tx_timer_activate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Bind the UDP socket to the DHCP Client port. */ - status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); - - /* Check status. */ - if (status) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - return(status); - } - - /* Set IP pointer. */ - ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; - - /* Loop to process interface records. */ - for (i = 0; i < NX_DHCP_CLIENT_MAX_RECORDS; i++) - { - - /* Check which interface record is valid. */ - if (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_record_valid) - { - - /* Get the interface index. */ - iface_index = dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_interface_index; - - /* Get the client MAC address from the device interface. */ - client_physical_msw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_msw; - client_physical_lsw = ip_ptr -> nx_ip_interface[iface_index].nx_interface_physical_address_lsw; - - /* Generate a 'unique' client transaction ID from the MAC address for each message to the server. */ - dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_xid = client_physical_msw ^ client_physical_lsw ^ NX_RAND(); - - /* If the DHCP Client is renewing or rebinding on being resumed, send a DHCP request. */ - if ((dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_RENEWING) || - (dhcp_ptr -> nx_dhcp_interface_record[i].nx_dhcp_state == NX_DHCP_STATE_REBINDING)) - { - - /* Transmit the request message. */ - _nx_dhcp_send_request_internal(dhcp_ptr, &dhcp_ptr -> nx_dhcp_interface_record[i], NX_DHCP_TYPE_DHCPREQUEST); - } - } - } - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the Client suspend */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_suspend Actual Client suspend service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_suspend(NX_DHCP *dhcp_ptr) -{ - -UINT status; - - - if (dhcp_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - status = _nx_dhcp_suspend(dhcp_ptr); - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends the DHCP Client task thread and unbinds the */ -/* socket port. The intented use of this service is to combine with the*/ -/* resume service such that the calling application can 'pause' the */ -/* DHCP Client for a certain amount of time, and resume it in the same */ -/* state. The DHCP Client application can then call the */ -/* nx_dhcp_client_udpate_remaining_time service to update the time */ -/* remaining on the client lease, then nx_dhcp_resume to actually */ -/* resume the DHCP Client task. */ -/* */ -/* This function does not change the Client state, lease timeout or */ -/* time remaining on the current lease. It requires the */ -/* NX_DHCP_CLIENT_RESTORE_STATE option to be enabled. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind port from UDP socket */ -/* tx_timer_deactivate Stop the timer */ -/* tx_thread_suspend Suspend the DHCP Client thread*/ -/* tx_mutex_get Obtain mutex protection */ -/* tx_mutex_put Release mutex protection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_suspend(NX_DHCP *dhcp_ptr) -{ - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Suspend the DHCP thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_thread)); - - /* Deactive the timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_timer)); - - /* Unbind the port. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ -#endif /* NX_DISABLE_IPV4 */ diff --git a/protocol_handlers/dhcp/nxd_dhcp_client.h b/protocol_handlers/dhcp/nxd_dhcp_client.h deleted file mode 100644 index 0ebf5887..00000000 --- a/protocol_handlers/dhcp/nxd_dhcp_client.h +++ /dev/null @@ -1,750 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol (DHCP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_dhcp_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Dynamic Host Configuration Protocol */ -/* (DHCP) component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_DHCP_CLIENT_H -#define NXD_DHCP_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_api.h" -#include "nx_udp.h" -#include "nx_ip.h" - - -/* Enable BOOTP protocol instead of DHCP, define this option. -#define NX_DHCP_ENABLE_BOOTP -*/ - -/* Enable support for client state preserved between reboots -#define NX_DHCP_CLIENT_RESTORE_STATE -*/ - -/* Enable the DHCP Client to accept a pointer to the DHCP packet pool. -#define NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL -*/ - -/* Enables an ARP probe for verifying the assigned DHCP address is - not owned by another host. This is recommended, but not required by RFC 2131 (4.4.1). -#define NX_DHCP_CLIENT_SEND_ARP_PROBE -*/ - -/* Enables DHCP Client send Maximum DHCP Message Size Option. RFC2132, Section9.10, Page29. -#define NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION -*/ - -/* Defined, the host name is checked, the host name must follow the rules for ARPANET host names. - RFC 1035, Section 2.3.1, Page 8. The default is disabled. -#define NX_DHCP_CLIENT_ENABLE_HOST_NAME_CHECK -*/ - -/* Define the DHCP ID that is used to mark the DHCP structure as created. */ -#define NX_DHCP_ID 0x44484350UL - - -/* Define the DHCP stack size. */ -#ifndef NX_DHCP_THREAD_STACK_SIZE -#define NX_DHCP_THREAD_STACK_SIZE (4096) -#endif - - -/* Define the number of interfaces the Client is running on. This can be any - size but practically speaking should be less than or equal to the number - of physical interfaces attached to the IP instance (NX_MAX_PHYSICAL_INTERFACES). */ -/* Note: User can redefine the symbol to reduce the size of records if the dhcp interfaces - are less than true physical interfaces. - For example: There are three physical interfaces, but only two interfaces enable DHCP, - the recommended value for NX_DHCP_CLIENT_MAX_RECORDS should be 2. */ -#ifndef NX_DHCP_CLIENT_MAX_RECORDS -#define NX_DHCP_CLIENT_MAX_RECORDS (NX_MAX_PHYSICAL_INTERFACES) -#endif - - -/* Define the DHCP stack priority. This priority must be high enough to insure the - DHCP client gets scheduled promptly, and thus assigned an IP address. Assigning - it a higher priority increases the risk of 'starving' out the IP thread task which - needs to initialize the network driver (which is required to be able to transmit packets). */ -#ifndef NX_DHCP_THREAD_PRIORITY -#define NX_DHCP_THREAD_PRIORITY 3 -#endif - - -/* Define DHCP timer expiration interval. */ -#ifndef NX_DHCP_TIME_INTERVAL -#define NX_DHCP_TIME_INTERVAL (1 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define the size of DHCP options buffer. */ -/* A DHCP client must be prepared to receive DHCP messages with an 'options' field of - at least length 312 octets. RFC 2131; Section 2. Protocol Summary. */ -#ifndef NX_DHCP_OPTIONS_BUFFER_SIZE -#define NX_DHCP_OPTIONS_BUFFER_SIZE 312 -#endif - - -/* Define the size of the BOOT buffer. This should be large enough for all the - required DHCP header fields plus the minimum requirement of 312 bytes of option data - (total: 548 bytes) as per RFC 2131; Section 2. Protocol Summary. */ -#define NX_BOOT_CLIENT_BUFFER_SIZE 548 - - -/* Define the minimum IP datafram size as per RFC 2131; Section 2. Protocol Summary. - A DHCP Client must be prepared to receive a message of up to 576 bytes: - IP header(20 bytes), UDP header (8 bytes), required DHCP header fields (236 bytes) - and the minimum requirement of option data(312 bytes). */ -#define NX_DHCP_MINIMUM_IP_DATAGRAM 576 - - -/* Define the packet payload size, keeping in mind the DHCP Client must be prepared to - receive a message of up to 576 octets and allow room for physical network header, - as per RFC 2131; Section 2. Protocol Summary. */ -#ifndef NX_DHCP_PACKET_PAYLOAD -#define NX_DHCP_PACKET_PAYLOAD (NX_DHCP_MINIMUM_IP_DATAGRAM + NX_PHYSICAL_HEADER) -#endif /* NX_DHCP_PACKET_PAYLOAD */ - - -/* Define the packet pool size. */ -#ifndef NX_DHCP_PACKET_POOL_SIZE -#define NX_DHCP_PACKET_POOL_SIZE (5 * NX_DHCP_PACKET_PAYLOAD) -#endif - - -/* Define time out options for retransmission in seconds. */ -/* Define the minimum amount of time to retransmit a DHCP IP address request. The - recommended wait time is 4 seconds in RFC 2131. */ -#ifndef NX_DHCP_MIN_RETRANS_TIMEOUT -#define NX_DHCP_MIN_RETRANS_TIMEOUT (4 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define the maximum amount of time to retransmit a DHCP IP address request. The - recommended wait time is 64 seconds in RFC 2131. */ -#ifndef NX_DHCP_MAX_RETRANS_TIMEOUT -#define NX_DHCP_MAX_RETRANS_TIMEOUT (64 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define the minimum amount of time to retransmit a DHCP renew/rebind request. The - recommended wait time is 60 seconds in RFC 2131. */ -#ifndef NX_DHCP_MIN_RENEW_TIMEOUT -#define NX_DHCP_MIN_RENEW_TIMEOUT (60 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define UDP socket create options. */ -#ifndef NX_DHCP_TYPE_OF_SERVICE -#define NX_DHCP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_DHCP_FRAGMENT_OPTION -#define NX_DHCP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_DHCP_TIME_TO_LIVE -#define NX_DHCP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_DHCP_QUEUE_DEPTH -#define NX_DHCP_QUEUE_DEPTH 4 -#endif - - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - -/* Define the timing and retry constants for ARP probe. RFC5227, Section1.1, Page 5. */ -#ifndef NX_DHCP_ARP_PROBE_WAIT -#define NX_DHCP_ARP_PROBE_WAIT (1 * NX_IP_PERIODIC_RATE) -#endif - -/* Define the number of ARP probes sent. */ -#ifndef NX_DHCP_ARP_PROBE_NUM -#define NX_DHCP_ARP_PROBE_NUM 3 -#endif - -/* Define the minimum and maximum variation in the interval between ARP probe transmissions. */ -#ifndef NX_DHCP_ARP_PROBE_MIN -#define NX_DHCP_ARP_PROBE_MIN (1 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_DHCP_ARP_PROBE_MAX -#define NX_DHCP_ARP_PROBE_MAX (2 * NX_IP_PERIODIC_RATE) -#endif -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - -/* Define the wait time before restarting the configuration process when DHCP detects that the address is - already in use. - - The client SHOULD wait a minimum of ten seconds before restarting the configuration process - to avoid excessive network traffic in case of looping. RFC2131, Section 3.1, Page 17. */ -#ifndef NX_DHCP_RESTART_WAIT -#define NX_DHCP_RESTART_WAIT (10 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define the BootP Message Area Offsets. The DHCP message format is identical to that of BootP, except - for the Vendor options that start at the offset specified by NX_BOOTP_OFFSET_OPTIONS. */ -#define NX_BOOTP_OFFSET_OP 0 /* 1 BootP Operation 1=req, 2=reply */ -#define NX_BOOTP_OFFSET_HTYPE 1 /* 1 Hardware type 1 = Ethernet */ -#define NX_BOOTP_OFFSET_HLEN 2 /* 1 Hardware address length, 6 for Ethernet */ -#define NX_BOOTP_OFFSET_HOPS 3 /* 1 Number of hops, usually 0 */ -#define NX_BOOTP_OFFSET_XID 4 /* 4 Transaction ID, pseudo random number */ -#define NX_BOOTP_OFFSET_SECS 8 /* 2 Seconds since boot */ -#define NX_BOOTP_OFFSET_FLAGS 10 /* 2 Flags, 0x80 = Broadcast response, 0 = unicast response */ -#define NX_BOOTP_OFFSET_CLIENT_IP 12 /* 4 Initial client IP, used as dest for unicast response */ -#define NX_BOOTP_OFFSET_YOUR_IP 16 /* 4 Assigned IP, initialized to 0.0.0.0 */ -#define NX_BOOTP_OFFSET_SERVER_IP 20 /* 4 Server IP, usually initialized to 0.0.0.0 */ -#define NX_BOOTP_OFFSET_GATEWAY_IP 24 /* 4 gateway IP, usually 0.0.0.0, only for BootP and TFTP */ -#define NX_BOOTP_OFFSET_CLIENT_HW 28 /* 16 Client hardware address */ -#define NX_BOOTP_OFFSET_SERVER_NM 44 /* 64 Server name, nulls if unused */ -#define NX_BOOTP_OFFSET_BOOT_FILE 108 /* 128 Boot file name, null if unused */ -#define NX_BOOTP_OFFSET_VENDOR 236 /* 64 Vendor options, set first 4 bytes to a magic number */ -#define NX_BOOTP_OFFSET_OPTIONS 240 /* First variable vendor option */ -#define NX_BOOTP_OFFSET_END 300 /* End of BOOTP buffer */ - - -/* Define the DHCP Specific Vendor Extensions. */ -#define NX_DHCP_OPTION_PAD 0 -#define NX_DHCP_OPTION_PAD_SIZE 0 -#define NX_DHCP_OPTION_SUBNET_MASK 1 -#define NX_DHCP_OPTION_SUBNET_MASK_SIZE 4 -#define NX_DHCP_OPTION_TIME_OFFSET 2 -#define NX_DHCP_OPTION_TIME_OFFSET_SIZE 4 -#define NX_DHCP_OPTION_GATEWAYS 3 -#define NX_DHCP_OPTION_TIMESVR 4 -#define NX_DHCP_OPTION_DNS_SVR 6 -#define NX_DHCP_OPTION_HOST_NAME 12 -#define NX_DHCP_OPTION_DNS_NAME 15 -#define NX_DHCP_OPTION_NTP_SVR 42 -#define NX_DHCP_OPTION_VENDOR_OPTIONS 43 -#define NX_DHCP_OPTION_DHCP_IP_REQ 50 -#define NX_DHCP_OPTION_DHCP_IP_REQ_SIZE 4 -#define NX_DHCP_OPTION_DHCP_LEASE 51 -#define NX_DHCP_OPTION_DHCP_LEASE_SIZE 4 -#define NX_DHCP_OPTION_DHCP_TYPE 53 -#define NX_DHCP_OPTION_DHCP_TYPE_SIZE 1 -#define NX_DHCP_OPTION_DHCP_SERVER 54 -#define NX_DHCP_OPTION_DHCP_SERVER_SIZE 4 -#define NX_DHCP_OPTION_DHCP_PARAMETERS 55 -#define NX_DHCP_OPTION_DHCP_MESSAGE 56 -#define NX_DHCP_OPTION_MAX_DHCP_MESSAGE 57 -#define NX_DHCP_OPTION_RENEWAL 58 -#define NX_DHCP_OPTION_RENEWAL_SIZE 4 -#define NX_DHCP_OPTION_REBIND 59 -#define NX_DHCP_OPTION_REBIND_SIZE 4 -#define NX_DHCP_OPTION_CLIENT_ID 61 -#define NX_DHCP_OPTION_CLIENT_ID_SIZE 7 /* 1 byte for address type (01 = Ethernet), 6 bytes for address */ -#define NX_DHCP_OPTION_FDQN 81 -#define NX_DHCP_OPTION_FDQN_FLAG_N 8 -#define NX_DHCP_OPTION_FDQN_FLAG_E 4 -#define NX_DHCP_OPTION_FDQN_FLAG_O 2 -#define NX_DHCP_OPTION_FDQN_FLAG_S 1 -#define NX_DHCP_OPTION_END 255 -#define NX_DHCP_OPTION_END_SIZE 0 - - -/* Define various BootP/DHCP constants. */ -#define NX_DHCP_SERVER_UDP_PORT 67 -#define NX_DHCP_SERVER_TCP_PORT 67 -#define NX_DHCP_CLIENT_UDP_PORT 68 -#define NX_DHCP_CLIENT_TCP_PORT 68 - -#define NX_BOOTP_OP_REQUEST 1 -#define NX_BOOTP_OP_REPLY 2 -#define NX_BOOTP_TYPE_ETHERNET 1 -#define NX_BOOTP_HLEN_ETHERNET 6 -#define NX_BOOTP_FLAGS_BROADCAST 0x80 -#define NX_BOOTP_FLAGS_UNICAST 0x00 -#define NX_BOOTP_MAGIC_COOKIE IP_ADDRESS(99, 130, 83, 99) -#define NX_BOOTP_NO_ADDRESS IP_ADDRESS(0, 0, 0, 0) -#define NX_BOOTP_BC_ADDRESS IP_ADDRESS(255, 255, 255, 255) -#define NX_AUTO_IP_ADDRESS IP_ADDRESS(169, 254, 0, 0) -#define NX_AUTO_IP_ADDRESS_MASK 0xFFFF0000UL - -#define NX_DHCP_INFINITE_LEASE 0xffffffffUL - - -/* Define the DHCP Message Types. */ -#define NX_DHCP_TYPE_DHCPDISCOVER 1 -#define NX_DHCP_TYPE_DHCPOFFER 2 -#define NX_DHCP_TYPE_DHCPREQUEST 3 -#define NX_DHCP_TYPE_DHCPDECLINE 4 -#define NX_DHCP_TYPE_DHCPACK 5 -#define NX_DHCP_TYPE_DHCPNACK 6 -#define NX_DHCP_TYPE_DHCPRELEASE 7 -#define NX_DHCP_TYPE_DHCPINFORM 8 -#define NX_DHCP_TYPE_DHCPFORCERENEW 9 -#ifdef NX_DHCP_ENABLE_BOOTP -#define NX_DHCP_TYPE_BOOT_REQUEST 10 -#endif - - -/* Define the states of the DHCP state machine. */ -#define NX_DHCP_STATE_NOT_STARTED 0 /* Not started */ -#define NX_DHCP_STATE_BOOT 1 /* Started with a previous address */ -#define NX_DHCP_STATE_INIT 2 /* Started with no previous address */ -#define NX_DHCP_STATE_SELECTING 3 /* Waiting to identify a DHCP server */ -#define NX_DHCP_STATE_REQUESTING 4 /* Address requested, waiting for the Ack */ -#define NX_DHCP_STATE_BOUND 5 /* Address established, no time outs */ -#define NX_DHCP_STATE_RENEWING 6 /* Address established, renewal time out */ -#define NX_DHCP_STATE_REBINDING 7 /* Address established, renewal and rebind time out */ -#define NX_DHCP_STATE_FORCERENEW 8 /* Address established, force renewal */ -#define NX_DHCP_STATE_ADDRESS_PROBING 9 /* Address probing, address conflict detection */ - -/* Define error codes from DHCP API. */ -#define NX_DHCP_ERROR 0x90 /* General DHCP error code */ -#define NX_DHCP_NO_RESPONSE 0x91 /* No response from server for option request */ -#define NX_DHCP_BAD_IP_ADDRESS 0x92 /* Bad IP address or invalid interface input */ -#define NX_DHCP_ALREADY_STARTED 0x93 /* DHCP was already started */ -#define NX_DHCP_NOT_BOUND 0x94 /* DHCP is not in a bound state */ -#define NX_DHCP_DEST_TO_SMALL 0x95 /* DHCP response is too big for destination */ -#define NX_DHCP_NOT_STARTED 0x96 /* DHCP was not started when stop was issued */ -#define NX_DHCP_PARSE_ERROR 0x97 /* Error extracting DHCP option data */ -#define NX_DHCP_BAD_XID 0x98 /* DHCP packet received with mismatched XID */ -#define NX_DHCP_BAD_MAC_ADDRESS 0x99 /* DHCP packet received with mismatched MAC address */ -#define NX_DHCP_INVALID_MESSAGE 0x9B /* Invalid message received or requested to send */ -#define NX_DHCP_INVALID_PAYLOAD 0x9C /* Client receives DHCP message exceeding packet payload */ -#define NX_DHCP_INVALID_IP_REQUEST 0x9D /* Null IP address input for requesting IP address */ -#define NX_DHCP_UNKNOWN_OPTION 0x9F /* This option is unknow. */ -#define NX_DHCP_INTERFACE_ALREADY_ENABLED 0xA3 /* Interface is already enabled */ -#define NX_DHCP_INTERFACE_NOT_ENABLED 0xA4 /* If interface not enabled for DHCP interaction */ -#define NX_DHCP_NO_INTERFACES_ENABLED 0xA5 /* No interfaces enabled for DHCP interaction */ -#define NX_DHCP_NO_INTERFACES_STARTED 0xA6 /* If DHCP CLient fails to start any interfacers */ -#define NX_DHCP_NO_RECORDS_AVAILABLE 0xA7 /* No Client record available to start DHCP on an interface */ -#define NX_DHCP_INVALID_NAME 0xA8 /* Client host name has invalid characters */ - - -/* Define DHCP Client thread events. */ -#define NX_DHCP_CLIENT_RECEIVE_EVENT 0x00000001 /* DHCP Server data received */ -#define NX_DHCP_CLIENT_TIMER_EVENT 0x00000002 /* DHCP timer expires */ -#define NX_DHCP_CLIENT_CONFLICT_EVENT 0x00000004 /* IP conflict event detected */ -#define NX_DHCP_CLIENT_ALL_EVENTS 0xFFFFFFFF /* All DHCP events */ - - -#ifdef NX_DHCP_CLIENT_RESTORE_STATE - -/* Define a Client record for restore DHCP Client state from non volatile memory/across reboots. */ -typedef struct NX_DHCP_CLIENT_RECORD_STRUCT -{ - UCHAR nx_dhcp_state; /* The current state of the DHCP Client */ - ULONG nx_dhcp_ip_address; /* Server assigned IP Address */ - ULONG nx_dhcp_network_mask; /* Server assigned network mask */ - ULONG nx_dhcp_gateway_address; /* Server assigned gateway address */ - UINT nx_dhcp_interface_index; /* Index of DHCP Client network interface */ - ULONG nx_dhcp_timeout; /* The current value of any timeout, in seconds */ - ULONG nx_dhcp_server_ip; /* The server IP Address */ - ULONG nx_dhcp_lease_remain_time; /* Time remaining before lease expires */ - ULONG nx_dhcp_lease_time; /* The current Lease Time in seconds */ - ULONG nx_dhcp_renewal_time; /* Renewal Time in seconds */ - ULONG nx_dhcp_rebind_time; /* Rebind Time in seconds */ - ULONG nx_dhcp_renewal_remain_time;/* Time remaining to renew (before rebinding necessary) */ - ULONG nx_dhcp_rebind_remain_time; /* Time remaining to rebind (before lease expires) */ -} NX_DHCP_CLIENT_RECORD; -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ - -/* Define the DHCP interface record that contains all the information necessary for a DHCP - instance on each interface. */ -typedef struct NX_DHCP_INTERFACE_RECORD_STRUCT -{ - UCHAR nx_dhcp_record_valid; /* The flag indicate this record is valid. NX_TRUE: valid */ - UCHAR nx_dhcp_state; /* The current state of the DHCP Client */ - UCHAR nx_dhcp_user_option; /* User option request */ - UCHAR reserved; - ULONG nx_dhcp_xid; /* Unique transaction ID */ - ULONG nx_dhcp_seconds; /* Track number of seconds for a DHCP request process */ - ULONG nx_dhcp_ip_address; /* Server assigned IP Address */ - ULONG nx_dhcp_gateway_address; /* Server assigned gateway address */ - ULONG nx_dhcp_server_ip; /* The server IP Address */ - ULONG nx_dhcp_network_mask; /* Server assigned network mask */ - UINT nx_dhcp_interface_index; /* Index of DHCP Client network interface */ - ULONG nx_dhcp_timeout; /* Count down timer for sending out DHCP message */ - ULONG nx_dhcp_rtr_interval; /* Interval between sending out another DHCP message */ - ULONG nx_dhcp_lease_remain_time; /* Time remaining before lease expires */ - ULONG nx_dhcp_lease_time; /* The current Lease Time in seconds */ - ULONG nx_dhcp_renewal_time; /* Renewal Time in seconds */ - ULONG nx_dhcp_rebind_time; /* Rebind Time in seconds */ - ULONG nx_dhcp_renewal_remain_time;/* Time remaining to renew (before rebinding necessary) */ - ULONG nx_dhcp_rebind_remain_time; /* Time remaining to rebind (before lease expires) */ -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - UINT nx_dhcp_probe_count; /* Number of ARP probes to send to prove IP address unique */ -#endif - UINT nx_dhcp_clear_broadcast; /* Client sends messages with unicast reply requested */ - UINT nx_dhcp_skip_discovery; /* Indicate if host should skip the discovery message */ - UCHAR nx_dhcp_options_buffer[NX_DHCP_OPTIONS_BUFFER_SIZE]; - UINT nx_dhcp_options_size; /* The total size of DHCP options. */ - - ULONG nx_dhcp_internal_errors; /* The number of internal DHCP errors encountered */ - ULONG nx_dhcp_discoveries_sent; /* The number of Discovery sent by the Client */ - ULONG nx_dhcp_offers_received; /* The number of Offers received by the Client */ - ULONG nx_dhcp_requests_sent; /* The number of Request attempts made by the Client */ - ULONG nx_dhcp_acks_received; /* The number of ACKs received by the Client */ - ULONG nx_dhcp_nacks_received; /* The number of NACKs received by the Client */ - ULONG nx_dhcp_releases_sent; /* The number of Releases sent by the Client */ - ULONG nx_dhcp_declines_sent; /* The number of Declines sent by the Client */ - ULONG nx_dhcp_force_renewal_rec; /* The number of Forced Renewal received by the Client */ - ULONG nx_dhcp_informs_sent; /* The number of Inform (option requests) sent by the Client*/ - ULONG nx_dhcp_inform_responses; /* The number of Inform responses */ - -} NX_DHCP_INTERFACE_RECORD; - - -/* Define the DHCP structure that contains all information common to all interfaces on - which DHCP Client may run. */ -typedef struct NX_DHCP_STRUCT -{ - - ULONG nx_dhcp_id; /* DHCP Structure ID */ - CHAR *nx_dhcp_name; /* DHCP name supplied at create */ - NX_IP *nx_dhcp_ip_ptr; /* The associated IP pointer for this DHCP instance */ -#ifndef NX_DHCP_CLIENT_USER_CREATE_PACKET_POOL - NX_PACKET_POOL nx_dhcp_pool; /* The pool of UDP data packets for DHCP messages */ - UCHAR nx_dhcp_pool_area[NX_DHCP_PACKET_POOL_SIZE]; -#endif - NX_PACKET_POOL *nx_dhcp_packet_pool_ptr; /* Pointer to DHCP Client packet pool */ - NX_UDP_SOCKET nx_dhcp_socket; /* The Socket used for DHCP messages */ - TX_THREAD nx_dhcp_thread; /* The DHCP processing thread */ - UCHAR nx_dhcp_thread_stack[NX_DHCP_THREAD_STACK_SIZE]; - TX_MUTEX nx_dhcp_mutex; /* The DHCP mutex for protecting access */ - TX_EVENT_FLAGS_GROUP - nx_dhcp_events; /* DHCP Client thread events */ - TX_TIMER nx_dhcp_timer; /* DHCP Client timeout timer */ - NX_DHCP_INTERFACE_RECORD - nx_dhcp_interface_record[NX_DHCP_CLIENT_MAX_RECORDS]; - /* Record of DHCP Client state on specific interface */ - -#ifdef NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION - ULONG nx_dhcp_max_dhcp_message_size; - /* Maximum length DHCP message DHCP Client will accept */ -#endif /* NX_DHCP_CLIENT_SEND_MAX_DHCP_MESSAGE_OPTION */ - -#ifdef NX_DHCP_CLIENT_SEND_ARP_PROBE - UINT nx_dhcp_interface_conflict_flag; /* The flag indicate IP addresses conflict on which interfaces, one bit represent one interface. - For examples: - 0x00000001: interface index 0; - 0x00000002: interface index 1; - 0x00000003: interface index 0 and 1; */ -#endif /* NX_DHCP_CLIENT_SEND_ARP_PROBE */ - - /* Define the callback function for DHCP state change notification. If specified - by the application, this function is called whenever a state change occurs for - the DHCP associated with this IP instance. */ - VOID (*nx_dhcp_state_change_callback)(struct NX_DHCP_STRUCT *dhcp_ptr, UCHAR new_state); - - /* Define the callback function for DHCP interface state change notification. - this function is similar as nx_dhcp_state_change_callback, - - Note: Suggest using state change notification, and use nx_dhcp_interface_state_change_callback - if DHCP is running on multiple interfaces. */ - VOID (*nx_dhcp_interface_state_change_callback)(struct NX_DHCP_STRUCT *dhcp_ptr, UINT iface_index, UCHAR new_state); - - /* Define the callback function for adding specific DHCP user option. */ - UINT (*nx_dhcp_user_option_add)(struct NX_DHCP_STRUCT *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length); - - /* This pointer is reserved for application specific use. */ - void *nx_dhcp_reserved_ptr; - -} NX_DHCP; - - -#ifndef NX_DHCP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map DHCP API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_dhcp_create _nx_dhcp_create -#define nx_dhcp_packet_pool_set _nx_dhcp_packet_pool_set -#define nx_dhcp_request_client_ip _nx_dhcp_request_client_ip -#define nx_dhcp_delete _nx_dhcp_delete -#define nx_dhcp_decline _nx_dhcp_decline -#define nx_dhcp_force_renew _nx_dhcp_force_renew -#define nx_dhcp_release _nx_dhcp_release -#define nx_dhcp_start _nx_dhcp_start -#define nx_dhcp_stop _nx_dhcp_stop -#define nx_dhcp_server_address_get _nx_dhcp_server_address_get -#define nx_dhcp_state_change_notify _nx_dhcp_state_change_notify -#define nx_dhcp_user_option_retrieve _nx_dhcp_user_option_retrieve -#define nx_dhcp_user_option_convert _nx_dhcp_user_option_convert -#define nx_dhcp_user_option_add_callback_set _nx_dhcp_user_option_add_callback_set -#define nx_dhcp_reinitialize _nx_dhcp_reinitialize -#define nx_dhcp_send_request _nx_dhcp_send_request -#define nx_dhcp_set_interface_index _nx_dhcp_set_interface_index -#define nx_dhcp_clear_broadcast_flag _nx_dhcp_clear_broadcast_flag -#define nx_dhcp_interface_clear_broadcast_flag _nx_dhcp_interface_clear_broadcast_flag -#define nx_dhcp_interface_enable _nx_dhcp_interface_enable -#define nx_dhcp_interface_disable _nx_dhcp_interface_disable -#define nx_dhcp_interface_decline _nx_dhcp_interface_decline -#define nx_dhcp_interface_force_renew _nx_dhcp_interface_force_renew -#define nx_dhcp_interface_reinitialize _nx_dhcp_interface_reinitialize -#define nx_dhcp_interface_release _nx_dhcp_interface_release -#define nx_dhcp_interface_request_client_ip _nx_dhcp_interface_request_client_ip -#define nx_dhcp_interface_start _nx_dhcp_interface_start -#define nx_dhcp_interface_stop _nx_dhcp_interface_stop -#define nx_dhcp_interface_send_request _nx_dhcp_interface_send_request -#define nx_dhcp_interface_server_address_get _nx_dhcp_interface_server_address_get -#define nx_dhcp_interface_state_change_notify _nx_dhcp_interface_state_change_notify -#define nx_dhcp_interface_user_option_retrieve _nx_dhcp_interface_user_option_retrieve -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -#define nx_dhcp_resume _nx_dhcp_resume -#define nx_dhcp_suspend _nx_dhcp_suspend -#define nx_dhcp_client_get_record _nx_dhcp_client_get_record -#define nx_dhcp_client_restore_record _nx_dhcp_client_restore_record -#define nx_dhcp_client_update_time_remaining _nx_dhcp_client_update_time_remaining -#define nx_dhcp_client_interface_get_record _nx_dhcp_client_interface_get_record -#define nx_dhcp_client_interface_restore_record _nx_dhcp_client_interface_restore_record -#define nx_dhcp_client_interface_update_time_remaining _nx_dhcp_client_interface_update_time_remaining -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ - -#else - -/* Services with error checking. */ - -#define nx_dhcp_create _nxe_dhcp_create -#define nx_dhcp_packet_pool_set _nxe_dhcp_packet_pool_set -#define nx_dhcp_request_client_ip _nxe_dhcp_request_client_ip -#define nx_dhcp_delete _nxe_dhcp_delete -#define nx_dhcp_decline _nxe_dhcp_decline -#define nx_dhcp_force_renew _nxe_dhcp_force_renew -#define nx_dhcp_release _nxe_dhcp_release -#define nx_dhcp_start _nxe_dhcp_start -#define nx_dhcp_stop _nxe_dhcp_stop -#define nx_dhcp_server_address_get _nxe_dhcp_server_address_get -#define nx_dhcp_state_change_notify _nxe_dhcp_state_change_notify -#define nx_dhcp_user_option_retrieve _nxe_dhcp_user_option_retrieve -#define nx_dhcp_user_option_convert _nxe_dhcp_user_option_convert -#define nx_dhcp_user_option_add_callback_set _nxe_dhcp_user_option_add_callback_set -#define nx_dhcp_reinitialize _nxe_dhcp_reinitialize -#define nx_dhcp_send_request _nxe_dhcp_send_request -#define nx_dhcp_set_interface_index _nxe_dhcp_set_interface_index -#define nx_dhcp_clear_broadcast_flag _nxe_dhcp_clear_broadcast_flag -#define nx_dhcp_interface_clear_broadcast_flag _nxe_dhcp_interface_clear_broadcast_flag -#define nx_dhcp_interface_enable _nxe_dhcp_interface_enable -#define nx_dhcp_interface_disable _nxe_dhcp_interface_disable -#define nx_dhcp_interface_decline _nxe_dhcp_interface_decline -#define nx_dhcp_interface_force_renew _nxe_dhcp_interface_force_renew -#define nx_dhcp_interface_reinitialize _nxe_dhcp_interface_reinitialize -#define nx_dhcp_interface_release _nxe_dhcp_interface_release -#define nx_dhcp_interface_request_client_ip _nxe_dhcp_interface_request_client_ip -#define nx_dhcp_interface_start _nxe_dhcp_interface_start -#define nx_dhcp_interface_stop _nxe_dhcp_interface_stop -#define nx_dhcp_interface_send_request _nxe_dhcp_interface_send_request -#define nx_dhcp_interface_server_address_get _nxe_dhcp_interface_server_address_get -#define nx_dhcp_interface_state_change_notify _nxe_dhcp_interface_state_change_notify -#define nx_dhcp_interface_user_option_retrieve _nxe_dhcp_interface_user_option_retrieve -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -#define nx_dhcp_resume _nxe_dhcp_resume -#define nx_dhcp_suspend _nxe_dhcp_suspend -#define nx_dhcp_client_get_record _nxe_dhcp_client_get_record -#define nx_dhcp_client_restore_record _nxe_dhcp_client_restore_record -#define nx_dhcp_client_update_time_remaining _nxe_dhcp_client_update_time_remaining -#define nx_dhcp_client_interface_get_record _nxe_dhcp_client_interface_get_record -#define nx_dhcp_client_interface_restore_record _nxe_dhcp_client_interface_restore_record -#define nx_dhcp_client_interface_update_time_remaining _nxe_dhcp_client_interface_update_time_remaining -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); -UINT nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); -UINT nx_dhcp_delete(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_decline(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_force_renew(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_release(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_start(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_stop(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); -UINT nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); -UINT nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); -ULONG nx_dhcp_user_option_convert(UCHAR *source_ptr); -UINT nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); -UINT nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); -UINT nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); -UINT nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); -UINT nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); -UINT nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); -UINT nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); -UINT nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); -UINT nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); -UINT nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); - -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -UINT nx_dhcp_resume(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_suspend(NX_DHCP *dhcp_ptr); -UINT nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); -UINT nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ - -#else - -/* DHCP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); -UINT _nx_dhcp_create(NX_DHCP *dhcp_ptr, NX_IP *ip_ptr, CHAR *name_ptr); -UINT _nxe_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT _nx_dhcp_packet_pool_set(NX_DHCP *dhcp_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT _nxe_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); -UINT _nx_dhcp_request_client_ip(NX_DHCP *dhcp_ptr, ULONG client_ip_address, UINT skip_discover_message); -UINT _nxe_dhcp_delete(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_delete(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_decline(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_decline(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_force_renew(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_force_renew(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_release(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_release(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_start(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_start(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_stop(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_stop(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); -UINT _nx_dhcp_server_address_get(NX_DHCP *dhcp_ptr, ULONG *server_address); -UINT _nxe_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); -UINT _nx_dhcp_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_state_change_notify)(NX_DHCP *dhcp_ptr, UCHAR new_state)); -UINT _nxe_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); -UINT _nx_dhcp_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT request_option, UCHAR *destination_ptr, UINT *destination_size); -ULONG _nxe_dhcp_user_option_convert(UCHAR *source_ptr); -ULONG _nx_dhcp_user_option_convert(UCHAR *source_ptr); -UINT _nxe_dhcp_reinitialize(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_reinitialize(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); -UINT _nx_dhcp_send_request(NX_DHCP *dhcp_ptr, UINT dhcp_message_type); -UINT _nxe_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); -UINT _nx_dhcp_set_interface_index(NX_DHCP *dhcp_ptr, UINT interface_index); -UINT _nxe_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); -UINT _nx_dhcp_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag); -UINT _nxe_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); -UINT _nx_dhcp_user_option_add_callback_set(NX_DHCP *dhcp_ptr, UINT (*dhcp_user_option_add)(NX_DHCP *dhcp_ptr, UINT iface_index, UINT message_type, UCHAR *user_option_ptr, UINT *user_option_length)); -UINT _nxe_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); -UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT iface_index, UINT clear_flag); -UINT _nxe_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_enable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_disable(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_decline(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_force_renew(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_release(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_reinitialize(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_start(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nx_dhcp_interface_stop(NX_DHCP *dhcp_ptr, UINT iface_index); -UINT _nxe_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); -UINT _nx_dhcp_interface_request_client_ip(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG client_ip_address, UINT skip_discover_message); -UINT _nxe_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); -UINT _nx_dhcp_interface_send_request(NX_DHCP *dhcp_ptr, UINT iface_index, UINT dhcp_message_type); -UINT _nxe_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); -UINT _nx_dhcp_interface_server_address_get(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG *server_address); -UINT _nxe_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); -UINT _nx_dhcp_interface_state_change_notify(NX_DHCP *dhcp_ptr, VOID (*dhcp_interface_state_change_notify)(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state)); -UINT _nxe_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); -UINT _nx_dhcp_interface_user_option_retrieve(NX_DHCP *dhcp_ptr, UINT iface_index, UINT option_request, UCHAR *destination_ptr, UINT *destination_size); - -#ifdef NX_DHCP_CLIENT_RESTORE_STATE -UINT _nxe_dhcp_resume(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_resume(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_suspend(NX_DHCP *dhcp_ptr); -UINT _nx_dhcp_suspend(NX_DHCP *dhcp_ptr); -UINT _nxe_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT _nx_dhcp_client_get_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT _nxe_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT _nx_dhcp_client_restore_record(NX_DHCP *dhcp_ptr, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT _nxe_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); -UINT _nx_dhcp_client_update_time_remaining(NX_DHCP *dhcp_ptr, ULONG time_elapsed); -UINT _nxe_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT _nx_dhcp_client_interface_get_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr); -UINT _nxe_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT _nx_dhcp_client_interface_restore_record(NX_DHCP *dhcp_ptr, UINT iface_index, NX_DHCP_CLIENT_RECORD *record_ptr, ULONG time_elapsed); -UINT _nxe_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); -UINT _nx_dhcp_client_interface_update_time_remaining(NX_DHCP *dhcp_ptr, UINT iface_index, ULONG time_elapsed); -#endif /* NX_DHCP_CLIENT_RESTORE_STATE */ - -#endif /* NX_DHCP_SOURCE_CODE */ - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* NXD_DHCP_CLIENT_H */ diff --git a/protocol_handlers/dhcp/nxd_dhcp_server.c b/protocol_handlers/dhcp/nxd_dhcp_server.c deleted file mode 100644 index 3190f209..00000000 --- a/protocol_handlers/dhcp/nxd_dhcp_server.c +++ /dev/null @@ -1,5532 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol (DHCP) Server */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_DHCP_SERVER_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_ip.h" -#include "nx_udp.h" -#include "nxd_dhcp_server.h" -#include "tx_timer.h" -#include "nx_packet.h" -#include "nx_system.h" - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - -#ifdef EL_PRINTF_ENABLE -#define EL_PRINTF printf -#endif - -/* Define the DHCP Internal Function. */ -static VOID _nx_dhcp_server_thread_entry(ULONG ip_instance); -static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info); -static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info); -static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr); -static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); -static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, NX_PACKET *packet_ptr, UINT iface_index); -static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_ptr, CHAR *buffer, ULONG value, UINT get_option_data, UINT size); -static UINT _nx_dhcp_add_option(UCHAR *bootp_message, UINT option, UINT size, ULONG value, UINT *index); -static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index); -static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_length); -static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index); -static UINT _nx_dhcp_parse_next_option(CHAR **buffer, UINT *digit, UINT length); -static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value); -static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value); -static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); -static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); -static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw, ULONG client_mac_lsw,NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on); -static UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, UINT iface_index, ULONG assigned_ip_address); -static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); -static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address, NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address); -static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, ULONG ip_address, UINT assign_status); -static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client); -static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time); -static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner); -static VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr); - - -/* To enable dhcp server output, define TESTOUTPUT. */ -/* #define TESTOUTPUT 1 */ - -/* To enable packet dump, define PACKET_DUMP. */ -/* #define PACKET_DUMP 1 */ - -#ifdef TESTOUTPUT - -static int add_client = 0; - -/* Define how often to print the server table of current clients. - For no output set to zero. For low volume, set to 1; - for very high volume, set higher so as not to overwelm the processor. */ - -#define TRACE_NTH_CLIENT_PACKET 1 - -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP create function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to free memory */ -/* stack_size Size of DHCP server stack */ -/* name_ptr DHCP name pointer */ -/* packet_pool Server packet pool for sending*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_server_create Actual DHCP create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - CHAR *name_ptr, NX_PACKET_POOL *packet_pool) -{ - -UINT status; - - - /* Check for pointer invalid input. */ - if ((dhcp_ptr == NX_NULL) || (packet_pool == NX_NULL) ||(stack_ptr == NX_NULL) ||(ip_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - if (stack_size == 0) - { - return(NX_DHCP_PARAMETER_ERROR); - } - - /* Check for appropriate caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual DHCP create service. */ - status = _nx_dhcp_server_create(dhcp_ptr, ip_ptr, stack_ptr, stack_size, name_ptr, packet_pool); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the DHCP Server with necessary components.*/ -/* It creates a packet pool for sending Server DHCP messages and a */ -/* thread task for the DHCP server operation. It also sets the standard*/ -/* DHCP options (e.g. lease time etc) for granting IP addresses. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to server thread on */ -/* the stack */ -/* stack_size Size of DHCP server stack */ -/* name_ptr DHCP name pointer */ -/* packet_pool Server packet pool for sending*/ -/* DHCP replies to client */ -/* */ -/* OUTPUT */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD */ -/* Packet payload too small error*/ -/* NX_DHCP_NO_SERVER_OPTION_LIST Missing option list error */ -/* */ -/* status Completion status of socket */ -/* and thread create calls */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_create Create the DHCP UDP socket */ -/* nx_udp_socket_delete Delete the DHCP UDP socket */ -/* tx_thread_create Create DHCP processing thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr) -{ - -UINT status; -UINT timer_ticks; -UINT i, j; - - - /* Initialize the DHCP control block to zero. */ - memset((void *) dhcp_ptr, 0, sizeof(NX_DHCP_SERVER)); - - /* Check the Server packet pool is at least large enough for a full sized DHCP message as per - RFC 2131, plus header data. */ - if (packet_pool_ptr -> nx_packet_pool_payload_size < NX_DHCP_MINIMUM_PACKET_PAYLOAD) - { - - /* Return the error status. */ - return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD); - } - - /* Set the packet pool pointer. */ - dhcp_ptr -> nx_dhcp_packet_pool_ptr = packet_pool_ptr; - - /* Save the DHCP name. */ - memcpy(&dhcp_ptr -> nx_dhcp_name[0], name_ptr, NX_DHCP_SERVER_HOSTNAME_MAX); - - /* Set the DHCP Server attributes. */ - dhcp_ptr -> nx_dhcp_ip_ptr = ip_ptr; - - /* Loop through all the interface tables and clear table memory. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - - /* Clear all the table's IP address entries. */ - for (j = 0; j < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE; j++) - { - - memset(&dhcp_ptr -> nx_dhcp_interface_table[i].nx_dhcp_ip_address_list[j], - 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS)); - } - - /* Clear the DHCP interface itself. */ - memset(&dhcp_ptr -> nx_dhcp_interface_table[i], 0, sizeof(NX_DHCP_INTERFACE_TABLE)); - } - - /* Loop through the entire client record table. */ - for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++) - { - - /* Clear the client record. */ - memset(&dhcp_ptr -> client_records[i], 0, sizeof(NX_DHCP_CLIENT)); - } - - /* Verify the application has defined a server option list. */ - if (sizeof(NX_DHCP_SERVER_OPTION_LIST) == 1) - { - - /* No, return the error status. */ - return(NX_DHCP_NO_SERVER_OPTION_LIST); - } - - /* Create the list of DHCP options the server can provide for the client. */ - status = _nx_dhcp_set_server_options(dhcp_ptr, (CHAR *)NX_DHCP_SERVER_OPTION_LIST, sizeof(NX_DHCP_SERVER_OPTION_LIST) - 1); - - /* Was the option list set successful? */ - if (status != NX_SUCCESS) - { - - /* No, return error status. */ - return(status); - } - - /* Update the dhcp structure ID. */ - dhcp_ptr -> nx_dhcp_id = NX_DHCP_SERVER_ID; - - /* Create the Socket and check the status */ - status = nx_udp_socket_create(ip_ptr, &(dhcp_ptr -> nx_dhcp_socket), "NetX DHCP Server Socket", - NX_DHCP_TYPE_OF_SERVICE, NX_DHCP_FRAGMENT_OPTION, NX_DHCP_TIME_TO_LIVE, NX_DHCP_QUEUE_DEPTH); - - /* Was the socket creation successful? */ - if (status != NX_SUCCESS) - { - - /* No, return error status. */ - return(status); - } - - /* Save the DHCP instance pointer in the socket. */ - dhcp_ptr -> nx_dhcp_socket.nx_udp_socket_reserved_ptr = (void *) dhcp_ptr; - - /* Set the DHCP request handler for packets received on the DHCP server socket. */ - status = nx_udp_socket_receive_notify(&(dhcp_ptr -> nx_dhcp_socket), _nx_dhcp_server_socket_receive_notify); - - /* Was the socket receive_notify set successful? */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* No, return error status. */ - return status; - } - - /* Create the DHCP processing thread. */ - status = tx_thread_create(&(dhcp_ptr -> nx_dhcp_server_thread), "NetX DHCP Server Thread", - _nx_dhcp_server_thread_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, - stack_ptr, stack_size, NX_DHCP_SERVER_THREAD_PRIORITY, - NX_DHCP_SERVER_THREAD_PRIORITY, 1, TX_DONT_START); - - NX_THREAD_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_server_thread), dhcp_ptr) - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* No, return error status. */ - return(status); - } - - /* Create the DHCP mutex. */ - status = tx_mutex_create(&dhcp_ptr -> nx_dhcp_mutex, "DHCP Server Mutex", TX_NO_INHERIT); - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Delete DHCP thead. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* No, return error status. */ - return(status); - } - - /* Convert seconds to timer ticks. */ - timer_ticks = NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE; - - /* Create the timer for Client DHCP session. This will keep track of when leases expire - and when a client session has timed out. */ - status = tx_timer_create(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), "DHCP Server IP Lease Timer", - _nx_dhcp_slow_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, - timer_ticks, timer_ticks, TX_NO_ACTIVATE); - - NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer), dhcp_ptr) - - /* Convert seconds to timer ticks. */ - timer_ticks = NX_DHCP_FAST_PERIODIC_TIME_INTERVAL * NX_IP_PERIODIC_RATE; - - /* Create the timer for Client DHCP session. This will keep track of when leases expire - and when a client session has timed out. */ - status += tx_timer_create(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), "DHCP Server Session Timer", - _nx_dhcp_fast_periodic_timer_entry, (ULONG)(ALIGN_TYPE)dhcp_ptr, - timer_ticks, timer_ticks, TX_NO_ACTIVATE); - - NX_TIMER_EXTENSION_PTR_SET(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer), dhcp_ptr) - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Delete DHCP thead. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Delete ThreadX resources. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete DHCP timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); - - /* Return the error status. */ - return(status); - } - - /* Create the DHCP event flag instance. */ - status = tx_event_flags_create(&dhcp_ptr -> nx_dhcp_server_events, "DHCP Server Events"); - - /* Check for error. */ - if (status != TX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Delete DHCP thread. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Delete ThreadX resources. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete DHCP Timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); - - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); - - /* Return the error status. */ - return(status); - } - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_fast_periodic_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function watches the session timeout on each active client */ -/* session. WHen it does it clears session data from the client record */ -/* and resets the client state to INIT. If a iP address had been */ -/* assigned, it is returned back to the server pool. */ -/* */ -/* INPUT */ -/* */ -/* info Generic pointer to DHCP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Adds a fast periodic event */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_fast_periodic_timer_entry(ULONG info) -{ - -NX_DHCP_SERVER *dhcp_ptr; - - - /* Setup DHCP pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) - - /* Signal the DHCP Server fast periodic event. */ - tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_FAST_PERIODIC_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_slow_periodic_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function watches lease timeout on assigned IP address in the */ -/* server database. When one has expired, the address is returned to */ -/* the available pool and the Client is reset to the INIT state. */ -/* */ -/* INPUT */ -/* */ -/* info Generic pointer to DHCP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Adds a slow periodic event */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX system timer thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_slow_periodic_timer_entry(ULONG info) -{ - -NX_DHCP_SERVER *dhcp_ptr; - - - /* Setup DHCP pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) - - /* Signal the DHCP Server slow periodic event. */ - tx_event_flags_set(&(dhcp_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_SLOW_PERIODIC_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_socket_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is notified by NetX Duo when a packet arrives in the */ -/* server socket. It sets a flag which the DHCP server thread */ -/* detect so it will know to process the incoming packet . */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to Server Socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* tx_event_flags_set Adds a packet receive event */ -/* CALLED BY */ -/* */ -/* Threads */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcp_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - -NX_DHCP_SERVER *dhcp_server_ptr; - - - /* Get a pointer to the DHCP server. */ - dhcp_server_ptr = (NX_DHCP_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr; - - /* Signal the DHCP Server it has a UDP packet on its socket receive queue. */ - tx_event_flags_set(&(dhcp_server_ptr -> nx_dhcp_server_events), NX_DHCP_SERVER_RECEIVE_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP delete function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_server_delete Actual DHCP delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (dhcp_ptr == NX_NULL) - return(NX_PTR_ERROR); - - if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) - { - return(NX_DHCP_PARAMETER_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP delete service. */ - status = _nx_dhcp_server_delete(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DHCP server and releases all of its */ -/* resources. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Free the UDP socket port */ -/* nx_udp_socket_delete Delete the DHCP UDP socket */ -/* tx_thread_terminate Terminate DHCP thread */ -/* tx_thread_terminate Terminate DHCP thread */ -/* tx_thread_delete Delete DHCP thread */ -/* tx_timer_delete Delete DHCP timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr) -{ - - - /* Determine if DHCP is stopped. */ - if (dhcp_ptr -> nx_dhcp_started != NX_FALSE) - { - - /* Stop the DHCP server. */ - _nx_dhcp_server_stop(dhcp_ptr); - } - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Delete the session ("fast") timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); - - /* Delete the IP lease ("slow") timer. */ - tx_timer_delete(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); - - /* Suspend the DHCP processing thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Terminate the DHCP processing thread. */ - tx_thread_terminate(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Delete the DHCP processing thread. */ - tx_thread_delete(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Delete the mutexes. */ - tx_mutex_delete(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Delete the flag event. */ - tx_event_flags_delete(&(dhcp_ptr -> nx_dhcp_server_events)); - - /* Clear the dhcp structure ID. */ - dhcp_ptr -> nx_dhcp_id = 0; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_create_server_ip_address_list PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the IP address list create*/ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* iface_index IP interface index to specify the */ -/* DHCP server interface to use */ -/* start_ip_address Starting IP address */ -/* end_ip_address Ending IP address */ -/* addresses_added Pointer to addresses added counter */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_create_server_ip_address_list */ -/* Actual IP address create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, - ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added) -{ - -UINT status; - - - /* Check for invalid input. */ - if ((dhcp_ptr == NX_NULL) || (addresses_added == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if ((start_ip_address > end_ip_address) || - (iface_index >= NX_MAX_PHYSICAL_INTERFACES) || - (start_ip_address == NX_DHCP_NO_ADDRESS)) - { - - return(NX_DHCP_INVALID_IP_ADDRESS); - } - - status = _nx_dhcp_create_server_ip_address_list(dhcp_ptr, iface_index, start_ip_address, end_ip_address, addresses_added); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_create_server_ip_address_list PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a list of available IP addresses for DHCP */ -/* clients on the specified interface. The caller supplies a start and */ -/* end IP address and all addresses in between are flagged as available.*/ -/* The start ip address is assumed to be the first entry in the list, */ -/* not appended to a previously started list. All the IP addresses may */ -/* not fit in the server interface table; the number actually added is */ -/* written to the 'addresses added' variable. The caller should check */ -/* this output. */ -/* */ -/* If some addresses within the specified range need to be reserved or */ -/* statically assigned the host application needs to set their lease to */ -/* infinity (0xffffffff) and assigned status is set. This function also */ -/* add the interface subnet, router, dns server for specified index. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP server */ -/* iface_index Index specifying server interface*/ -/* start_ip_address Beginning IP address in list. */ -/* end_ip_address Ending IP address in list. */ -/* addresses_added Number of addresses added to list*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP list creation */ -/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */ -/* NX_DHCP_INVALID_IP_ADDRESS_LIST Invalid IP list parameter input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_update_assignable_ip_address */ -/* Updates interface table entry */ -/* with IP address status and owner*/ -/* _nx_dhcp_clear_client_session Clears client record of session */ -/* data from most recent client */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, - ULONG start_ip_address, ULONG end_ip_address, - UINT *addresses_added) -{ - -UINT i; -ULONG next_ip_address; -NX_IP *ip_ptr; -NX_DHCP_INTERFACE_IP_ADDRESS *ip_address_entry_ptr; -NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; - - - /* Check for an invalid interface index. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_DHCP_SERVER_BAD_INTERFACE_INDEX; - } - - /* Obtain DHCP Server mutex protection,. */ - tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); - - *addresses_added = 0; - next_ip_address = start_ip_address; - - /* Set local pointer to the list being created for convenience. */ - dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; - - /* Fill in the interface table with DHCP attributes for the specified interface. */ - - /* Set up a local variable for convenience. */ - ip_ptr = dhcp_ptr -> nx_dhcp_ip_ptr; - - /* Assign the IP interface specified by the IP interface index to the DHCP interface. */ - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_incoming_interface = &(ip_ptr -> nx_ip_interface[iface_index]); - - /* Set the server ip address based on the specified interface. */ - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address; - - /* Set the dns server, subnet mask, and router (default gateway) for this interface. */ - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_address; - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask; - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = ip_ptr -> nx_ip_gateway_address; - - - /* Make sure the start/end address subnet match the interface subnet. */ - if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & start_ip_address) != - (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) - { - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); - } - if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & end_ip_address) != - (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) - { - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); - } - - /* Zero out the list size. */ - dhcp_interface_table_ptr -> nx_dhcp_address_list_size = 0; - - /* Check for invalid list parameters. */ - if ((start_ip_address > end_ip_address) || !start_ip_address || !end_ip_address) - { - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_DHCP_INVALID_IP_ADDRESS_LIST); - } - - /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ - i = 0; - - /* Fit as many IP addresses in the specified range as will fit in the table. */ - while (i < NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE && next_ip_address <= end_ip_address) - { - - /* Set local pointer to the next entry for convenience. */ - ip_address_entry_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; - - /* Clear existing entry; client identifier and available status - must be initialized to NULL and not assigned respectively. */ - memset(ip_address_entry_ptr, 0, sizeof(NX_DHCP_INTERFACE_IP_ADDRESS)); - - /* Add the next IP address to the list. */ - ip_address_entry_ptr -> nx_assignable_ip_address = next_ip_address; - - /* Increase the list size. */ - dhcp_interface_table_ptr -> nx_dhcp_address_list_size++; - - next_ip_address++; - i++; - } - - /* Set the actual number of available addresses added to the table. */ - *addresses_added = dhcp_interface_table_ptr -> nx_dhcp_address_list_size; - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_set_interface_network_parameters PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking services for the set interface */ -/* network parameters service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP server */ -/* iface_index Index specifying server interface*/ -/* subnet_mask Network mask for DHCP clients */ -/* default_gateway_address Router/default gateway for client*/ -/* dns_server_address DNS server for DHCP clients */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid interface index input */ -/* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_update_assignable_ip_address */ -/* Updates interface table entry */ -/* with IP address status and owner*/ -/* _nx_dhcp_clear_client_session Clears client record of session */ -/* data from most recent client */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, - ULONG subnet_mask, ULONG default_gateway_address, - ULONG dns_server_address) -{ -UINT status; - - /* Check for invalid pointer input. */ - if (dhcp_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Check for non pointer input. */ - if ((subnet_mask == 0) || (default_gateway_address == 0) || (dns_server_address == 0)) - { - return(NX_DHCP_INVALID_NETWORK_PARAMETERS); - } - - /* Call the actual service. */ - status = _nx_dhcp_set_interface_network_parameters(dhcp_ptr, iface_index, - subnet_mask, default_gateway_address, - dns_server_address); - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_set_interface_network_parameters PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DHCP server default options for 'network */ -/* critical parameters:' gateway, dns server and network mask for the */ -/* specified interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP server */ -/* iface_index Index specifying server interface*/ -/* subnet_mask Network mask for DHCP clients */ -/* default_gateway_address Router/default gateway for client*/ -/* dns_server_address DNS server for DHCP clients */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Valid parameters received */ -/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Invalid interface index input */ -/* NX_DHCP_INVALID_NETWORK_PARAMETERS Invalid network parameter input */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, - ULONG subnet_mask, ULONG default_gateway_address, - ULONG dns_server_address) -{ - - /* Check for invalid non pointer input. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); - } - - /* The default gateway should be on the same network as the dhcp server interface. */ - if ((default_gateway_address & subnet_mask) != - (dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address & - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask)) - { - return(NX_DHCP_INVALID_NETWORK_PARAMETERS); - } - - /* Obtain DHCP Server mutex protection,. */ - tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); - - /* Set the subnet, dns server, and router address for this interface. */ - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address = dns_server_address; - - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask = subnet_mask; - - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address = default_gateway_address; - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP start function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_start Actual DHCP start function */ -/* nx_udp_socket_bind Bind the DHCP UDP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if (dhcp_ptr == NX_NULL) - return(NX_PTR_ERROR); - - if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) - { - return(NX_DHCP_PARAMETER_ERROR); - } - - /* Check for appropriate caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual DHCP start service. */ - status = _nx_dhcp_server_start(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initiates the DHCP processing thread. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_bind Bind DHCP socket */ -/* nx_udp_socket_unbind Unbind DHCP socket */ -/* tx_thread_resume Initiate DHCP processing */ -/* tx_mutex_get Get the DHCP mutex */ -/* tx_mutex_put Release the DHCP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr) -{ - -UINT status; - - - /* Determine if DHCP has already been started. */ - if (dhcp_ptr -> nx_dhcp_started) - { - - /* Error DHCP has already been started. */ - - /* Return completion status. */ - return(NX_DHCP_SERVER_ALREADY_STARTED); - } - - dhcp_ptr -> nx_dhcp_started = NX_TRUE; - - /* Bind the UDP socket to the DHCP Socket port. */ - status = nx_udp_socket_bind(&(dhcp_ptr -> nx_dhcp_socket), NX_DHCP_SERVER_UDP_PORT, TX_WAIT_FOREVER); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the DHCP socket. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Set status to DHCP error code. */ - return(status); - } - - /* Start the session ("fast") timer. */ - tx_timer_activate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); - - /* Start the IP lease ("slow") timer. */ - tx_timer_activate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); - - /* Start the DHCP server thread. */ - tx_thread_resume(&(dhcp_ptr -> nx_dhcp_server_thread)); - - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DHCP stop function call. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_stop Actual DHCP stop function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if (dhcp_ptr == NX_NULL) - return(NX_PTR_ERROR); - - if (dhcp_ptr -> nx_dhcp_id != NX_DHCP_SERVER_ID) - { - return(NX_DHCP_PARAMETER_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP stop service. */ - status = _nx_dhcp_server_stop(dhcp_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function halts the DHCP processing thread. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind the DHCP UDP socket */ -/* tx_thread_preemption_change Change the thread preemption */ -/* tx_thread_suspend Suspend DHCP processing */ -/* tx_thread_wait_abort Remove any thread suspension */ -/* tx_timer_deactivate Deactivate timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr) -{ - -UINT current_preemption; - - - /* Determine if DHCP is started. */ - if (dhcp_ptr -> nx_dhcp_started == NX_FALSE) - { - - /* DHCP is not started so it can't be stopped. */ - return(NX_DHCP_SERVER_NOT_STARTED); - } - - /* Obtain mutex protection, which is to say don't interrupt a DHCP server - if it is processing a packet from a DHCP client. */ - tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); - - /* Stop the session ("fast") timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_fast_periodic_timer)); - - /* Stop the IP lease ("slow") timer. */ - tx_timer_deactivate(&(dhcp_ptr -> nx_dhcp_slow_periodic_timer)); - - /* Clear the started flag here to ensure other threads can't issue a stop while - this stop is in progress. */ - dhcp_ptr -> nx_dhcp_started = NX_FALSE; - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Suspend the DHCP thread. */ - tx_thread_suspend(&(dhcp_ptr -> nx_dhcp_server_thread)); - - /* Unbind the port. */ - nx_udp_socket_unbind(&(dhcp_ptr -> nx_dhcp_socket)); - - /* Restore preemption. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is top level server processing thread for the DHCP */ -/* service. It listens for and processes client requests in an infinite*/ -/* loop. */ -/* */ -/* Note that the current implementation expects a Client to initiate */ -/* a session with DISCOVER message rather than using the option of */ -/* skipping to the REQUEST message. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_instance Pointer to the DHCP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_process Main DHCP processing function */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_server_thread_entry(ULONG info) -{ - -NX_DHCP_SERVER *dhcp_ptr; -ULONG dhcp_events; -NX_DHCP_INTERFACE_TABLE *iface_table_ptr; -NX_DHCP_INTERFACE_IP_ADDRESS *iface_address_ptr; -NX_DHCP_CLIENT *dhcp_client_ptr; -UINT iface_index, i; -UINT status; -NX_PACKET *packet_ptr; - - - /* Setup the DHCP pointer. */ - NX_THREAD_EXTENSION_PTR_GET(dhcp_ptr, NX_DHCP_SERVER, info) - - /* Enter while loop. */ - while(1) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcp_ptr -> nx_dhcp_mutex)); - - /* Pick up IP event flags. */ - tx_event_flags_get(&dhcp_ptr -> nx_dhcp_server_events, NX_DHCP_SERVER_ALL_EVENTS, - TX_OR_CLEAR, &dhcp_events, TX_WAIT_FOREVER); - - /* Obtain the DHCP mutex before processing the DHCP event. */ - tx_mutex_get(&(dhcp_ptr -> nx_dhcp_mutex), TX_WAIT_FOREVER); - - /* Check events. */ - - /* Packet receive event. */ - if (dhcp_events & NX_DHCP_SERVER_RECEIVE_EVENT) - { - - /* Loop to receive DHCP message. */ - while(1) - { - - /* Check for an incoming DHCP packet with non blocking option. */ - status = _nx_udp_socket_receive(&dhcp_ptr -> nx_dhcp_socket, &packet_ptr, NX_NO_WAIT); - - /* Check for packet receive errors. */ - if (status != NX_SUCCESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Error receiving DHCP packet 0x%x\n", status); -#endif - break; - } - - /* Process DHCP packet. */ - _nx_dhcp_server_packet_process(dhcp_ptr, packet_ptr); - } - } - - /* FAST periodic event. */ - if (dhcp_events & NX_DHCP_SERVER_FAST_PERIODIC_EVENT) - { - - /* Check the clients in active session with the server. */ - for (i = 0; i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE; i++) - { - - /* Create a local pointer for convenience. */ - dhcp_client_ptr = &dhcp_ptr -> client_records[i]; - - /* Skip empty records. */ - if ((dhcp_client_ptr -> nx_dhcp_client_mac_lsw == 0) && (dhcp_client_ptr -> nx_dhcp_client_mac_msw == 0)) - continue; - - /* Skip clients not in active session with the Server, static members, - or client in the bound state. */ - if (dhcp_client_ptr -> nx_dhcp_session_timeout == TX_WAIT_FOREVER) - continue; - if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND) - continue; - - /* Skip clients whose session timeout is not set e.g. previous session - failed and no longer configured with this server. */ - if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0) - continue; - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) - continue; - - /* Check how much time is left before decreasing the time remaining on the session timeout. */ - if (dhcp_client_ptr -> nx_dhcp_session_timeout >= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL) - { - /* Ok to decrement the full amount. */ - dhcp_client_ptr -> nx_dhcp_session_timeout -= NX_DHCP_FAST_PERIODIC_TIME_INTERVAL; - } - else - { - - /* Set to zero. Time's up! */ - dhcp_client_ptr -> nx_dhcp_session_timeout = 0; - } - - /* Has time expired on this session? */ - if (dhcp_client_ptr -> nx_dhcp_session_timeout == 0) - { - - /* Yes, the client has bailed on the session, intentionally or otherwise. If it wants to - get an IP address it must start again. Reset status to 'INIT'. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: client session has timed out. Clear session data\n"); -#endif - - /* Does the client have an assigned IP address? */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) - { - - /* Yes, return it back to the available pool. */ - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, - dhcp_client_ptr -> nx_dhcp_assigned_ip_address, - NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); - - /* The assigned address must be removed. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - /* Clear the session data, including any data read from last client DHCP message. */ - _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr); - } - } - } - } - - /* Slow periodic event. */ - if (dhcp_events & NX_DHCP_SERVER_SLOW_PERIODIC_EVENT) - { - - for (iface_index = 0; iface_index < NX_MAX_PHYSICAL_INTERFACES; iface_index++) - { - - /* Set a local pointer for convenience. */ - iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; - - /* Check the interface addresses in the table for lease expiration. */ - for (i = 0; i < iface_table_ptr -> nx_dhcp_address_list_size; i++) - { - - iface_address_ptr = &iface_table_ptr -> nx_dhcp_ip_address_list[i]; - - /* Skip all the entries who are not assigned or assigned indefinately (static). */ - if(iface_address_ptr -> assigned == NX_FALSE) - continue; - if(iface_address_ptr -> lease_time == TX_WAIT_FOREVER) - continue; - - /* Check how much time is left before decreasing the time remaining on the lease timeout. */ - if (iface_address_ptr -> lease_time >= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL) - { - - /* Ok to decrement the full amount. */ - iface_address_ptr -> lease_time -= NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL; - } - else - { - - /* Set to zero. Time's up! */ - iface_address_ptr -> lease_time = 0; - } - - /* Has time expired on this lease? */ - if (iface_address_ptr -> lease_time == 0) - { - - /* Yes, make this address available. */ - - /* Clear the 'owner' field. */ - _nx_dhcp_clear_ip_address_owner(iface_address_ptr); - - /* Look up the client in the server database by its assigned address. */ - _nx_dhcp_find_client_record_by_ip_address(dhcp_ptr, &dhcp_client_ptr, iface_index, - iface_address_ptr -> nx_assignable_ip_address); - - /* Did we find it? */ - if (dhcp_client_ptr != NX_NULL) - { - - /* Remove the assigned IP address and reset the Client to the INIT state. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: client IP lease expired. Clear client data, release IP address\n"); -#endif - - /* Clear all session data if there is any for this client. */ - _nx_dhcp_clear_client_session(dhcp_ptr, dhcp_client_ptr); - - /* No, we should have this client in the server client records table but we don't. - That's all we can do right now. */ - } - } - } - } - } - }; - - /* We only break out of this loop in the event of the server stopping - or a fatal error occurring.*/ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_respond_to_client_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function prepares a DHCP message response and sends it back to */ -/* the Client. Most of the information is obtained from specified */ -/* input or from client session record. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to client to respond to*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status from various*/ -/* NetX calls */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a DHCP packet */ -/* nx_packet_release Release DHCP packet */ -/* nx_udp_socket_send Send DHCP packet */ -/* _nx_dhcp_add_option Add an option to the request */ -/* _nx_dhcp_add_requested_option Adds non standard option to */ -/* server reply to client */ -/* _nx_dhcp_load_server_options Load option data from server */ -/* option list */ -/* _nx_dhcp_server_store_data Store data into buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_listen_for_messages Service Client DHCP messages */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_respond_to_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer; -UINT status; -UINT destination_ip_address; -UINT destination_port; -UINT index = 0; - - -#ifdef EL_PRINTF_ENABLE - /* Set local variables for convenience. */ - EL_PRINTF("DHCPserv: respond to client message on interface %d\n", dhcp_client_ptr -> nx_dhcp_client_iface_index); -#endif - - /* Allocate a DHCP packet. */ - status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Setup the packet buffer pointer. */ - buffer = packet_ptr -> nx_packet_prepend_ptr; - - /* Clear the buffer memory. */ - memset((void *) buffer, 0, NX_DHCP_OFFSET_END); - - /* Setup the standard DHCP fields. */ - buffer[NX_DHCP_OFFSET_OP] = NX_DHCP_OP_REPLY; - buffer[NX_DHCP_OFFSET_HTYPE] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwtype; - buffer[NX_DHCP_OFFSET_HLEN] = (UCHAR)dhcp_client_ptr -> nx_dhcp_client_hwlen; - buffer[NX_DHCP_OFFSET_HOPS] = 0; - buffer[NX_DHCP_OFFSET_BOOT_FILE] = 0; - - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_XID, 4, dhcp_client_ptr -> nx_dhcp_xid); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SECS, 2, 0); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_IP, 4, NX_DHCP_NO_ADDRESS); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_SERVER_IP, 4, NX_DHCP_NO_ADDRESS); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_RELAY_IP, 4, NX_DHCP_NO_ADDRESS); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_FLAGS, 1, dhcp_client_ptr -> nx_dhcp_broadcast_flag_set); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW, 2, dhcp_client_ptr -> nx_dhcp_client_mac_msw); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_CLIENT_HW + 2, 4, dhcp_client_ptr -> nx_dhcp_client_mac_lsw); - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_VENDOR, 4, NX_DHCP_MAGIC_COOKIE); - - /* Update the index. */ - index = NX_DHCP_OFFSET_OPTIONS; - - /* Add the list of options that go out with ALL server messages. */ - status = _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_ALL_REPLIES, &index); - - /* Unless the server is sending a NACK, there are more options to add for the server reply. */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) - { - - /* Add the list of options that go out with server ACK replies (standard network parameters). */ - _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_GENERIC_ACK, &index); - - /* Determine if there are any message specific options to add. */ - switch (dhcp_client_ptr -> nx_dhcp_message_type) - { - - case NX_DHCP_TYPE_DHCPDISCOVER: - - /* Are we returning an OFFER to the Client? */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER) - { - - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_your_ip_address); - - /* Add the list of options that go out with server OFFER replies. */ - _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER, &index); - } - - /* Increment the number of Discovery messages received. */ - dhcp_ptr -> nx_dhcp_discoveries_received++; - break; - - - case NX_DHCP_TYPE_DHCPREQUEST: - - /* Are we returning an ACK to the Client? */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) - { - - _nx_dhcp_server_store_data(buffer + NX_DHCP_OFFSET_YOUR_IP, 4, dhcp_client_ptr -> nx_dhcp_assigned_ip_address); - - /* Add the list of options that go out with server ACKs replies. */ - _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST, &index); - } - - /* Increment the number of Request messages received. */ - dhcp_ptr -> nx_dhcp_requests_received++; - break; - - /* Note: DHCP Servers should not reply to NX_DHCP_REPLY_TO_RELEASE or NX_DHCP_REPLY_TO_DECLINE messages. */ - case NX_DHCP_TYPE_DHCPRELEASE: - dhcp_ptr -> nx_dhcp_releases_received++; - break; - - case NX_DHCP_TYPE_DHCPDECLINE: - dhcp_ptr -> nx_dhcp_declines_received++; - break; - - case NX_DHCP_TYPE_DHCPINFORM: - - /* At this time the server sends just standard network parameters to INFORM requests. - so no additional options to add. */ - - /* Increment the number of Inform messages received. */ - dhcp_ptr -> nx_dhcp_informs_received++; - break; - - /* No other DHCP messages are supported by NetX DHCP Server at this time. */ - default: - break; - } - - /* Determine which of the remaining client requested options the server has information for. */ - _nx_dhcp_load_server_options(dhcp_ptr, dhcp_client_ptr, buffer, NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT, &index); - } - - /* Setup the packet pointers. */ - /* Added the END option. */ - *(buffer + index) = NX_DHCP_SERVER_OPTION_END; - index ++; - - /* Check the option length. */ - if (index > NX_DHCP_OFFSET_END) - { - packet_ptr -> nx_packet_length = index; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; - } - else - { - packet_ptr -> nx_packet_length = NX_DHCP_OFFSET_END; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_END; - } - - /* DHCP Server set the correct destination address and port to send resposne. RFC2131, Section4.1, Page23. - 1. If the 'giaddr' field in a DHCP message from a client is non-zero, the server sends any return messages to the 'DHCP server' port on the - BOOTP relay agent whose address appears in 'giaddr'. - 2. If the 'giaddr'field is zero and the 'ciaddr' field is nonzero, then the server unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'. - 3. If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set, then the server broadcasts DHCPOFFER and DHCPACK messages to 0xffffffff. - 4. If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware address and 'yiaddr' address. - 5. In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK messages to 0xffffffff. */ - - /* Check the 'giaddr' field. */ - if (dhcp_client_ptr -> nx_dhcp_relay_ip_address) - { - - /* Set the destination address and port. */ - destination_ip_address = dhcp_client_ptr -> nx_dhcp_relay_ip_address; - destination_port = NX_DHCP_SERVER_UDP_PORT; - } - else - { - /* Check the DHCP response message type. */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) - { - - /* Check the 'ciaddr' field*/ - if (dhcp_client_ptr -> nx_dhcp_clientip_address) - { - destination_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address; - } - /* Check the broadcast bit. */ - else if (dhcp_client_ptr -> nx_dhcp_broadcast_flag_set & NX_DHCP_FLAGS_BROADCAST) - { - destination_ip_address = NX_DHCP_BC_ADDRESS; - } - else - { - destination_ip_address = dhcp_client_ptr -> nx_dhcp_your_ip_address; - - /* Add the dynamic arp entry. */ - status = nx_arp_dynamic_entry_set(dhcp_ptr -> nx_dhcp_ip_ptr, destination_ip_address, dhcp_client_ptr -> nx_dhcp_client_mac_msw, dhcp_client_ptr -> nx_dhcp_client_mac_lsw); - - /* Check the status. */ - if (status) - { - nx_packet_release(packet_ptr); - - return(status); - } - } - } - else - { - destination_ip_address = NX_DHCP_BC_ADDRESS; - } - - /* Set the destination port. */ - destination_port = NX_DHCP_CLIENT_UDP_PORT; - } - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: DHCP reply packet destination 0x%x\n", destination_ip_address); - EL_PRINTF("DHCPserv: DHCP reply buffer size (bytes) %d\n", packet_ptr -> nx_packet_length); - EL_PRINTF("DHCPserv: DHCP reply packet payload size (bytes) %d\n\n", packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_payload_size); -#endif - -#ifdef PACKET_DUMP -{ - - ULONG *work_ptr; - ULONG uword; - UINT i = 0; - UINT index = 0; - UINT length; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: server reply to client - packet dump:\n"); -#endif - - work_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; - length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)); - - while(i < length) - { - uword = *work_ptr; - - if (index == 10) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\n"); -#endif - index = 0; - } - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF(" %08x", uword); -#endif - work_ptr++; - index++; - i++; - } -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\n\n"); -#endif -} -#endif /* #ifdef PACKET_DUMP */ - - /* Send the packet. */ - status = nx_udp_socket_interface_send(&(dhcp_ptr -> nx_dhcp_socket), packet_ptr, destination_ip_address, destination_port, dhcp_client_ptr -> nx_dhcp_client_iface_index); - - if (status != NX_SUCCESS) - { - nx_packet_release(packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_clear_client_session PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears data from the current client session (e.g. read*/ -/* from the most recent client message. It does remove anything in the */ -/* interface table associated with this client's subnet, nor change the*/ -/* client state. */ -/* */ -/* Permanent client info such as client host name, client mac address */ -/* assigned IP address, or lease time is not cleared (left to the */ -/* caller). */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to DHCP Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful outcome */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_listen_for_messages Handle Client DHCP messages */ -/* _nx_dhcp_fast_periodic_timer_entry Session timer entry function */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_clear_client_session(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -UINT i; - - NX_PARAMETER_NOT_USED(dhcp_ptr); - - dhcp_client_ptr -> nx_dhcp_message_type = 0; - dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0; - dhcp_client_ptr -> nx_dhcp_xid = 0; - dhcp_client_ptr -> nx_dhcp_requested_ip_address = 0x0; - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0x0; - dhcp_client_ptr -> nx_dhcp_your_ip_address = 0x0; - dhcp_client_ptr -> nx_dhcp_clientip_address = 0x0; - dhcp_client_ptr -> nx_dhcp_server_id = 0x0; - dhcp_client_ptr -> nx_dhcp_clientrec_server_ip = 0x0; - dhcp_client_ptr -> nx_dhcp_broadcast_flag_set = NX_DHCP_FLAGS_BROADCAST; - dhcp_client_ptr -> nx_dhcp_session_timeout = 0; - dhcp_client_ptr -> nx_dhcp_destination_ip_address = 0; - dhcp_client_ptr -> nx_dhcp_source_ip_address = 0; - - /* Clear out the option data. */ - dhcp_client_ptr -> nx_dhcp_client_option_count = 0; - for (i = 0; i < NX_DHCP_CLIENT_OPTIONS_MAX; i++) - { - dhcp_client_ptr -> nx_dhcp_user_options[0] = 0; - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcp_clear_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the clear client record */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to DHCP Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful outcome */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_client_record Actual clear client record service */ -/* */ -/* CALLED BY */ -/* */ -/* Host Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -UINT status; - - - /* Check for invalid input. */ - if ((dhcp_ptr == NX_NULL) || (dhcp_client_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCP clear client record service. */ - status = _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_clear_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the entire client record from the server table.*/ -/* It also frees up the client's IP address in the server IP address */ -/* table. */ -/* */ -/* The DHCP server does not use this function, it is strictly for the */ -/* host application to remove clients from the table (e.g. to free up */ -/* room for new clients by removing old 'stale' client entries no */ -/* longer configured with the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to DHCP Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful outcome */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_ip_address_owner Clear IP address owner */ -/* */ -/* CALLED BY */ -/* */ -/* Host Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -UINT i; -NX_DHCP_INTERFACE_TABLE *iface_table_ptr; - - - if (dhcp_client_ptr == 0x0) - { - /* Benign error. Return success. */ - return(NX_SUCCESS); - } - - /* Obtain DHCP Server mutex protection,. */ - tx_mutex_get(&dhcp_ptr -> nx_dhcp_mutex, NX_WAIT_FOREVER); - - /* Set local pointer for convenience. */ - iface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index]; - - i = 0; - - /* Does the client have an assigned IP address? */ - if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address) - { - - /* Yes, We need to free up the Client's assigned IP address in the server database. */ - while (i < iface_table_ptr -> nx_dhcp_address_list_size) - { - - /* Find the interface table entry by matching IP address. */ - if (iface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address == - dhcp_client_ptr -> nx_dhcp_assigned_ip_address) - { - - /* Clear the owner information. */ - _nx_dhcp_clear_ip_address_owner(&(iface_table_ptr -> nx_dhcp_ip_address_list[i])); - - /* Address now available for DHCP client. */ - break; - } - i++; - } - } - - /* Ok to clear the Client record. */ - memset(dhcp_client_ptr, 0, sizeof(NX_DHCP_CLIENT)); - - /* Update the total number of dhcp clients. */ - if (dhcp_ptr -> nx_dhcp_number_clients > 0) - { - - dhcp_ptr -> nx_dhcp_number_clients--; - } - - /* Release DHCP Server mutex. */ - tx_mutex_put(&dhcp_ptr -> nx_dhcp_mutex); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_load_server_options PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the specified options in the server's DHCP option */ -/* list to the DHCP server response to the Client message. There is a */ -/* required set of options that go out with all server messages, as well */ -/* as a standard (user configurable) set of options for all 'ACK' */ -/* messages. Lastly, there are certain options that are specific to the */ -/* client message request e.g. RENEW vs OFFER etc */ -/* */ -/* There is no support for responding to specific client options in this */ -/* revision. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to client session record*/ -/* buffer Packet buffer to load options to*/ -/* option_type Category of options to load */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_add_option Add option to response (specify */ -/* option and data to add)*/ -/* _nx_dhcp_add_requested_option Add option to response */ -/* (specify option and client */ -/* interface) */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_respond_to_dhcp_message Create and send response back */ -/* DHCP Client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_load_server_options(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, UCHAR *buffer, UINT option_type, UINT *index) -{ - -UINT i; -UINT iface_index; -UINT renew_time; -UINT rebind_time; -UINT lease_time; - - - /* Compute default lease, renew and rebind times to offer the client. */ - lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time; - -#if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF) - if (lease_time == 0) -#else - if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME)) -#endif - { - lease_time = NX_DHCP_DEFAULT_LEASE_TIME; - } - - renew_time = lease_time/2; - rebind_time = 7 * (lease_time/8); - - /* Set a local pointer for convenience. */ - iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - - /* Determine what set of options to apply based on caller input. */ - if (option_type == NX_DHCP_OPTIONS_FOR_ALL_REPLIES) - { - - /* This is the generic set of options for ALL server replies. */ - - /* Set the DHCP message type the server is sending back to client. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_TYPE, NX_DHCP_SERVER_OPTION_DHCP_TYPE_SIZE, - dhcp_client_ptr -> nx_dhcp_response_type_to_client, index); - - /* Add the server identifier to all messages to the client. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_SERVER_ID, NX_DHCP_SERVER_OPTION_DHCP_SERVER_SIZE, - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address, index); - - return(NX_SUCCESS); - } - else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER) - { - - /* Offer an IP lease. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index); - /* With the computed renew time. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index); - /* And rebind time. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index); - } - else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST) - { - - /* Confirm the assigned IP lease, renew and rebind times. */ - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_DHCP_LEASE, NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE, lease_time, index); - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_RENEWAL, NX_DHCP_SERVER_OPTION_RENEWAL_SIZE, renew_time, index); - _nx_dhcp_add_option(buffer, NX_DHCP_SERVER_OPTION_REBIND, NX_DHCP_SERVER_OPTION_REBIND_SIZE, rebind_time, index); - } - else if (option_type == NX_DHCP_OPTIONS_FOR_REPLY_TO_INFORM) - { - - /* The NetX DHCP Server reply to Inform messages includes the standard server option - list which is automatically included. */ - } - else if (option_type == NX_DHCP_OPTIONS_FOR_GENERIC_ACK) - { - - /* Add the standard DHCP server information (e.g. subnet, router IP etc) which are - appended to the required server options. */ - for (i= NX_DHCP_REQUIRED_SERVER_OPTION_SIZE; i < dhcp_ptr -> nx_dhcp_server_option_count; i++) - { - - /* Append this DHCP option to the client message. */ - _nx_dhcp_add_requested_option(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index, - buffer, dhcp_ptr -> nx_dhcp_server_options[i], index); - } - } - else if (option_type == NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT) - { - - /* The NetX DHSP Server does not (yet) support this feature in the current release. */ - - /* Clear the current DHCP Client's requested option list. */ - for (i = 0; i < dhcp_client_ptr -> nx_dhcp_client_option_count; i++) - { - - dhcp_client_ptr -> nx_dhcp_user_options[i] = 0; - } - - dhcp_client_ptr -> nx_dhcp_client_option_count = 0; - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_set_default_server_options PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses a set of options from the supplied buffer into */ -/* the server's list of options to supply data to the DHCP Client. If the*/ -/* server is configured to use default option data, it will use this list*/ -/* of options to compose the response to the Client. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* buffer Pointer to option list */ -/* size Size of option list buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual error status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_server_create Create the DHCP Server instance*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_set_server_options(NX_DHCP_SERVER *dhcp_ptr, CHAR *buffer, UINT buffer_size) -{ - -UINT j; -UINT digit; -UINT status; -CHAR *work_ptr; - - - j = 0; - /* Search through the text for all options to load. */ - while(buffer_size && (j < NX_DHCP_SERVER_OPTION_LIST_SIZE)) - { - - /* Check if we're off the end of the buffer. */ - if (buffer == 0x0) - { - break; - } - - work_ptr = buffer; - - /* This should advance the buffer past the digit.*/ - status = _nx_dhcp_parse_next_option(&buffer, &digit, buffer_size); - if (status) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Unable to set server DHCP option data list. Status 0x%x\n", status); -#endif - - return(status); - } - - buffer_size -= (UINT)(buffer - work_ptr); - - /* Load the parsed option into the server 'option list.' */ - dhcp_ptr -> nx_dhcp_server_options[j] = digit; - j++; - } - - /* Update the number of server options in the list. */ - dhcp_ptr -> nx_dhcp_server_option_count = j; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_parse_next_option PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses space or comma separated numeric data from the */ -/* supplied buffer, for example, the server option list. */ -/* */ -/* INPUT */ -/* */ -/* option_list Pointer to buffer to parse */ -/* option Data parsed from buffer */ -/* length Size of option list buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCP_INTERNAL_OPTION_PARSE_ERROR Parsing error status */ -/* */ -/* CALLS */ -/* */ -/* atoi Convert ascii number to integer*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_set_default_server_options Creates the server option list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_parse_next_option(CHAR **option_list, UINT *option, UINT length) -{ - -CHAR c; -UINT j; -UINT buffer_index; -CHAR num_string[3]; -CHAR *buffer; - - - /* Check for invalid input. */ - if ((option_list == 0x0) || (option == 0) || (length == 0)) - { - return(NX_DHCP_INTERNAL_OPTION_PARSE_ERROR); - } - - buffer = *option_list; - memset(&num_string[0], 0, 3); - - /* Initialize parsed option to undefined option (sorry, zero is taken by the PAD option - which I personally think was a bad programming decision). */ - *option = 999; - j = 0; - buffer_index = 0; - - /* Get the first character in the buffer. */ - c = *buffer++; - - /* Get the first digit (non separator character)*/ - while ((c == ' ') || (c == ',')) - { - - c = *buffer++; - j++; - } - - /* Now parse the next characters until the end of the buffer or next separator character. */ - while ((j < length) && (buffer_index < 3)) - { - - /* Check for separator marking the end of the option string. */ - if ((c == ' ') || (c == ',') || (c == 0x0)) - break; - - /* Check for an invalid digit or out of range option. */ - if (c < 0x30 || c > 0x39 || buffer_index > 2) - { - return(NX_DHCP_BAD_OPTION_LIST_ERROR); - } - - num_string[buffer_index] = c; - j++; - - /* Append the character ('digit') into a number buffer. */ - c = *buffer++; - buffer_index++; - } - - *option_list += j; - - /* Convert the number string to an actual integer. */ - *option = (UINT) atoi(num_string); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a Client DHCP message and extracts */ -/* information from a client DHCP message to create or update the */ -/* client record. It handles the DHCP message based on type, sets */ -/* a timer on the client record if a response is expected from the */ -/* client, and waits for another DHCP packet. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Message handled successfully */ -/* NO_PACKET No packet received */ -/* NX_DHCP_SERVER_BAD_INTERFACE_INDEX Packet interface not recognized*/ -/* status Actual completion outcome */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release DHCP packet */ -/* nx_udp_socket_receive Receive DHCP packet */ -/* _nx_dhcp_server_extract_information Extract DHCP packet info */ -/* _nx_dhcp_validate_client_message Process the Client message */ -/* _nx_dhcp_server_assign_ip_address Assign IP address to Client */ -/* _nx_dhcp_respond_to_client_message Create and send response back */ -/* _nx_dhcp_clear_client_session Clears client session data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_server_thread_entry DHCP Server thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_server_packet_process(NX_DHCP_SERVER *dhcp_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -UINT iface_index; -NX_DHCP_CLIENT *dhcp_client_ptr = NX_NULL; -NX_PACKET *new_packet_ptr; -ULONG bytes_copied = 0; -ULONG offset; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\n"); - EL_PRINTF("DHCPserv: Waiting to receive next packet\n"); -#endif - - /* Check for minimum sized DHCP packet (e.g. just the DHCP header and 0 bytes of option data). */ - if (packet_ptr -> nx_packet_length < NX_DHCP_HEADER_SIZE) - { -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Client DHCP packet is malformed or empty. Invalid DHCP packet.\n"); -#endif - - /* No; Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return successful completion status. */ - return(NX_DHCP_MALFORMED_DHCP_PACKET); - } - - /* Get the interface index. */ - nx_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index); - - /* Does the DHCP server have a table for this packet interface? */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: No interface found for DHCP packet\n"); -#endif - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* No, return the error status. */ - return(NX_DHCP_SERVER_BAD_INTERFACE_INDEX); - } - - /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release - the packet from the receive packet pool as soon as possible. */ - status = nx_packet_allocate(dhcp_ptr -> nx_dhcp_packet_pool_ptr, &new_packet_ptr, NX_IPv4_UDP_PACKET, NX_DHCP_PACKET_ALLOCATE_TIMEOUT); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Error allocating packet, return error status. */ - return(status); - } - - /* Verify the incoming packet does not exceed our DHCP Server packet payload. */ - if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length)) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the newly allocated packet and return an error. */ - nx_packet_release(new_packet_ptr); - - return(NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD); - } - - /* Update the prepend pointer to make sure that the IP header and UDP header also are copied into new packet. */ - packet_ptr -> nx_packet_prepend_ptr -= 28; - packet_ptr -> nx_packet_length += 28; - - /* Initialize the offset to the beginning of the packet buffer. */ - offset = 0; - status = nx_packet_data_extract_offset(packet_ptr, offset, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); - - /* Check status. */ - if ((status != NX_SUCCESS) || (bytes_copied != packet_ptr -> nx_packet_length)) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the allocated packet we'll never send. */ - nx_packet_release(new_packet_ptr); - - /* Error extracting packet buffer, return error status. */ - return(status); - } - - /* Update the new packet with the bytes copied, and removed. - For chained packets, this will reflect the total 'datagram' length. */ - new_packet_ptr -> nx_packet_prepend_ptr += 28; - new_packet_ptr -> nx_packet_length = bytes_copied - 28; - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + new_packet_ptr -> nx_packet_length; - - /* Now we can release the original packet. */ - nx_packet_release(packet_ptr); - - /* Extract the DHCP specific information from the packet. This will create new record or update existing - client record in the server database. */ - status = _nx_dhcp_server_extract_information(dhcp_ptr, &dhcp_client_ptr, new_packet_ptr, iface_index); - -#ifdef PACKET_DUMP -{ - - ULONG *work_ptr; - ULONG uword; - UINT i = 0; - UINT index = 0; - UINT length; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: received client packet dump:\n"); -#endif - - /* Get a pointer to the IP header and adjust the packet length for IP and UDP header size. */ - work_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); - length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)) + sizeof(NX_UDP_HEADER) + sizeof(NX_IPV4_HEADER); - - while(i < length) - { - uword = *work_ptr; - - if (index == 10) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\n"); -#endif - index = 0; - } -#ifdef EL_PRINTF_ENABLE - EL_PRINTF(" %08x", uword); -#endif - work_ptr++; - index++; - i++; - } -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\n\n"); -#endif -} -#endif /* #ifdef PACKET_DUMP */ - - /* We are done with this packet now regardless of the success of the above operations. */ - nx_packet_release(new_packet_ptr); - - /* Check if we have an invalid client record. */ - if ((status != NX_SUCCESS) && dhcp_client_ptr) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Error extracting DHCP packet (invalid): 0x%x\n", status); -#endif - - /* Client record was created but there was a problem with the packet - or client message. Since we're not sure what got written to the Client record, - remove packet data out completely. */ - _nx_dhcp_clear_client_record(dhcp_ptr, dhcp_client_ptr); - } - - /* Check for general errors or failure to produce a client record. */ - if ((status != NX_SUCCESS) || !dhcp_client_ptr) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Internal error extracting DHCP packet: 0x%x\n", status); -#endif - - /* Return the error from extracting packet data. */ - return(status); - } - - /* Clear any previous response type in the client record. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = 0; - - /* Validate the client message including how the server should respond to it. */ - status = _nx_dhcp_validate_client_message(dhcp_ptr, dhcp_client_ptr); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: DHCP packet failed validation: 0x%x\n", status); -#endif - - /* Return all other errors as completion status. Do not send a message to the client. */ - return(status); - } - - /* Assign/confirm the assigned IP address of the Client if the server is not returning - a NACK, responding to an INFORM message, or not responding at all. */ - if ((dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPNACK) && - (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT) && - (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPINFORM)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: assigning IP address to DHCP client...\n"); -#endif - - /* Assign/confirm an IP address to the client. If the client is renewing or rebinding - this will verify they sent the correct IP address and reset the lease time. */ - status = _nx_dhcp_server_assign_ip_address(dhcp_ptr, dhcp_client_ptr); - - /* Has the server run out of available addresses? Handle this 'error' - condition separately. */ - if (status == NX_DHCP_NO_AVAILABLE_IP_ADDRESSES) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Unable to assign IP address; none available\n"); -#endif - - /* Actually as yet, there is no callback to the host application - for handling this situation. - - The server should still send a NACK to the Client that it cannot - provide what it requests. */ - } - /* Check for errors other than running out of available IP addresses. */ - else if (status != NX_SUCCESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Unable to assign IP address. Status: 0x%x\n", status); -#endif - - /* Return all other errors as completion status. Do not send a message to the client. */ - return(status); - } - } - -#ifdef EL_PRINTF_ENABLE - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPOFFER) - EL_PRINTF("DHCPserv: response to client: OFFER\n"); - else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) - EL_PRINTF("DHCPserv: response to client: ACK\n"); - else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK) - EL_PRINTF("DHCPserv: response to client: NACK\n"); - else if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPSILENT) - EL_PRINTF("DHCPserv: response to client: SILENT (no response)\n"); -#endif - - - /* Is there a response to send to the Client? */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client != NX_DHCP_TYPE_DHCPSILENT) - { - - /* Yes; use the session data in the client record to compose the server reply. */ - status = _nx_dhcp_respond_to_client_message(dhcp_ptr, dhcp_client_ptr); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Error sending response to DHCP client. Status: 0x%x\n", status); -#endif - - /* Return error completion status. Error sending a message to client. */ - return(status); - } - - /* Update the client state if an ACK was sent successfully. */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPACK) - { - - /* Was the client was in a requesting, renewing or rebinding state? */ - if ((dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_RENEWING) || - (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REBINDING) || - (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_REQUESTING)) - { - - /* Yes, the client should now be bound to an IP address. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOUND; - } - } - } - - /* - If the Client is BOUND, the session is over. Clear the session including - the sesison timeout. - - If the Client is still in the BOOT or INIT state something was wrong with their - message or else the server had a problem. Clear the record and they - can start a new session with a retransmission of their request. - */ - - /* Do we need to clear the session data depending? */ - if (dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOOT || - dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_INIT || - dhcp_client_ptr -> nx_dhcp_client_state == NX_DHCP_STATE_BOUND) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: client session completed. Clear session data.\n"); -#endif - - /* Yes, clear all data from the session. Client assigned IP address - and hardware address are not cleared.*/ - _nx_dhcp_clear_client_session(dhcp_ptr,dhcp_client_ptr); - } - else - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Waiting for DHCP client response...\n"); -#endif - - /* No; assume the Client is Renewing, rebinding, or selecting, - to set the session timeout to await the next Client response; - (not finished with this DHCP session yet). */ - - /* Assume we have received at least one message from the Client, so - reset the timer on the client session timeout. */ - dhcp_client_ptr -> nx_dhcp_session_timeout = NX_DHCP_CLIENT_SESSION_TIMEOUT; - } - - -/* Output Server session data if enabled. */ -#ifdef TESTOUTPUT - add_client++; - - /* Only print out the session table depending on trace interval. */ - if ((TRACE_NTH_CLIENT_PACKET > 0) && (add_client % TRACE_NTH_CLIENT_PACKET == 0)) - { - - UINT i; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\nClient\t\tAssigned\tLease\t\tSession\tState\n"); -#endif - for (i = 0; i < dhcp_ptr -> nx_dhcp_number_clients; i++) - { - NX_DHCP_CLIENT *client_ptr; - - client_ptr = &(dhcp_ptr -> client_records[i]); - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("0x%x 0x%x\t0x%08x\t0x%08x\t%d\t%d\n", - client_ptr -> nx_dhcp_client_mac_msw, - client_ptr -> nx_dhcp_client_mac_lsw, - client_ptr -> nx_dhcp_assigned_ip_address, - client_ptr -> nx_dhcp_requested_lease_time, - client_ptr -> nx_dhcp_session_timeout, - client_ptr -> nx_dhcp_client_state); -#endif - } - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("\nHost\tIP address\tAssigned? Lease\n"); - EL_PRINTF("Interface 0\n"); - for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_address_list_size; i++) - { - NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; - - interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[0].nx_dhcp_ip_address_list[i]); - EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n", - interface_address_ptr -> owner_mac_msw, - interface_address_ptr -> owner_mac_lsw, - interface_address_ptr -> nx_assignable_ip_address, - interface_address_ptr -> assigned, - interface_address_ptr -> lease_time); - } - - EL_PRINTF("\nInterface 1\n"); - for (i = 0; i < dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_address_list_size; i++) - { - NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; - - interface_address_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[1].nx_dhcp_ip_address_list[i]); - EL_PRINTF("0x%x 0x%x\t0x%x\t%d\t 0x%x\n", - interface_address_ptr -> owner_mac_msw, - interface_address_ptr -> owner_mac_lsw, - interface_address_ptr -> nx_assignable_ip_address, - interface_address_ptr -> assigned, - interface_address_ptr -> lease_time); - } -#endif - } -#endif - - /* Return actual outcome status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_find_client_record_by_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function looks up a client record using the client's last known*/ -/* assigned IP address. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP server */ -/* dhcp_client_ptr Pointer to DHCP client */ -/* iface_index Client network interface index*/ -/* assigned_ip_address Client's assigned IP address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_DHCP_CLIENT_RECORD_NOT_FOUND Client record not found in */ -/* Server database */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_client_record Remove Client record from */ -/* Server database */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcp_find_client_record_by_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, - UINT iface_index, ULONG assigned_ip_address) -{ - -UINT i; -NX_DHCP_CLIENT *client_record_ptr; - - - /* Initialize the search results to unsuccessful. */ - *dhcp_client_ptr = NX_NULL; - - i = 0; - - /* Records are not necessarily added and deleted sequentially, - so search the whole table until a match is found. */ - while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE) - { - /* Set local pointer for convenience. */ - client_record_ptr = &dhcp_ptr -> client_records[i]; - - /* Check the mac address for a match. */ - if (client_record_ptr -> nx_dhcp_assigned_ip_address == assigned_ip_address) - { - - /* Verify the client packet interface matches the interface on record. */ - if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index) - { - /* Return the client record location. */ - *dhcp_client_ptr = client_record_ptr; - - return(NX_SUCCESS); - } - else - { - - /* It appears the client has changed its subnet location but not hardware type e.g. - same mac address/hardware type but not interface. Clear the old record. */ - - /* This will remove the client record both in the - server's client table and in the IP address database. */ - _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr); - - /* Search through the rest of the server records for - another instance of this client. Either way, if not found - with the expected interface a null pointer is returned, - or new record created depending on the caller. */ - } - } - i++; - } - - return(NX_DHCP_CLIENT_RECORD_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function looks up a client record by the client hardware mac */ -/* address. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* iface_index Client interface index */ -/* client_mac_msw MSB of client hardware address*/ -/* client_mac_lsw LSB of client hardware address*/ -/* dhcp_client_ptr Pointer to client record entry*/ -/* add_on Option to add if not found */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Message handled successfully */ -/* NX_DHCP_CLIENT_TABLE_FULL No more room in Client table */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_client_record Removes client record from */ -/* server table */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_server_extract_information Extract DHCP info from Client */ -/* message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_find_client_record_by_chaddr(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG client_mac_msw, - ULONG client_mac_lsw, NX_DHCP_CLIENT **dhcp_client_ptr, UINT add_on) -{ - -UINT i; -UINT available_index; -NX_DHCP_CLIENT *client_record_ptr; - - - /* Initialize the search results to unsuccessful. */ - *dhcp_client_ptr = NX_NULL; - - /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */ - available_index = NX_DHCP_CLIENT_RECORD_TABLE_SIZE; - - /* Records are not necessarily added and deleted sequentially, - so search the whole table until a match is found. */ - i = 0; - while (i < NX_DHCP_CLIENT_RECORD_TABLE_SIZE) - { - - /* Set local pointer for convenience. */ - client_record_ptr = &dhcp_ptr -> client_records[i]; - - /* Skip empty records. Assume a client with no mac address is empty. */ - if ((client_record_ptr -> nx_dhcp_client_mac_msw == 0) && (client_record_ptr -> nx_dhcp_client_mac_lsw == 0)) - { - - /* Flag the first empty record in case we need to add the current client to the table. */ - if (i < available_index) - available_index = i; - - i++; - continue; - } - - /* Check the mac address of each record for a match. */ - if ((client_record_ptr -> nx_dhcp_client_mac_msw == client_mac_msw) && - (client_record_ptr -> nx_dhcp_client_mac_lsw == client_mac_lsw)) - { - - /* Verify the client packet interface matches the interface on record. */ - if (client_record_ptr -> nx_dhcp_client_iface_index == iface_index) - { - /* Return the client record location. */ - *dhcp_client_ptr = client_record_ptr; - - return(NX_SUCCESS); - } - else - { - - /* It appears the client has changed its location (subnet) but not hardware type e.g. same mac - address/hware type but not interface. Remove the client record entirely and - free up any assigned IP address in the server database. */ - _nx_dhcp_clear_client_record(dhcp_ptr, client_record_ptr); - - /* Continue searching through the rest of the server records for - another instance of this client. Either way, if not found - with the expected interface a null pointer is returned, - or new record created depending on the caller. */ - } - } - - i++; - } - - /* Not found. Create a record for this client? */ - if (add_on == NX_FALSE) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Client HW address not found. Do not add to server database\n"); -#endif - - /* No, we're done then. */ - return(NX_SUCCESS); - } - - /* Check if there is available room in the table for a new client. */ - if (available_index >= NX_DHCP_CLIENT_RECORD_TABLE_SIZE) - { - - /* No, we cannot add this client so the server's table. */ - return(NX_DHCP_CLIENT_TABLE_FULL); - } - - /* Set local pointer to an available slot. */ - client_record_ptr = &dhcp_ptr -> client_records[available_index]; - - /* Add this client to the server's total number of clients. */ - dhcp_ptr -> nx_dhcp_number_clients++; - - /* Add the supplied information to the new client record. */ - client_record_ptr -> nx_dhcp_client_mac_msw = client_mac_msw; - client_record_ptr -> nx_dhcp_client_mac_lsw = client_mac_lsw; - client_record_ptr -> nx_dhcp_client_iface_index = iface_index; - - /* Initialize the client state as the init state. */ - client_record_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - /* Return the location of the newly created client record. */ - *dhcp_client_ptr = client_record_ptr; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_find_interface_table_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function looks up a table entry by IP address in the specified */ -/* server interface table. If not found, a NULL entry pointer is */ -/* returned but successful search completion. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* iface_index Network interface index */ -/* ip_address IP address to look up */ -/* return_interface_address Pointer to table entry */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Message handled successfully */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_client_record Removes client record from */ -/* server table */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_server_extract_information Extract DHCP info from Client */ -/* message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_find_interface_table_ip_address(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG ip_address, - NX_DHCP_INTERFACE_IP_ADDRESS **return_interface_address) -{ - -UINT i; -NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; - - - /* Initialize search results to NULL (not found). */ - *return_interface_address = NX_NULL; - - /* Set a local varible to the IP address list for this client. */ - dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[iface_index]); - - /* Yes, search for an available ip address in the IP list for this interface */ - for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++) - { - - /* Is this address a match? */ - if (dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i].nx_assignable_ip_address == ip_address) - { - /* Yes, set a pointer to the location and return. */ - *return_interface_address = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; - - /* And we're done! */ - return(NX_SUCCESS); - } - } - - /* Not found, so return null pointer and successful search status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_update_assignable_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the IP address status in the server interface */ -/* table address for the current client. This will return an error */ -/* status if the IP address being updated is not owned by the client. */ -/* */ -/* Note: No changes are made to the associated client record. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to DHCP client */ -/* ip_address IP address to update */ -/* assign_status Status to assign */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Entry updated successfully */ -/* NX_DHCP_IP_ADDRESS_NOT_FOUND IP address not found */ -/* NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER IP address not assigned to */ -/* current client */ -/* NX_DHCP_INVALID_UPDATE_ADDRESS_CMD Unknown status input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_find_interface_table_ip_address */ -/* Find IP address in server */ -/* interface table */ -/* _nx_dhcp_find_ip_address_owner Verify Client is address owner */ -/* _nx_dhcp_clear_ip_address_owner Clear IP address owner */ -/* _nx_dhcp_record_ip_address_owner Sets Client as IP address owner */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_validate_client_message Process DHCP Client message*/ -/* _nx_dhcp_fast_periodic_timer_entry Timer on client sessions */ -/* _nx_dhcp_slow_periodic_timer_entry Timer on IP address leases */ -/* message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_update_assignable_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr, - ULONG ip_address, UINT assign_status) -{ - -UINT iface_index; -UINT assigned_to_client; -UINT lease_time; -NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; - - - /* Create a local variable for convenience. */ - iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - - /* Look up the IP address in the server interface IP address table. */ - _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, iface_index, ip_address, &interface_address_ptr); - - /* Was it found? */ - if (interface_address_ptr == 0x0) - { - - /* No, return an error status address not found. */ - return(NX_DHCP_IP_ADDRESS_NOT_FOUND); - } - - /* Is the Client releasing IP address? */ - if (assign_status == NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE) - { - - /* Check if owner of this IP address matches with this client's record. */ - _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client); - - /* Is the IP address owned (leased) to this client? */ - if (assigned_to_client == NX_FALSE) - { - - /* No, this IP address is assigned to another host. We cannot change - the IP address status. */ - return(NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER); - } - - /* Yes, clear the owner information. */ - _nx_dhcp_clear_ip_address_owner(interface_address_ptr); - } - - /* Was the IP address assigned externally from the DHCP process? */ - else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT) - { - - /* Check the lease time. */ - if (interface_address_ptr -> lease_time) - { - /* If this already has a lease time (because we assigned it most likely) don't change it. */ - lease_time = interface_address_ptr -> lease_time; - } - else - { - /* Otherwise, make this lease time infinity e.g. the time out will not expire on it.*/ - lease_time = NX_WAIT_FOREVER; - } - - /* Set the current client as the owner. */ - _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time); - } - - /* Is the client informing us the IP address is already in use (e.g. it has - sent the server a DECLINE message) or accepting another DHCP server's offer? */ - else if (assign_status == NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER) - { - - /* Yes; Is the client is declining the IP address? */ - if (dhcp_client_ptr -> nx_dhcp_message_type == NX_DHCP_TYPE_DHCPDECLINE) - { - - /* Yes, remove the Client as owner of this IP lease. - Record owner information with null 'owner' ID since we don't know who the owner is. */ - _nx_dhcp_record_ip_address_owner(interface_address_ptr, NX_NULL, NX_WAIT_FOREVER); - } - else - { - - /* Record owner information. */ - _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, NX_WAIT_FOREVER); - } - } - else - { - - /* Received an invalid update address command. */ - return(NX_DHCP_INVALID_UPDATE_ADDRESS_CMD); - } - - /* Successful completion! */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_find_ip_address_owner PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the owner of the specified IP address and checks*/ -/* it against the specified client record to insure the client is the */ -/* owner of the IP address. The result of the search is updated in the */ -/* assigned_to_client pointer. */ -/* */ -/* INPUT */ -/* */ -/* iface_owner Pointer to table entry */ -/* dhcp_client_ptr Pointer to DHCP client */ -/* assign_status Status to assign */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Table searched successfully */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ -/* the server database */ -/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ -/* current client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_find_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT *assigned_to_client) -{ - - - /* Initialize the value. */ - *assigned_to_client = NX_FALSE; - - /* Compare the owner in the interface table entry with the client record mac address. */ - if ((iface_owner -> owner_hwtype == client_record_ptr -> nx_dhcp_client_hwtype) && - (iface_owner -> owner_mac_msw == client_record_ptr -> nx_dhcp_client_mac_msw) && - (iface_owner -> owner_mac_lsw == client_record_ptr -> nx_dhcp_client_mac_lsw)) - { - - /* They match; This verifies the IP address is assigned to this client. */ - *assigned_to_client = NX_TRUE; - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_record_ip_address_owner PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function fills in the address owner in the interface table from*/ -/* the specified client record. */ -/* */ -/* INPUT */ -/* */ -/* iface_owner Pointer to table entry */ -/* client_record_ptr Pointer to DHCP client */ -/* lease_time Lease duration in secs */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Table searched successfully */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ -/* the server database */ -/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ -/* current client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_record_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner, NX_DHCP_CLIENT *client_record_ptr, UINT lease_time) -{ - - /* Check the client_record_ptr. */ - if (client_record_ptr) - { - - /* Parse the mac address and hardware type from the client record. */ - iface_owner -> owner_hwtype = client_record_ptr -> nx_dhcp_client_hwtype; - iface_owner -> owner_mac_msw = client_record_ptr -> nx_dhcp_client_mac_msw; - iface_owner -> owner_mac_lsw = client_record_ptr -> nx_dhcp_client_mac_lsw; - } - else - { - - /* We don't know who the owner is, set the owner information as zero. */ - iface_owner -> owner_hwtype = 0; - iface_owner -> owner_mac_msw = 0; - iface_owner -> owner_mac_lsw = 0;; - } - - /* Record the lease time. */ - iface_owner -> lease_time = lease_time; - - /* Set the assigned status. */ - iface_owner -> assigned = NX_TRUE; - - /* Return. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_clear_ip_address_owner PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the address owner information. */ -/* */ -/* INPUT */ -/* */ -/* iface_owner Pointer to table entry */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_slow_periodic_timer_entry Update IP lease time outs */ -/* _nx_dhcp_clear_client_record Clear Client record */ -/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ -/* the server database */ -/* _nx_dhcp_server_assign_ip_address Assign an IP address to the */ -/* current client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_clear_ip_address_owner(NX_DHCP_INTERFACE_IP_ADDRESS *iface_owner) -{ - - /* Clear the owner information. */ - iface_owner -> owner_hwtype = 0; - iface_owner -> owner_mac_msw = 0; - iface_owner -> owner_mac_lsw = 0; - - /* Clear the lease time. */ - iface_owner -> lease_time = 0; - - /* Clear the assigned status. */ - iface_owner -> assigned = NX_FALSE; - - /* Return. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_validate_client_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function verifies the client message is a valid DHCP request, */ -/* determines if an IP address need to be assigned, what state the DHCP*/ -/* Client should be advanced to, and what the server DHCP response type*/ -/* should be. in the client record the specified client record. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_ptr Pointer to DHCP Server */ -/* client_record_ptr Pointer to DHCP client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Table searched successfully */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ -/* the server database */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_listen_for_messages Listen for, process and respond*/ -/* to DHCP Client messages */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_validate_client_message(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -ULONG server_ip_address; -UINT iface_index; -NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; - - - /* Create a local variable for the client's interface for convenience. */ - iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - dhcp_interface_table_ptr = &dhcp_ptr -> nx_dhcp_interface_table[iface_index]; - - if (dhcp_client_ptr -> nx_dhcp_xid == 0x0) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: DHCP packet missing transaction ID. Reject the packet silently. \n"); -#endif - - /* Return the request denied message to clients and return. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - return(NX_SUCCESS); - } - - /* Client messages should never fill in the "Your (Client) IP" or "Next Server IP" fields. */ - else if ((dhcp_client_ptr -> nx_dhcp_your_ip_address != NX_DHCP_NO_ADDRESS) || - (dhcp_client_ptr -> nx_dhcp_clientrec_server_ip != NX_DHCP_NO_ADDRESS)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! 'Your IP'/'Server IP' fields should not be filled in.\n"); -#endif - - /* Return the 'request denied' message to the client. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - } - - /* Check for missing required fields. */ - else if ((dhcp_client_ptr -> nx_dhcp_client_hwtype == 0) || - (dhcp_client_ptr -> nx_dhcp_client_hwlen == 0)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! DHCP packet missing MAC and/or hardware type\n"); -#endif - - /* Return the request denied message to clients and return. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - } - - else - { - - /* Do validation specific the for message type. This section will also - advance the Client DHCP state and set the server response message type. - */ - switch (dhcp_client_ptr -> nx_dhcp_message_type) - { - - - case NX_DHCP_TYPE_DHCPDISCOVER: - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received DISCOVER message\n"); -#endif - - /* Determine if server needs to assign an IP address based on assigned IP address. - e.g. If this appears to be a retransmission of a previous IP address DISOVERY request, - only assign another IP address if the client appears not to have been assigned one already.*/ - /* Initialize response back to be an offer pending validation check. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPOFFER; - - /* Check for invalid IP address field(s). */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Client IP address field must not be filled in.\n"); -#endif - - /* Let the client know it has an invalid request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - } - else - { - - /* DHCP client state advances to SElECTING state. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_SELECTING; - } - - break; - } - - case NX_DHCP_TYPE_DHCPREQUEST: - { - - - /* This is a more complex message since a client request can be generated from - 4 different states: boot, selecting, renew, rebind. This requires that - we determine the Client state based on what's previously known about - the client and which fields are filled in the Request message. */ - - /* Get the DHCP server IP address for the client package interface. */ - server_ip_address = dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_server_ip_address; - - /* Get the index of the client packet interface. */ - iface_index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - - /* If the client does not specify a server id but is requesting an IP address... */ - if ((dhcp_client_ptr -> nx_dhcp_server_id == 0) && - (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received REQUEST (BOOT state) message\n"); -#endif - /* ...Then it is in the boot state as per RFC 2131 4.3.2 (requests - an IP address but is skipping the DISCO message). */ - - /* This client may NOT specify a Client IP address e.g. that field must - be left blank. */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n"); -#endif - - /* Let the client know it has an invalid request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - break; - } - - /* Server SHOULD send a DHCPNAK message to the client if the 'requested IP address' is incorrect, or is on the wrong network. - RFC 2131, Section 4.3.2, Page31. */ - if ((dhcp_client_ptr -> nx_dhcp_assigned_ip_address != 0) && - (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address)) - { - - ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message contains incorrect requested IP address. \n"); -#endif - - /* No; invalid request. Return the IP address tentatively assigned to - the client back to the available IP address pool. */ - - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, - NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); - - /* Clear requested IP lease time because the client is not granted an IP address lease. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - /* Let the client know it made an invalid request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - break; - } - - /* Set the client state to the BOOT state */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_BOOT; - - /* Indicate the server will grant the IP lease. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; - - /* Advance the client state to requesting (waiting for an ACK). */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING; - break; - } - /* Else if the client is specifying a server id, and a requested IP address... */ - else if (dhcp_client_ptr -> nx_dhcp_server_id && - (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received REQUEST (SELECT state) message\n"); -#endif - - /* ...Then the client is in the SELECT state as per RFC 2131 4.3.2 (sent a - DISCOVERY message and is responding to a server OFFER message). */ - - /* Client may NOT specify a Client IP address. */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address != NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message may not specify Client IP address.\n"); -#endif - - /* Let the client know it has an invalid request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - break; - } - - /* Check if the Client has chosen this server's offer (e.g.server ID option in the - REQUEST message). */ - if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip_address) - { - - ULONG ip_address_assigned; - - /* We are not. */ - - /* Is the Client accepting the same IP address this server offered? */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == dhcp_client_ptr -> nx_dhcp_requested_ip_address) - { - - /* Yes, so do not change the client record IP address and IP address - status in the server interface table as assigned. */ - ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; - } - else - { - - /* No, it is accepting a different IP address from another server. */ - ip_address_assigned = dhcp_client_ptr -> nx_dhcp_requested_ip_address; - - /* So update the client record's assigned address to the one it is accepting - from another server. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address; - } - - /* Update the server interface table with the information. */ - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, - NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER); - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: SILENCE! REQUEST message indicates Client accepting another server IP.\n"); -#endif - - /* If this client wants an IP address from this server it must start - over at the init state. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - /* No need to respond. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - - return(NX_SUCCESS); - } - - /* Make sure the Client did in fact receive an OFFER from this server (e.g. has - been tentatively assigned an IP address from us). */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message does not indicate valid assigned IP address.\n"); -#endif - - /* It did not. This is an invalid request. Let the client know. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - - /* Clear requested IP lease times because the client was not assigned an IP address. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - /* Nothing more to do! */ - break; - } - - /* Does the Client's requested IP address match the "Your IP" field in the server OFFER - previously sent to this client (e.g. Client's assigned IP address)? */ - else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address != dhcp_client_ptr -> nx_dhcp_requested_ip_address) - { - - ULONG ip_address_assigned = dhcp_client_ptr -> nx_dhcp_assigned_ip_address; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message contains requested IP address. \n"); -#endif - - /* No; invalid request. Return the IP address tentatively assigned to - the client back to the available IP address pool. */ - - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, ip_address_assigned, - NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); - - /* Clear requested IP lease time because the client is not granted an IP address lease. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - /* Let the client know it made an invalid request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - break; - } - - /* The Client accepts this Server's offer. We will grant the client the IP lease now. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; - - /* UPdate the client state to REQUESTING (waiting on an ACK). */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REQUESTING; - } - - /* Is this a RENEW or REBIND request? If so the server ID and requested IP options must - NOT be filled in as per RFC 2131 4.3.2. */ - else if ((dhcp_client_ptr -> nx_dhcp_server_id == NX_DHCP_NO_ADDRESS) && - (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS)) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received REQUEST (RENEW/REBIND state) message\n"); -#endif - - /* Yes, this is a renew/rebind request! */ - - /* Extending an IP lease is a administration decision vs RFC mandate. The - NetX DHCP Server automatically extends IP leases. */ - - /* Go ahead and ACK the renew request pending any DHCP violations. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; - - /* The "Client IP" address field MUST be filled in. */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message no 'Client IP' address specified. \n"); -#endif - - /* This is an invalid renew/rebind request. Reject the request but - do not change or advance the Client state (SHOULD be bound). */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - - break; - } - - /* The "Client IP" address subnet should match the Client packet source IP address subnet. */ - if ((dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_client_ptr -> nx_dhcp_clientip_address) != - (dhcp_interface_table_ptr -> nx_dhcp_subnet_mask & dhcp_interface_table_ptr -> nx_dhcp_server_ip_address)) - { -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message; the 'Client IP' address subnet does not match the DHCP server subnet. \n"); -#endif - - /* This is an invalid renew/rebind request. Reject the request but - do not change or advance the Client state (SHOULD be bound). */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - break; - } - - /* Is there an assigned IP address in the Client record? */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! REQUEST message; server has no record of assigned IP address.\n"); -#endif - - /* No; possibly assigned by another DHCP server or outside of DHCP protocol. - Reject the renewal request. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - - /* This client needs to start the configuration process with this - server from the INIT start if it wants an IP address from it. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - break; - } - - /* Determine if this is a renew or a rebind request. */ - if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received REQUEST (renewing) message\n"); -#endif - - /* Renewing: DHCP clients' renew requests must be unicast. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_RENEWING; - } - else - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received REQUEST (rebinding) message\n"); -#endif - - /* Rebinding DHCP clients' rebind request must be broadcast. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_REBINDING; - } - } - else - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Received unknown REQUEST message type.\n"); -#endif - - /* Do not respond to unknown requests. This is kind of a dealer's choice - because it is not specified in the RFC 2132 how to handle undefined - request IDs or message types. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - return(NX_SUCCESS); - } - - break; - } - - case NX_DHCP_TYPE_DHCPRELEASE: - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received RELEASE response type.\n"); -#endif - - - /* The Client is releasing it's IP address back to the server. A client is not - required to do this; usually it indicates the client may have moved on the - network. - - Clear the client record and mark the IP address as available. If the request proves - invalid, this server will ignore it and let the Client's assigned IP lease expire. */ - - /* Regardless what happens the server does not send a reply to a RELEASE message. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - - /* Was an address previously assigned? */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) - { - - /* No; nothing to do here. */ - return(NX_SUCCESS); - } - - /* The client IP field must be filled in for RELEASE requests. Was it? */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) - { - - /* No; This is an invalid release request. */ - return(NX_SUCCESS); - } - - /* Does client IP field match what this Server assigned the Client? */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address != dhcp_client_ptr -> nx_dhcp_assigned_ip_address) - { - - /* No; Not sure how this happened but let the existing assigned - IP address lease expire. Ignore this message. */ - return(NX_SUCCESS); - } - - /* A RELEASE request must be unicasted to the server. Was this a broadcast - message? */ - if (dhcp_client_ptr -> nx_dhcp_destination_ip_address == NX_DHCP_BC_ADDRESS) - { - - /* Yes, so not a valid RELEASE request. */ - return(NX_SUCCESS); - } - else - { - - UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address; - - /* Check that we are the intended server. */ - if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != server_ip) - { - - /* We are not. Not a valid Release request. */ - return(NX_SUCCESS); - } - } - - /* Legitimate release request: return the IP address to the available pool, - and clear the client session. */ - - /* Release the client's assigned IP address (in the "CI-ADDR" field). */ - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, - dhcp_client_ptr -> nx_dhcp_assigned_ip_address, - NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE); - - /* Clear the Client's assigned IP address. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - /* If this client wants to configure its network parameters with us it - must start at the INIT state. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - - break; - } - - case NX_DHCP_TYPE_DHCPDECLINE: - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received DECLINE response type.\n"); -#endif - - /* The Client is informing us an IP address we assigned to it is apparently already - in use by another host. It needs to restart in the INIT/BOOT state for this - server to assign it another IP address. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - /* Regardless what happens do not send a reply. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - - /* If no address previously assigned, silently ignore this message. */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address == NX_DHCP_NO_ADDRESS) - { - - /* This client never had an address assigned by this server. Do nothing. */ - return(NX_SUCCESS); - } - - /* A DECLINE message must specify the requested address. */ - if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS) - { - - /* This is an invalid decline request. Reject it silently. */ - return(NX_SUCCESS); - } - - /* A Decline request is supposed to be unicasted to the server. If it is not, - ignore it. */ - if (dhcp_client_ptr -> nx_dhcp_destination_ip_address != NX_DHCP_BC_ADDRESS) - { - - return(NX_SUCCESS); - } - else - { - - UINT index = dhcp_client_ptr -> nx_dhcp_client_iface_index; - ULONG server_ip = (&dhcp_ptr -> nx_dhcp_interface_table[index]) ->nx_dhcp_server_ip_address; - - /* Check that we are the intended server. */ - if (dhcp_client_ptr -> nx_dhcp_server_id != server_ip) - { - - /* We are not. Ignore the request. */ - return(NX_SUCCESS); - } - } - - /* Release the client's assigned IP address. */ - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, - dhcp_client_ptr -> nx_dhcp_assigned_ip_address, - NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER); - - /* Clear the Client's assigned IP address. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - break; - } - - case NX_DHCP_TYPE_DHCPINFORM: - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: Received INFORM response type.\n"); -#endif - - - /* A DHCP client sends an INFORM message when it has been assigned an IP address - with another server or outside DHCP but still needs local configuration data. - The DHCP server must update its database with their address (specified in the "CI-ADDR" field) - as no longer available. When the server forms a reply ACK, it must leave the - 'Your IP' and lease time fields blank as per RFC 2131 3.4. */ - - - /* A DHCP server must respond (ACK) to INFORM messages unless the message - is invalid. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPACK; - - /* The INFORM message must have the Client IP address filled in to be valid. */ - if (dhcp_client_ptr -> nx_dhcp_clientip_address == NX_DHCP_NO_ADDRESS) - { - - /* Invalid message. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - } - - /* It cannot have a requested IP option in the options. */ - if (dhcp_client_ptr -> nx_dhcp_requested_ip_address != NX_DHCP_NO_ADDRESS) - { - - /* Invalid message. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - } - - /* Make sure the server interface table is up to date for this IP address. */ - _nx_dhcp_update_assignable_ip_address(dhcp_ptr, dhcp_client_ptr, dhcp_client_ptr -> nx_dhcp_clientip_address, - NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT); - - /* And update the client record assigned IP address in case it is not set yet. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_clientip_address; - - /* Has client IP address leased (bound) from this server? */ - if (dhcp_client_ptr -> nx_dhcp_client_state != NX_DHCP_STATE_BOUND) - { - - /* No, so if this client needs to configure an IP address assigned - with this server it must start at the INIT state. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - } - - break; - } - default: - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Received unknown response type.\n"); - #endif - - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - - return(NX_SUCCESS); - - /* No further processing to do. Leave the client state unchanged, whatever it was/is. */ - } - - } /* switch case on client message*/ - } - - /* Were there were any conditions requiring a NACK response? */ - if (dhcp_client_ptr -> nx_dhcp_response_type_to_client == NX_DHCP_TYPE_DHCPNACK) - { - /* Yes, the caller knows to send the NACK message. No processing to do. */ - return NX_SUCCESS; - } - - /* If this is not a DISCOVERY or REQUEST message, we are done! */ - if ((dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER) && - (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPREQUEST)) - { - - return(NX_SUCCESS); - } - - /* If the boot/init state client did not request an address, we are done. */ - if (dhcp_client_ptr -> nx_dhcp_requested_ip_address == NX_DHCP_NO_ADDRESS) - { - - return(NX_SUCCESS); - } - - /* Check if the Client has requested a valid IP address. This is only permitted - with a DISCO or REQUEST messages while the Client is in either the BOOT/INIT - or SELECT states. - - As per RFC 2131 4.3.1, the DHCP server should assign an IP address in order of preference as follows: - 1) the client currently is bound to - 2) client ip address in client records (e.g. previously assigned to) - 3) the currently requested IP - 4) the server will assign one. */ - - /* Find the currently binding source address in the server's database. */ - if (dhcp_client_ptr -> nx_dhcp_source_ip_address != NX_DHCP_NO_ADDRESS) - { - - /* Assign this as the Client's IP address. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_source_ip_address; - } - - /* Next best option: Has the client previously been assigned an IP address? */ - else if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) - { - - /* Yes, let's leave it assigned to it. */ - return(NX_SUCCESS); - } - else - { - - /* Last option: Set the client's requested IP address as the one to assign. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = dhcp_client_ptr -> nx_dhcp_requested_ip_address; - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_assign_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service finds an available IP address for the client if none is */ -/* provided, and updates the client's record with the new IP address. It */ -/* updates the interface table entry with current client data (lease */ -/* time, owner). */ -/* */ -/* If there already is an assigned IP address on the client record, this */ -/* function will verify the IP address has not been assigned to another */ -/* client before setting the current client as owner. If it has, this */ -/* function will look for another available IP address for the client. */ -/* */ -/* Once an address is assigned, this function updates the fields in the */ -/* interface pointer entry, and the "Your IP address" in its message back*/ -/* to the client. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_cptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to client record */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_DHCP_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_find_interface_table_ip_address */ -/* Look up IP address in */ -/* server interface table */ -/* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/ -/* in server interfce table */ -/* _nx_dhcp_record_ip_address_owner Set the client as IP address */ -/* owner in interface table */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_validate_client_message Check Client DHCP messages for*/ -/* proper data and determine */ -/* server response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_server_assign_ip_address(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr) -{ - -NX_DHCP_INTERFACE_TABLE *dhcp_interface_table_ptr; -NX_DHCP_INTERFACE_IP_ADDRESS *interface_address_ptr; -UINT assigned_to_client; -UINT assigned_ip; -UINT lease_time; - - - /* Set a flag on the outcome of finding an available address. */ - assigned_ip = NX_FALSE; - - /* Compute the client lease time based on client's requested - lease time and server default lease time. */ - lease_time = dhcp_client_ptr -> nx_dhcp_requested_lease_time; - - -#if (NX_DHCP_DEFAULT_LEASE_TIME >= 0xFFFFFFFF) - if (lease_time == 0) -#else - if ((lease_time == 0) || (lease_time > NX_DHCP_DEFAULT_LEASE_TIME)) -#endif - { - lease_time = NX_DHCP_DEFAULT_LEASE_TIME; - } - - - interface_address_ptr = (NX_DHCP_INTERFACE_IP_ADDRESS *)NX_NULL; - - /* Does the Client have a candidate already assigned? */ - if (dhcp_client_ptr -> nx_dhcp_assigned_ip_address) - { - - /* The client does have one assigned, but we need to verify it is available - or already assigned to the client. */ - - /* Look for this IP address in the specified interface IP address list (table). */ - _nx_dhcp_find_interface_table_ip_address(dhcp_ptr, dhcp_client_ptr -> nx_dhcp_client_iface_index, - dhcp_client_ptr -> nx_dhcp_assigned_ip_address, &interface_address_ptr); - - /* Was the ip address found? */ - if (interface_address_ptr) - { - - /* Yes; Is it assigned to anyone yet? */ - if (interface_address_ptr -> assigned == NX_FALSE) - { - /* No, We will assign this one further below. */ - } - else - { - - /* Determine who if is assigned to. */ - _nx_dhcp_find_ip_address_owner(interface_address_ptr, dhcp_client_ptr, &assigned_to_client); - - /* Assigned to this client? */ - if (assigned_to_client) - { - - - /* Yes, so we're done here, except for checking a few fields. */ - - /* Renew the lease time. */ - interface_address_ptr -> lease_time = lease_time; - - /* Set the Your IP address field for the server response message. */ - dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address; - - return(NX_SUCCESS); - } - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (already assigned)\n"); -#endif - - /* No, assigned to someone else. We cannot provide this so return a NACK. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - /* Clear the client's assigned IP address since it is assigned to someone else. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - return(NX_SUCCESS); - } - } - else - { - - /* If this is a NOT discovery message, the server can not very well - assign a different IP address becaause an ACK reply cannot contain - different information. */ - if (dhcp_client_ptr -> nx_dhcp_message_type != NX_DHCP_TYPE_DHCPDISCOVER) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not owned by server)\n"); -#endif - - /* Apparently the client has asked for an IP address either not - in the server database or on another network. We cannot provide this - so return a NACK. */ - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - - /* Clear the client record's 'assigned' IP address since none was assigned. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - /* Since the client did not get assigned an IP address - make sure the requested lease time is reset to zero. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - return(NX_SUCCESS); - } - - /* For a Discovery request, the server will go ahead and find an - available IP address to offer the client. */ - } - } - - /* If the client doesn't have an address assigned yet, find one in the server table not - yet assigned. */ - if (interface_address_ptr == 0x0) - { - - UINT i; - - /* Set a local varible to the IP address list for this client. */ - dhcp_interface_table_ptr = &(dhcp_ptr -> nx_dhcp_interface_table[dhcp_client_ptr -> nx_dhcp_client_iface_index]); - - /* Yes, search for an available ip address in the IP list for this interface */ - for(i = 0; i < dhcp_interface_table_ptr -> nx_dhcp_address_list_size; i++) - { - - /* Set a local pointer variable to the next address. */ - interface_address_ptr = &dhcp_interface_table_ptr -> nx_dhcp_ip_address_list[i]; - - /* Is this address assigned already? */ - if (interface_address_ptr -> assigned == NX_FALSE) - { - - /* No, but it is now! */ - - /* Indicate the search was successful. */ - assigned_ip = NX_TRUE; - - break; - } - } - - /* Check if we were able to find an available IP address. */ - if (assigned_ip == NX_FALSE) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Cannot assign requested IP address (not found in server IP list)\n"); -#endif - - - /* The server is not obliged to respond, but it should let the client - know if it cannot provide what it requests. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - - /* Since the client did not get assigned an IP address - make sure the requested lease time is reset to zero. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - /* No, return the error status. */ - return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES); - } - } - - /* Was the assigned ip address available? */ - if (interface_address_ptr) - { - - /* Set the client as the IP address owner in the server interface table. */ - _nx_dhcp_record_ip_address_owner(interface_address_ptr, dhcp_client_ptr, lease_time); - - /* Set the client's assigned IP address. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = interface_address_ptr -> nx_assignable_ip_address; - - /* Set the Your IP address field for the server response message. */ - dhcp_client_ptr -> nx_dhcp_your_ip_address = interface_address_ptr -> nx_assignable_ip_address; - - /* We are done! */ - return(NX_SUCCESS); - } - - /* If we're here we were not able to assign an IP address. */ - - /* The server is not obliged to respond, but it should let the client - know if it cannot provide what it requests. */ - dhcp_client_ptr -> nx_dhcp_client_state = NX_DHCP_STATE_INIT; - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: NACK! Server cannot assign requested IP address\n"); -#endif - - dhcp_client_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPNACK; - - /* Make sure the client record's 'assigned' IP address ir removed since it was not assigned. */ - dhcp_client_ptr -> nx_dhcp_assigned_ip_address = NX_DHCP_NO_ADDRESS; - - /* Since the client did not get assigned an IP address - make sure the requested lease time is reset to zero. */ - dhcp_client_ptr -> nx_dhcp_requested_lease_time = 0; - - return(NX_DHCP_NO_AVAILABLE_IP_ADDRESSES); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_extract_information PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts information from a DHCP Client packet and */ -/* updates the server's client database. If no client record exists for*/ -/* the client this function will create one for it. It does some */ -/* message validation but primary extracts DHCP header and option */ -/* fields to the client record. */ -/* */ -/* If an internal error is encountered parsing the packet buffer, this */ -/* function returns the error status. If it finds the client DHCP */ -/* message invalid, it returns successful completion but sets the DHCP */ -/* server to respond with either NACK or silence. */ -/* */ -/* When this function is finished, the caller releases the packet. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_cptr Pointer to DHCP Server */ -/* dhcp_client_ptr Pointer to client record */ -/* packet_ptr Pointer to DHCP client packet */ -/* iface_index Interface index packet was */ -/* received on */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_find_client_record_by_chaddr Find Client record using the */ -/* parsed mac address */ -/* _nx_dhcp_server_get_data Parse DHCP data from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_listen_for_messages Process DHCP Client messages */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_server_extract_information(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT **dhcp_client_ptr, - NX_PACKET *packet_ptr, UINT iface_index) -{ - -UINT status; -ULONG value; -UINT size; -ULONG xid; -UCHAR *work_ptr; -ULONG client_mac_msw; -ULONG client_mac_lsw; -NX_IPV4_HEADER *ip_header_ptr; -NX_DHCP_CLIENT *temp_client_rec_ptr; - - - /* Initialize the DHCP Client pointer to null pending successful data extraction. */ - *dhcp_client_ptr = NX_NULL; - - /* Set up UCHAR pointer to HW address field to extract client hardware address - which we will use as the client's unique identifier, since not all clients may use - Option 61/Client Identifier. */ - work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_HW; - - /* Pickup the MSW of the MAC address. */ - client_mac_msw = (((ULONG) work_ptr[0]) << 8) | ((ULONG) work_ptr[1]); - client_mac_lsw = (((ULONG) work_ptr[2]) << 24) | - (((ULONG) work_ptr[3]) << 16) | - (((ULONG) work_ptr[4]) << 8) | - ((ULONG) work_ptr[5]); - - /* Check the client hardware (mac address) field is filled in. */ - if ((client_mac_msw == 0) && (client_mac_lsw == 0)) - { - - return(NX_DHCP_INVALID_HW_ADDRESS); - } - - /* Look up the client record by IP address and interface index in Client Records table. */ - status = _nx_dhcp_find_client_record_by_chaddr(dhcp_ptr, iface_index, client_mac_msw, - client_mac_lsw, &temp_client_rec_ptr, NX_TRUE); - - - /* Check for error during search. */ - if ((status != NX_SUCCESS) || !temp_client_rec_ptr) - { - return(status); - } - - - /* Note: No need to check for NULL pointer because we asked to add the - record if no match is found. */ - - - /* Get the client's current binding IP address from the packet interface. */ - ip_header_ptr = (NX_IPV4_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); - - temp_client_rec_ptr -> nx_dhcp_source_ip_address = ip_header_ptr -> nx_ip_header_source_ip; - temp_client_rec_ptr -> nx_dhcp_destination_ip_address = ip_header_ptr -> nx_ip_header_destination_ip; - - /* Get the message type. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_OP, 1, &value); - if (status) - { - return(status); - } - - /* Check this is a 'request' DHCP Client message (not to be confused with the REQUEST - message type. */ - if (value != NX_DHCP_OP_REQUEST) - { - -#ifdef EL_PRINTF_ENABLE - EL_PRINTF("DHCPserv: SILENCE! Client DHCP packet not coded as a BOOT Request. Invalid request.\n"); -#endif - - /* Set the server to ignore the 'reply'. */ - temp_client_rec_ptr -> nx_dhcp_response_type_to_client = NX_DHCP_TYPE_DHCPSILENT; - - /* Return successful completion status. */ - return(NX_SUCCESS); - } - - /* Get the hardware type. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HTYPE, 1, &value); - if (status) - { - return(status); - } - - /* This is the Client interface type which is used in the default client identifier tag. */ - temp_client_rec_ptr -> nx_dhcp_client_hwtype = value; - - /* Get the hardware length. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_HLEN, 1, &value); - if (status) - { - return(status); - } - - /* This is the size of the hardware address. Used in the default client identifier tag. */ - temp_client_rec_ptr -> nx_dhcp_client_hwlen = value; - - /* Extract the message ID. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_XID, 4, &xid); - if (status) - { - return(status); - } - - /* Save the client xid to use in the server's reply back. */ - temp_client_rec_ptr -> nx_dhcp_xid = xid; - - /* Check if response to client should unicast or (default) broadcast. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_FLAGS, 1, &value); - if (status) - { - return(status); - } - - /* Get the Client's preference for unicast vs broadcast. */ - temp_client_rec_ptr -> nx_dhcp_broadcast_flag_set = (value & NX_DHCP_FLAGS_BROADCAST) ? 0x80 : 0x0; - - /* Extract the Requested Client IP address, if there is one. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_CLIENT_IP, 4, &value); - if (status) - { - return(status); - } - - /* This is the Client IP address reported by the Client. */ - temp_client_rec_ptr -> nx_dhcp_clientip_address = value; - - /* Update the IP address assigned to the Client "Your/client IP address". */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_YOUR_IP, 4, &value); - if (status) - { - return(status); - } - - /* This is the "Your IP address" which only the server should fill in. Should be zero in - client messages. */ - temp_client_rec_ptr -> nx_dhcp_your_ip_address = value; - - /* Extract the "Next Server IP address". */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_SERVER_IP, 4, &value); - if (status) - { - return(status); - } - temp_client_rec_ptr -> nx_dhcp_clientrec_server_ip = value; - - /* Store relay IP address for DHCP server (on another subnet) if there is one. */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_RELAY_IP, 4, &value); - if (status) - { - return(status); - } - temp_client_rec_ptr -> nx_dhcp_relay_ip_address = value; - - /* Look for the marker indicating option data (magic cookie). */ - status = _nx_dhcp_server_get_data(packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR, 4, &value); - if (status) - { - return(status); - } - - /* Note we don't store the magic cookie value. */ - - /* Are there user options? */ - if (value == NX_DHCP_MAGIC_COOKIE) - { - /* Yes there are user options in the Client message. */ - - /* Move up the buffer pointer past the magic cookie thing. */ - work_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DHCP_OFFSET_VENDOR + 4; - - /* Extract all the client option data. */ - while (*work_ptr != 0xFF) - { - - /* Guard against a missing "END" marker by checking if we are at the end of the DHCP packet data. */ - if (work_ptr >= packet_ptr -> nx_packet_append_ptr) - { - - /* Yes, Client must have sent a DHCP message with improperly terminated option - data (or Client is using a super large DHCP packet). */ - return(NX_DHCP_IMPROPERLY_TERMINATED_OPTION); - } - - /* Get the next option. */ - _nx_dhcp_server_get_data(work_ptr, 1, &value); - - /* Move up the buffer pointer to the option length. */ - work_ptr++; - - /* Get the option length. */ - _nx_dhcp_server_get_data(work_ptr, 1, (ULONG *)&size); - - /* Move up the buffer pointer to the next option. */ - work_ptr++; - - - /* Is this the client ID option? */ - if (value != NX_DHCP_SERVER_OPTION_CLIENT_ID) - { - - /* No, process as any other option. */ - _nx_dhcp_process_option_data(temp_client_rec_ptr, (CHAR *)work_ptr, value, NX_TRUE, size); - - /* Move up the buffer pointer past the current option data size to the next option. */ - work_ptr += size; - } - else - { - - work_ptr += size; - } - - /* Check that we haven't exceeded the limit on Client option requests. */ - if (temp_client_rec_ptr -> nx_dhcp_client_option_count >= NX_DHCP_CLIENT_OPTIONS_MAX) - { - - /* We have. This is all we have room to process. */ - break; - } - } - } - - /* Return the location of the client record. */ - *dhcp_client_ptr = temp_client_rec_ptr; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_get_option_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine extracts data from the specified location and adds the */ -/* Client's requested option to the Client record. The caller can ask */ -/* for the option data as well to be extracted and stored to client */ -/* record. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_client_ptr Pointer to DHCP Client */ -/* buffer Pointer to data buffer */ -/* option Option from Client DHCP packet */ -/* size Size of data buffer */ -/* get_option_data Indicate if server wants option*/ -/* data stored in client record */ -/* */ -/* OUTPUT */ -/* */ -/* status Error status extracting data */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_server_get_data Extract data from specified */ -/* buffer location */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_server_extract_information Extract DHCP data from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_process_option_data(NX_DHCP_CLIENT *dhcp_client_ptr, CHAR *buffer, ULONG option, UINT get_option_data, UINT size) -{ - -CHAR *temp_ptr; -UINT status; -ULONG option_value = 0; - - - - /* Do we parse option data for this option? */ - if (get_option_data) - { - - /* Yes, store to local variable to be applied to the Client record below. */ - status = _nx_dhcp_server_get_data((UCHAR *)buffer, size, &option_value); - if (status) - { - return(status); - } - } - - switch (option) - { - - case 1: - /* Subnet mask */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - dhcp_client_ptr -> nx_dhcp_subnet_mask = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 3: - /* Router or gateway */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - dhcp_client_ptr -> nx_dhcp_router_ip_address = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 6: - /* Domain name server */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - dhcp_client_ptr -> nx_dhcp_dns_ip_address = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - - case 12: - /* Client host name */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - - /* Only store as much of the host name as will fit in the host name buffer. */ - size = (size <= NX_DHCP_CLIENT_HOSTNAME_MAX) ? size : NX_DHCP_CLIENT_HOSTNAME_MAX; - - /* Clear the memory buffer before writing the host name to it. */ - memset(&dhcp_client_ptr -> nx_dhcp_client_name[0], 0, NX_DHCP_CLIENT_HOSTNAME_MAX); - memcpy(&dhcp_client_ptr -> nx_dhcp_client_name[0], buffer, size); - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 50: - - /* Client's requested IP address */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - - dhcp_client_ptr -> nx_dhcp_requested_ip_address = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 51: - - /* Client's requested IP address lease time */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - - dhcp_client_ptr -> nx_dhcp_requested_lease_time = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 53: - /* Message type */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = (UCHAR)option; - dhcp_client_ptr -> nx_dhcp_message_type = (UCHAR)option_value; - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 54: - /* Server ID by which server identifies itself to client(usually server IP address). - The Client includes this option in a REQUEST message to identify which server - it wants to lease an IP address from. */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - if (get_option_data) - { - - dhcp_client_ptr -> nx_dhcp_server_id = option_value; - } - dhcp_client_ptr -> nx_dhcp_client_option_count++; - break; - - case 55: - /* Option parameter list */ - temp_ptr = buffer ; - - /* Call this function to handle options within the option 55. */ - while (size) - { - - /* Get the next option in the Option parameter list. */ - _nx_dhcp_server_get_data((UCHAR *)temp_ptr, 1, &option); - - /* Update the client record with that option. */ - _nx_dhcp_process_option_data(dhcp_client_ptr, temp_ptr, option, NX_FALSE, 1); - - /* Move down the buffer containing the option parameter list data. */ - temp_ptr++; - - /* Update the amount of option data left for option 55. */ - size--; - } - break; - - case 61: - - /* Note Client ID is handled separately. */ - dhcp_client_ptr -> nx_dhcp_user_options[dhcp_client_ptr -> nx_dhcp_client_option_count] = option; - dhcp_client_ptr -> nx_dhcp_client_option_count++; - - break; - - case 116: /* Auto configuration option */ - case 60: /* Vendor class Identifier. */ - - /* Not supported at this time. */ - break; - - default: - break; - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_add_requested_option PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine receives options and which interface the DHCP client is*/ -/* on and adds the server information if there is any for that option */ -/* into the packet reply buffer. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_message Pointer to message buffer */ -/* iface_index Index to server interface table*/ -/* buffer Pointer to buffer to write to */ -/* option Option to add */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_add_option Adds the actual option to the */ -/* DHCP message buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_respond_to_dhcp_message Prepare and send out DHCP */ -/* response to client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_add_requested_option(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, UCHAR *buffer, UINT option, UINT *index) -{ - -UINT status = NX_SUCCESS; - - /* The NetX DHCP server provides a limited list of DHCP options for ACK responses. These do NOT - include the server's 'required' options. */ - switch (option) - { - - case 1: /* Subnet mask */ - status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_SUBNET_MASK_SIZE, - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_subnet_mask, index); - break; - - case 3: /* Router IP address */ - - - status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ROUTER_SIZE, - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_router_ip_address, index); - break; - - case 6: /* DNS IP address */ - status = _nx_dhcp_add_option(buffer, option, NX_DHCP_SERVER_OPTION_ADDRESS_SIZE, - dhcp_ptr -> nx_dhcp_interface_table[iface_index].nx_dhcp_dns_ip_address, index); - break; - - /* The NetX DHCP server does not reply to other options at this time. */ - default: - break; - } - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_add_option PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine adds a DHCP option data to the DHCP message in the */ -/* supplied buffer. Adding the option includes adding the option code,*/ -/* length of the data and option data value. */ -/* */ -/* INPUT */ -/* */ -/* dhcp_message Pointer to message buffer */ -/* option Option to add */ -/* value Value of Option to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_server_store_data Store data value */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_process Process the DHCP state machine*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_add_option(UCHAR *dhcp_message, UINT option, UINT size, ULONG value, UINT *index) -{ - - - /* Store the option. */ - *(dhcp_message + (*index)) = (UCHAR)option; - (*index) ++; - - /* Store the option size. */ - *(dhcp_message + (*index)) = (UCHAR)size; - (*index) ++; - - /* Store the option value. */ - _nx_dhcp_server_store_data(dhcp_message + (*index), size, value); - (*index) += size; - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_get_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine gets a data value from a buffer, assuming the data is */ -/* stored in standard Network format (big endian). Up to 4 bytes of */ -/* data are used, if there are more than 4 bytes, only the lower 4 */ -/* bytes are returned. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* value Data value retrieved */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_DHCP_PARAMETER_ERROR Invalid parameter input */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_get_response Get response from server */ -/* _nx_dhcp_server_extract_information Extract server information */ -/* _nx_dhcp_update_address_list Update address list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dhcp_server_get_data(UCHAR *data, UINT size, ULONG *value) -{ - - - /* Check for invalid buffer parameters. */ - if ((size == 0) || (data == 0x0) || (value == 0)) - { - return(NX_DHCP_PARAMETER_ERROR); - } - - /* Initialize value to zero. */ - *value = 0; - - /* Store each byte of data from buffer into result. */ - while (size > 0) - { - - /* Build return value. */ - *value = (*value << 8) | *data++; - size--; - } - - /* Return value. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_server_store_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores a data value in a buffer in standard Network */ -/* format (big endian) where the destination may be unaligned. Up to */ -/* 4 bytes of data are stored, if the size is larger than 4 bytes, the */ -/* remaining bytes are set to zero. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* value Value to store */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcp_send_request Send DHCP request */ -/* _nx_dhcp_add_option Add a DHCP option */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_dhcp_server_store_data(UCHAR *data, UINT size, ULONG value) -{ - - /* Make sure that data is left justified. */ - switch (size) - { - - case 1: - - value <<= 24; - break; - - case 2: - - value <<= 16; - break; - - case 3: - - value <<= 8; - break; - - default: - break; - } - - /* Store the value. */ - while (size-- > 0) - { - - *data = (UCHAR)((value >> 24) & 0xff); - data++; - value <<= 8; - } -} - -#endif /* NX_DISABLE_IPV4 */ diff --git a/protocol_handlers/dhcp/nxd_dhcp_server.h b/protocol_handlers/dhcp/nxd_dhcp_server.h deleted file mode 100644 index bb91b67f..00000000 --- a/protocol_handlers/dhcp/nxd_dhcp_server.h +++ /dev/null @@ -1,592 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol (DHCP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_dhcp_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Dynamic Host Configuration Protocol */ -/* (DHCP) server component, including all data types and external */ -/* references. It is assumed that nx_api.h and nx_port.h have already */ -/* been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_DHCP_SERVER_H -#define NXD_DHCP_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -/* Define the DHCP Server ID that is used to mark the DHCP Server structure as created. */ - -#define NX_DHCP_SERVER_ID 0x44484360UL - - -/* Define the DHCP stack size. */ - -#ifndef NX_DHCP_SERVER_THREAD_STACK_SIZE -#define NX_DHCP_SERVER_THREAD_STACK_SIZE 1024 -#endif - - -/* Define the DHCP stack priority. */ - -#ifndef NX_DHCP_SERVER_THREAD_PRIORITY -#define NX_DHCP_SERVER_THREAD_PRIORITY 2 -#endif - - -/* Define the DHCP packet allocation timeout in timer ticks. */ - -#ifndef NX_DHCP_PACKET_ALLOCATE_TIMEOUT -#define NX_DHCP_PACKET_ALLOCATE_TIMEOUT NX_IP_PERIODIC_RATE -#endif - - -/* Define UDP socket create options. */ - -#ifndef NX_DHCP_TYPE_OF_SERVICE -#define NX_DHCP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_DHCP_FRAGMENT_OPTION -#define NX_DHCP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_DHCP_TIME_TO_LIVE -#define NX_DHCP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_DHCP_QUEUE_DEPTH -#define NX_DHCP_QUEUE_DEPTH 5 -#endif - - -/* Define the server interface subnet mask (DHCP Client standard option). */ - -#ifndef NX_DHCP_SUBNET_MASK -#define NX_DHCP_SUBNET_MASK 0xFFFFFF00UL -#endif - - - -/* Define the client's host name buffer size. */ - -#ifndef NX_DHCP_CLIENT_HOSTNAME_MAX -#define NX_DHCP_CLIENT_HOSTNAME_MAX 32 -#endif - - -/* Define DHCP server's name and buffer size. */ -#ifndef NX_DHCP_SERVER_HOSTNAME_MAX -#define NX_DHCP_SERVER_HOSTNAME_MAX 32 -#endif - -#ifndef NX_DHCP_SERVER_NAME -#define NX_DHCP_SERVER_NAME "NetX DHCP Server" -#endif - - - -/* Define an interval in seconds for the session timer to check the time remaining on - all the active clients in the server database. */ - -#ifndef NX_DHCP_FAST_PERIODIC_TIME_INTERVAL -#define NX_DHCP_FAST_PERIODIC_TIME_INTERVAL 10 -#endif - -/* Set a length of time in seconds in which server can expect a client response during - Client DHCP session. Once a client is BOUND, the session timeout is set - to the IP address lease time. Note the maximum wait time between Client retransmissions - is 64 seconds, so this timeout should be in that neighborhood. Must be greater than - the fast periodic time interva. */ - -#ifndef NX_DHCP_CLIENT_SESSION_TIMEOUT -#define NX_DHCP_CLIENT_SESSION_TIMEOUT (10 * NX_DHCP_FAST_PERIODIC_TIME_INTERVAL) -#endif - - -/* Define an interval in seconds for the IP lease timer to check the time remaining on - all the assigned IP addresses in the server database. */ - -#ifndef NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL -#define NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL 1000 -#endif - - -/* Set the default lease time in seconds on the IP address the server - will assign to the Client. */ - -#ifndef NX_DHCP_DEFAULT_LEASE_TIME -#define NX_DHCP_DEFAULT_LEASE_TIME (10 * NX_DHCP_SLOW_PERIODIC_TIME_INTERVAL) -#endif - - - -/* Set a size of the Server option list requested by the Client. Since the NetX DHCP Server - does not as yet support the complete set of options in DHCP, this number can be optimized - down to a smaller size that the largest possible number of options a Client could request. -*/ - -#ifndef NX_DHCP_CLIENT_OPTIONS_MAX -#define NX_DHCP_CLIENT_OPTIONS_MAX 12 -#endif - - -/* There are optional and required elements of the server option list. - Use the required plus the user configurable option list for the - server list to respond back to the client. -*/ - -/* At the very least, a DHCP server should supply the - Client's subnet mask, router (default gateway) address and dns server. This list must be - space separated. The combined required and optional server options - should be less than NX_DHCP_CLIENT_OPTIONS_MAX. -*/ - -#ifndef NX_DHCP_OPTIONAL_SERVER_OPTION_LIST -#define NX_DHCP_OPTIONAL_SERVER_OPTION_LIST "1 3 6" -#endif - -/* Set the number of default options in the optional server list above. */ -#ifndef NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE -#define NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE 3 -#endif - - -/* The NetX DHCP Server includes its server identifier, message type in all messages. */ -#define NX_DHCP_REQUIRED_SERVER_OPTION_LIST "53 54" -#define NX_DHCP_REQUIRED_SERVER_OPTION_SIZE 2 - -/* Compute the total option list size. */ -#define NX_DHCP_SERVER_OPTION_LIST_SIZE (NX_DHCP_REQUIRED_SERVER_OPTION_SIZE + NX_DHCP_OPTIONAL_SERVER_OPTION_SIZE) - -/* Combine the actual lists maintaining a space between all options. */ -#define NX_DHCP_SERVER_OPTION_LIST NX_DHCP_REQUIRED_SERVER_OPTION_LIST \ - " " \ - NX_DHCP_OPTIONAL_SERVER_OPTION_LIST - - -/* Define the maximum size of each IP address list. Each interface the server assigns - IP addresses for will be limited to this size. */ - -/* Define the max size of an IP addresses list (applies to each interfaces). */ - -#ifndef NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE -#define NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE 20 -#endif - -/* Define the size of client record table (All clients e.g.on all interfaces). */ - -#ifndef NX_DHCP_CLIENT_RECORD_TABLE_SIZE -#define NX_DHCP_CLIENT_RECORD_TABLE_SIZE 50 -#endif - - /* END OF CONFIGURABLE OPTIONS */ - - -/* Define the size of the BOOT buffer. This should be large enough for all the - required DHCP fields plus the minimum requirement of 312 bytes of option data - stated in RFC 2131; 2. Protocol Summary. */ -#ifndef NX_BOOT_BUFFER_SIZE -#define NX_BOOT_BUFFER_SIZE 548 -#endif - -/* Define the size of the DHCP header as per RFC 213 Section Protocol Summery, page 10. */ - -#ifndef NX_DHCP_HEADER_SIZE -#define NX_DHCP_HEADER_SIZE 236 -#endif - - -/* - Define the packet payload size, keeping in mind the DHCP Server must support - at least a 548 byte DHCP Client message as per RFC 2131 and allow room for Ethernet, UDP and - IP headers and 4 byte alignment. -*/ -#ifndef NX_DHCP_MINIMUM_PACKET_PAYLOAD -#define NX_DHCP_MINIMUM_PACKET_PAYLOAD (NX_BOOT_BUFFER_SIZE + NX_PHYSICAL_HEADER + sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER)) -#endif /* NX_DHCP_MINIMUM_PACKET_PAYLOAD */ - - -/* Define the DHCP Message Area Offsets. The DHCP message format is identical to that of BootP, except - for the Vendor options that start at the offset specified by NX_DHCP_OFFSET_OPTIONS. */ - -#define NX_DHCP_OFFSET_OP 0 /* 1 BootP Operation 1=req, 2=reply */ -#define NX_DHCP_OFFSET_HTYPE 1 /* 1 Hardware type 1 = Ethernet */ -#define NX_DHCP_OFFSET_HLEN 2 /* 1 Hardware address length, 6 for Ethernet */ -#define NX_DHCP_OFFSET_HOPS 3 /* 1 Number of hops, usually 0 */ -#define NX_DHCP_OFFSET_XID 4 /* 4 Transaction ID, pseudo random number */ -#define NX_DHCP_OFFSET_SECS 8 /* 2 Seconds since boot */ -#define NX_DHCP_OFFSET_FLAGS 10 /* 2 Flags, 0x80 = Broadcast response, 0 = unicast response */ -#define NX_DHCP_OFFSET_CLIENT_IP 12 /* 4 Initial client IP, used as dest for unicast response */ -#define NX_DHCP_OFFSET_YOUR_IP 16 /* 4 Assigned IP, initialized to 0.0.0.0 */ -#define NX_DHCP_OFFSET_SERVER_IP 20 /* 4 Server IP, usually initialized to 0.0.0.0 */ -#define NX_DHCP_OFFSET_RELAY_IP 24 /* 4 Relay IP, usually 0.0.0.0, only for DHCP */ -#define NX_DHCP_OFFSET_CLIENT_HW 28 /* 16 Client hardware address */ -#define NX_DHCP_OFFSET_SERVER_NM 44 /* 64 Server name, nulls if unused */ -#define NX_DHCP_OFFSET_BOOT_FILE 108 /* 128 Boot file name, null if unused */ -#define NX_DHCP_OFFSET_VENDOR 236 /* 64 Vendor options, set first 4 bytes to a magic number */ -#define NX_DHCP_OFFSET_OPTIONS 240 /* First variable vendor option */ -#define NX_DHCP_OFFSET_END 300 /* End of BOOTP buffer */ -#define NX_DHCP_SERVER_OPTION_ADDRESS_SIZE 4 - -/* Define the DHCP Specific Vendor Extensions. */ - -#define NX_DHCP_SERVER_OPTION_PAD 0 -#define NX_DHCP_SERVER_OPTION_PAD_SIZE 0 -#define NX_DHCP_SERVER_OPTION_SUBNET_MASK 1 -#define NX_DHCP_SERVER_OPTION_SUBNET_MASK_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE -#define NX_DHCP_SERVER_OPTION_TIME_OFFSET 2 -#define NX_DHCP_SERVER_OPTION_TIME_OFFSET_SIZE 4 -#define NX_DHCP_SERVER_OPTION_ROUTER 3 -#define NX_DHCP_SERVER_OPTION_ROUTER_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE -#define NX_DHCP_SERVER_OPTION_TIMESVR 4 -#define NX_DHCP_SERVER_OPTION_DNS_SVR 6 -#define NX_DHCP_SERVER_OPTION_HOST_NAME 12 -#define NX_DHCP_SERVER_OPTION_DNS_NAME 15 -#define NX_DHCP_SERVER_OPTION_NTP_SVR 42 -#define NX_DHCP_SERVER_OPTION_VENDOR_OPTIONS 43 -#define NX_DHCP_SERVER_OPTION_DHCP_IP_REQ 50 -#define NX_DHCP_SERVER_OPTION_DHCP_IP_REQ_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE -#define NX_DHCP_SERVER_OPTION_DHCP_LEASE 51 -#define NX_DHCP_SERVER_OPTION_DHCP_LEASE_SIZE 4 -#define NX_DHCP_SERVER_OPTION_DHCP_TYPE 53 -#define NX_DHCP_SERVER_OPTION_DHCP_TYPE_SIZE 1 -#define NX_DHCP_SERVER_OPTION_DHCP_SERVER_ID 54 -#define NX_DHCP_SERVER_OPTION_DHCP_SERVER_SIZE NX_DHCP_SERVER_OPTION_ADDRESS_SIZE -#define NX_DHCP_SERVER_OPTION_DHCP_PARAMETERS 55 -#define NX_DHCP_SERVER_OPTION_DHCP_MESSAGE 56 -#define NX_DHCP_SERVER_OPTION_RENEWAL 58 -#define NX_DHCP_SERVER_OPTION_RENEWAL_SIZE 4 -#define NX_DHCP_SERVER_OPTION_REBIND 59 -#define NX_DHCP_SERVER_OPTION_REBIND_SIZE 4 -#define NX_DHCP_SERVER_OPTION_CLIENT_ID 61 -#define NX_DHCP_SERVER_OPTION_CLIENT_ID_SIZE 7 -#define NX_DHCP_SERVER_OPTION_FDQN 81 -#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_N 8 -#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_E 4 -#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_O 2 -#define NX_DHCP_SERVER_OPTION_FDQN_FLAG_S 1 -#define NX_DHCP_SERVER_OPTION_END 255 -#define NX_DHCP_SERVER_OPTION_END_SIZE 0 - -#define NX_DHCP_MINIMUM_PACKET (NX_DHCP_OFFSET_END + NX_UDP_PACKET+ 100) - - -/* Define various BootP/DHCP constants. */ - -#define NX_DHCP_SERVER_UDP_PORT 67 -#define NX_DHCP_SERVER_TCP_PORT 67 -#define NX_DHCP_CLIENT_UDP_PORT 68 -#define NX_DHCP_CLIENT_TCP_PORT 68 - -#define NX_DHCP_OP_REQUEST 1 -#define NX_DHCP_OP_REPLY 2 -#define NX_DHCP_FLAGS_BROADCAST 0x80 -#define NX_DHCP_FLAGS_UNICAST 0x00 -#define NX_DHCP_MAGIC_COOKIE IP_ADDRESS(99, 130, 83, 99) -#define NX_DHCP_NO_ADDRESS IP_ADDRESS(0, 0, 0, 0) -#define NX_DHCP_BC_ADDRESS IP_ADDRESS(255, 255, 255, 255) -#define NX_AUTO_IP_ADDRESS IP_ADDRESS(169, 254, 0, 0) -#define NX_AUTO_IP_ADDRESS_MASK 0xFFFF0000UL -#define NX_DHCP_SERVER_INFINITE_LEASE 0xFFFFFFFFUL - - -/* Define the DHCP Message Types. */ - -#define NX_DHCP_TYPE_DHCPDISCOVER 1 -#define NX_DHCP_TYPE_DHCPOFFER 2 -#define NX_DHCP_TYPE_DHCPREQUEST 3 -#define NX_DHCP_TYPE_DHCPDECLINE 4 -#define NX_DHCP_TYPE_DHCPACK 5 -#define NX_DHCP_TYPE_DHCPNACK 6 -#define NX_DHCP_TYPE_DHCPRELEASE 7 -#define NX_DHCP_TYPE_DHCPINFORM 8 -#define NX_DHCP_TYPE_DHCPFORCERENEW 9 -#define NX_DHCP_TYPE_DHCPSILENT 10 - - -/* Define the states of the DHCP state machine. */ - -#define NX_DHCP_STATE_BOOT 1 /* Started with a previous address */ -#define NX_DHCP_STATE_INIT 2 /* Started with no previous address */ -#define NX_DHCP_STATE_SELECTING 3 /* Waiting to identify a DHCP server */ -#define NX_DHCP_STATE_REQUESTING 4 /* Address requested, waiting for the Ack */ -#define NX_DHCP_STATE_BOUND 5 /* Address established, no time outs */ -#define NX_DHCP_STATE_RENEWING 6 /* Address established, renewal time out */ -#define NX_DHCP_STATE_REBINDING 7 /* Address established, renewal and rebind time out */ -#define NX_DHCP_STATE_FORCERENEW 8 /* Address established, force renewal */ - - -/* Define error codes from DHCP Server operation. */ - -#define NX_DHCP_SERVER_ALREADY_STARTED 0x90 /* DHCP Server already started */ -#define NX_DHCP_SERVER_NOT_STARTED 0x91 /* DHCP Server not started when stop was issued */ -#define NX_DHCP_PARAMETER_ERROR 0x92 /* Invalid non pointer input */ -#define NX_DHCP_INADEQUATE_PACKET_POOL_PAYLOAD 0x93 /* DHCP Server packet pool has inadequate packet payload for DHCP messages. */ -#define NX_DHCP_BAD_OPTION_LIST_ERROR 0x94 /* Server default option list has invalid characters. */ -#define NX_DHCP_INTERNAL_OPTION_PARSE_ERROR 0x95 /* Internal error parsing options from string to ULONG. */ -#define NX_DHCP_NO_SERVER_OPTION_LIST 0x96 /* Server default option list is empty when server is configured to use it. */ -#define NX_DHCP_IMPROPERLY_TERMINATED_OPTION 0x97 /* Improperly formatted client option data e.g missing terminating symbol 0xFF. */ -#define NX_DHCP_ADD_OPTION_ERROR 0x98 /* Unable to add option to buffer of server DHCP response packet */ -#define NX_DHCP_INVALID_IP_ADDRESS_LIST 0x99 /* Invalid start or end IP address list parameter for creating assignable IP address list. */ -#define NX_DHCP_NO_AVAILABLE_IP_ADDRESSES 0x9A /* Server has no available IP addresses for DHCP Clients */ -#define NX_DHCP_INVALID_IP_ADDRESS 0x9B /* Invalid IP address e.g. null address received or obtained from client record. */ -#define NX_DHCP_IP_ADDRESS_NOT_FOUND 0x9C /* No match found for IP address search */ -#define NX_DHCP_IP_ADDRESS_ASSIGNED_TO_OTHER 0x9D /* IP address not assigned to the current client */ -#define NX_DHCP_INVALID_UPDATE_ADDRESS_CMD 0x9E /* Unable to ascertain assigned ip address status (e.g. assign, mark available etc) */ -#define NX_DHCP_CLIENT_RECORD_NOT_FOUND 0x9F /* Unable to find client in Client records table. */ -#define NX_DHCP_CLIENT_TABLE_FULL 0xA0 /* Server unable to add record to client table; table is full. */ -#define NX_DHCP_SERVER_BAD_INTERFACE_INDEX 0xA1 /* Interface index exceeds the NX_MAX_PHYSICAL_INTERFACES limit. */ -#define NX_DHCP_INVALID_HW_ADDRESS 0xA2 /* Invalid hardware address e.g. null or exceeding 6 bytes. */ -#define NX_DHCP_INVALID_NETWORK_PARAMETERS 0xA3 /* Invalid network parameters (subnet, dns server, default gateway/router). */ -#define NX_DHCP_MALFORMED_DHCP_PACKET 0xA4 /* DHCP packet was malformed. */ - - -/* Define DHCP Server event flags. These events are processed by the DHCP Server thread. */ -#define NX_DHCP_SERVER_ALL_EVENTS 0xFFFFFFFFUL /* All DHCP Server event flags. */ -#define NX_DHCP_SERVER_RECEIVE_EVENT 0x00000001UL /* Packet received event. */ -#define NX_DHCP_SERVER_FAST_PERIODIC_EVENT 0x00000002UL /* Fast periodic timer event. */ -#define NX_DHCP_SERVER_SLOW_PERIODIC_EVENT 0x00000004UL /* Slow periodic timer event. */ - - -/* Define Assignable IP status 'commands'. */ - -#define NX_DHCP_ADDRESS_STATUS_NO_ACTION 0x01 /* No change in Client address. */ -#define NX_DHCP_ADDRESS_STATUS_SERVER_ASSIGN 0x02 /* Server will assign IP address to client. */ -#define NX_DHCP_ADDRESS_STATUS_ASSIGNED_EXT 0x03 /* Client assigned IP address elesewhere, mark client as owner and IP as not available. */ -#define NX_DHCP_ADDRESS_STATUS_MARK_AVAILABLE 0x04 /* Mark client's IP address as available and clear owner field. */ -#define NX_DHCP_ADDRESS_STATUS_ASSIGNED_OTHER 0x05 /* Mark client's IP address as assigned already (owner unknown). */ - -/* Define types of options to load in server response to DHCP client. */ - -#define NX_DHCP_OPTIONS_FOR_ALL_REPLIES 0x01 -#define NX_DHCP_OPTIONS_FOR_REPLY_TO_OFFER 0x02 -#define NX_DHCP_OPTIONS_FOR_REPLY_TO_REQUEST 0x03 -#define NX_DHCP_OPTIONS_FOR_REPLY_TO_INFORM 0x04 -#define NX_DHCP_OPTIONS_FOR_GENERIC_ACK 0x05 -#define NX_DHCP_OPTIONS_REQUESTED_BY_CLIENT 0x06 - -/* Define the DHCP structure that contains DHCP client information during DHCP session. Note - this is not the same control block as the NX_DHCP_STRUCT in nx_dhcp.h for the NetX DHCP Client - package. */ - -typedef struct NX_DHCP_CLIENT_STRUCT -{ - - UINT nx_dhcp_client_state; /* Client DHCP state: e.g. INIT, BOOT, SELECTING, RENEWING etc */ - UCHAR nx_dhcp_message_type; /* DHCP message type (DISCOVER, REQUEST etc) received from Client. */ - CHAR nx_dhcp_client_name[NX_DHCP_CLIENT_HOSTNAME_MAX]; - /* DHCP Client host name buffer. */ - ULONG nx_dhcp_xid; /* Transaction ID for client DHCP session */ - ULONG nx_dhcp_source_ip_address; /* Source IP of the client DHCP message. */ - ULONG nx_dhcp_destination_ip_address; - /* Destination IP of the client DHCP message. */ - ULONG nx_dhcp_clientip_address; /* "Client IP address" (sometimes called "ci-addr" field). */ - ULONG nx_dhcp_your_ip_address; /* "Your IP address" field in client DHCP message. */ - ULONG nx_dhcp_requested_ip_address;/* IP address requested in client message option. */ - ULONG nx_dhcp_requested_lease_time;/* IP address lease time requested in client message option. */ - ULONG nx_dhcp_assigned_ip_address; /* IP address the Server offers/assigns the client. */ - UINT nx_dhcp_client_iface_index; /* Index into the server interface table matching the DHCP client's packet interface. */ - ULONG nx_dhcp_clientrec_server_ip; /* Next Server IP Address (may be another DHCP server) for advanced DHCP features */ - ULONG nx_dhcp_server_id; /* Requested/assigned Server ID (usually set to DHCP server IP address) */ - ULONG nx_dhcp_router_ip_address; /* Requested/assigned router on DHCP Client network. */ - ULONG nx_dhcp_dns_ip_address; /* Requested/assigned DNS IP address; usually set to zero. */ - ULONG nx_dhcp_relay_ip_address; /* Requested/assigned Relay IP address; usually set to zero. */ - ULONG nx_dhcp_subnet_mask; /* Requested/assigned network mask */ - ULONG nx_dhcp_client_mac_msw; /* Client MAC address high bits */ - ULONG nx_dhcp_client_mac_lsw; /* Client MAC address low bits */ - UINT nx_dhcp_client_hwlen; /* Length of hardware address. */ - UINT nx_dhcp_client_hwtype; /* Client interface hardware type e.g. Ethernet. */ - ULONG nx_dhcp_broadcast_flag_set; /* Parse broadcast flags from DHCP messages. */ - UINT nx_dhcp_client_option_count; /* Number of user options in client request */ - UINT nx_dhcp_user_options[NX_DHCP_CLIENT_OPTIONS_MAX]; - ULONG nx_dhcp_session_timeout; /* Time out on waiting for client's next response */ - UINT nx_dhcp_response_type_to_client; - /* DHCP code for response to send back to client. */ - -} NX_DHCP_CLIENT; - -/* Define the interface address structure which the server will use to assign IP addresses - in a previously specified network interface. */ -typedef struct NX_DHCP_INTERFACE_IP_ADDRESS_STRUCT -{ - ULONG nx_assignable_ip_address; /* IP address available to assign to DHCP Client. */ - UINT assigned; /* IP address status e.g if currently assigned to a client host. */ - UINT lease_time; /* Lease duration in secs. */ - UINT owner_hwtype; /* Hardware type. */ - UINT owner_mac_msw; /* MAC address high bits. */ - UINT owner_mac_lsw; /* MAC address low bits. */ -} NX_DHCP_INTERFACE_IP_ADDRESS; - - -typedef struct NX_DHCP_INTERFACE_TABLE_STRUCT -{ - NX_DHCP_INTERFACE_IP_ADDRESS - nx_dhcp_ip_address_list[NX_DHCP_IP_ADDRESS_MAX_LIST_SIZE]; - /* IP address available to assign to DHCP Client. */ - NX_INTERFACE *nx_dhcp_incoming_interface; /* Pointer to DHCP Server interface. */ - ULONG nx_dhcp_server_ip_address; /* DHCP Server's IP address for this interface. */ - ULONG nx_dhcp_dns_ip_address; /* DHCP server DNS Server Address in message to DHCP Client.. */ - ULONG nx_dhcp_subnet_mask; /* DHCP server interface subnet mask. */ - ULONG nx_dhcp_subnet; /* DHCP server interface subnet. */ - ULONG nx_dhcp_router_ip_address; /* The router IP Address for DHCP client configuration */ - UINT nx_dhcp_address_list_size; /* Actual number of assignable addresses for this interface. */ - -} NX_DHCP_INTERFACE_TABLE; - -/* Define the Interface address list. */ - -/* Define the DHCP structure that contains all the server information necessary for this DHCP - instance. */ - -typedef struct NX_DHCP_SERVER_STRUCT -{ - ULONG nx_dhcp_id; /* DHCP thread ID */ - CHAR nx_dhcp_name[NX_DHCP_SERVER_HOSTNAME_MAX]; - /* DHCP server name buffer */ - NX_PACKET_POOL *nx_dhcp_packet_pool_ptr; /* Pointer to DHCP server packet pool */ - TX_TIMER nx_dhcp_slow_periodic_timer; /* Timer for watching IP lease time outs. */ - TX_TIMER nx_dhcp_fast_periodic_timer; /* Timer for watching session time outs. */ - UCHAR nx_dhcp_started; /* DHCP started flag */ - NX_IP *nx_dhcp_ip_ptr; /* The Server IP Instance */ - TX_THREAD nx_dhcp_server_thread; /* The DHCP server processing thread */ - TX_MUTEX nx_dhcp_mutex; /* Mutex protection for client and interface tables. */ - TX_EVENT_FLAGS_GROUP nx_dhcp_server_events; /* DHCP Server events. */ - UINT nx_dhcp_number_clients; /* Number of clients currently assigned IP address by this server. */ - NX_DHCP_CLIENT client_records[NX_DHCP_CLIENT_RECORD_TABLE_SIZE]; /* Table of DHCP clients.*/ - /* List of IP addresses server can assign to DHCP Clients */ - NX_UDP_SOCKET nx_dhcp_socket; /* DHCP server socket to receive DHCP messages on its interfaces. */ - UINT nx_dhcp_server_options[NX_DHCP_SERVER_OPTION_LIST_SIZE]; - /* List of max number of options in supply data to Client */ - UINT nx_dhcp_server_option_count; /* Actual number of options the server is supplying back to client. */ - - NX_DHCP_INTERFACE_TABLE nx_dhcp_interface_table[NX_MAX_PHYSICAL_INTERFACES]; - /* Interface specific table of addresses available for DHCP clients. */ - ULONG nx_dhcp_discoveries_received; /* The number of Discovery messages received */ - ULONG nx_dhcp_requests_received; /* The number of Request messages received */ - ULONG nx_dhcp_informs_received; /* The number of Inform messages received */ - ULONG nx_dhcp_declines_received; /* The number of Decline messages received */ - ULONG nx_dhcp_releases_received; /* The number of Release messages received */ - -} NX_DHCP_SERVER; - - -#ifndef NX_DHCP_SERVER_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map DHCP API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_dhcp_server_create _nx_dhcp_server_create -#define nx_dhcp_create_server_ip_address_list _nx_dhcp_create_server_ip_address_list -#define nx_dhcp_set_interface_network_parameters _nx_dhcp_set_interface_network_parameters -#define nx_dhcp_server_delete _nx_dhcp_server_delete -#define nx_dhcp_server_start _nx_dhcp_server_start -#define nx_dhcp_server_stop _nx_dhcp_server_stop -#define nx_dhcp_clear_client_record _nx_dhcp_clear_client_record - -#else - -/* Services with error checking. */ - -#define nx_dhcp_server_create _nxe_dhcp_server_create -#define nx_dhcp_create_server_ip_address_list _nxe_dhcp_create_server_ip_address_list -#define nx_dhcp_set_interface_network_parameters _nxe_dhcp_set_interface_network_parameters -#define nx_dhcp_server_delete _nxe_dhcp_server_delete -#define nx_dhcp_server_start _nxe_dhcp_server_start -#define nx_dhcp_server_stop _nxe_dhcp_server_stop -#define nx_dhcp_clear_client_record _nxe_dhcp_clear_client_record -#endif - -/* Define the prototypes accessible to the application software. */ - -UINT nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); -UINT nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); -UINT nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); -UINT nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); -UINT nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); -UINT nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); -UINT nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); - -#else - -/* DHCP source code is being compiled, do not perform any API mapping. */ - - -UINT _nxe_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); -UINT _nx_dhcp_server_create(NX_DHCP_SERVER *dhcp_ptr, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, CHAR *name_ptr, NX_PACKET_POOL *packet_pool); -UINT _nx_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); -UINT _nxe_dhcp_create_server_ip_address_list(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG start_ip_address, ULONG end_ip_address, UINT *addresses_added); -UINT _nxe_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); -UINT _nx_dhcp_set_interface_network_parameters(NX_DHCP_SERVER *dhcp_ptr, UINT iface_index, ULONG subnet_mask, ULONG default_gateway_address, ULONG dns_server_address); -UINT _nxe_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); -UINT _nx_dhcp_server_delete(NX_DHCP_SERVER *dhcp_ptr); -UINT _nxe_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); -UINT _nx_dhcp_server_start(NX_DHCP_SERVER *dhcp_ptr); -UINT _nxe_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); -UINT _nx_dhcp_server_stop(NX_DHCP_SERVER *dhcp_ptr); -UINT _nxe_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); -UINT _nx_dhcp_clear_client_record(NX_DHCP_SERVER *dhcp_ptr, NX_DHCP_CLIENT *dhcp_client_ptr); - - -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* NXD_DHCP_SERVER_H */ diff --git a/protocol_handlers/dhcp/nxd_dhcpv6_client.c b/protocol_handlers/dhcp/nxd_dhcpv6_client.c deleted file mode 100644 index 3f689710..00000000 --- a/protocol_handlers/dhcp/nxd_dhcpv6_client.c +++ /dev/null @@ -1,12222 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6 Client) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_DHCPV6_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include -#include "nx_api.h" -#include "nx_system.h" -#include "nx_ip.h" -#include "nx_ipv6.h" -#include "nx_udp.h" -#include "nxd_dhcpv6_client.h" -#include "tx_timer.h" - -#ifdef FEATURE_NX_IPV6 - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/* Define the address of All DHCP Relay Agents and Servers as per RFC3315. */ -static NXD_ADDRESS All_DHCPv6_Relay_Servers_Address; - -/* Keep the DHCPv6 instance for DAD callback notify. */ -static NX_DHCPV6 *_nx_dhcpv6_DAD_ptr; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_client_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the client DUID to the Client request packet */ -/* based on the Client DUID on record, checking to make sure it does */ -/* not go past the end of the packet payload. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the Client */ -/* DUID in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG message_word; -ULONG available_payload; -UCHAR mac[8]; -UINT i = 0; - - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index; - - /* Check if the largest possible client DUID will fit in the packet buffer. */ - if ((available_payload - 4) < ((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length))) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Build the header from the client DUID. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_op_code)) << 16); - message_word |= (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy first half of the Client DUID option to packet buffer. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); - (*index) += (ULONG)sizeof(UINT); - - /* Build the DUID type and hardware type. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type)) << 16); - message_word |= dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Set up the DUID type and hardware type. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); - (*index) += (ULONG)sizeof(UINT); - - /* Include the 'time' field if this is a Link layer time DUID type. */ - if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Build the time. */ - message_word = dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Set up the time. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - } - - /* Build the link layer address. */ - if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) - { - - /* The length of link layer address is 48 bit. */ - - /* Build the MSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw); - } - else if(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) - { - - /* The length of link layer address is 64 bits. */ - - /* Build the MSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 24); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 16); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw); - } - - /* Build the LSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 24); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 16); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw); - - /* Set up the link layer address. */ - memcpy((buffer_ptr + (*index)), mac, i); - (*index) += i; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_elapsed_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the elapsed time option to the Client request */ -/* packet using the session duration time tracked by the DHCPv6 Client */ -/* thread, and checks to make sure it does not go past the end of the */ -/* packet payload. */ -/* */ -/* Note that the elapsed time is the time from which the Client */ -/* initiates the request to the time the it gets and processes a valid */ -/* server reply. Its accuracy depends on the resolution of the session*/ -/* timer. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the elapsed */ -/* time option in the packet payload*/ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_elapsed_time(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG available_payload; - - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); - - /* Check if the data will fit in the packet buffer. */ - if (available_payload < sizeof(NX_DHCPV6_ELAPSED_TIME)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_code); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_length); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time); - - /* Set up the elapsed time option, in hundredths of seconds. */ - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_elapsed_time), sizeof(NX_DHCPV6_ELAPSED_TIME)); - *index += (ULONG)sizeof(NX_DHCPV6_ELAPSED_TIME); - - /* Swap bytes back. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_code); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_op_length); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_ia_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the IA address option to the Client request */ -/* packet using the Client IA on record. Also checks to make sure */ -/* adding the IA option does not go past the end of the packet payload.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* index Location into buffer to write data*/ -/* ia_index The index of IA address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_IA_ADDRESS IA address on record is NULL */ -/* NX_DHCPV6_OPTION_NO_DATA No IA option in client record */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the IA address*/ -/* option in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_add_iana Adds the IANA and optionally the */ -/* IA option to Client request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_ia_address(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index, UINT ia_index) -{ - -ULONG message_word; -ULONG available_payload; - - /* Set the IA option length. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length = (6 * sizeof(ULONG)); - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); - - /* Check if the client IA address option will fit in the packet buffer. */ - if (available_payload < (((ULONG)dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length) + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Check that the IA address option has been created. */ - if (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code != NX_DHCPV6_OP_IA_ADDRESS) - { - - /* Missing or invalid IA option and/or data. */ - return NX_DHCPV6_INVALID_IA_DATA; - } - - /* Make sure the IA address block has a non zero IP address. */ - if ((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0] == 0) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1] == 0) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2] == 0) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3] == 0)) - { - - return NX_DHCPV6_INVALID_IA_ADDRESS; - } - - /* If the client has created an address option, apply it to the message. */ - - /* Clear memory to make the first word of the IA option header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Extract the IA data from the client record. */ - message_word = (((ULONG)dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code) << 16); - message_word |= dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy IA data into the packet and update the index into the buffer. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - - /* Add the IPv6 address. */ - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]); - - /* Copy the Client preferred IPv6 address to the packet. */ - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - - /* Swap bytes back. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3]); - - /* Add the preferred lifetime and valid lifetime option. */ - if((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) - { - - /* When sending a confirm request, DHCPv6 Client should set its T1,T2,preferred-lifetime and - valid-lifetime to zero, as the server will ignore these fields, RFC3315,page41. */ - memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - } - else - { - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime); - - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - - /* Swap bytes back. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime); - - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the IANA option to the Client request packet */ -/* using the Client IANA on record. Also checks to make sure adding */ -/* the IANA option does not go past the end of the packet payload. If */ -/* exist IA options, it will call the service to add the IA option */ -/* within the IANA option data. It then updates the IANA length field */ -/* for the embedded IA option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the IANA */ -/* option in the packet payload */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_add_ia_address Adds the IA option to buffer */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -UINT status; -UINT temp_index; -UINT ia_index; -UINT ia_length; -ULONG message_word; -ULONG available_payload; - - - /* Initialize the completion status variable. */ - status = NX_SUCCESS; - ia_length = 0; - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index; - - /* Check if the client IANA will fit in the packet buffer. */ - if (available_payload < (((ULONG)dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length) + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Save this location in the buffer. */ - temp_index = *index; - - /* Skip the option code and option lenght of IA_NA, write these option after padding the all IA option. */ - (*index) += (ULONG)sizeof(ULONG); - - /* Add the IA_NA ID. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id); - - /* Add the T1 and T2 option. */ - if((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) - { - - /* When sending a confirm request, DHCPv6 Client should set its T1,T2,preferred-lifetime and - valid-lifetime to zero, as the server will ignore these fields, RFC3315,page41. */ - memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memset((buffer_ptr + (*index)), 0, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - } - else - { - - /* Adjust the data. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2); - - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2), sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - - /* Swap bytes back. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2); - } - - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Check the IA address status. */ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) - { - - /* Yes, so add one...*/ - status = _nx_dhcpv6_add_ia_address(dhcpv6_ptr, buffer_ptr, index, ia_index); - - /* Was the IA address option get appended successfully? */ - if (status == NX_SUCCESS) - { - - /* Update the IA address to record the IANA option length. */ - ia_length = (UINT)(ia_length + dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length + 4); - } - } - } - - /* Clear memory to make the first word of the IA-NA header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Set the IA_NA option code and option length. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code = NX_DHCPV6_OP_IA_NA; - dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length = (USHORT)(ia_length + 12); - - /* Write the IANA opcode and data length into one word. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code)) << 16); - message_word |= dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the word into the packet buffer going to the server. */ - memcpy((buffer_ptr + temp_index), &message_word, sizeof(ULONG)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_option_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the option request option to the Client request */ -/* packet using the internal 'register' in the DHCPv6 Client instance */ -/* for what DHCPv6 options have been set or cleared. Also checks to */ -/* make sure it does not go past the end of the packet payload. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the option */ -/* request in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_option_request(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -USHORT message_word; -USHORT option_list; -USHORT option_length = 0; -UCHAR *option_length_ptr; -ULONG available_payload; - - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); - - /* Check if the option request option will fit in the packet buffer. */ - if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_option_length)) + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Set a local variable for convenience. */ - option_list = dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request; - - /* Update the option code. - Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code); - - /* Copy the option code to the packet. */ - memcpy((buffer_ptr + (*index)), &(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code), sizeof(USHORT)); - *index += (ULONG)sizeof(USHORT); - - /* Swap bytes back. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_code); - - /* Record the option length pointer and skip it, update the option length after fill the option data. */ - option_length_ptr = buffer_ptr + (*index); - *index += (ULONG)sizeof(USHORT); - - /* Now check to see which options we add as option data: */ - - /* Is the DNS server option requested? */ - if(option_list & NX_DHCPV6_DNS_SERVER_OPTION) - { - - /* Yes, add this option code into the option request data. */ - message_word = NX_DHCPV6_OP_DNS_SERVER; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_word); - - memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); - - /* Update the location of the buffer write pointer. */ - *index += (ULONG)sizeof(SHORT); - option_length = (USHORT)(option_length + sizeof(SHORT)); - } - - /* Is the timeS server option requested? */ - if(option_list & NX_DHCPV6_SNTP_SERVER_OPTION) - { - - /* Yes, add this option code into the option request data. */ - message_word = NX_DHCPV6_OP_SNTP_SERVER; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_word); - - memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); - - /* Update the location of the buffer write pointer. */ - *index += (ULONG)sizeof(SHORT); - option_length = (USHORT)(option_length + sizeof(SHORT)); - } - - /* Is the time zone option requested? */ - if(option_list & NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION) - { - - /* Yes, add this option code into the option request data. */ - message_word = NX_DHCPV6_OP_NEW_POSIX_TIMEZONE; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_word); - - memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); - - /* Update the location of the buffer write pointer. */ - *index += (ULONG)sizeof(SHORT); - option_length = (USHORT)(option_length + sizeof(SHORT)); - } - - /* Is the domain name option requested? */ - if(option_list & NX_DHCPV6_DOMAIN_NAME_OPTION) - { - - /* Yes, add this option code into the option request data. */ - message_word = NX_DHCPV6_OP_DOMAIN_NAME; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_word); - - memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); - - /* Update the location of the buffer write pointer. */ - *index += (ULONG)sizeof(SHORT); - option_length = (USHORT)(option_length + sizeof(SHORT)); - } - - /* Is the fully qualified domain name option requested? - A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND message. - A client that sends the Client FQDN option MUST also include the option in the Option Requst option - if it expects the server to include the Client FQDN option in any responses. RFC4704, Section5, Page7. */ - if(((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) && - (option_list & NX_DHCPV6_CLIENT_FQDN_OPTION)) - { - - /* Yes, add this option code into the option request data. */ - message_word = NX_DHCPV6_OP_CLIENT_FQDN; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_word); - - memcpy((buffer_ptr + (*index)), &message_word, sizeof(SHORT)); - - /* Update the location of the buffer write pointer. */ - *index += (ULONG)sizeof(SHORT); - option_length = (USHORT)(option_length + sizeof(SHORT)); - } - - /* Now record and update the option lenght. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_option_length = option_length; - NX_CHANGE_USHORT_ENDIAN(option_length); - memcpy(option_length_ptr, &option_length, sizeof(SHORT)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_server_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the server DUID to the Client request packet */ -/* based on the server DUID on record, checking to make sure it does */ -/* not go past the end of the packet payload. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the server */ -/* DUID in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG message_word; -ULONG available_payload; -UCHAR mac[8]; -UINT i = 0; - - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); - - /* Check if the largest possible server DUID will fit in the packet buffer. */ - if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length)) + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Make sure the Client has a valid Server DUID. */ - if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code != NX_DHCPV6_OP_SERVER_ID) - { - - /* Missing or invalid option data. */ - return NX_DHCPV6_INVALID_SERVER_DUID; - } - - /* Build the header from the client's record of its DHCPv6 Server DUID. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code)) << 16); - message_word |= (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy first half of the Server DUID option to packet buffer. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Build the DUID type and hardware type. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type)) << 16); - message_word |= dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Set up the DUID type and hardware type. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(UINT)); - *index += (ULONG)sizeof(UINT); - - /* Include the 'time' field if this is a Link layer time DUID type. */ - if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Build the time. */ - message_word = dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Set up the time. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); - (*index) += (ULONG)sizeof(ULONG); - } - - /* Build the link layer address. */ - if (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) - { - - /* The length of link layer address is 48 bit. */ - - /* Build the MSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw); - } - else if(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) - { - - /* The length of link layer address is 64 bits. */ - - /* Build the MSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 24); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 16); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw); - } - - /* Build the LSW. */ - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 24); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 16); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw >> 8); - mac[i++] = (UCHAR)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw); - - /* Set up the link layer address. */ - memcpy((buffer_ptr + (*index)), mac, i); - (*index) += i; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_client_FQDN PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the DHCPv6 Client FQDN Option to the Client */ -/* request packet , checking to make sure it does not go past the end */ -/* of the packet payload. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the server */ -/* DUID in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Client */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_client_FQDN(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG message_word; -ULONG available_payload; -UINT domain_name_length; - - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - (ULONG)sizeof(NX_IPV6_HEADER) - (ULONG)sizeof(NX_UDP_HEADER) - *index); - - /* Check if the largest possible server DUID will fit in the packet buffer. */ - if (available_payload < (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length)) + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - memset(&message_word, 0, sizeof(ULONG)); - - /* Set the option code and option length. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_code)) << 16); - message_word |= (dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_length); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Add the option code and option length into packet buffer. */ - memcpy((buffer_ptr + (*index)), &message_word, sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Add the flags into packet buffer. */ - *(buffer_ptr + (*index)) = dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags; - *index += 1; - - /* Encode the domain name into the packet buffer. */ - domain_name_length = _nx_dhcpv6_name_string_encode(buffer_ptr + (*index), (UCHAR *)dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_domain_name); - *index += domain_name_length; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX create dhcpv6 */ -/* client service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client */ -/* ip_ptr Pointer to Client IP instance */ -/* name_ptr DHCPV6 name pointer */ -/* packet_pool_ptr Pointer to Client packet pool */ -/* stack_ptr Pointer to free memory */ -/* stack_size Size of client stack memory */ -/* dhcpv6_state_change_notify Client state change handler */ -/* dhcpv6_server_error_handler Server error status handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_client_create Actual Client create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -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); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the DHCPv6 Client instance with a Netx packet */ -/* pool, processing thread, and various flag event queues, timers and */ -/* mutexes necessary for DHCPv6 Client operations. Reocrd the DHCPv6 */ -/* pointer for DAD callback function process. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client */ -/* ip_ptr Pointer to Client IP instance */ -/* name_ptr DHCPV6 name pointer */ -/* packet_pool_ptr Pointer to Client packet pool */ -/* stack_ptr Pointer to free memory */ -/* stack_size Size of Client stack memory */ -/* dhcpv6_state_change_notify Client state change handler */ -/* dhcpv6_server_error_handler Server error status handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_create Create ThreadX flag event queue*/ -/* tx_mutex_create Create mutex lock on resource */ -/* nx_packet_pool_delete Delete the DHCPV6 packet pool */ -/* nx_udp_socket_create Create the DHCPV6 UDP socket */ -/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ -/* tx_mutex_create Create DHCPV6 mutex */ -/* tx_mutex_delete Delete DHCPV6 mutex */ -/* tx_thread_create Create DHCPV6 thread */ -/* tx_timer_create Create DHCPV6 timer */ -/* tx_timer_delete Delete DHCPV6 timer */ -/* nxd_ipv6_address_change_notify Set the DAD callback function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -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); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX delete dhcpv6 */ -/* client service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_client_delete Actual DHCPV6 delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 delete service. */ - status = _nx_dhcpv6_client_delete(dhcpv6_ptr); - - /* Return commpletion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DHCPV6 Client instance and releases all */ -/* NetX Duo and ThreadX resources. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Release DHCPV6 UDP socket port*/ -/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ -/* tx_thread_terminate Terminate DHCPV6 thread */ -/* tx_thread_delete Delete DHCPV6 thread */ -/* tx_timer_delete Delete DHCPV6 timers */ -/* tx_mutex_delete Delete DHCPV6 mutexes */ -/* tx_event_flags_delete Delete DHCPV6 flag queue */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr) -{ - - - /* Terminate the DHCPV6 processing thread. */ - tx_thread_terminate(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Delete the DHCPV6 processing thread. */ - tx_thread_delete(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Delete the flag event queue. */ - tx_event_flags_delete(&dhcpv6_ptr -> nx_dhcpv6_events); - - /* 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)); - - /* Release the UDP socket port. */ - nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_ptr -> nx_dhcpv6_socket)); - - /* Clear the dhcpv6 structure ID. */ - dhcpv6_ptr -> nx_dhcpv6_id = 0; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_create_client_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create Client DUID */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* duid_type Type of DUID (link layer +/- time)*/ -/* hardware_type Network hardware type e.g IEEE 802*/ -/* time Time stamp unique DUID identifier */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* NX_DHCPV6_UNSUPPORTED_DUID_TYPE Unsupported DUID type */ -/* NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE Unsupported DUID hardware type */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_create_client_duid Actual create client DUID service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - - return NX_PTR_ERROR; - } - - /* Check for valid non pointer input. */ - if ((duid_type < NX_DHCPV6_DUID_TYPE_LINK_TIME) || (duid_type > NX_DHCPV6_DUID_TYPE_LINK_ONLY)) - { - return NX_DHCPV6_PARAM_ERROR; - } - - /* Ethernet is the only a hardware type supported by this API. */ - if ((hardware_type != NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) && (hardware_type != NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64)) - { - - /* Return any other type as an error status. */ - return NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE; - } - - /* This DUID type is not supported by this API. */ - if (duid_type == NX_DHCPV6_DUID_TYPE_VENDOR_ASSIGNED) - { - - /* Return as an error status. */ - return NX_DHCPV6_UNSUPPORTED_DUID_TYPE; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_create_client_duid(dhcpv6_ptr, duid_type, hardware_type, time); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_create_client_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCPv6 client DHCP Unique Identifier */ -/* (DUID) with the input values, sets the linklocal address while the */ -/* Client does not have an assigned global IP address, after waiting */ -/* for the IPv6 thread task to read its MAC address. If the caller */ -/* does not supply a time ID, it will generate one in place for Link */ -/* Layer Plus Time DUIDs. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* duid_type Type of DUID (link layer +/- time)*/ -/* hardware_type Network hardware type e.g IEEE 802*/ -/* time Time stamp unique DUID identifier */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* rand Generate random number for time ID*/ -/* tx_thread_sleep Relinquish thread control (sleep) */ -/* nxd_ipv6_linklocal_address_set Use MAC address as temporary IP */ -/* source address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time) -{ - -NX_INTERFACE *interface_ptr; -USHORT option_length; - - - /* Set the interface pointer. */ - interface_ptr = &(dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[dhcpv6_ptr -> nx_dhcpv6_client_interface_index]); - - /* Initialize the DUID to null. */ - memset(&(dhcpv6_ptr -> nx_dhcpv6_client_duid), 0, sizeof(NX_DHCPV6_DUID)); - - /* Assign the DUID op code. */ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_op_code = NX_DHCPV6_OP_CLIENT_ID; - - /* Assign field attributes depending on the DUID type. */ - if ((duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) || (duid_type == NX_DHCPV6_DUID_TYPE_LINK_ONLY)) - { - - /* Set the option data length minus the option header and size of the time field. */ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type = (USHORT)duid_type; - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type = (USHORT)hardware_type; - option_length = 4; - - /* Is the Link Layer Time DUID type? */ - if (duid_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Yes; add the size of the time field to the data length. */ - option_length = (USHORT)(option_length + 4); - - /* Did the caller supplied a time? */ - if (!time) - { - /* No, create a time field using the defined time constant plus a randomizing factor.*/ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time = (SECONDS_SINCE_JAN_1_2000_MOD_32 + (ULONG)(NX_RAND())) & 0xFFFFFFFF; - } - else - { - /* Apply the input time. */ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time = time; - } - } - - /* Set the globally unique link layer address. */ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw = interface_ptr -> nx_interface_physical_address_msw; - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw = interface_ptr -> nx_interface_physical_address_lsw; - - /* Check the hardware type. */ - if (hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) - { - - /* The length of link layer address is 48 bits. */ - option_length = (USHORT)(option_length + 6); - } - else if (hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) - { - - /* The length of link layer address is 64 bits. */ - option_length = (USHORT)(option_length + 8); - } - - /* Set the option length. */ - dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length = option_length; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_add_client_ia PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the add Client IA */ -/* (Identity Association) option service, including checking for invalid*/ -/* preferred and valid lifetimes. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* ipv6_address Requested IPv6 address */ -/* preferred_lifetime Requested IP lease time before */ -/* address is deprecated */ -/* valid_lifetime Requested IP lease time before */ -/* address is expired */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_add_client_ia Actual add client IA service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, - ULONG preferred_lifetime, ULONG valid_lifetime) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr || !ipv6_address) - { - - return NX_PTR_ERROR; - } - - /* Make sure the IPv6 address valid. */ - if ((ipv6_address -> nxd_ip_address.v6[0] == 0) && - (ipv6_address -> nxd_ip_address.v6[1] == 0) && - (ipv6_address -> nxd_ip_address.v6[2] == 0) && - (ipv6_address -> nxd_ip_address.v6[3] == 0)) - { - - return NX_DHCPV6_INVALID_IA_ADDRESS; - } - - /* Check for valid non pointer input. */ - if (preferred_lifetime > valid_lifetime) - { - - /* Client preferred time must be less than valid time or - server will reject it. */ - return NX_DHCPV6_PARAM_ERROR; - } - - /* Check for an empty IANA instance. */ - if (!dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code) - { - - return NX_DHCPV6_PARAM_ERROR; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_add_client_ia(dhcpv6_ptr, ipv6_address, preferred_lifetime, valid_lifetime); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_client_ia PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the Client Identity Association address with */ -/* the input values. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* ipv6_address Requested IPv6 address */ -/* preferred_lifetime Requested IP lease time before */ -/* address is deprecated */ -/* valid_lifetime Requested IP lease time before */ -/* address is expired */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_REACHED_MAX_IA_ADDRESS No space to record IA address */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, - ULONG preferred_lifetime, ULONG valid_lifetime) -{ -UINT ia_index; - - - /* Perform duplicate address detection. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0] == ipv6_address->nxd_ip_address.v6[0]) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[1] == ipv6_address->nxd_ip_address.v6[1]) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[2] == ipv6_address->nxd_ip_address.v6[2]) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[3] == ipv6_address->nxd_ip_address.v6[3])) - { - - /* The IA address has already exists. */ - return (NX_DHCPV6_IA_ADDRESS_ALREADY_EXIST); - } - } - - /* Find one valid space to set the IA address. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(!dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) - { - - /* Yes, got it. */ - break; - } - } - - if(ia_index < NX_DHCPV6_MAX_IA_ADDRESS) - { - - /* Yes, get it, set the IA address. */ - - /* Initialize the IA-Address to null. */ - memset(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index]), 0, sizeof(NX_DHCPV6_IA_ADDRESS)); - - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; - - /* Set the IA option length - minus the option header. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_option_length = (7 * sizeof(ULONG)) - 4; - - /* Set the IP address parameters as a hint to the server. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_version = NX_IP_VERSION_V6; - COPY_IPV6_ADDRESS(&(ipv6_address -> nxd_ip_address.v6[0]), &(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0])); - - /* Set the life time parameters as a hint to the server. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime = preferred_lifetime; - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime = valid_lifetime; - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_INITIAL; - - return NX_SUCCESS; - } - else - { - return NX_DHCPV6_REACHED_MAX_IA_ADDRESS; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_create_client_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create Client IA-NA */ -/* option service, including checking for invalid T1 and T2 times. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* IA_ident Interface Association ID */ -/* T1 Requested lease time with server */ -/* assigning IP (renew) */ -/* T2 Requested lease time with any */ -/* other server (rebind) */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_create_client_iana Actual create client IANA service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr || !IA_ident) - { - - return NX_PTR_ERROR; - } - - /* Check for valid non pointer input. */ - if (T1 > T2) - { - - /* Client preferred time must be less than valid time or server will reject it. */ - return NX_DHCPV6_PARAM_ERROR; - } - - - /* Call the actual service. */ - status = _nx_dhcpv6_create_client_iana(dhcpv6_ptr, IA_ident, T1, T2); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_create_client_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the Client's Identity Association for Non */ -/* Temporary Address (IANA) with the input values. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* IA_ident Interface Association ID */ -/* T1 Requested lease time with server */ -/* assigning IP (renew) */ -/* T2 Requested lease time with any */ -/* other server (rebind) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2) -{ - - /* Initialize the IANA to null. */ - memset(&(dhcpv6_ptr -> nx_dhcpv6_iana), 0, sizeof(NX_DHCPV6_IA_NA)); - - /* Assign the IANA attributes. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_op_code = NX_DHCPV6_OP_IA_NA; - dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id = IA_ident; - - /* Set the IANA option data length, minus the option header. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length = 3 * sizeof(ULONG); - - /* Apply the Client's preference for IP renew/rebind times. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = T1; - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = T2; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_client_duid_time_id PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get Client DUID time ID*/ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_id Pointer to DUID time field */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_client_duid_time_id Actual get Client DUID time ID */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !time_id) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_client_duid_time_id(dhcpv6_ptr, time_id); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_client_duid_time_id PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the Client DUID time ID saved to the client */ -/* record. It does not check if the DUID is properly filled out. It is*/ -/* up to the caller to check for a zero value (invalid) time ID. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_id Pointer to DUID time field */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_client_duid_time_id Actual get Client DUID time ID */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id) -{ - - /* The Time field is part of the NX_DHCPV6_DUID struct in the Client record. */ - *time_id = dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time; - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_register_IP_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function registers the assigned IP address to the IP task, */ -/* which adds the input address to the IP address table.In either case,*/ -/* the address index in the IP address table is recorded to the Client */ -/* record.It will require it if the DHCPv6 Client wants to clear the */ -/* IPv6 address. */ -/* */ -/* Note: the host application should perform address verification */ -/* e.g. Duplicate Address Detection to verify uniqueness of the input */ -/* address. If duplicate address detection is enabled in NetX Duo this */ -/* is done automatically. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_ipv6_address_set Add global address to IP */ -/* tx_mutex_get Get the DHCPv6 mutex */ -/* tx_mutex_put Put the DHCPv6 mutex */ -/* */ -/* CALLED BY */ -/* */ -/* nx_dhcpv6_process Process received packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_register_IP_address(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UINT address_index; -UINT ia_index; - - /* Set the DHCPv6 Client IPv6 addresses. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_INITIAL) - { - - /* Add the address to the IP instance address table. */ - status = nxd_ipv6_address_set(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_interface_index, - &dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address, 64, &address_index); - - /* Check for successful result. */ - if (status == NX_SUCCESS) - { - - /* Get the mutex protection for DHCP client. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - -#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) - - /* Set the IPv6 address status as DAD tentative, the status will be updated in _nx_dhcpv6_ipv6_address_DAD_notify. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_DAD_TENTATIVE; -#else - - /* Set the IPv6 address status as valid. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_VALID; -#endif - - /* Record the address index in the Client record. */ - dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = address_index; - - /* All done! Release the mutex.*/ - tx_mutex_put(&dhcpv6_ptr -> nx_dhcpv6_client_mutex); - } - - } - } - - /* Add the default router. */ - nxd_ipv6_default_router_add(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, &(dhcpv6_ptr-> nx_dhcpv6_server_address), - NX_WAIT_FOREVER, dhcpv6_ptr -> nx_dhcpv6_client_interface_index); - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_IP_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get Client global IP */ -/* address service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* ip_address Pointer to global IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_IP_address Actual get Client global IP */ -/* address service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !ip_address) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_IP_address(dhcpv6_ptr, ip_address); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_IP_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the IP address from the DHCPv6 */ -/* Client record. If the client address is not valid, a null IP */ -/* address is returned and an error status is set. */ -/* */ -/* Note that if the Client has received an IP address from the DHCPv6 */ -/* server the host must register that ddress with NetX Duo by calling */ -/* address with NetX Duo by calling the service nxd_ipv6_address_set. */ -/* Once the address is registered, the host can confirm its address by */ -/* calling nxd_ipv6_address_get. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* ip_address Pointer to NetX Duo address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Returned non zero IP address */ -/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Client not assigned an address */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address) -{ - -UINT status; - - - /* Clear the address buffer. */ - SET_UNSPECIFIED_ADDRESS(&ip_address -> nxd_ip_address.v6[0]); - - /* Initialize the outcome as no address assigned. */ - status = NX_DHCPV6_IA_ADDRESS_NOT_VALID; - - /* Is the client assigned a valid address? */ - if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - /* Yes; return the assigned IP address from the DHCPv6 Client record. */ - COPY_IPV6_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_global_address.nxd_ip_address.v6[0]), - &(ip_address -> nxd_ip_address.v6[0])); - - status = NX_SUCCESS; - } - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_lease_time_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get Client IP lease */ -/* time service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* T1 Pointer to T1 time */ -/* T2 Pointer to T2 time */ -/* preferred_lifetime Pointer to preferred lifetime */ -/* valid_lifetime Pointer to valid lifetime */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_lease_time_data Actual get Client IP lease time */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, - ULONG *valid_lifetime) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !T1 || !T2 || !preferred_lifetime || !valid_lifetime ) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_lease_time_data(dhcpv6_ptr, T1, T2, preferred_lifetime, valid_lifetime); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_lease_time_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the Client's global IP lease times T1 and T2*/ -/* and valid and preferred lifetimes. The address_status input field */ -/* indicates if the IP address on the Client record is valid and */ -/* registered. If so the lease and valid lifetimes are also registered */ -/* with the server (not merely Client preference or left over from an */ -/* expired IP address). */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* T1 Pointer to T1 time */ -/* T2 Pointer to T2 time */ -/* preferred_lifetime Pointer to preferred lifetime */ -/* valid_lifetime Pointer to valid lifetime */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, - ULONG *valid_lifetime) -{ - - /* Initialize data to zero. */ - *T1 = 0; - *T2 = 0; - *valid_lifetime = 0; - *preferred_lifetime = 0; - - /* If the client has a valid IP address status, return the actual lease time data. */ - if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - /* Get the time data from the Client record IA. */ - *T1 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1; - *T2 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; - *preferred_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_preferred_lifetime; - *valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_valid_lifetime; - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_DNS_server_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* index Index into DNS server list */ -/* server_address Pointer to copy address to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* _nx_dhcpv6_get_DNS_server_address Actual get DNS server address */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (dhcpv6_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_DNS_server_address(dhcpv6_ptr, index, server_address); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_DNS_server_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the DNS server address at the specified */ -/* index in the DHCP Client DNS list. The Client DNS server list is */ -/* compiled from DHCP Server messages supplying DNS server address */ -/* data. */ -/* */ -/* Note: the DHCPv6 Client is configured to store up to */ -/* NX_DHCPV6_NUM_DNS_SERVERS DNS server addresses. It is up to the */ -/* caller to supply the index to get each server in the list if there */ -/* is more than one stored. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* index Index into DNS server list */ -/* server_address Pointer to copy address to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_PARAM_ERROR Invalid index supplied */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_DNS_server_address Actual get DNS server address */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) -{ - - - /* Check for a valid input. */ - if (index >= NX_DHCPV6_NUM_DNS_SERVERS) - { - - return NX_DHCPV6_PARAM_ERROR; - } - - /* Store the specified DNS server addresses in the DHCPv6 Client list. */ - COPY_NXD_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[index]), server_address); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_time_server_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* index Index into time server list */ -/* server_address Pointer to copy address to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* _nx_dhcpv6_get_time_server_address Actual get time server address */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (dhcpv6_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_time_server_address(dhcpv6_ptr, index, server_address); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_time_server_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the time server address at the specified */ -/* index in the DHCP Client time list. The Client time server list is */ -/* compiled from DHCP Server messages supplying time server address */ -/* data. */ -/* */ -/* Note: the DHCPv6 Client is configured to store up to */ -/* NX_DHCPV6_NUM_TIME_SERVERS TIME server addresses. It is up to the */ -/* caller to supply the index to get each server in the list if there */ -/* is more than one stored. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* index Index into time server list */ -/* server_address Pointer to copy address to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_PARAM_ERROR Invalid index supplied */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_time_server_address Actual get time server address */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address) -{ - - - /* Check for a valid input. */ - if (index >= NX_DHCPV6_NUM_TIME_SERVERS) - { - - return NX_DHCPV6_PARAM_ERROR; - } - - /* Store the specified time server addresses in the DHCPv6 Client list. */ - COPY_NXD_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_time_server_address[index]), server_address); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_other_option_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* option_code Option code of requested data */ -/* buffer Buffer to copy data to */ -/* buffer_length Size of buffer to copy to */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* */ -/* CALLS */ -/* _nx_dhcpv6_get_other_option_data Actual get other option data */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer,UINT buffer_length) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !buffer) - { - return NX_PTR_ERROR; - } - - /* Check for invalid non pointer input. */ - if (!option_code || !buffer_length) - { - - return NX_DHCPV6_PARAM_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_other_option_data(dhcpv6_ptr, option_code, buffer, buffer_length); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_other_option_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the option information requested in the */ -/* input parameter. Note that there are only 2 options which the */ -/* NetX DHCPv6 client supports. Some options have their own specific */ -/* API such as _nx_dhcpv6_get_DNS_server_address. The complete list */ -/* of options is not supported by the NetX Duo DHCPv6 Client. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* option_code Option code of requested data */ -/* buffer Buffer to copy data to */ -/* buffer_length Size of buffer to copy to */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCPV6_UNKNOWN_OPTION Unknown option specified */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copy specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length) -{ - - -UINT length = 0; - - /* Check to see which option data is requested: */ - switch (option_code) - { - - case NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION: - - /* Update the amount of data we are copying into the buffer. */ - length += NX_DHCPV6_TIME_ZONE_BUFFER_SIZE; - - /* Check that we don't overrun the buffer. */ - if (length > buffer_length) - { - return NX_DHCPV6_INVALID_DATA_SIZE; - } - - /* Copy the time zone data to the supplied buffer. */ - memcpy(buffer, dhcpv6_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); - - break; - - - case NX_DHCPV6_DOMAIN_NAME_OPTION: - - /* Update the amount of data we are copying into the buffer. */ - length += NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE; - - /* Check that we don't overrun the buffer. */ - if (length > buffer_length) - { - return NX_DHCPV6_INVALID_DATA_SIZE; - } - - /* Copy the domain name data to the supplied buffer. */ - memcpy(buffer, dhcpv6_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); - break; - - /* Unknown or unsupported option*/ - default: - - return NX_DHCPV6_UNKNOWN_OPTION; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_time_accrued PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get time accrued on */ -/* Client IP lease service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_accrued Pointer to time since IP lease */ -/* assigned (secs) */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_time_accrued Actual get time accrued on Client */ -/* IP address lease service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !time_accrued) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_time_accrued(dhcpv6_ptr, time_accrued); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_time_accrued PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the time accrued on the assigned global IP */ -/* address lease. IP address to verify the address is still valid. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_accrued Pointer to time since IP lease */ -/* assigned (secs) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain exclusive lock on Client */ -/* time accrued variable */ -/* tx_mutex_put Release exclusive lock in Client */ -/* time variable */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued) -{ -UINT ia_index; -UINT found_ia = 0; - - /* Initialize the time accrued to zero. */ - *time_accrued = 0; - - /* Check if the client currently has a valid IP address assigned. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - - /* Yes, got it. */ - found_ia= 1; - break; - } - } - - if(found_ia == 1) - { - - /* Get the time accrued on the IP address lease. */ - *time_accrued = dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued; - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_iana_lease_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get T1 and T2 value */ -/* of IANA option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* T1 Pointer to T1 time */ -/* T2 Pointer to T2 time */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_iana_lease_time Actual get Client IP T1/T2 time */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !T1 || !T2) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_iana_lease_time(dhcpv6_ptr, T1, T2); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_iana_lease_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the T1 and T2 of Client's global IP. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* T1 Pointer to T1 time */ -/* T2 Pointer to T2 time */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2) -{ -UINT ia_index; -UINT found_ia = 0; - - /* Initialize data to zero. */ - *T1 = 0; - *T2 = 0; - - /* Check if the client currently has a valid IP address assigned. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - - /* Yes, got it. */ - found_ia= 1; - break; - } - } - - if(found_ia == 1) - { - - /* Get the time data from the Client record IA. */ - *T1 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1; - *T2 = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_valid_ip_address_count PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get valid IP address */ -/* count. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* address_count The count of valid IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_valid_ip_address_count */ -/* Actual get the valid IP count */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !address_count) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_valid_ip_address_count(dhcpv6_ptr, address_count); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_valid_ip_address_count PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the Client's global IP, then record the */ -/* count of valid IP address */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* address_count The count of valid IP address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count) -{ - -UINT ia_index; - - /* Initialize data to zero. */ - *address_count = 0; - - /* Check if the client currently has a valid IP address assigned. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - - /* Yes, get one, update the count. */ - (*address_count)++; - } - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_get_valid_ip_address_lease_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get valid IP address, */ -/* the preferred lifetime and the valid lifetime by the address index. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* address_index The valid address index */ -/* ip_address Pointer to IP address */ -/* preferred_lifetime Pointer to preferred lifetime */ -/* valid_lifetime Pointer to valid lifetime */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_get_lvalid_ip_address_lease_time */ -/* Actual get Client IP valid address*/ -/* and the lease time of IP */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, - ULONG *preferred_lifetime, ULONG *valid_lifetime) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr || !ip_address || !preferred_lifetime || !valid_lifetime ) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_get_valid_ip_address_lease_time(dhcpv6_ptr, address_index, ip_address, preferred_lifetime, valid_lifetime); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_get_valid_ip_address_lease_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the Client's valid global IP addresses, */ -/* preferred lifetime and valid lifetime by address index. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* address_index The valid address index */ -/* ip_address Pointer to IPv6 address */ -/* preferred_lifetime Pointer to preferred lifetime */ -/* valid_lifetime Pointer to valid lifetime */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, - ULONG *preferred_lifetime, ULONG *valid_lifetime) -{ - -UINT status; -UINT ia_index; -UINT valid_ia_count; - - - /* Initialize data to zero. */ - valid_ia_count = 0; - *valid_lifetime = 0; - *preferred_lifetime = 0; - status = NX_DHCPV6_IA_ADDRESS_NOT_VALID; - - /* Clear the address buffer. */ - SET_UNSPECIFIED_ADDRESS(&ip_address -> nxd_ip_address.v6[0]); - - /* Check if the client currently has a valid IP address assigned. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Skip empty or invalidated addresses. */ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - - if((valid_ia_count++) == address_index) - { - - /* Yes, got it. */ - break; - } - } - } - - if(ia_index < NX_DHCPV6_MAX_IA_ADDRESS) - { - - /* Yes; return the assigned IP address from the DHCPv6 Client record. */ - COPY_IPV6_ADDRESS(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), - &(ip_address -> nxd_ip_address.v6[0])); - - /* Set the IP version. */ - ip_address -> nxd_ip_version = NX_IP_VERSION_V6; - - /* Return the preferred lifetime and valid lifetime. */ - *preferred_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime; - *valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime; - - status = NX_SUCCESS; - } - - /* Return. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_IP_lifetime_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is scheduled by the ThreadX scheduler on a user */ -/* configurable time interval. It updates the time accrued since the */ -/* Client was assigned its global IP address so that the DHCP Client */ -/* knows when to renew or rebind its IP address. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr_value Pointer to the DHCPV6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_IP_lifetime_timeout_entry(ULONG dhcpv6_ptr_value) -{ - -NX_DHCPV6 *dhcpv6_ptr; - - - /* Setup DHCPv6 Client pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, dhcpv6_ptr_value) - - /* Check if the DHCPv6 Client has valid IP address assigned and a finite IP - address lease (no point in waiting for an infinite lease to time out!) */ - if ((dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 != NX_DHCPV6_INFINITE_LEASE) && - (dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 != 0)) - { - - /* Update the time remaining on the Client IP address lease. - The current time expressed in units of seconds. */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued += NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL; - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function executes the DHCPV6 Client request. It compiles */ -/* and sends the DHCPv6 request message, and updates the Client record */ -/* with server data. It maintains the DHCPv6 Client state and calls */ -/* the state change callback if one is registered with the DHCPv6 */ -/* Client. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_send_request Send the Client DHCPv6 request */ -/* _nx_dhcpv6_waiting_on_reply Wait for valid DHCPv6 server reply*/ -/* _nx_dhcpv6_request_decline Send the DHCPv6 DECLINE request */ -/* _nx_dhcpv6_register_IP_address Register Client IP address */ -/* _nx_dhcpv6_remove_assigned_address */ -/* Remove Client global IP address */ -/* _nx_dhcpv6_update_retransmit_info Update the retransmit information */ -/* _nx_dhcpv6_send_solicit Send the DHCPv6 solicit message */ -/* _nx_dhcpv6_flush_queue_packets Flush the queue packets */ -/* tx_mutex_get Obtain lock on Client resource */ -/* tx_mutex_put Release lock on Client resourse */ -/* tx_timer_deactivate Deactivate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_thread_entry Processing thread for DHCPv6 */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_process(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UCHAR original_state; - - /* Initialize the DHCPv6 Client status as no errors. */ - dhcpv6_ptr -> nx_status_code = NX_DHCPV6_SUCCESS; - - /* Clear any previous messages from the DHCPv6 server. */ - memset(dhcpv6_ptr -> nx_status_message, 0, NX_DHCPV6_MAX_MESSAGE_SIZE); - - /* Remember the original DHCPv6 state for the changed state callback function. */ - original_state = dhcpv6_ptr -> nx_dhcpv6_state; - - /* Process the DHCPv6 Client for the state it is in. */ - switch (dhcpv6_ptr -> nx_dhcpv6_state) - { - - /* The DHCPv6 remains initial status or DHCPv6 interactive process has completed. - Just clear the timer and message ID. */ - case NX_DHCPV6_STATE_INIT: - case NX_DHCPV6_STATE_BOUND_TO_ADDRESS: - { - - /* Clear the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Flush the queue packets. */ - _nx_dhcpv6_flush_queue_packets(dhcpv6_ptr); - - return; - } - - /* The caller has requested to send a solicit message. */ - case NX_DHCPV6_STATE_SENDING_SOLICIT: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_SOLICIT; - - dhcpv6_ptr -> nx_dhcpv6_solicitations_sent++; - - /* Send the DHCPV6 Solicit message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - /* Make sure the server DUID is cleared. Client should be accepting any server reply. */ - memset(&(dhcpv6_ptr -> nx_dhcpv6_server_duid), 0, sizeof(NX_DHCPV6_DUID)); - - /* Wait for a reply from the server. This will also extract the - server packet information and update the DHCPv6 Client record (and state). */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for processing error or error code sent by server. As per RFC 3315 section 17.1.3, - the Client ignores status errors (e.g. No Addresses Available) from the server, and continues - sending Solicit messages. */ - if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* The retry limit on Solicit messages is exceeded. Set the CLient back to - the INIT state and stop sending solicit messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Request attempt failed. The state change callback if set will be called. */ - } - } - else - { - - if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_NORMAL) - { - /* Server has responded to and accepted the SOLICIT request with an ADVERTISE message. - Move to the next state to continue the DHCPv6 protocol. */ - - /* Set the DHCP Client state to Requesting. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; - - /* Reset the retransmission timeout and retry. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Increment the number of solicitation responses. */ - dhcpv6_ptr -> nx_dhcpv6_solicitation_responses++; - } - else - { - - /* Server sending the REPLY message responded to and accepted the SOLICIT request with Rapid Commit option, - Move to the next state to continue the DHCPv6 protocol. */ - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Increment the number of solicitation responses. */ - dhcpv6_ptr -> nx_dhcpv6_solicitation_responses++; - - /* Clear the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Set the DHCP Client state to Requesting. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - - /* Yes, get the IPv6 address by DHCPv6. set it. */ - status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); - - } - - } - - break; - } - - - /* The DHCP Client is in the REQUEST state; send the Request message till the server responds - or the number of retries exceeds the max. */ - case NX_DHCPV6_STATE_SENDING_REQUEST: - { - - /* Reset the initial timeout and zero out transmission count. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_REQUEST; - - /* Transmit the Request message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for transmission error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - dhcpv6_ptr -> nx_dhcpv6_requests_sent++; - - /* Send the message to the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error or Server error code. */ - if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Check the status. */ - if ((status == NX_SUCCESS) && - ((dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NOT_ON_LINK) || - (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_ADDRESS_AVAILABLE))) - { - - /* Indicate the DHCP Client process is idle. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Clear the assigned IP address. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr,NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* When the client receives a NotOnLink status from the server in response to a Request, - the client can restart the DHCP server discovery process. RFC3315, Section18.1.8, Page48. */ - _nx_dhcpv6_request_solicit(dhcpv6_ptr); - } - - else - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* The retry limit on Request messages is exceeded. Set the Client back to - the INIT state and stop sending request messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Request attempt failed. The state change callback if set will be called. */ - } - } - } - else - { - - /* The Server responded to and accepted the REQUEST message. The Client is now bound to assigned - IPv6 address. The Client must still register this IPv6 address with NetX Duo to verify it is - unique on the network. */ - - /* Clear the time accrued on the new IP lease to zero. */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Increment the number of Request responses received. */ - dhcpv6_ptr -> nx_dhcpv6_request_responses++; - - /* Indicate the Client is bound to an assigned IPv6 address. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - - /* Yes, get the IPv6 address by DHCPv6. set it. */ - status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); - } - - break; - } - - /* The caller has requested a RENEW request message be sent. */ - case NX_DHCPV6_STATE_SENDING_RENEW: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_RENEW; - - dhcpv6_ptr -> nx_dhcpv6_renews_sent++; - - /* Send the DHCPV6 RENEW message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for transmission error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - /* Send the message to the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error or Server error code. */ - if ((status != NX_SUCCESS) || - (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS) || - ((dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) == 0)) - { - - /* Process the NoBinding status. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_BINDING)) - { - - /* When the client receives a Reply message in response to a Renew or Rebind message, - send a Request message if the IA contains a Status Code option with the NoBinding status. - RFC 3315, Sectoon 18.1.8, Page 48. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; - - /* Reset the retransmission timeout and retry. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - } - else - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* Clear the assigned IP address. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* The retry limit on Renew messages is exceeded. Set the Client back to - the INIT state and stop sending Renew messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Renew attempt failed. The state change callback if set will be called. */ - } - } - } - else - { - - /* The Server responded to and accepted our RENEW request. Update the Client to a bound - state and reset the lease timers. */ - - /* Indicate the Client is bound to an assigned IPv6 address. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - - /* Reset the time keeper! */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Yes, get the IPv6 address by DHCPv6. set it. */ - status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); - - /* Increment the number of renew responses received. */ - dhcpv6_ptr -> nx_dhcpv6_renew_responses++; - } - - break; - } - - /* The caller has requested to send a rebind request message. */ - case NX_DHCPV6_STATE_SENDING_REBIND: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_REBIND; - - /* Increase the count of retries. */ - dhcpv6_ptr -> nx_dhcpv6_rebinds_sent++; - - /* Send the DHCPV6 Rebind message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for socket send error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - /* Make sure the server DUID is cleared. Client should be accepting any server reply. */ - memset(&(dhcpv6_ptr -> nx_dhcpv6_server_duid), 0, sizeof(NX_DHCPV6_DUID)); - - /* Send the message to the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error or Server error code. */ - if ((status != NX_SUCCESS) || - (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS) || - ((dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) == 0)) - { - - /* Process the NoBinding status. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NO_BINDING)) - { - - /* When the client receives a Reply message in response to a Renew or Rebind message, - send a Request message if the IA contains a Status Code option with the NoBinding status. - RFC 3315, Section 18.1.8, Page 48. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_REQUEST; - - /* Reset the retransmission timeout and retry. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - } - else - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* Clear the assigned IP address. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* The retry limit on Rebind messages is exceeded. Set the Client back to - the INIT state and stop sending Rebind messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Rebind attempt failed. The client state change callback if set will be called. */ - } - } - } - else - { - - /* Make sure the Client state is set to Bound to an assigned IPv6 address. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - - /* Reset the time keeper! */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Yes, get the IPv6 address by DHCPv6. set it. */ - status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); - - /* Increment the number of rebind responses received. */ - dhcpv6_ptr -> nx_dhcpv6_rebind_responses++; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - } - - break; - } - - case NX_DHCPV6_STATE_SENDING_CONFIRM: - { - - /* Set the message type. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_CONFIRM; - - /* Increase the count of retries. */ - dhcpv6_ptr -> nx_dhcpv6_confirms_sent++; - - /* Send the DHCPV6 Confirm message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Send the message until we get a reply from the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error or Server error code. */ - if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code == NX_DHCPV6_NOT_ON_LINK)) - { - - /* Indicate the DHCP Client process is idle. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Clear the assigned IP address. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr,NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* When the client receives a NotOnLink status from the server in response to a Confirm messag, - the client performs DHCP server solicitation. RFC3315, Section18.1.8, Page48. */ - _nx_dhcpv6_request_solicit(dhcpv6_ptr); - } - - /* Retransmit the Confirm message. */ - else - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* The retry limit on Confirm messages is exceeded. Set the Client back to - the INIT state and stop sending rebind messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Confirm request failed. The state change callback if set will be called. */ - } - } - } - else - { - - /* Successful confirmation. Set the assigned address status to valid (confirmed). */ - - /* Yes, get the IPv6 address by DHCPv6. set it. */ - status = _nx_dhcpv6_register_IP_address(dhcpv6_ptr); - - /* Increment the number of responses to confirm. */ - dhcpv6_ptr -> nx_dhcpv6_confirm_responses++; - - /* Restore the Client state depending on its IANA address status. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - } - - break; - - } - - case NX_DHCPV6_STATE_SENDING_RELEASE: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_RELEASE; - - /* Increase the count of releases. */ - dhcpv6_ptr -> nx_dhcpv6_releases_sent++; - - /* Send the DHCPV6 Release message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for socket error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - /* Send the message to the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error. For the release message, consider the release - request completed if the server responds, regardless of Server error code. RFC 3315 Section 18.1.8 */ - if (status != NX_SUCCESS) - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* Clear global ip address and lifetime parameters from the Client record. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* The retry limit on release messages is exceeded. Set the Client back to - the INIT state and stop sending rebind messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* No response to release message from server. The state change callback if set will be called. */ - } - } - else - { - /* Increment the number of responses to release request. */ - dhcpv6_ptr -> nx_dhcpv6_release_responses++; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Clear global ip address and lifetime parameters from the Client record. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* Update the Client state to not bound. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - } - - break; - } - - case NX_DHCPV6_STATE_SENDING_DECLINE: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_DECLINE; - - /* Increase the count of declines. */ - dhcpv6_ptr -> nx_dhcpv6_declines_sent++; - - /* Send the DHCPV6 Decline message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for interal error. */ - if (status != NX_SUCCESS) - { - - /* Return. Can't do any more now. */ - return; - } - - /* Send the message to the server. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error. For the decline message, consider the release - request completed if the server responds, regardless of Server error code. RFC3315,Section 18.1.7 */ - if (status != NX_SUCCESS) - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* Clear global ip address and lifetime parameters from the Client record. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* The retry limit on decline messages is exceeded. Set the Client back to - the INIT state and stop sending rebind messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* No response to decline message from server. The state change callback if set will be called. */ - } - } - else - { - - /* Increment the number of server responses to Decline request. */ - dhcpv6_ptr -> nx_dhcpv6_decline_responses++; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Clear global ip address and lifetime parameters from the Client record. */ - status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - /* Change the DHCPv6 Client to the unbound state. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - } - - break; - } - - case NX_DHCPV6_STATE_SENDING_INFORM_REQUEST: - { - - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type = NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST; - - /* Increase the count of declines. */ - dhcpv6_ptr -> nx_dhcpv6_inform_req_sent++; - - /* Send the Inform Request message. */ - status = _nx_dhcpv6_send_request(dhcpv6_ptr); - - /* Check for transmission error. */ - if (status != NX_SUCCESS) - { - - /* Return. Nothing more to do. */ - return; - } - - /* Wait for a reply from the server. This will also extract the - server packet information and update the DHCPv6 Client state. */ - status = _nx_dhcpv6_waiting_on_reply(dhcpv6_ptr); - - /* Check for socket receive error or Server error code. */ - if ((status != NX_SUCCESS) || (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Update the retransmission information. */ - if (_nx_dhcpv6_update_retransmit_info(dhcpv6_ptr)) - { - - /* The retry limit on decline messages is exceeded. Set the Client back to - the INIT state and stop sending rebind messages for now. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - } - } - else - { - /* Increment the number of responses to Inform Request received. */ - dhcpv6_ptr -> nx_dhcpv6_inform_req_responses++; - - /* The next sending packet is the new packet, so reset the message id. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = 0; - - /* Receive the correct response, so deactivate the session timer of elapsed time. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Restore the Client state depending on its IANA address status. */ - if (dhcpv6_ptr -> nx_dhcpv6_ia[0].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND_TO_ADDRESS; - } - else - { - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - } - } - - break; - } - - default: - { - - /* Unknown or unsupported DHCPv6 request (state). */ - return; - } - } - - /* Is there a state change callback registered with the Client? */ - if ((dhcpv6_ptr -> nx_dhcpv6_state_change_callback) && (original_state != (dhcpv6_ptr -> nx_dhcpv6_state))) - { - - /* Yes, call the the state change callback with the original and new state. */ - (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_client_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the client DUID from the server reply and */ -/* verifies that it matches the Client DUID on record. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_CLIENT_DUID Client DUID is missing data or */ -/* does not match the DUID on record*/ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_data Parses data from specified buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts server reply from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -ULONG data; -UINT index; - - - /* Set an index past the option code and data length. */ - index = 4; - - /* The Client should already have its own DUID on record. So just parse the - data and compare each DUID field with the Client's DUID. */ - - /* Extract the DUID type which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); - - /* Does this match the Client DUID type on record? */ - if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type)) - { - - /* No, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - index += 2; - - /* Extract the hardware type which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); - - /* Does this match the Client DUID hardware type on record? */ - if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type)) - { - - /* No, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - index += 2; - - /* IS this a link layer plus time DUID type? */ - if ((dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_type) == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Yes; Extract the time which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); - - /* Does this match the Client DUID time on record? */ - if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_duid_time)) - { - - /* No, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - index += 4; - } - - /* Check the hardware type to extract the MSW. */ - if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) - { - - /* The length of link layer address is 48 bits. */ - - /* Yes; Extract the link local address msw which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &data); - index += 2; - } - else if (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) - { - - /* The length of link layer address is 64 bits. */ - - /* Yes; Extract the link local address msw which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); - index += 4; - } - - /* Does this match the Client DUID link layer most significant bytes on record? */ - if (data != (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw)) - { - - /* No, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - /* Yes; Extract the link local address lsw which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &data); - index += 4; - - /* Does this match the Client DUID link layer least significant bytes on record? */ - if (data != ((dhcpv6_ptr -> nx_dhcpv6_client_duid).nx_link_layer_address_lsw)) - { - - /* No, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - /* Are we past the end of the buffer, subtracting for the toplevel opcode and - length of the IANA option? */ - if (((index - 4) > length) || ((index - 4) < length)) - { - - /* Yes, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_CLIENT_DUID; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_domain_name PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the domain name option from the server reply.*/ -/* It will save as much of the domain name that will fit in the Client */ -/* domain name buffer. Buffer size is user configurable. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts DHCPv6 options from */ -/* server reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_domain_name(NX_DHCPV6 *dhcpv6_ptr, UCHAR *packet_start, UCHAR *received_buffer, UINT length) -{ - -UINT domain_name_length; -UINT temp_length; -UCHAR *domain_name_ptr; -UCHAR *buffer_prepend_ptr; -UINT buffer_size; -UINT i; - - - /* Initialize the value. */ - domain_name_length = 0; - temp_length = 0; - domain_name_ptr = received_buffer + 4; - buffer_prepend_ptr = &dhcpv6_ptr -> nx_dhcpv6_domain_name[0]; - buffer_size = NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE; - - /* Process the domain search list options. */ - while(temp_length < length) - { - - /* Calculate the domain name length in the Domaim Search List option,include the null flag '\0'. */ - for (i = 0; (i + temp_length < length) && (domain_name_ptr[i] != '\0'); i++); - - if (i + temp_length == length) - { - return(NX_DHCPV6_PROCESSING_ERROR); - } - else - { - temp_length += (i + 1); - } - - /* Record the real domain name and return the length, one less for NULL termination. */ - domain_name_length = _nx_dhcpv6_name_string_unencode(packet_start, (UINT)(domain_name_ptr - packet_start), buffer_prepend_ptr, (UINT)((buffer_size - 1) & 0xFFFFFFFF)); - - /* Check the domain name length. */ - if(!domain_name_length) - { - - /* Process error, return. */ - return NX_DHCPV6_PROCESSING_ERROR; - } - - else - { - - /* Update the buffer value,include the null flag '\0'. */ - domain_name_ptr += temp_length; - buffer_prepend_ptr += (domain_name_length + 1); - buffer_size -= (domain_name_length + 1); - } - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_name_string_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a string containing the name as a list of */ -/* labels separated by dots to the encoded list of labels specified */ -/* in RFC1035 for DNS servers. This conversion doesn't handle */ -/* compression and doesn't check on the lengths of the labels or the */ -/* entire name. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* count Count of characters encoded */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_add_client_FQDN Add FQDN Option to DHCPv6 packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_name_string_encode(UCHAR *ptr, UCHAR *name) -{ - -UCHAR *length; -UINT count = 1; - - - /* Point to the first character position in the buffer. This will point - to the length of the following name. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - - /* Move through string, copying bytes and updating length. - Whenever a "." is found, start a new string by updating the - pointer to the length and setting the length to zero. */ - while (*name) - { - - /* Is a dot been found? */ - if (*name == '.') - { - - /* Yes, setup a new length pointer. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - name++; - } - else - { - - /* Copy a character to the destination. */ - *ptr++ = *name++; - - /* Adjust the length of the current segment. */ - (*length)++; - } - - /* Increment the total count here. */ - count++; - } - - /* Add the final zero length, like a NULL terminator. */ - *ptr = 0; - - /* Increment the total count. */ - count++; - - /* Return the count. */ - return(count); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_name_string_unencode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts from the encoded list of labels as specified */ -/* in RFC 1035 to a string containing the name as a list of labels */ -/* separated by dots. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer to decode */ -/* start Location of start of data */ -/* buffer Pointer to decoded data */ -/* size Size of data buffer to decode */ -/* */ -/* OUTPUT */ -/* */ -/* Size of decoded data */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process_domain_name Process the domain name */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_name_string_unencode(UCHAR *data, UINT start, UCHAR *buffer, UINT size) -{ - -UCHAR *character = data + start; -UINT length = 0; - - - /* As long as there is space in the buffer and we haven't - found a zero terminating label */ - while ((size > length) && (*character != '\0')) - { - - UINT labelSize = *character++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_DHCPV6_LABEL_MAX) - { - - /* Simple count, check for space and copy the label. */ - while ((size > length) && (labelSize > 0)) - { - - *buffer++ = *character++; - length++; - labelSize--; - } - - /* Now add the '.' */ - *buffer++ = '.'; - length++; - } - else if ((labelSize & NX_DHCPV6_COMPRESS_MASK) == NX_DHCPV6_COMPRESS_VALUE) - { - - /* This is a pointer, just adjust the source. */ - character = data + ((labelSize & NX_DHCPV6_LABEL_MAX) << 8) + *character; - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - - /* Validate the length. */ - if (length == 0) - { - return(length); - } - - /* Done copying the data, set the last . to a trailing null */ - if (*(buffer - 1) == '.') - { - - buffer--; - length --; - } - - /* Null terminate name. */ - *buffer = '\0'; - - /* Return name size. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_DNS_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the DNS server option from the server reply. */ -/* It will save as many DNS name server addresses as are in the reply */ -/* for which the Client is configured to save. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_OPTION_DATA DNS server option missing data or */ -/* improperly formatted */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts DHCPv6 options from */ -/* server reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT index; -UINT w, j; - - - /* Set the location of the read pointer into the buffer. */ - index = 4; - j = 0; - - /* Loop through the length of the buffer to parse. */ - while ((index - 4) < length) - { - - /* Set the IP version. */ - dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; - - /* Get the next IPv6 DNS server address. */ - for (w = 0; w <= 3; w++) - { - - /* Is the DHCPv6 Client configured to store another DNS server address? */ - if (j < NX_DHCPV6_NUM_DNS_SERVERS) - { - - /* Yes; copy the next word into the current DNS server address. */ - memcpy(&(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_address.v6[w]), - (received_buffer + index), sizeof(ULONG)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_address.v6[w]); - } - - /* Move to the next IPv6 address word. */ - index += 4; - } - - dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; - - /* Get the next DNS server address in the reply buffer. */ - j++; - } - - /* Is there any more data in the buffer? */ - if (((index - 4 ) > length) || ((index - 4 )< length)) - { - - /* Yes, not sure what is going on with this packet. Treat as an error. */ - return NX_DHCPV6_INVALID_OPTION_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_ia PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the IA address option from the server reply. */ -/* It also checks that the server preferred and valid lifetimes are */ -/* legitamate. If the IANA option contains an IA option, that will also*/ -/* be processed as well as any status code options. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Size of server reply buffer */ -/* ia_index The index of IA address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_IA_DATA IA option is missing data or */ -/* improperly formatted */ -/* NX_DHCPV6_INVALID_IA_TIME IA option lifetime data is invalid*/ -/* NX_DHCPV6_UNKNOWN_OPTION Unkonw option type */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Get the option code and length */ -/* _nx_dhcpv6_process_status Processes STAUTS in reply buffer */ -/* nx_dhcpv6_server_error_handler Pointer to error code handler */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process_iana Processes IANA in reply buffer */ -/* DHCPv6 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_ia(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length, UINT ia_index) -{ - -ULONG preferred_lifetime; -ULONG valid_lifetime; -UINT index, w; -UINT status; -ULONG opcode, option_length; - - - /* Fill in the IA address code and length. Client might already have one on - record, but use the server's data instead. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; - - /* Set the index for the read pointer past the option header. */ - index = 4; - - for (w = 0; w <= 3; w++) - { - - /* Copy each IPv6 address word into the IA address. */ - memcpy(&(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[w]), - (received_buffer + index), sizeof(ULONG)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[w]); - - /* Move to the next IPv6 address word. */ - index += 4; - - /* Check if we're going past the end of the option data. */ - if ((index - 4) > length) - { - /* Yes, return an error status.*/ - return NX_DHCPV6_INVALID_IA_DATA; - } - } - - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* Copy the lifetime data from the reply buffer to temporary variables.*/ - memcpy(&preferred_lifetime, (received_buffer + index), sizeof(ULONG)); - index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(preferred_lifetime); - - memcpy(&valid_lifetime, (received_buffer + index), sizeof(ULONG)); - index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(valid_lifetime); - - /* Check for invalid lifetime data. The preferred lifetime MUST be less than - the valid lifetime. Note that a zero lifetime is acceptable - (the server is letting the Client use its own preference). */ - if (preferred_lifetime > valid_lifetime) - { - /* Discard this address. We cannot use it. */ - return NX_DHCPV6_INVALID_IA_TIME; - } - - /* OK to assign time data to the client. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_preferred_lifetime = preferred_lifetime; - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime = valid_lifetime; - - /* Update the address status. */ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_INVALID) - { - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_INITIAL; - } - - /* Update the map status, 0xFFFFFFFF indicate the IPv6 address of IA option has been processed. */ - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map = 0xFFFFFFFF; - - /* Check if we're at the end of option data yet. */ - if (index - 4 == length) - { - - /* Yes, all done. */ - return NX_SUCCESS; - } - - /* Process the status code option. */ - status = _nx_dhcpv6_utility_get_block_option_length(received_buffer + index, &opcode, &option_length); - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Check if this is an IAaddr status option request. */ - if (opcode == NX_DHCPV6_OP_STATUS_CODE) - { - /* The IAaddr option returned by the DHCPv6 server includes a status option. */ - - /* Process the status. */ - status = _nx_dhcpv6_process_status(dhcpv6_ptr, (received_buffer + index), option_length); - - /* Now check on the server status of the previous option in the DHCP message. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Does the dhcpv6 client have a server error handler? */ - if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) - { - - /* Call the error handler with status code, option (IAaddr) and which message type it refers to. */ - dhcpv6_ptr -> nx_dhcpv6_server_error_handler(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_ADDRESS, dhcpv6_ptr -> nx_status_code, - dhcpv6_ptr -> nx_dhcpv6_received_message_type); - } - } - - /* Check for errors processing the DHCPv6 message. */ - if (status != NX_SUCCESS) - { - - /* Abort further processing. Return error status. */ - return status; - } - } - - else - { - return NX_DHCPV6_UNKNOWN_OPTION; - } - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - - /* Check if we went past the reported size of IA address data. */ - if ((index - 4) != length) - { - - /* Return an error status. Cannot accept this reply. */ - return NX_DHCPV6_INVALID_IA_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the IANA option from the server reply. It */ -/* verifies the IANA option ID matches the IANA option ID on client */ -/* record. It also checks that the server T1 and T2 lease times are */ -/* legitamate. If the IANA option contains an IA option, that will also*/ -/* be processed as well as any status code options. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_BAD_IANA_ID IANA option ID does not match IANA*/ -/* option on client record */ -/* NX_DHCPV6_INVALID_IANA_TIME IANA T1 and T2 values are invalid */ -/* NX_DHCPV6_STATE_IP_FAILURE Indicates server rejected IANA/IA */ -/* NX_DHCPV6_INVALID_IANA_DATA IANA option is missing data or */ -/* improperly formatted */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_data Parses data from reply buffer */ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Parses option header from buffer */ -/* _nx_dhcpv6_process_ia Process IA option in reply buffer */ -/* _nx_dhcpv6_process_status Process status option in buffer */ -/* nx_dhcpv6_server_error_handler Pointer to server error code handler*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts server reply from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT status; -ULONG T1, T2, data; -UINT index; -ULONG opcode, option_length; -UINT ia_index; -UINT ia_count = 0; -UINT ia_status; - - - /* Set up the location of the read pointer past option header. */ - index = 4; - - /* The first word should contain the IANA option code and its option data length. */ - memcpy(&data, (received_buffer + index), sizeof(ULONG)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(data); - - /* The server response must return the correct IANA ID; this is applicable - to clients configured with more than one IANA. */ - if (data != (dhcpv6_ptr -> nx_dhcpv6_iana.nx_IA_NA_id)) - { - - /* IANA does not match. */ - return NX_DHCPV6_BAD_IANA_ID; - } - - /* Update the write location index. */ - index += 4; - - /* Copy T1 and T2 from the buffer into temporary variables. */ - memcpy(&T1, (received_buffer + index), sizeof(ULONG)); - index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(T1); - - memcpy(&T2, (received_buffer + index), sizeof(ULONG)); - index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(T2); - - /* Check for invalid T1/T2 lifetimes. */ - if (T1 > T2) - { - - /* Reject the server DHCPv6 response. */ - return NX_DHCPV6_INVALID_IANA_TIME; - } - - /* Record the T1 and T2. */ - /* Yes, the server will let the Client use its own T1 time? */ - if (T1 != 0) - { - - /* Now, assign the server T1 to the client IA-NA. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = T1; - } - - /* Yes,the server will let the Client use its own T2 time? */ - if (T2 != 0) - { - /* Now, assign the server T2 to the client IA-NA. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = T2; - } - - /* Check if we're at the end of option data yet. */ - if (index == length) - { - - /* Yes, all done. */ - return NX_SUCCESS; - } - - /* If the reply message includes IA address option, clear the record. */ - if(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION) - { - - /* Clear the IA address table according to the address map value. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* The reply message does not include this IA option.*/ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == 0) - { - - /* Clear it. */ - status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, ia_index); - } - } - } - - /* Now we recurse into the options embedded in the IANA option. */ - do - { - - /* Get the next option code and length. */ - status = _nx_dhcpv6_utility_get_block_option_length((received_buffer + index), &opcode, &option_length); - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Check if this is an IA address option request. */ - if (opcode == NX_DHCPV6_OP_IA_ADDRESS) - { - - /* Set the ia count to record the IA option of reply message. */ - ia_count ++; - ia_status = 0; - - /* First, find the same IPv6 address. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* The IPv6 address is new,so find the empty space to record it. */ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == ia_count) - { - - /* Yes, find it, update the IA option. */ - status = _nx_dhcpv6_process_ia(dhcpv6_ptr, (received_buffer + index), option_length, ia_index); - - /* Check the process status. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Yes, set success. */ - ia_status = 1; - - break; - } - } - - /* Record the IA option failure. */ - if(ia_status == 0) - { - - /* Second, find one empty IA to record it. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* The IPv6 address is new,so find the empty space to record it. */ - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map == 0) - { - - /* Yes, it is available, update the IA option. */ - status = _nx_dhcpv6_process_ia(dhcpv6_ptr, (received_buffer + index), option_length, ia_index); - - /* Check the process status. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - break; - } - } - } - } - - /* Check if this is an IAaddr status option request. */ - if (opcode == NX_DHCPV6_OP_STATUS_CODE) - { - /* The IAaddr option returned by the DHCPv6 server includes a status option. */ - - /* Process the status. */ - status = _nx_dhcpv6_process_status(dhcpv6_ptr, (received_buffer + index), option_length); - - /* Now check on the server status of the previous option in the DHCP message. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Does the dhcpv6 client have a server error handler? */ - if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) - { - - /* Call the error handler with status code, option (IA_NA) and which message type it refers to. */ - dhcpv6_ptr -> nx_dhcpv6_server_error_handler(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_NA, dhcpv6_ptr -> nx_status_code, - dhcpv6_ptr -> nx_dhcpv6_received_message_type); - } - } - - /* Check for errors processing the DHCPv6 message. */ - if (status != NX_SUCCESS) - { - - /* Abort further processing. Return error status. */ - return status; - } - } - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - - } while ((index - 4) < length); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_preference PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the preference option from the server reply. */ -/* It will save as much of the time zone that will fit in the Client */ -/* time zone buffer. Buffer size is user configurable. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_PREF_DATA Preference option is missing data */ -/* or improperly formatted */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts DHCPv6 options from */ -/* server reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_preference(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT index; -USHORT temp; - - - /* Fill in the option code and length. */ - dhcpv6_ptr -> nx_dhcpv6_preference.nx_op_code = NX_DHCPV6_OP_PREFERENCE; - dhcpv6_ptr -> nx_dhcpv6_preference.nx_option_length = (USHORT)length; - - /* Set the location of the read pointer into the buffer. */ - index = 4; - - /* set local variable for convenience. */ - temp = *(received_buffer + index); - - /* Get the server preference field, and apply to the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = temp; - - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value); - - /* Update the pointer past the data we just extracted. */ - index++; - - /* Is there any more data in this option? */ - if (((index - 4) > length) || ((index - 4) < length)) - { - - /* Yes, but there shouldn't be. Return as an error status. */ - return NX_DHCPV6_INVALID_PREF_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_server_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the server DUID from the server reply and, */ -/* if the Client already has a DHCPv6 server on record, verifies that */ -/* it matches the Client's server DUID. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to server reply */ -/* length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_SERVER_DUID Server DUID is missing data or */ -/* does not match the DUID on record*/ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_data Parses data from specified buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts server reply from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT index; -ULONG temp_type; -ULONG temp_hardware_type; -ULONG temp_time = 0; -ULONG temp_msw = 0; -ULONG temp_lsw = 0; - - - /* Set the DHCPv6 option header fields for a Server DUID. */ - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_op_code = NX_DHCPV6_OP_SERVER_ID; - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_option_length = (USHORT)length; - - /* Set the index past the option code and length. */ - index = 4; - - /* Extract the DUID type which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_type); - - /* Update the index for moving the buffer pointer forward. */ - index += 2; - - /* Extract the hardware type which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_hardware_type); - - /* Update the index for moving the buffer pointer forward. */ - index += 2; - - /* Is this a link layer plus time DUID type? */ - if (temp_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Yes; Extract the time which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_time); - - /* Update the index for moving the buffer pointer forward. */ - index += 4; - } - - /* Check the hardware type to extract the MSW. */ - if (temp_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET) - { - - /* The length of link layer address is 48 bits. */ - - /* Yes; Extract the link local address msw which should be the next 2 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 2, &temp_msw); - - /* Update the index for moving the buffer pointer forward. */ - index += 2; - } - else if (temp_hardware_type == NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64) - { - - /* The length of link layer address is 64 bits. */ - - /* Yes; Extract the link local address msw which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_msw); - - /* Update the index for moving the buffer pointer forward. */ - index += 4; - } - - /* Yes; Extract the link local address lsw which should be the next 4 bytes. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), 4, &temp_lsw); - - /* Update the index for moving the buffer pointer forward. */ - index += 4; - - /* Check if we are past the end of the buffer, subtracting for the toplevel opcode and - length of the IANA option. */ - if (((index - 4) > length) || ((index - 4) < length)) - { - - /* Yes, return the error status to reject the packet. */ - return NX_DHCPV6_INVALID_SERVER_DUID; - } - - /* If the client state in SENDING SOLICIT/CONFRIM/REBIND/INFORM_REQUEST, record the server DUID. */ - if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_SOLICIT || - dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_CONFIRM || - dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND || - dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_INFORM_REQUEST ) - { - - /* No previous server DUID in the Client record. Copy it over now. */ - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_type = (USHORT)temp_type; - - /* Is this a TIME Duid type? */ - if (temp_type == NX_DHCPV6_DUID_TYPE_LINK_TIME) - { - - /* Yes, write in the time data. */ - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time = temp_time; - } - - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_hardware_type = (USHORT)temp_hardware_type; - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw = temp_msw; - dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw = temp_lsw; - } - else - { - - /* Yes; Verify this Server DUID matches the Server DUID from the Client record. */ - if ((dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_duid_time != temp_time) || - (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != temp_msw) || - (dhcpv6_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw != temp_lsw)) - { - - /* It doesn't. Return an error status to reject this packet! */ - return NX_DHCPV6_INVALID_SERVER_DUID; - } - } - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_status PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the option status option from the server */ -/* reply. It also attempts to save the as much of server status message*/ -/* that will fit into the status message buffer. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process_iana Processes IANA in reply buffer */ -/* DHCPv6 request */ -/* _nx_dhcpv6_process_ia Processes IA in reply buffer */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_status(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT index; -UINT message_length; -ULONG status_code; - - - /* Set the location for the buffer read pointer. */ - index = 4; - - /* Get the status field itself. */ - _nx_dhcpv6_utility_get_data((received_buffer + index), sizeof(USHORT), &status_code); - - /* Update the index for moving the buffer pointer forward. */ - index += (ULONG)sizeof(USHORT); - - /* Set the status code. */ - dhcpv6_ptr -> nx_status_code = (USHORT)status_code; - - /* Now figure out how much of the message we can save, if not all of it. */ - if ((length - sizeof(USHORT)) > NX_DHCPV6_MAX_MESSAGE_SIZE) - { - - /* Store up to this much, message is truncated but possibly still useful. */ - message_length = NX_DHCPV6_MAX_MESSAGE_SIZE; - } - else - { - - /* Store all of it. */ - message_length = length - (ULONG)sizeof(USHORT); - } - - /* Copy the status into the Client record. */ - memcpy(dhcpv6_ptr -> nx_status_message, (received_buffer + index), message_length); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_time_zone PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the time zone option from the server reply. */ -/* It will save as much of the time zone that will fit in the Client */ -/* time zone buffer. Buffer size is user configurable. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts DHCPv6 options from */ -/* server reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_time_zone(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT i; -UINT index; - - - /* Set the location of the read pointer into the buffer. */ - index = 4; - - /* Make sure the time zone fits in the client buffer. */ - if (length > NX_DHCPV6_TIME_ZONE_BUFFER_SIZE) - { - - /* It doesn't. Fit what we can. */ - length = NX_DHCPV6_TIME_ZONE_BUFFER_SIZE; - } - - /* Copy the time zone from the buffer to the Client record. */ - for (i = 0; i < length; i++) - { - - dhcpv6_ptr -> nx_dhcpv6_time_zone[i] = *(received_buffer + 4 + i); - } - - /* Is there any more data in this option? */ - if (((index - 4 + i) > length) || ((index - 4 + i) < length)) - { - - /* Yes, treat as in improperly formatted packet. */ - return NX_DHCPV6_INVALID_OPTION_DATA; - } - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_time_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the time server option from the server reply.*/ -/* It will save as many time server addresses as are in the reply for */ -/* which the Client is configured to save. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to request packet buffer */ -/* length Location into buffer to read data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extracts DHCPv6 options from */ -/* server reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_time_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT index; -UINT w, j; - - - /* Set the location of the read pointer into the buffer. */ - index = 4; - j = 0; - - /* Loop through the length of the buffer to parse. */ - while ((index - 4) < length) - { - - /* Set the IP version. */ - dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; - - /* Get the next IPv6 time server address. */ - for (w = 0; w <= 3; w++) - { - - /* Check that the DHCPv6 Client configured to store this time server address e.g. it may - only store one address, but the server could be sending two or more. */ - if (j < NX_DHCPV6_NUM_TIME_SERVERS) - { - - /* Yes; copy each IPv6 address word into the time server address. */ - memcpy(&(dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_address.v6[w]), - (received_buffer + index), sizeof(ULONG)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_address.v6[w]); - } - - /* Move to the next IPv6 address word. */ - index += 4; - } - - dhcpv6_ptr -> nx_dhcpv6_time_server_address[j].nxd_ip_version = NX_IP_VERSION_V6; - - /* Start parsing the next time server address, if there is one*/ - j++; - } - - /* Is there any more data in this option? */ - if (((index - 4) > length) || ((index - 4) < length)) - { - - /* Yes, treat as in improperly formatted packet. */ - return NX_DHCPV6_INVALID_OPTION_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_remove_assigned_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes the DHCPv6 Client address from the Client */ -/* record and from the IP address table. IP lease lifetimes and IP */ -/* addresses in the Client record are also cleared. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* NX_INVALID_INTERFACE Invalid index in IP address table*/ -/* status Failed mutex get */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get exclusive lock on time keeper*/ -/* tx_mutex_put Release the lock on time keeper */ -/* _nx_dhcpv6_set_IP_address_NULL Set the IP address to NULL */ -/* */ -/* CALLED BY */ -/* */ -/* nx_dhcpv6_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_remove_assigned_address(NX_DHCPV6 *dhcpv6_ptr, UINT ia_index) -{ -UINT index; - - /* Only clear one address. */ - if(ia_index != NX_DHCPV6_REMOVE_ALL_IA_ADDRESS) - { - - /* Check for invalid IA index. */ - if (ia_index >= NX_DHCPV6_MAX_IA_ADDRESS) - { - return(NX_DHCPV6_REACHED_MAX_IA_ADDRESS); - } - - if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) && - (dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] != 0) && - (dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] != 0xFFFFFFFF)) - { - - /* Now remove the address from the IP address table. */ - nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); - - /* Set the address index to invalid. */ - dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; - } - - /* Clear the IA data. */ - memset(&dhcpv6_ptr -> nx_dhcpv6_ia[ia_index], 0, sizeof(NX_DHCPV6_IA_ADDRESS)); - - } - - /* Clear the all addresses. */ - else - { - - /* Zero out time accrued on the current lease. */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - - /* Set all lease lifetime and time fields to zero. */ - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - - /* Delete the IPv6 address of IP instance. */ - for(index = 0; index < NX_DHCPV6_MAX_IA_ADDRESS; index++) - { - - if((dhcpv6_ptr -> nx_dhcpv6_ia[index].nx_address_status) && - (dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] != 0) && - (dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] != 0xFFFFFFFF)) - { - - /* Now remove the address from the IP address table. */ - nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[index]); - - /* Set the address index to invalid. */ - dhcpv6_ptr -> nx_dhcpv6_client_address_index[index] = 0xFFFFFFFF; - } - } - - /* Clear the all IA data. */ - memset(&dhcpv6_ptr -> nx_dhcpv6_ia[0], 0, NX_DHCPV6_MAX_IA_ADDRESS * sizeof(NX_DHCPV6_IA_ADDRESS)); - - /* Removed the default router. */ - if (dhcpv6_ptr -> nx_dhcpv6_state >= NX_DHCPV6_STATE_SENDING_RENEW) - { - nxd_ipv6_default_router_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, &(dhcpv6_ptr -> nx_dhcpv6_server_address)); - memset(&(dhcpv6_ptr -> nx_dhcpv6_server_address), 0, sizeof(NXD_ADDRESS)); - } - } - - /* Clear the all address. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DHCPv6 Client state with the supplied state */ -/* (request). The DHCP Client thread will detect a state change and */ -/* process the new state. */ -/* */ -/* Note the return status only reflects the outcome of sending the */ -/* message, it does not indicate whether the request was successfully */ -/* granted. The host application is notified of "state" changes e.g. */ -/* NX_DHCPV6_STATE_SUCCESS or NX_DHCPV6_STATE_IP_FAILURE in the */ -/* callback function nx_dhcpv6_state_change_callback. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* dhcpv6_state State for making DHCPv6 request */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCP_NOT_STARTED DHCPv6 Client not started */ -/* status Get mutex status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DHCPv6 Client mutex */ -/* tx_mutex_put Releases the Client mutex */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_request_solicit Submits a SOLICIT request to Client*/ -/* _nx_dhcpv6_request_renew Submits a RENEW request to Client */ -/* _nx_dhcpv6_request_rebind Submits a REBIND request to Client */ -/* _nx_dhcpv6_request_release Submits a RELEASE request to Client*/ -/* _nx_dhcpv6_request_decline Submits a DECLINE request to Client*/ -/* _nx_dhcpv6_request_confirm Submits a CONFIRM request to Client*/ -/* _nx_dhcpv6_request_inform_request */ -/* Submits an Inform Request request */ -/* to Client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request(NX_DHCPV6 *dhcpv6_ptr, UINT dhcpv6_state) -{ - -UINT status; - - - /* First get an exclusive lock on the DHCPv6 Client. */ - status = tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Check for error. */ - if (status != TX_SUCCESS) - { - - /* Return the error status. */ - return status; - } - - /* Determine if DHCP is started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started == NX_FALSE) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - - /* DHCP is not started so it can't be stopped. */ - return(NX_DHCPV6_NOT_STARTED); - } - - /* Wait for an opportunity to stop the DHCPv6 Client thread e.g. not in the midst of - modifying the host DHCP profile! */ - while (dhcpv6_ptr -> nx_dhcpv6_sleep_flag != NX_TRUE) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Sleep temporarily. */ - tx_thread_sleep(1); - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - } - - /* Set the Client state to process the DHCPv6 request. */ - dhcpv6_ptr -> nx_dhcpv6_state = (UCHAR)dhcpv6_state; - - /* Release the Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_confirm PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX DHCPv6 Confirm */ -/* request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_confirm Actual DHCPV6 process Confirm */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_confirm(dhcpv6_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_confirm PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a confirm request to the server for the Client */ -/* to know the DHCPv6 IP address already assigned to it by the server. */ -/* */ -/* A host application should call this service after a host has been */ -/* disconnected from the network or powered down to verify its address */ -/* is still valid. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - /* Set the initial and max retransmission timeouts, and max number of retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Call the internal function. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_CONFIRM); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_decline PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a decline request to the server for the Client */ -/* to tell the server it does not accept the assigned address. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process Processes server replies to */ -/* DHCPv6 Client requests */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_decline(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UINT ia_index; - - /* Set the initial and max retransmission timeout and max number of retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining - as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ - - /* Set the DHCPv6 Client IPv6 addresses. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining - as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ - - /* Verify we have a valid address index. */ - if(dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] >= NX_MAX_IPV6_ADDRESSES) - { - - return NX_INVALID_INTERFACE; - } - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE) - { - /* Remove the address from the IP instance address table. */ - - nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); - - /* Record the address index in the Client record. */ - dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; - } - } - - /* Call the internal function and return completion status. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_DECLINE); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_inform_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX DHCPv6 information*/ -/* request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_inform_request Actual DHCPV6 process Inform */ -/* Request request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_inform_request(dhcpv6_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_inform_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a inform request to the server for the Client */ -/* to obtain network parameters from any DHCPv6 server on the network. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Set the initial and max retransmission timeout and max number of retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Call the internal function and return completion status. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_INFORM_REQUEST); - - /* Return actual completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_option_DNS_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX submit and process*/ -/* the DNS server request option from the DHPCv6 Server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* enable Flag indicating if the DNS server*/ -/* request enabled or disabled */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_option_DNS_server */ -/* Actual DHCPV6 process DNS server */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_option_DNS_server(dhcpv6_ptr, enable); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_option_DNS_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables or disables the DHCPv6 DNS server option. If */ -/* enabled this option is added to the option list in DHCPv6 messages */ -/* the Client sends to the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* enable Flag indicating if the DNS server*/ -/* request enabled or disabled */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - - /* Are we enabling this feature? */ - if (enable == NX_TRUE) - { - - /* Yes, register this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_DNS_SERVER_OPTION; - } - else - { - - /* Clear this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_DNS_SERVER_OPTION); - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_option_domain_name PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX submit and process*/ -/* the domain name request option from the DHPCv6 Server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* enable Flag indicating if the domain name*/ -/* request enabled or disabled */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_option_time_server */ -/* Actual DHCPV6 process domain name*/ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_option_domain_name(dhcpv6_ptr, enable); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_option_domain_name PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables or disables the DHCPv6 domain name option. If*/ -/* enabled this option is added to the option list in DHCPv6 messages */ -/* the Client sends to the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* enable Flag indicating if the domain name*/ -/* request enabled or disabled */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - - /* Are we enabling this feature? */ - if (enable == NX_TRUE) - { - /* Yes, register this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_DOMAIN_NAME_OPTION; - } - else - { - - /* Clear this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_DOMAIN_NAME_OPTION); - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_option_time_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX submit and process*/ -/* the time server request option from the DHPCv6 Server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* enable Flag indicating if the time server*/ -/* request enabled or disabled */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_option_time_server */ -/* Actual DHCPV6 process time server*/ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_option_time_server(dhcpv6_ptr, enable); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_option_time_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables or disables the DHCPv6 time server option. If*/ -/* enabled this option is added to the option list in DHCPv6 messages */ -/* the Client sends to the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* enable Flag indicating if the time server*/ -/* request enabled or disabled */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - - /* Is the caller requesting the time server option? */ - if (enable == NX_TRUE) - { - /* Yes, register this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= (USHORT)NX_DHCPV6_SNTP_SERVER_OPTION; - } - else - { - - /* Clear this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_SNTP_SERVER_OPTION); - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_option_timezone PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX submit and process*/ -/* the time zone request option from the DHPCv6 Server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* enable Flag indicating if the time zone */ -/* request enabled or disabled */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_option_time_zone Actual DHCPV6 process time zone */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_option_timezone(dhcpv6_ptr, enable); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_option_timezone PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables or disables the DHCPv6 time zone option. If */ -/* enabled this option is added to the option list in DHCPv6 messages */ -/* the Client sends to the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* enable Flag indicating if the time zone */ -/* request enabled or disabled */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable) -{ - - /* Are we enabling this feature? */ - if (enable == NX_TRUE) - { - /* Yes, register this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION; - } - else - { - - /* Clear this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request &= (USHORT)(~NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION); - } - - return NX_SUCCESS; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_option_FQDN PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the request fully qualified*/ -/* domain name option service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* domain_name DHCPv6 CLient domain name */ -/* op DHCPv6 Client operation */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_option_FQDN Actual DHCPv6 process FQDN */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((!dhcpv6_ptr) || (!domain_name)) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_option_FQDN(dhcpv6_ptr, domain_name, op); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_option_FQDN PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the DHCPv6 Client fully qualified domain */ -/* name. DHCPv6 Client sends this option to indicate if the server */ -/* SHOULD or SHOULD NOT perform the AAAA RR or DNS updates. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* domain_name DHCPv6 CLient domain name */ -/* op DHCPv6 Client operation */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op) -{ -UINT name_length; - - /* Set the Client FQDN option code. */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_code = NX_DHCPV6_OP_CLIENT_FQDN; - - /* Check domain name lengrh. The total length of a domain name is restricted to 255 octets or less. RFC1035. */ - if (_nx_utility_string_length_check(domain_name, &name_length, NX_DHCPV6_MAX_NAME_SIZE)) - { - return(NX_DHCPV6_PARAM_ERROR); - } - - /* Set the Client FQDN option length. 1 + length of domain name(domain name length + label + terminator) . */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_op_length = (USHORT)(1 + name_length + 2); - - /* Set the Client fully qualified domain name. */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_domain_name = domain_name; - - /* Flags Field. - 0 1 2 3 4 5 6 7 - +-+-+-+-+-+-+-+-+ - | MBZ |N|O|S| - +-+-+-+-+-+-+-+-+ - */ - - /* Set the flags. */ - if (op == NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR) - { - - /* DHCPv6 Client chooses to update the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the Cslient. - Set the "S", "O" and "N" bits as 0. */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x00; - } - else if (op == NX_DHCPV6_CLIENT_DESIRES_SERVER_DO_DNS_UPDATE) - { - - /* DHCPv6 Client chooses to update the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the Client to the Server. - Set the "S" bit as 1, Set "O" and "N" bits as 0. */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x01; - } - else - { - - /* DHCPv6 Client choose to request that the Server perform no DNS updates on its behalf. - Set the "N" bit as 1, Set "O" and "S" bits as 0. */ - dhcpv6_ptr -> nx_dhcpv6_client_FQDN.nx_flags = 0x04; - } - - /* Yes, register this option request with the DHCPv6 Client. */ - dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request |= NX_DHCPV6_CLIENT_FQDN_OPTION; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_rebind PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a rebind request to the server for the Client to*/ -/* obtain or rebind an IP address with a DHCPv6 server on the network. */ -/* */ -/* Note: the Client thread task will detect when it is time to rebind */ -/* the Client IP address and call the expired address handler if one is*/ -/* set. The expired address handler is where the host should call this*/ -/* service from. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Rebind already initiated */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* _nx_dhcpv6_thread_entry DHCPv6 Client thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_rebind(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UINT ia_index; -UINT max_valid_lifetime = 0; - - - /* Is the Client state set to REBIND yet? */ - if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND) - { - - /* Yes, the rebind process is already started. No need to re-request it. - Also must not zero out retry count or reset timeout back to starting value. */ - return NX_SUCCESS; - } - - - /* Set the initial and max retransmission timeouts and max number of retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT; - - /* Find the max valid lifetime. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Check the address status. */ - if((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) && - (dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime > max_valid_lifetime)) - { - - /* Find the max valid lifetime of all IAs. */ - max_valid_lifetime = dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime; - } - } - - /* Set the max duration time.The message exchange is terminated when the valid lifetimes of all the addresses assigned to the IA expire, - RFC3315, Section18.1.4, Page43. */ - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = max_valid_lifetime; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Call the internal function and return completion status. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_REBIND); - - /* Return the actual completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX DHCPv6 Release */ -/* request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_release Actual DHCPV6 process Release */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_release(dhcpv6_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_release PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a release request to the server for the Client */ -/* to release a assigned IP address back to the DHCPv6 server who */ -/* previously assigned it. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Client not assigned an address */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UINT ia_index; - - /* Check if the Client is bound to an assigned address. */ - if((dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && - (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_RENEW) && - (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_REBIND)) - { - - /* It is not. The host application should use the nx_dhcpv6_stop if the DHCP Client - has simply failed to obtain an IP address from the server instead. */ - - /* Benign error so return successful outcome. */ - return NX_DHCPV6_IA_ADDRESS_NOT_VALID; - } - - /* Set the initial and max retransmission timeouts and max number of retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Set the DHCPv6 Client IPv6 addresses. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Now remove the address from the IP address table,the client MUST NOT use any of the addresses it is declining - as the source address in the Release message or in any subsequently transmitted message, RFC3315,section18.1.7.. */ - - /* Verify we have a valid address index. */ - if(dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] >= NX_MAX_IPV6_ADDRESSES) - { - - return NX_INVALID_INTERFACE; - } - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_op_code) - { - /* Remove the address from the IP instance address table. */ - - nxd_ipv6_address_delete(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); - - /* Record the address index in the Client record. */ - dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index] = 0xFFFFFFFF; - } - } - - /* Call the internal function and return completion status. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_RELEASE); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_renew PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls the internal request service to renew the */ -/* DHCPv6 IP address assigned to it by the server. */ -/* */ -/* Note: the Client thread task will detect when it is time to renew */ -/* the Client IP address and call the deprecated address handler if one*/ -/* is set. The deprecated address handler is where the host should */ -/* call this service from. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Renew already initiated */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* _nx_dhcpv6_thread_entry DHCPv6 Client thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_renew(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Is the Client state set to RENEW yet? */ - if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) - { - - /* Yes, the renew process is already started. No need to re-request it. - Also must not zero out retry count or reset timeout back to starting value. */ - return NX_SUCCESS; - } - - /* Set initial retry and timeout values for sending the Renew request. */ - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Set the Client to the Renewing state for the DHCP Client thread to process. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_RENEW); - - /* Actual completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_solicit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX DHCPv6 solicit */ -/* request service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_solicit Actual DHCPV6 process Solicit */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_solicit(dhcpv6_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_solicit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a solicit request for the Client to obtain an IP*/ -/* address from any DHCPv6 server on the network. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* _nx_dhcpv6_process Send the DHCPv6 solicit message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Set the mode of sending the solicit message. Do not override a rapid option if set. */ - if (dhcpv6_ptr ->nx_dhcpv6_request_solicit_mode != NX_DHCPV6_SOLICIT_RAPID) - { - - /* Set the mode of sending the solicit message. */ - dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode = NX_DHCPV6_SOLICIT_NORMAL; - } - - /* Set the initial and maximum timeout and retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION; - - /* Reset the preference value if the Client previously accepted an Advertise message. */ - dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = 0; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Set the Client to the Solicity state for the DHCP Client thread to process. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_SOLICIT); - - /* Return the completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_request_solicit_rapid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX DHCPv6 solicit */ -/* request service with rapid commit option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request_solicit_rapid Actual DHCPV6 process Solicit */ -/* request service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_dhcpv6_request_solicit_rapid(dhcpv6_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_request_solicit_rapid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a solicit request with rapid commit option for */ -/* the Client to rapidly obtain an IP address from any DHCPv6 server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_request Actual DHCPV6 request service */ -/* tx_timer_activate Activate the session timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Set the mode of sending the solicit message. */ - dhcpv6_ptr ->nx_dhcpv6_request_solicit_mode = NX_DHCPV6_SOLICIT_RAPID; - - /* Set the initial and maximum timeout and retries. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Set the initaial elasped time of DHCPv6 message. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - - /* Set the retransmission information(IRT, MRC, MRT, MRD). */ - dhcpv6_ptr -> nx_dhcpv6_init_retransmission_timeout = NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count = NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout = NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT; - dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration = NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION; - - /* Reset the preference value if the Client previously accepted an Advertise message. */ - dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value = 0; - - /* Activate the session timer to update the elapsed time. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_session_timer); - - /* Set the Client to the Solicity state for the DHCP Client thread to process. */ - status = _nx_dhcpv6_request(dhcpv6_ptr, NX_DHCPV6_STATE_SENDING_SOLICIT); - - /* Return the completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the resume NetX DHCPv6 */ -/* client task service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_resume Actual DHCPV6 resume function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - UINT _nxe_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 stop service. */ - status = _nx_dhcpv6_resume(dhcpv6_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resumes DHCPV6 processing thread and updates the */ -/* DHCPv6 client state according to nx_dhcpv6_IP_lifetime_time_accrued.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_dhcpv6_start Starts DHCPV6 thread task */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; -UCHAR original_state; - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Determine if DHCPV6 has already been started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started) - { - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Error, the DHCPV6 client has already been started. */ - return(NX_DHCPV6_ALREADY_STARTED); - } - - /* Determine if Client has created its DUID and IANA yet. */ - if ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr == NX_NULL) || - (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length == 0) || - (dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length == 0)) - { - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* No, this DHCPv6 Client is not ready to run! */ - return NX_DHCPV6_MISSING_REQUIRED_OPTIONS; - } - - /* Remember the original DHCPv6 state for the changed state callback function. */ - original_state = dhcpv6_ptr -> nx_dhcpv6_state; - - /* Bind the UDP socket to the DHCPV6 Client port. */ - status = nx_udp_socket_bind(&(dhcpv6_ptr -> nx_dhcpv6_socket), NX_DHCPV6_CLIENT_UDP_PORT, TX_WAIT_FOREVER); - - /* Check for success */ - if (status) - { - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Return completion status. */ - return(status); - } - - /* Check the DHCPv6 Client state. */ - if ((dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && - (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_RENEW) && - (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_SENDING_REBIND)) - { - - /* Set the DHCPv6 Client state to Init.*/ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Clear the session time, lease lifetime, retransmission counters. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 0; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - } - else - { - - /* Check the accrued time to upate the state. */ - if ((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) && ((dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2))) - { - - /* Update the status as NX_DHCPV6_STATE_SENDING_RENEW to send rebinding message in _nx_dhcpv6_thread_entry function. */ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_SENDING_RENEW; - } - } - - - /* Set the DHCPv6 started flag to indicate DHCPv6 Client is now running. */ - dhcpv6_ptr -> nx_dhcpv6_started = NX_TRUE; - - /* Activate the DHCPv6 timers. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer); - - /* Resume the DHCPv6 processing thread. */ - tx_thread_resume(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Is there a state change callback registered with the Client? */ - if ((dhcpv6_ptr -> nx_dhcpv6_state_change_callback) && (original_state != (dhcpv6_ptr -> nx_dhcpv6_state))) - { - - /* Yes, call the the state change callback with the original and new state. */ - (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); - } - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_send_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a DHCPV6 request to the server. All options */ -/* required for each Client DHCPv6 message are compiled into the Client */ -/* request package. Since each message must have a unique transaction */ -/* ID, it is up to the caller to set the Client transaction ID in the */ -/* Client record before calling this service. The server reply must */ -/* contain the matching message transaction ID for each message type the*/ -/* Client sends it. This function will check for invalid message types. */ -/* */ -/* To send a message, the Client allocates a packet from its own packet */ -/* pool. It then must set the IPv6 packet interface depending if the */ -/* Client has a valid global IP address or is using its link local */ -/* address till it can get a global IP address. It can send the packet */ -/* either to all servers on its network or include server and relays */ -/* (user configurable). */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Illegal message type to send */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a DHCPV6 packet */ -/* nx_packet_release Release DHCPV6 packet */ -/* nx_udp_socket_send Send DHCPV6 packet */ -/* _nx_dhcpv6_add_client_duid Add Client DUID to request */ -/* _nx_dhcpv6_add_server_duid Add server DUID to request */ -/* _nx_dhcpv6_add_elapsed_time Add elapsed time option */ -/* _nx_dhcpv6_add_iana Add IANA option to request */ -/* _nx_dhcpv6_add_ia_address Add IA address option */ -/* _nx_dhcpv6_add_option_request Add option request option */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process Process DHCPv6 client request */ -/* _nx_dhcpv6_waiting_on_reply Process replies to valid server*/ -/* reply received */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_send_request(NX_DHCPV6 *dhcpv6_ptr) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer; -UINT status; -ULONG message_word; -UINT index; -NX_INTERFACE *interface_ptr; -NXD_IPV6_ADDRESS *ipv6_address; -ULONG available_payload; - - - /* Initialize local variables. */ - index = 0; - - /* Check for invalid or illegal message type. */ - if ((dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) || - (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type == 0)) - { - - /* Return error status. */ - return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; - } - - /* Allocate a DHCPV6 packet. */ - status = nx_packet_allocate(dhcpv6_ptr -> nx_dhcpv6_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Indicate this is an IPv6 packet. */ - packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6; - - /* Setup the buffer pointer. */ - buffer = packet_ptr -> nx_packet_prepend_ptr; - - /* Use the message id value to judge whether the next packet is retransmit packet or not. - If the id value is 0, indicate the new dhcpv6 request, then generate a random number, else,leave the transaction ID unchanged. - A client MUST leave the transaction ID unchanged in retransmissions of a message,RFC3315,section 15.1,page 28. */ - if(dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid == 0) - { - - /* Generate "random" transaction ID using physical address and a random factor for each request - to the Server. The Server must include a matching transaction ID in its reply. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = - ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_msw) ^ - (dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_arp_physical_address_lsw) ^ - (ULONG)(NX_RAND())); - - /* Now reduce it to three bytes. */ - dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid = (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid & (ULONG)(0x0ffffff)); - } - - /* Clear memory to make the message header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Add the message type and transaction ID as the DHCPv6 header fields. */ - message_word = (((ULONG)(dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type)) << 24); - - message_word |= (((ULONG)(0x0ffffff)) & (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the message header to the packet buffer. */ - memcpy(buffer, &message_word, 4); - - /* Update the buffer 'pointer'. */ - index += (ULONG)sizeof(ULONG); - - /* Add the Client DUID to the packet buffer. */ - status = _nx_dhcpv6_add_client_duid(dhcpv6_ptr, buffer, &index); - - /* Check for error. */ - if(status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - return status; - } - - /* Determine if any additional options need to be added relative to the DHCPV6 message type. */ - switch (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_type) - { - - case NX_DHCPV6_MESSAGE_TYPE_SOLICIT: - { - /* Append the IA-NA option and depending on host state. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Did the Client ask for a DHCPv6 Client FQDN option ? - A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ - if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* Did the Client ask for a requested option? */ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* Did the Client ask for rapid commit option? */ - if (dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) - { - - /* Compute the available payload for DHCP data in the packet buffer. */ - available_payload = (dhcpv6_ptr -> nx_dhcpv6_pool_ptr -> nx_packet_pool_payload_size - - sizeof(NX_IPV6_HEADER) - sizeof(NX_UDP_HEADER) - index); - - /* Check if the data will fit in the packet buffer. */ - if (available_payload < sizeof(ULONG)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Add the rapid commit option request. */ - /* Clear memory to make the message header, and add the message type. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Add the message type. */ - message_word = (((ULONG)NX_DHCPV6_OP_RAPID_COMMIT) << 16); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the message to the packet buffer. */ - memcpy((buffer + index), &message_word, sizeof(ULONG)); - - /* Update the index. */ - index += (ULONG)sizeof(ULONG); - } - - /* Increment the number of Solicit messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_solicitations_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_REQUEST: - { - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Append an IA-NA with the IA address option received from server added to the IA-NA option. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Did the Client ask for a DHCPv6 Client FQDN option ? - A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ - if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* Did the Client ask for a requested option? */ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - } - - /* Increment the number of Request messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_requests_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_RENEW: - { - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Did the Client ask for a DHCPv6 Client FQDN option ? - A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ - if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* A client MAY include an Option Request option in a Solicit, Request, Renew, Rebind, Confirm or Information-request - message to inform the server about options the client wants the server to send to the client. RFC3315, Section22.7, Page78.*/ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - } - - dhcpv6_ptr -> nx_dhcpv6_renews_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_REBIND: - { - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Rebind message includes the current IA/IA-NA, current IA address. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Did the Client ask for a DHCPv6 Client FQDN option ? - A client MUST only include the Client FQDN option in SOLICIT, REQUEST, RENEW, or REBIND messsage. */ - if (dhcpv6_ptr ->nx_dhcpv6_client_FQDN.nx_op_code) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_client_FQDN(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* Did the Client ask for a requested option? */ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - - /* Increment the number of Solicit messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_rebinds_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_CONFIRM: - { - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Rebind message includes the current IA/IA-NA, current IA address. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - /* Return the error status and abort. */ - return status; - } - - /* A client MAY include an Option Request option in a Solicit, Request, Renew, Rebind, Confirm or Information-request - message to inform the server about options the client wants the server to send to the client. RFC3315, Section22.7, Page78.*/ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - } - - /* Increment the number of Solicit messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_confirms_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_DECLINE: - { - - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - /* Return the error status and abort. */ - return status; - } - - /* Decling the message in the current IA/IA-NA, current IA address. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Increment the number of Decline messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_declines_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_RELEASE: - { - - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_server_duid(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Decling the message in the current IA/IA-NA, current IA address. */ - status = _nx_dhcpv6_add_iana(dhcpv6_ptr, buffer, &index); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - - /* Increment the number of Releases messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_releases_sent++; - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST: - { - - /* Did the Client ask for a requested option? */ - if (!dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - - /* No, so don't bother sending out the request. */ - - nx_packet_release(packet_ptr); - - return NX_SUCCESS; - } - - /* Compute the session time so far and add an elapsed time option. */ - status = _nx_dhcpv6_add_elapsed_time(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - - /* Did the Client ask for a requested option? */ - if (dhcpv6_ptr -> nx_dhcpv6_option_request.nx_op_request) - { - /* Add the server DUID just extracted from the Server Advertise message. */ - status = _nx_dhcpv6_add_option_request(dhcpv6_ptr, buffer, &index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return status; - } - } - - /* Increment the number of Inform Request messages sent. */ - dhcpv6_ptr -> nx_dhcpv6_inform_req_sent++; - - break; - } - - default: - { - nx_packet_release(packet_ptr); - - return NX_DHCPV6_UNKNOWN_MSG_TYPE; - } - } - - /* Setup the packet pointers. */ - packet_ptr -> nx_packet_length = index; - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; - - - /* Select Client Source address: - 1. When a client sends a DHCP message to the All_DHCP_Relay_Agents_and_Servers address, - the client must use a link-local address assigned to the interface for which it - is requesting configuration as the source address. - 2. When a client sends a DHCP message directly to a server using unicast, - the source address must be an address assigned to the interface for which the - client is interested in obtaining configuration. - RFC 3315, Section 16. Client Source Address and Interface Selection, Page 32. */ - - /* Set the interface pointer. */ - interface_ptr = &(dhcpv6_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[dhcpv6_ptr ->nx_dhcpv6_client_interface_index]); - - /* Check the destination address. */ - if (CHECK_IPV6_ADDRESSES_SAME(dhcpv6_ptr -> nx_dhcpv6_client_destination_address.nxd_ip_address.v6, All_DHCPv6_Relay_Servers_Address.nxd_ip_address.v6)) - { - - /* Find the link-local address as source adress. Get first address from interface. */ - ipv6_address = interface_ptr -> nxd_interface_ipv6_address_list_head; - - /* Loop to check the address. */ - while (ipv6_address) - { - - /* Check for a valid address. */ - if (ipv6_address -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID) - { - ipv6_address = ipv6_address -> nxd_ipv6_address_next; - } - - /* Check for link-local address. */ - else if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL) - { - - /* Find the Link-Local Address. */ - break; - } - else - { - ipv6_address = ipv6_address -> nxd_ipv6_address_next; - } - } - - /* Check if found the link-local address. */ - if(ipv6_address == NX_NULL) - { - - /* No valid link-local address. */ - nx_packet_release(packet_ptr); - return(NX_IP_ADDRESS_ERROR); - } - } - else - { - - /* Find the source address. */ - status = _nxd_ipv6_interface_find(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_destination_address.nxd_ip_address.v6, - &ipv6_address, interface_ptr); - - /* Check if found the address. */ - if (status) - { - - /* No valid source address. */ - nx_packet_release(packet_ptr); - return(NX_IP_ADDRESS_ERROR); - } - } - - /* Send the packet out! */ - status = _nxd_udp_socket_source_send(&(dhcpv6_ptr -> nx_dhcpv6_socket), packet_ptr, - &dhcpv6_ptr -> nx_dhcpv6_client_destination_address, NX_DHCPV6_SERVER_UDP_PORT, - ipv6_address -> nxd_ipv6_address_index); - - /* If an error is detected, the packet was not sent and we have to release the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_session_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the Client session duration time with the */ -/* Server. This information is used for the Elapsed Time data in DHCPv6*/ -/* Client messages sends to the server as part of the DHCPv6 protocol. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr_value Pointer to the DHCPV6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_session_timeout_entry(ULONG dhcpv6_ptr_value) -{ - -NX_DHCPV6 *dhcpv6_ptr; - - - /* Setup DHCPv6 Client pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, dhcpv6_ptr_value) - - /* Check the elapsed time, the time is expressed in hundredths of 1 second, 65500 is the largest time value. */ - if(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time < 65500) - { - - /* Update the elapsed time of current DHCP session. - This time is expressed in hundredths of a second. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = (USHORT)(dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time + NX_DHCPV6_SESSION_TIMER_INTERVAL * 100); - } - else - { - - /* Set the value 0xFFFF to represent any elapsed time values greater than the largest time value . */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0xFFFF; - } - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_set_time_accrued PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the set time accrued on */ -/* Client IP lease service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_accrued Pointer to time since IP lease */ -/* assigned (secs) */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_set_time_accrued Actual set time accrued on Client */ -/* IP address lease service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_set_time_accrued(dhcpv6_ptr, time_accrued); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_set_time_accrued PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables the host to set the time accrued on the */ -/* Client's IP address lease. The caller must first suspend the */ -/* DHCPv6 Client using the nx_dhcpv6_suspend service before using this */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* time_accrued Pointer to time to set the */ -/* lient accrued time (secs) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued) -{ - - - /* Check if the DHCPv6 Client has been started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started) - { - /* It has. We cannot set the time accrued if the DHCPv6 client thread is running. */ - return NX_DHCPV6_ALREADY_STARTED; - } - - /* Set the time accrued on the Client IP address lease. */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = time_accrued; - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the set client interface */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* interface_index Index for DHCP network interface*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_client_set_interface Actual set interface service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index) -{ - -UINT status; - - - /* Check for valid pointer input. */ - if (!dhcpv6_ptr) - { - return NX_PTR_ERROR; - } - - /* Check for an invalid interface specified. */ - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_client_set_interface(dhcpv6_ptr, interface_index); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function specifies the physical interface for DHCP */ -/* communications with the server in NetX Duo environments that support*/ -/* mult-homed hosts. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* interface_index Index for DHCP network interface*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_NOT_ENABLED NetXDuo version does not support*/ -/* multiple network interfaces */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index) -{ - - - /* Set the client interface. */ - dhcpv6_ptr -> nx_dhcpv6_client_interface_index = interface_index; - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_set_destination_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the set destination */ -/* address service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* destination_address Destination address */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_client_set_destination_address */ -/* Actual set address service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for an invalid address type. */ - if (destination_address -> nxd_ip_version != NX_IP_VERSION_V6) - { - - /* Invalid address type. */ - return(NX_DHCPV6_PARAM_ERROR); - } - - /* Check if the server address is unspecified (::). */ - if(CHECK_UNSPECIFIED_ADDRESS(destination_address -> nxd_ip_address.v6)) - { - - /* Null address input. */ - return(NX_DHCPV6_PARAM_ERROR); - } - - /* Call the actual service. */ - status = _nx_dhcpv6_client_set_destination_address(dhcpv6_ptr, destination_address); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_set_destination_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the destination address where DHCP message should */ -/* be sent. By default is All_DHCP_Relay_Agents_and_Servers(FF02::1:2).*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* destination_address Destination address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address) -{ - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_WAIT_FOREVER); - - /* Set the destination address. */ - COPY_NXD_ADDRESS(destination_address, &(dhcpv6_ptr -> nx_dhcpv6_client_destination_address)); - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX start the dhcpv6 */ -/* client service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_start Actual DHCPV6 start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 start service. */ - status = _nx_dhcpv6_start(dhcpv6_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the DHCPV6 processing thread and readies the */ -/* DHCPv6 Client to initiate DHCPv6 requests. The Client state is set */ -/* to INIT and awaits the host application requesting a DHCPv6 meesage */ -/* sent e.g. the SOLICIT message. For hosts binding (or attempting to */ -/* obtain) a IP address in a previous session, this will clear session */ -/* parameters such as accrued lease time and message retry count. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCPV6_ALREADY_STARTED DHCPv6 Client already started */ -/* NX_DHCPV6_MISSING_REQUIRED_OPTIONS Client missing required options */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_create Create the Client UDP socket */ -/* nx_udp_socket_bind Bind the Client socket */ -/* nx_udp_socket_unbind Unbind the Client socket */ -/* tx_timer_activate Activate Client timers */ -/* tx_timer_deactivate Deactivate Client timers */ -/* tx_thread_resume Resume Client thread task */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Determine if DHCPV6 has already been started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started) - { - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Error, the DHCPV6 client has already been started. */ - return(NX_DHCPV6_ALREADY_STARTED); - } - - /* Determine if Client has created its DUID and IANA yet. */ - if ((dhcpv6_ptr -> nx_dhcpv6_ip_ptr == NX_NULL) || - (dhcpv6_ptr -> nx_dhcpv6_client_duid.nx_option_length == 0) || - (dhcpv6_ptr -> nx_dhcpv6_iana.nx_option_length == 0)) - { - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* No, this DHCPv6 Client is not ready to run! */ - return NX_DHCPV6_MISSING_REQUIRED_OPTIONS; - } - - /* Set the DHCPv6 Client state to Init.*/ - dhcpv6_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_INIT; - - /* Clear the session time, lease lifetime, retransmission counters. */ - dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = 0; - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = 0; - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 0; - dhcpv6_ptr -> nx_dhcpv6_retransmission_count = 0; - - /* Bind the UDP socket to the DHCPV6 Client port. */ - status = nx_udp_socket_bind(&(dhcpv6_ptr -> nx_dhcpv6_socket), NX_DHCPV6_CLIENT_UDP_PORT, TX_WAIT_FOREVER); - - /* Check for success */ - if (status == NX_SUCCESS) - { - - /* Resume the DHCPv6 processing thread. */ - status = tx_thread_resume(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Determine if the resume was successful. */ - if (status == NX_SUCCESS) - { - - /* Set the DHCPv6 started flag to indicate DHCPv6 Client is now running. */ - dhcpv6_ptr -> nx_dhcpv6_started = NX_TRUE; - - /* Activate the DHCPv6 timers. */ - tx_timer_activate(&dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer); - } - else - { - - /* Error, unbind the DHCPv6 socket. */ - nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); - } - } - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the suspend NetX DHCPv6 */ -/* client task service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_suspend Actual DHCPV6 suspend function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 stop service. */ - status = _nx_dhcpv6_suspend(dhcpv6_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends (stops) DHCPV6 processing thread, stops the */ -/* DHCP session and IP address lease timers, and clears the started */ -/* status of the DHCPv6 Client. It resets the DHCPv6 Client to the */ -/* INIT. The DHCP socket is unbound and the DHCP thread aborted. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ -/* suspended */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend DHCPV6 thread task */ -/* tx_timer_deactivate Deactivate timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - status = _nx_dhcpv6_stop(dhcpv6_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the DHCPv6 Client stop */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_stop Actual stop DHCPV6 thread task */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_ptr == NX_NULL) || (dhcpv6_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 stop service. */ - status = _nx_dhcpv6_stop(dhcpv6_ptr); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends (stops) DHCPV6 processing thread, stops the */ -/* DHCP session and IP address lease timers. The DHCP socket is unbound*/ -/* and the DHCP thread aborted. */ -/* */ -/* Stopping the DHCP Client is necessary to restart the DHCP client, */ -/* example if a previously assigned address is declined or released, */ -/* and the host would like to solicit an IP address again. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ -/* suspended */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend DHCPV6 thread task */ -/* tx_timer_deactivate Deactivate timer */ -/* tx_mutex_get Obtain Client mutex */ -/* tx_mutex_put Release Client mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT current_preemption; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Determine if DHCPV6 is started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started == NX_FALSE) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* DHCPV6 has not been started so we cannot stop it. */ - return(NX_DHCPV6_NOT_STARTED); - } - - /* Clear the DHCPV6 started flag to indicate DHCPV6 task is not running. */ - dhcpv6_ptr -> nx_dhcpv6_started = NX_FALSE; - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Loop to wait for the DHCP Client thread to be in a position to be stopped. */ - while (dhcpv6_ptr -> nx_dhcpv6_sleep_flag != NX_TRUE) - { - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Sleep temporarily. */ - tx_thread_sleep(1); - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - } - - /* Clear the flag. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - - /* Suspend the DHCP thread. */ - tx_thread_suspend(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Abort the wait on the DHCP Client thread. */ - tx_thread_wait_abort(&(dhcpv6_ptr -> nx_dhcpv6_thread)); - - /* Unbind the port. */ - nx_udp_socket_unbind(&(dhcpv6_ptr -> nx_dhcpv6_socket)); - - /* Stop the timers. */ - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_timer)); - tx_timer_deactivate(&(dhcpv6_ptr -> nx_dhcpv6_session_timer)); - - /* Restore preemption. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dhcpv6_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the reinitializes the */ -/* DHCPv6 Client service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_reinitialize Actual clear address service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - if (dhcpv6_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_dhcpv6_reinitialize(dhcpv6_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_reinitialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reinitializes the DHCP instance for restarting the */ -/* DHCP client state machine and re-running the DHCPv6 protocol. This */ -/* is not necessary if the Client has not previously obtained an */ -/* IP address from the server. The IP address in both the DHCP Client */ -/* data record and in the IP instance is cleared. */ -/* */ -/* Note: the host MUST stop the DHCPv6 client before calling this */ -/* service with the nx_dhcpv6_stop service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCPV6_ALREADY_STARTED DHCPv6 client is running */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_remove_assigned_address Clears client IP address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status; - - - /* Check that the DHCPv6 client is started. */ - if (dhcpv6_ptr -> nx_dhcpv6_started == NX_TRUE) - { - - /* Need to stop the DHCP client before we can reinitialize it. */ - return NX_DHCPV6_ALREADY_STARTED; - } - - /* This clears the assigned IP address from the Client record, as well as - removes the assigned IP address from the IP address table. */ - status = _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, NX_DHCPV6_REMOVE_ALL_IA_ADDRESS); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the background processing thread for the DHCPV6 */ -/* Client. It waits to be notified by ThreadX event flags when to */ -/* perform certain actions. These include updating the time remaining */ -/* on the Client IP address lease time, and maintaining the duration of*/ -/* the current Client Server session (if Client has made a request). */ -/* It will terminate if a host application handler is called and */ -/* indicates the Client should abort. */ -/* */ -/* INPUT */ -/* */ -/* info Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Receive notice of event flags set */ -/* tx_mutex_get Obtain lock on Client resource */ -/* tx_mutex_put Release lock on Client resource */ -/* _nx_dhcpv6_request_renew Initiate the RENEW request */ -/* _nx_dhcpv6_request_rebind Initiate the REBIND request */ -/* _nx_dhcpv6_request_decline Initiate the DECLINE request */ -/* _nx_dhcpv6_remove_assigned_address */ -/* Remove the assigned IPv6 address */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_thread_entry(ULONG info) -{ - -UINT status; -NX_DHCPV6 *dhcpv6_ptr; -UINT current_preemption; -ULONG dhcpv6_events; -UINT ia_index; -UINT original_state; - - /* Setup the DHCPV6 Client pointer. */ - NX_THREAD_EXTENSION_PTR_GET(dhcpv6_ptr, NX_DHCPV6, info) - - /* Process periodic DHCPv6 Client tasks. */ - do - { - - /* Loop to get the DHCP mutex to handle error, release, and - stop requests properly. */ - do - { - - /* Get the DHCP mutex. */ - status = tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - } while (status != TX_SUCCESS); - - - /* Check the state of the DHCP Client state for further DHCP messaging. */ - _nx_dhcpv6_process(dhcpv6_ptr); - - /* Release the DHCP mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Indicate the DHCP Client process is idle. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* Sleep for timer interval. */ - tx_thread_sleep(NX_DHCPV6_SESSION_TIMER_INTERVAL); - - /* Clear flag to indicate DHCP thread is not in a position to be stopped. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - - /* Restore original preemption. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - /* Check the expiration on valid and preferred lifetimes only if the Client is in the Bound state. */ - if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) - { - - /* At time T1 for an IA, the client initiates a Renew message exchange to extend the lifetimes. RFC3315,page 42.*/ - if (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T1) - { - - /* Indicate the DHCP Client process is idle while the handler executes. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* Sending the renew message. */ - _nx_dhcpv6_request_renew(dhcpv6_ptr); - - /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - } - } - - /* Check the expiration on valid and preferred lifetimes only if the Client is in the sending renew state. */ - if (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) - { - - /* At time T2 for an IA, The Client initiates a Rebind message exchanges. RFC3315, page 43. */ - if (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_iana.nx_T2) - { - - /* Indicate the DHCP Client process is idle while the handler executes. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* Sending the rebind message. */ - _nx_dhcpv6_request_rebind(dhcpv6_ptr); - - /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - } - } - - /* Check the DHCPv6 Client state. */ - if ((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_BOUND_TO_ADDRESS) || - (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_RENEW) || - (dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_REBIND)) - { - - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - /* Has the IP address valid lifetime expired? */ - if ((dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status) && - (dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued >= dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_valid_lifetime)) - { - - /* Save the existing state of the DHCPv6 Client. */ - original_state = dhcpv6_ptr -> nx_dhcpv6_state; - - /* Clear the assigned IP address. */ - _nx_dhcpv6_remove_assigned_address(dhcpv6_ptr, ia_index); - - /* Indicate the DHCP Client process is idle while the handler executes. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* Restart the Client to the solicit IP address request state. */ - _nx_dhcpv6_request_solicit(dhcpv6_ptr); - - /* Indicate the DHCP Client process is idle while the handler executes. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - - if (dhcpv6_ptr -> nx_dhcpv6_state_change_callback && (original_state != dhcpv6_ptr -> nx_dhcpv6_state)) - { - /* Yes, call the state change callback with the original and new state. */ - (dhcpv6_ptr -> nx_dhcpv6_state_change_callback)(dhcpv6_ptr, original_state, dhcpv6_ptr -> nx_dhcpv6_state); - } - } - } - } - - - - /* Pickup IP event flags. */ - status = tx_event_flags_get(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_events), NX_IP_ALL_EVENTS, TX_OR_CLEAR, &dhcpv6_events, TX_NO_WAIT); - - /* Check for an IP receive packet event. */ - if ((status == TX_SUCCESS) && (dhcpv6_events & NX_DHCPV6_DAD_FAILURE_EVENT)) - { - - /* Indicate the DHCP Client process is idle while the handler executes. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - /* The DAD process failure, send DHCPv6 DECLINE message. */ - _nx_dhcpv6_request_decline(dhcpv6_ptr); - - dhcpv6_events = dhcpv6_events & ~(ULONG)(NX_DHCPV6_DAD_FAILURE_EVENT); - - /* Reset flag to indicate DHCP thread is not idle (not stoppable). */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - } - - } while (1); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_utility_get_block_option_length PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the input buffer (assuming to be an option */ -/* block in a server reply) for option code and length. It assumes the */ -/* buffer pointer is pointed to the first byte of the option buffer. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ Pointer to DHCPv6 Client */ -/* option Option code of requested data */ -/* buffer_ptr Buffer to copy data to */ -/* length Size of buffer */ -/* valid */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCPV6_INCOMPLETE_OPTION_BLOCK Unknown option specified */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_data Parses a specific data from the */ -/* DHCPv6 option */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Parses option code and length */ -/* _nx_dhcpv6_extract_packet_information */ -/* Parses each option from server */ -/* reply and updates Client record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length) -{ - - /* Initialize to zero. */ - *option = 0; - *length = 0; - - /* First byte should be the op code. */ - _nx_dhcpv6_utility_get_data(buffer_ptr, 2, option); - - buffer_ptr += 2; - - /* Next byte should be the option length. */ - _nx_dhcpv6_utility_get_data(buffer_ptr, 2, length); - - /* Buffer is now pointed at the data (past the length field). */ - buffer_ptr += 2; - - /* Check for null data. */ - if (*option == 0) - { - - return NX_DHCPV6_INCOMPLETE_OPTION_BLOCK; - } - - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_utility_get_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the input buffer and returns numeric data */ -/* specified by the size argument, up to 4 bytes long. Note that if */ -/* caller is using this utility to extract bytes from a DHCPv6 packet */ -/* there is no need for byte swapping, as compared to using memcpy in */ -/* which case there is for little endian processors. */ -/* */ -/* INPUT */ -/* */ -/* buffer Pointer to data buffer */ -/* value Pointer to data parsed from buffer*/ -/* size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCPV6_INVALID_DATA_SIZE Requested data size too large */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* _nx_dhcpv6_process_server_duid Process server duid in server reply*/ -/* _nx_dhcpv6_process_client_duid Process server duid in server reply*/ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Parses option code and length */ -/* _nx_dhcpv6_extract_packet_information */ -/* Parses each option from server */ -/* reply and updates Client record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_utility_get_data(UCHAR *buffer, UINT size, ULONG *value) -{ - - - /* Check that the size of the data fits in a ULONG. */ - if (size > sizeof(ULONG)) - { - return NX_DHCPV6_INVALID_DATA_SIZE; - } - - *value = 0; - - /* Process the data retrieval request. */ - while (size-- > 0) - { - - /* Build return value. */ - *value = (((*value) << 8) | (*buffer)); - buffer++; - } - - /* Return value. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_utility_time_randomize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns a value of between -1 seconds and 1 second */ -/* in system ticks. It is used to randomize timeouts as required by */ -/* the RFC's so as to not overload a network server after power out. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* ticks Number of ticks between 1 & -1*/ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_convert_delay_to_ticks Convert seconds to ticks */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT _nx_dhcpv6_utility_time_randomize(void) -{ - -UINT temp; -UINT sign; -INT temp_signed; - - temp = (UINT)(NX_RAND()); - temp &= (UINT)(0x001F); - sign = (temp & (UINT)(0x8)); - temp_signed = (INT)temp; - - /* Try for a number between 0 and 0x1F. */ - if (sign) - { - temp_signed = -temp_signed; - } - - return temp_signed; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_waiting_on_reply PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function waits to receive a DHCPv6 server packet for the wait */ -/* time set by the DHCPv6 client previously. If a reply is received, */ -/* call function to process it. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Valid packet received */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_receive Receive UDP packet */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_dhcpv6_packet_procss Process the dhcpv6 packet */ -/* _nx_dhcpv6_flush_queue_packets Flush the queue packets */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process Process current client state */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_waiting_on_reply(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT current_preemption; -UINT status; -NX_PACKET *packet_ptr; -ULONG start_time; -ULONG current_time; -ULONG elapsed_time; -ULONG receive_wait; -UINT time_remaining; -UINT valid_answer; - - /* Initialize the parameters. */ - packet_ptr = NX_NULL; - valid_answer = NX_FALSE; - time_remaining = dhcpv6_ptr -> nx_dhcpv6_transmission_timeout; - - /* Wait in short intervals to receive a valid packet while continuously checking for packets not intended - for this DHCP Client to be removed from the receive queue. */ - do - { - - /* Release the DHCP mutex while the Client will be blocked on a receive socket call. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Indicate the DHCP Client can be stopped. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_TRUE; - - start_time = tx_time_get(); - - if (time_remaining < NX_DHCPV6_TIME_INTERVAL) - { - receive_wait = time_remaining; - } - else - { - receive_wait = NX_DHCPV6_TIME_INTERVAL; - } - - status = nx_udp_socket_receive(&(dhcpv6_ptr -> nx_dhcpv6_socket), &packet_ptr, receive_wait); - - /* Indicate the DHCP Client can not be stopped. */ - dhcpv6_ptr -> nx_dhcpv6_sleep_flag = NX_FALSE; - - /* Restore preemption/ end of critical section. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - /* Yes, receive a packet. */ - if (status == NX_SUCCESS) - { - - /* Get the DHCP mutex. */ - while((tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_NO_WAIT) != TX_SUCCESS) && - (time_remaining > 0)) - { - - if (time_remaining < NX_DHCPV6_TIME_INTERVAL) - { - tx_thread_sleep(time_remaining); - time_remaining = 0; - } - else - { - tx_thread_sleep(NX_DHCPV6_TIME_INTERVAL); - time_remaining -= NX_DHCPV6_TIME_INTERVAL; - } - } - - /* Process the dhcpv6 packet. */ - status = _nx_dhcpv6_packet_process(dhcpv6_ptr, packet_ptr); - - /* Check the status. */ - if(status == NX_SUCCESS) - { - - /* Yes, Get a valid advertise or reply message. */ - valid_answer = NX_TRUE; - - /* DHCPv6 client MUST collect Advertise messages for the first RT seconds, - unless it receives an Advertise message with a preference value of 255. - RFC 3315, Section 17.1.2, Page 34. */ - if((dhcpv6_ptr -> nx_dhcpv6_state == NX_DHCPV6_STATE_SENDING_SOLICIT) && - (dhcpv6_ptr -> nx_dhcpv6_retransmission_count == 0)) - { - - /* Process the rapid solicit mode. */ - if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) - { - - /* Client terminates the waiting process as soon as a reply message - with a Rapid Commit option is received. RFC3315, Section17.1.2, Page34. */ - break; - } - - /* Process the normal solicit mode. */ - if(dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value == 255) - { - - /* If the client receives an Advertise message that includes a Preference option with - a preference value of 255, the client can terminates the waiting. */ - break; - } - } - else - { - - /* Yes, Get the answer. */ - break; - } - } - } - - /* How much time has elapsed? */ - current_time = tx_time_get(); - - /* Has the time wrapped? */ - if (current_time >= start_time) - { - /* No, simply subtract to get the elapsed time. */ - elapsed_time = current_time - start_time; - } - else - { - - /* Yes it has. Time has rolled over the 32-bit boundary. */ - elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; - } - - /* Update the time remaining. */ - if (time_remaining > elapsed_time) - { - time_remaining -= elapsed_time; - } - else - { - /* Time is up, break out of this loop. */ - time_remaining = 0; - - /* But not before restoring preemption/ end of critical section! */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - break; - } - - } while(time_remaining > 0); - - /* Flush the queue packets. */ - _nx_dhcpv6_flush_queue_packets(dhcpv6_ptr); - - /* Check the valid answer flag. */ - if (valid_answer == NX_TRUE) - { - return NX_SUCCESS; - } - else - { - return NX_DHCPV6_INVALID_SERVER_PACKET; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the receive pacet. the data is copied to */ -/* another packet from the DHCPv6 Client packet pool,and the original */ -/* received packet is released back to the receive pool immediately. */ -/* Then process the reply message. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* packet_ptr Pointer to received packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Process correctly */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_extract Get the reply information */ -/* nx_packet_release Release packet to packet pool */ -/* nx_packet_allocate Allocate a new packet. */ -/* nx_packet_data_extract_offset Store the received pacet data. */ -/* _nx_dhcpv6_scan_packet_options Scan and record the reply options. */ -/* _nx_dhcpv6_preprocess_packet_information */ -/* Preprocess the packet according to */ -/* the options record. */ -/* _nx_dhcpv6_extract_packet_information */ -/* Extract server reply data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_waiting_on_reply Process current client message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_packet_process(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -UINT port; -ULONG bytes_copied; -NXD_ADDRESS server_IP_Address; -NX_PACKET *new_packet_ptr; - - - /* Check for valid packet length (message type and ID). */ - if (packet_ptr -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_DHCPV6_INVALID_DATA_SIZE); - } - - /* Extract the IP and port number from the packet and set the reply address. */ - status = nxd_udp_source_extract(packet_ptr, &server_IP_Address, &port); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. We don't want it. */ - nx_packet_release(packet_ptr); - - /* Error extracting packet source information, return error status. */ - return(status); - } - - /* Copy the received packet into the packet allocated by the DHCPv6 Client. */ - status = nx_packet_allocate(dhcpv6_ptr -> nx_dhcpv6_pool_ptr, - &new_packet_ptr, NX_IPv6_UDP_PACKET, - NX_DHCPV6_PACKET_TIME_OUT); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Release the receive packet. We can't use it. */ - nx_packet_release(packet_ptr); - - return status; - } - - /* Verify the incoming packet does not exceed our DHCPv6 Client packet payload. */ - if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < packet_ptr -> nx_packet_length) - { - - /* Release the packet allocated from the Client pool*/ - nx_packet_release(new_packet_ptr); - - /* Release the received packet. We can't use it. */ - nx_packet_release(packet_ptr); - - return(NX_DHCPV6_INVALID_DATA_SIZE); - } - - /* Use a packet from the DHCP Client as a buffer to store the received packet data. - Then we can release the received packet back to its packet pool. */ - status = nx_packet_data_extract_offset(packet_ptr, 0,(VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); - - /* Check status. */ - if ((status != NX_SUCCESS) || (bytes_copied == 0)) - { - - /* Release the packet allocated from the Client pool*/ - nx_packet_release(new_packet_ptr); - - /* Release the received packet. We can't use it. */ - nx_packet_release(packet_ptr); - - /* Error extracting packet buffer, return error status. */ - return(status); - } - - /* Now we can release the received packet. */ - nx_packet_release(packet_ptr); - - /* Update the new packet with the bytes copied. For chained packets, this will reflect the total - 'datagram' length. */ - new_packet_ptr -> nx_packet_length = bytes_copied; - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + bytes_copied; - - /* Process the DHCPv6 packet.*/ - - /* Scan the packet options and record it. */ - status = _nx_dhcpv6_scan_packet_options(dhcpv6_ptr, new_packet_ptr); - - /* Check for errors processing the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the Client packet. We can't use it. */ - nx_packet_release(new_packet_ptr); - - /* Return error status. */ - return status; - } - - /* Preprocess the packet options. */ - status = _nx_dhcpv6_preprocess_packet_information(dhcpv6_ptr, new_packet_ptr); - - /* Check for errors processing the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the Client packet. We can't use it. */ - nx_packet_release(new_packet_ptr); - - /* Return error status. */ - return status; - } - - /* Extract the info from the packet buffer into the Client record. */ - status = _nx_dhcpv6_extract_packet_information(dhcpv6_ptr, new_packet_ptr); - - /* Release the Client packet. We are done with it. */ - nx_packet_release(new_packet_ptr); - - /* Store the DHCPv6 server address. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_dhcpv6_received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY)) - { - COPY_NXD_ADDRESS(&server_IP_Address, &(dhcpv6_ptr-> nx_dhcpv6_server_address)); - } - - /* Successfully processed response from the server. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_scan_packet_options PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function scan the packet options of DHCPv6 server response and */ -/* record the relevant options. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* packet_ptr Pointer to received packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Extract option and length data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_packet_process Process dhcpv6 packet. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_scan_packet_options(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -UCHAR *dhcpv6_option_ptr; -UINT index; -ULONG option_code; -ULONG option_length; -UCHAR *dhcpv6_iana_option_ptr; -UINT iana_index; -ULONG iana_option_code; -ULONG iana_option_length; -UCHAR *dhcpv6_ia_option_ptr; -ULONG ia_option_index; -ULONG ia_option_code; -ULONG ia_option_length; -ULONG ipv6_address[4]; -USHORT status_code; -UINT ia_index; -UINT w; -UINT ia_count = 0; - - /* Set a pointer to the start of DHCPv6 options. */ - dhcpv6_option_ptr = (packet_ptr -> nx_packet_prepend_ptr + 4); - - /* Initialize local variables. */ - index = 0; - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags = 0; - dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value = 0; - - /* Clear the IA address map status. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_map = 0; - } - - /* Now parse all the DHCPv6 option blocks in the packet buffer. */ - /* 4 bytes is data pointer offset, and 4 bytes for option code and option length. */ - while (index <= (packet_ptr -> nx_packet_length - 4 - 4)) - { - - /* Get the option code and length of data of the current option block. */ - status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_option_ptr, &option_code, &option_length); - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Check if option data is in the packet. */ - if ((dhcpv6_option_ptr + 4 + option_length) > packet_ptr -> nx_packet_append_ptr) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - /* Process the option code with an option specific API. */ - switch (option_code) - { - - /* Note - these 'process' functions will not move the buffer pointer. */ - case NX_DHCPV6_OP_CLIENT_ID: - { - - /* Yes, The message includes the Client DUID option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION; - break; - } - - case NX_DHCPV6_OP_SERVER_ID: - { - - /* Yes, The message includes the Server DUID option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_SERVER_ID_OPTION; - break; - } - case NX_DHCPV6_OP_IA_NA: - { - - /* Yes, The message includes the Server DUID option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_IA_NA_OPTION; - - /* Skip the IA_NA header data. */ - dhcpv6_iana_option_ptr = dhcpv6_option_ptr + 16; - iana_index = 0; - - /* Process the IA and status options embedded in the IANA option. */ - /* 12 bytes is IA_NA header, 4 bytes for iana option code and option length. */ - while(iana_index <= (option_length - 12 - 4)) - { - - /* Get the next option code and length. */ - status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_iana_option_ptr, &iana_option_code, &iana_option_length); - - /* Check if the option data is in the packet. */ - if ((dhcpv6_iana_option_ptr + 4 + iana_option_length) > packet_ptr -> nx_packet_append_ptr) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - /* Check the IA address option embedded in the IANA option. */ - if(iana_option_code == NX_DHCPV6_OP_IA_ADDRESS) - { - - /* The minimum length of IA address option is 24 bytes. */ - if (iana_option_length < 24) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - /* Yes, The message includes the IA option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION; - - /* Increase the IA option count. */ - ia_count ++; - - /* Skip the IA type and length option. */ - ia_option_index = 4; - - /* Get the IPv6 address of IA option. */ - for (w = 0; w <= 3; w++) - { - - /* Copy each IPv6 address word into the IA address. */ - memcpy(&ipv6_address[w], (dhcpv6_iana_option_ptr + ia_option_index), sizeof(ULONG)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(ipv6_address[w]); - - ia_option_index += 4; - } - - /* Check the IA table, find the same IPv6 address. */ - for(w = 0; w < NX_DHCPV6_MAX_IA_ADDRESS; w++) - { - - if(!(memcmp(&(dhcpv6_ptr->nx_dhcpv6_ia[w].nx_global_address.nxd_ip_address.v6[0]), &ipv6_address[0], 16))) - { - - /* Yes, it is, record the index to store the IA option, 0 means is IA address inexistence. - Then update the IA option according to the IA count in nx_dhcpv6_update_ia function. */ - dhcpv6_ptr -> nx_dhcpv6_ia[w].nx_address_map = ia_count; - break; - } - } - - /* Check the IA option whether include the status codes or not. */ - /* 24 bytes is IA address option, 4 bytes for next option code and option length. */ - if(iana_option_length >= (24 + 4)) - { - - /* Yes, include status codes, skip the IA header data. */ - dhcpv6_ia_option_ptr = dhcpv6_iana_option_ptr + 28; - - /* Get the status code and length. */ - status = _nx_dhcpv6_utility_get_block_option_length(dhcpv6_ia_option_ptr, &ia_option_code, &ia_option_length); - - /* Check if the option data is in the packet. */ - if ((dhcpv6_ia_option_ptr + 4 + ia_option_length) > packet_ptr -> nx_packet_append_ptr) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - if(ia_option_code == NX_DHCPV6_OP_STATUS_CODE) - { - if (ia_option_length < 2) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - /* Yes, the message includes the STATUS option, get the code. */ - memcpy(&status_code, (dhcpv6_ia_option_ptr + 4), sizeof(USHORT)); - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(status_code); - - if(status_code == 0) - { - - /* Yes, The message includes the Success status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; - } - else if(status_code == 1) - { - - /* Yes, The message includes the UnspecFail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; - } - else if(status_code == 2) - { - - /* Yes, The message includes the NoAddrsAvail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; - } - else if(status_code == 3) - { - - /* Yes, The message includes the NoBinding status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; - } - else if(status_code == 4) - { - - /* Yes, The message includes the NotOnLink status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; - } - else if(status_code == 5) - { - - /* Yes, The message includes the UseMulticast status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; - } - else - { - - /* This is an unsupported or unknown option. */ - return NX_DHCPV6_UNKNOWN_OPTION; - } - - } - else - { - - /* This is an unsupported or unknown option. */ - return NX_DHCPV6_UNKNOWN_OPTION; - } - } - } - - /* Check if this is an status option request. */ - else if(iana_option_code == NX_DHCPV6_OP_STATUS_CODE) - { - if (iana_option_length < 2) - { - return(NX_DHCPV6_INCOMPLETE_OPTION_BLOCK); - } - - /* Yes, the message includes the STATUS option, get the code. */ - memcpy(&status_code, (dhcpv6_iana_option_ptr + 4), sizeof(USHORT)); - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(status_code); - - if(status_code == 0) - { - - /* Yes, The message includes the Success status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; - } - else if(status_code == 1) - { - - /* Yes, The message includes the UnspecFail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; - } - else if(status_code == 2) - { - - /* Yes, The message includes the NoAddrsAvail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; - } - else if(status_code == 3) - { - - /* Yes, The message includes the NoBinding status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; - } - else if(status_code == 4) - { - - /* Yes, The message includes the NotOnLink status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; - } - else if(status_code == 5) - { - - /* Yes, The message includes the UseMulticast status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; - } - else - { - - /* This is an unsupported or unknown option. */ - return NX_DHCPV6_UNKNOWN_OPTION; - } - } - else - { - - /* This is an unsupported or unknown option. */ - return NX_DHCPV6_UNKNOWN_OPTION; - } - - /* Move to the next top level option. */ - dhcpv6_iana_option_ptr += iana_option_length + 4; - - /* Update the iana_index. */ - iana_index += iana_option_length + 4; - - } - - break; - } - - case NX_DHCPV6_OP_PREFERENCE: - { - USHORT temp; - - /* Yes, The message includes the preference option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_PREFERENCE_OPTION; - - /* Set the pointer. */ - temp = *(dhcpv6_option_ptr + 4); - - /* Record the preference option value of current advetise message. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value = temp; - - /* Adjust the endianness. */ - NX_CHANGE_USHORT_ENDIAN(dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value); - break; - } - - case NX_DHCPV6_OP_STATUS_CODE: - { - - /* Yes, the message includes the STATUS option, get the code. */ - memcpy(&status_code, (dhcpv6_option_ptr + 4), sizeof(USHORT)); - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(status_code); - - if(status_code == 0) - { - - /* Yes, The message includes the Success status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION; - } - else if(status_code == 1) - { - - /* Yes, The message includes the UnspecFail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION; - } - else if(status_code == 2) - { - - /* Yes, The message includes the NoAddrsAvail status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION; - } - else if(status_code == 3) - { - - /* Yes, The message includes the NoBinding status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION; - } - else if(status_code == 4) - { - - /* Yes, The message includes the NotOnLink status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION; - } - else if(status_code == 5) - { - - /* Yes, The message includes the UseMulticast status option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION; - } - else - { - - /* This is an unsupported or unknown option. */ - return NX_DHCPV6_UNKNOWN_OPTION; - } - break; - } - - case NX_DHCPV6_OP_RAPID_COMMIT: - { - - /* Yes, The message includes the Rapid Commit option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION; - break; - } - - case NX_DHCPV6_OP_DNS_SERVER: - { - - /* Yes, The message includes the DNS server option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_DNS_SERVER_OPTION; - break; - } - - case NX_DHCPV6_OP_DOMAIN_NAME: - { - - /* Yes, The message includes the domain name option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_DOMAIN_NAME_OPTION; - break; - } - - case NX_DHCPV6_OP_SNTP_SERVER: - { - - /* Yes, The message includes the timer server option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_SNTP_SERVER_OPTION; - break; - } - - case NX_DHCPV6_OP_CLIENT_FQDN: - { - - /* Yes, The message includes the Client FQDN option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_CLIENT_FQDN_OPTION; - break; - } - - case NX_DHCPV6_OP_NEW_POSIX_TIMEZONE: - { - - /* Yes, The message includes the time zone option. */ - dhcpv6_ptr -> nx_dhcpv6_reply_option_flags |= NX_DHCPV6_INCLUDE_NEW_POSIX_TIIMEZONE_OPTION; - break; - } - - default: - { - break; - } - } - - /* Move to the next top level option. */ - dhcpv6_option_ptr += option_length + 4; - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - } - - /* Yes, scan is complete, just return success. */ - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_preprocess_packet_information PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function preprocess packet information according to reply */ -/* message option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* packet_ptr Pointer to received packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCPv6_SUCCESS Successful completion status */ -/* NX_DHCPV6_NO_DUID_OPTION Message has no DUID option */ -/* NX_DHCPV6_NO_RAPID_COMMIT_OPTION Message has no rapid */ -/* commit option */ -/* NX_DHCPV6_IA_ADDRESS_NOT_VALID Message has no IA option */ -/* NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE Preference value is equal to */ -/* or less than */ -/* NX_DHCPV6_UNKNOWN_MSG_TYPE Unknown message type */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_data Get the data in reply message */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_packet_process Process the packet. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_preprocess_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) -{ - -ULONG received_message_type; -ULONG returned_xid; - - /* Preprocess the DHCPv6 packet. */ - - /* Extract the message type which should be the first byte. */ - _nx_dhcpv6_utility_get_data(packet_ptr -> nx_packet_prepend_ptr, 1, &received_message_type); - - /* Check for an illegal message type. */ - if ((received_message_type != NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) && - (received_message_type != NX_DHCPV6_MESSAGE_TYPE_REPLY) && - (received_message_type != NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE)) - { - - /* These should only be sent to DHCPv6 servers! */ - return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; - } - - /* Set the received message type. */ - dhcpv6_ptr -> nx_dhcpv6_received_message_type = (UCHAR)received_message_type; - - /* This is a unicast packet (valid). Parse the transaction ID. */ - _nx_dhcpv6_utility_get_data((packet_ptr -> nx_packet_prepend_ptr + 1), 3, &returned_xid); - - /* Make sure the DHCP transaction ID matches our current session. */ - if (returned_xid != (dhcpv6_ptr -> nx_dhcpv6_message_hdr.nx_message_xid)) - { - - /* Return the bad transmaction ID. */ - return NX_DHCPV6_BAD_TRANSACTION_ID; - } - - /* Check the options. */ - switch (dhcpv6_ptr -> nx_dhcpv6_state) - { - - /* The DHCPv6 remains initial status or DHCPv6 interactive process has been completed. - Just clear the timer and message ID. */ - case NX_DHCPV6_STATE_BOUND_TO_ADDRESS: - case NX_DHCPV6_STATE_INIT: - { - - /* In these state, DHCPv6 Client do not expect any packet. */ - return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; - } - - /* The DHCPv6 CLient has sent a solicit message and expect advertise message. */ - case NX_DHCPV6_STATE_SENDING_SOLICIT: - { - - /* DHCPv6 Client must discrd the received advertise messages - that meet the message does not inlcude SERVER ID or CLIENT ID. */ - if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION) || - !(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_SERVER_ID_OPTION)) - { - - /* The packet does not include DUID option.*/ - return NX_DHCPV6_NO_DUID_OPTION; - } - - /* DHcpv6 Client must ignore any advertise message that includes a status code option - containing the value NoAddrsAvail. */ - if(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION) - { - return NX_DHCPV6_IA_ADDRESS_NOT_VALID; - } - - if(dhcpv6_ptr -> nx_dhcpv6_request_solicit_mode == NX_DHCPV6_SOLICIT_RAPID) - { - if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION)) - { - - return NX_DHCPV6_NO_RAPID_COMMIT_OPTION; - } - } - else - { - - /* Check the preference value. */ - if((dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value != 0) && - (dhcpv6_ptr -> nx_dhcpv6_reply_option_current_pref_value <= dhcpv6_ptr -> nx_dhcpv6_preference.nx_pref_value)) - { - - /* The current preference value is equal to or less than the recorded preference valude, - DHCPv6 Client need not process the message, return. */ - return NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE; - } - } - - break; - } - - /* The DHCPv6 CLien has sent a request message and expect reply message. */ - case NX_DHCPV6_STATE_SENDING_REQUEST: - case NX_DHCPV6_STATE_SENDING_RENEW: - case NX_DHCPV6_STATE_SENDING_REBIND: - case NX_DHCPV6_STATE_SENDING_CONFIRM: - case NX_DHCPV6_STATE_SENDING_RELEASE: - case NX_DHCPV6_STATE_SENDING_DECLINE: - case NX_DHCPV6_STATE_SENDING_INFORM_REQUEST: - { - - /* DHCPv6 Client must discrd the received advertise messages - that meet the message does not inlcude SERVE ID or CLIENT ID. */ - if(!(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION) || - !(dhcpv6_ptr -> nx_dhcpv6_reply_option_flags & NX_DHCPV6_INCLUDE_SERVER_ID_OPTION)) - { - - /* The packet does not include DUID option.*/ - return NX_DHCPV6_NO_DUID_OPTION; - } - break; - } - - default: - { - - /* Unknown or unsupported DHCPv6 request (state). */ - return NX_DHCPV6_UNKNOWN_MSG_TYPE; - } - } - - return NX_DHCPV6_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_extract_packet_information PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the DHCPv6 server response to Client requests. */ -/* It checks for valid reply message types for the current Client */ -/* request, and if all is well, then parses each option in sequential */ -/* order and updates the server reply data to the Client record. At the*/ -/* end of the data extraction, it then verifies that the server reply */ -/* contained both valid Client and server DUID options. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* packet_ptr Pointer to received packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal */ -/* NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up */ -/* NX_DHCPV6_PROCESSING_ERROR Packet length is different than */ -/* expected */ -/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ -/* NX_DHCPV6_MISSING_IANA_OPTION Message has no IANA option */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_utility_get_block_option_length */ -/* Extract option header data */ -/* _nx_dhcpv6_process_client_duid Extract Client DUID from reply */ -/* _nx_dhcpv6_process_server_duid Extract Server DUID from reply */ -/* _nx_dhcpv6_process_iana Extract IANA option from reply */ -/* _nx_dhcpv6_process_preference Extract server preference */ -/* _nx_dhcpv6_process_DNS_server Extract DNS server from reply */ -/* _nx_dhcpv6_process_time_server Extract time server from reply */ -/* _nx_dhcpv6_process_time_zone Extract time zone from reply */ -/* _nx_dhcpv6_process_domain_name Extract domain name from reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_packet_process Process the dhcpv6 reply message*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_extract_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -ULONG op_code; -ULONG option_length; -UCHAR *buffer_ptr; -UINT index; - - /* The DHCPv6 header has been processed in preprocess function, so process the options. */ - /* Set a pointer to the options of DHCPv6. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 4; - - /* Initialize local variables. */ - index = 0; - - /* Now parse all the DHCPv6 option blocks in the packet buffer. */ - while (index < (packet_ptr -> nx_packet_length - 4)) - { - - /* Get the option code and length of data of the current option block. */ - status = _nx_dhcpv6_utility_get_block_option_length(buffer_ptr, &op_code, &option_length); - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Process the option code with an option specific API. */ - switch (op_code) - { - /* Note - these 'process' functions will not move the buffer pointer. */ - - case NX_DHCPV6_OP_CLIENT_ID: - { - - /* Process the Client DUID. */ - status = _nx_dhcpv6_process_client_duid(dhcpv6_ptr, buffer_ptr, option_length); - - break; - } - - case NX_DHCPV6_OP_SERVER_ID: - { - - /* Process the Server DUID. */ - status = _nx_dhcpv6_process_server_duid(dhcpv6_ptr, buffer_ptr, option_length); - - break; - } - case NX_DHCPV6_OP_IA_NA: - { - - status = _nx_dhcpv6_process_iana(dhcpv6_ptr, buffer_ptr, option_length); - - /* Note: this API directly handles any server error codes received. */ - - break; - } - - /* This should not happen. The IA address option must be embedded in the IANA option. */ - case NX_DHCPV6_OP_IA_ADDRESS: - { - - /* Don't process an IA address option outside of an address association (IANA). */ - status = NX_DHCPV6_MISSING_IANA_OPTION; - - break; - } - - /* The RFC for DHCPv6 indicates any option can have a status option applied to it. So a status - option outside of an IANA option (where it is usually found) has to be handled. */ - case NX_DHCPV6_OP_STATUS_CODE: - { - status = _nx_dhcpv6_process_status(dhcpv6_ptr, buffer_ptr, option_length); - - /* Now check on the server status of the previous option in the DHCP message. */ - if ((status == NX_SUCCESS) && (dhcpv6_ptr -> nx_status_code != NX_DHCPV6_SUCCESS)) - { - - /* Does the dhcpv6 client have a server error handler? */ - if (dhcpv6_ptr -> nx_dhcpv6_server_error_handler) - { - - /* Send the status and which option the status is reported for to the handler. */ - (dhcpv6_ptr -> nx_dhcpv6_server_error_handler)(dhcpv6_ptr, NX_DHCPV6_ERROR_STATUS_CODE_IN_OPTION_FIELD, dhcpv6_ptr -> nx_status_code, - dhcpv6_ptr -> nx_dhcpv6_received_message_type); - } - } - - break; - } - - /* Process the preference option. */ - case NX_DHCPV6_OP_PREFERENCE: - { - - status = _nx_dhcpv6_process_preference(dhcpv6_ptr, buffer_ptr, option_length); - break; - } - - /* The remainder are RFC mandated option codes for specific options. Not all of these - have been finalized by IANA as of this release. */ - - case NX_DHCPV6_OP_DNS_SERVER: - { - - status = _nx_dhcpv6_process_DNS_server(dhcpv6_ptr, buffer_ptr, option_length); - - break; - } - - case NX_DHCPV6_OP_DOMAIN_NAME: - { - status = _nx_dhcpv6_process_domain_name(dhcpv6_ptr, packet_ptr -> nx_packet_prepend_ptr, buffer_ptr, option_length); - break; - } - - case NX_DHCPV6_OP_SNTP_SERVER: - { - - status = _nx_dhcpv6_process_time_server(dhcpv6_ptr, buffer_ptr, option_length); - break; - } - - case NX_DHCPV6_OP_NEW_POSIX_TIMEZONE: - { - status = _nx_dhcpv6_process_time_zone(dhcpv6_ptr, buffer_ptr, option_length); - break; - } - - default: - { - break; - } - } - - /* Check for errors from option block processing. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Move to the next top level option. */ - buffer_ptr += option_length + 4; - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - - } - - /* Now, the index should be the packet length. */ - if(index != (packet_ptr -> nx_packet_length - 4)) - { - return NX_DHCPV6_INVALID_DATA_SIZE; - } - - /* Yes, the packet data processing is completed. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_flush_queue_packets PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function flush the useless queue packets. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_receive Receive UDP packet */ -/* nx_packet_release Release packet to packet pool */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process Process the DHCPv6 Client request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_flush_queue_packets(NX_DHCPV6 *dhcpv6_ptr) -{ - -UINT status = NX_SUCCESS; -NX_PACKET *packet_ptr; - - - /* Loop to receive the queue packets. */ - while(status == NX_SUCCESS) - { - - /* Receive the queue packets and release it. */ - status = nx_udp_socket_receive(&(dhcpv6_ptr -> nx_dhcpv6_socket), &packet_ptr, NX_NO_WAIT); - - /* Check the status. */ - if (status == NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_update_retransmit_info PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the retransmission,update the retransmission */ -/* count and retransmission timeout according to the RFC3315,Section14.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Valid retransmit */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_process Process current client state */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_update_retransmit_info(NX_DHCPV6 *dhcpv6_ptr) -{ - - /* Process the retransmission according to the RFC3315, Section 14, page26. */ - if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count != 0) || (dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration != 0)) - { - - if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count != 0) && - (dhcpv6_ptr -> nx_dhcpv6_retransmission_count >= dhcpv6_ptr -> nx_dhcpv6_max_retransmission_count)) - { - - /* Has reached the max retransmission count, return. */ - return NX_DHCPV6_REACHED_MAX_RETRANSMISSION_COUNT; - } - - if((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration != 0) && - (dhcpv6_ptr -> nx_dhcpv6_elapsed_time.nx_session_time >= (dhcpv6_ptr -> nx_dhcpv6_max_retransmission_duration * 100))) - { - - /* Has reached the max retransmission timeout, return. */ - return NX_DHCPV6_REACHED_MAX_RETRANSMISSION_TIMEOUT; - } - } - - /* Increase the count of retransmission. */ - dhcpv6_ptr -> nx_dhcpv6_retransmission_count++; - - /* Double the retransmission timeout for the next retransmit. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = 2 * dhcpv6_ptr -> nx_dhcpv6_transmission_timeout; - - /* Is the retransmission timeout greater than the max allowable timeout, if there is one? */ - if ((dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout != 0) && - (dhcpv6_ptr -> nx_dhcpv6_transmission_timeout > dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout)) - { - - /* Limit the transmission time to the max for the next message. */ - dhcpv6_ptr -> nx_dhcpv6_transmission_timeout = dhcpv6_ptr -> nx_dhcpv6_max_retransmission_timeout; - } - - /* Can retransmit the request. */ - return NX_SUCCESS; -} - - -#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_ipv6_address_DAD_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the IPv6 address perform DAD notify callback. */ -/* And set the DHCPv6 event to notify DHCPv6 Client thread. If this */ -/* function is used in DHCPv6 function, nxd_ipv6_address_change_notify */ -/* function should not be used again. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr Pointer to IP instance */ -/* status DAD process status */ -/* interface_index The interface index */ -/* ipv6_addr_index The IPv6 address index */ -/* ipv6_address Pointer to IPv6 address */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags to wake */ -/* DHCPv6 thread to process */ -/* */ -/* CALLED BY */ -/* */ -/* UDP receive callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_ipv6_address_DAD_notify(NX_IP *ip_ptr, UINT status, UINT interface_index, UINT ipv6_addr_index, ULONG *ipv6_address) -{ -UINT ia_index; - - NX_PARAMETER_NOT_USED(interface_index); - - /* Make sure the DHCPv6 DAD instance is normal. */ - if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_id != NX_DHCPV6_ID) || - (!_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_name) || - (_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ip_ptr != ip_ptr) || - (_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS)) - return; - - - /* Check the DAD status. */ - if(status == NX_IPV6_ADDRESS_DAD_FAILURE) - { - - /* Now find where this address cross references in the DHCP address list. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_client_address_index[ia_index] == ipv6_addr_index) && - (!memcmp(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), ipv6_address, 16))) - { - - /* Set the IPv6 address status DAD failure. */ - _nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE; - - /* Wakeup DHCPv6 thread for processing DAD failure event. */ - tx_event_flags_set(&_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_events, NX_DHCPV6_DAD_FAILURE_EVENT, TX_OR); - - break; - } - } - } - - /* Check the DAD status. */ - if(status == NX_IPV6_ADDRESS_DAD_SUCCESSFUL) - { - - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if((_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_client_address_index[ia_index] == ipv6_addr_index) && - (!memcmp(&(_nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address.nxd_ip_address.v6[0]), ipv6_address, 16))) - { - - /* Set the IPv6 address status valid. */ - _nx_dhcpv6_DAD_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status = NX_DHCPV6_IA_ADDRESS_STATE_VALID; - - break; - } - } - } - - return; -} -#endif - - -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the get DHCPv6 Client */ -/* record service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 instance */ -/* client_record_ptr Pointer to memory to save */ -/* Client record to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status from */ -/* internal DHCP calls */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_client_create_record */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dhcpv6_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Call actual DHCPv6 client get record service. */ - status = _nx_dhcpv6_client_get_record(dhcpv6_ptr, client_record_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_get_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a DHCPv6 Client record for restoring the */ -/* Client state between power cycles or idle (sleep) mode. It then */ -/* copies the Client record to the supplied client record pointer. It */ -/* should be that the DHCPv6 Client state be restored from the Client */ -/* record saved to the input pointer client_record_ptr. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 instance */ -/* client_record_ptr Pointer to memory to save */ -/* Client record to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_NOT_BOUND DHCPv6 was not bound */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr) -{ - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Clear memory before filling with data. */ - memset(client_record_ptr, 0, sizeof(NX_DHCPV6_CLIENT_RECORD)); - - /* The DHCPv6 Client is not Bound to an IP address. Cannot create a record for restoring Client - state if not bound to an IP lease. */ - if (dhcpv6_ptr -> nx_dhcpv6_state != NX_DHCPV6_STATE_BOUND_TO_ADDRESS) - { - return NX_DHCPV6_NOT_BOUND; - } - - /* Set the DHCPv6 record. */ - client_record_ptr -> nx_dhcpv6_state = dhcpv6_ptr -> nx_dhcpv6_state; - - /* Set the interface and address index. */ - client_record_ptr -> nx_dhcpv6_client_interface_index = dhcpv6_ptr -> nx_dhcpv6_client_interface_index; - memcpy(client_record_ptr -> nx_dhcpv6_client_address_index, dhcpv6_ptr -> nx_dhcpv6_client_address_index, sizeof(UINT) * NX_DHCPV6_MAX_IA_ADDRESS); - - /* Set the time since client set its IP address. */ - client_record_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued; - - /* Set the Client DUID. */ - memcpy(&client_record_ptr -> nx_dhcpv6_client_duid, &dhcpv6_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_DUID)); - - /* Set the Server DUID. */ - memcpy(&client_record_ptr -> nx_dhcpv6_server_duid, &dhcpv6_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_DUID)); - - /* Set the IANA. */ - memcpy(&client_record_ptr -> nx_dhcpv6_iana, &dhcpv6_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_IA_NA)); - - /* Set the IA Address. */ - memcpy(&client_record_ptr -> nx_dhcpv6_ia, &dhcpv6_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_IA_ADDRESS) * NX_DHCPV6_MAX_IA_ADDRESS); - - /* Set the Option request. */ - memcpy(&client_record_ptr -> nx_dhcpv6_option_request, &dhcpv6_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_OPTIONREQUEST)); - - /* Set the Client FQDN. */ - memcpy(&client_record_ptr -> nx_dhcpv6_client_FQDN, &dhcpv6_ptr -> nx_dhcpv6_client_FQDN, sizeof(NX_DHCPV6_CLIENT_FQDN)); - - /* Set the dns name server address. */ - memcpy(&client_record_ptr -> nx_dhcpv6_DNS_name_server_address, &dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_DNS_SERVERS); - - /* Set the time server address. */ - memcpy(&client_record_ptr -> nx_dhcpv6_time_server_address, &dhcpv6_ptr -> nx_dhcpv6_time_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_TIME_SERVERS); - - /* Set the domain name. */ - memcpy(client_record_ptr -> nx_dhcpv6_domain_name, dhcpv6_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); - - /* Set the time zone. */ - memcpy(client_record_ptr -> nx_dhcpv6_time_zone, dhcpv6_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_client_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the client restore service.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 instance */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERRPR Invalid pointer input */ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_client_restore_record */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dhcpv6_ptr == NX_NULL) || (client_record_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Call actual DHCPv6 client get record service. */ - status = _nx_dhcpv6_client_restore_record(dhcpv6_ptr, client_record_ptr, time_elapsed); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_restore_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the DHCPv6 CLient state with the supplied DHCP*/ -/* Client record pointed to by the client_record_ptr pointer. It then */ -/* updates the time out parameters of the DHCPv6 Client with the */ -/* time_elapsed parameter (in timer ticks). It is intended for */ -/* restoring Client state between reboots and assumes the DHCPv6 Client*/ -/* state was previously obtained and stored in NVRAM before power down.*/ -/* */ -/* Note: after restore the DHCPv6 Client record, should call */ -/* nx_dhcpv6_resume to update the DHCPv6 Client state and resume the */ -/* DHCPv6 processing thread. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 instance */ -/* client_record_ptr Pointer to previously saved */ -/* Client record */ -/* time_elapsed time input in timer ticks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status NetX completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_ip_interface_address_set */ -/* nx_ip_address_set */ -/* _nx_dhcp_client_update_time_remaining */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed) -{ - -UINT ia_index; - - - /* Get the DHCP mutex. */ - tx_mutex_get(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex), NX_DHCPV6_MUTEX_WAIT); - - /* Set the DHCPv6 record. */ - dhcpv6_ptr -> nx_dhcpv6_state = client_record_ptr -> nx_dhcpv6_state; - - /* Set the interface and address index. */ - dhcpv6_ptr -> nx_dhcpv6_client_interface_index = client_record_ptr -> nx_dhcpv6_client_interface_index; - memcpy(dhcpv6_ptr -> nx_dhcpv6_client_address_index, client_record_ptr -> nx_dhcpv6_client_address_index, sizeof(UINT) * NX_DHCPV6_MAX_IA_ADDRESS); - - /* Set the Client DUID. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_client_duid, &client_record_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_DUID)); - - /* Set the Server DUID. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_server_duid, &client_record_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_DUID)); - - /* Set the IANA. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_iana, &client_record_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_IA_NA)); - - /* Set the IA Address. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_ia, &client_record_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_IA_ADDRESS) * NX_DHCPV6_MAX_IA_ADDRESS); - - /* Set the Option request. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_option_request, &client_record_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_OPTIONREQUEST)); - - /* Set the Client FQDN. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_client_FQDN, &client_record_ptr -> nx_dhcpv6_client_FQDN, sizeof(NX_DHCPV6_CLIENT_FQDN)); - - /* Set the dns name server address. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_DNS_name_server_address, &client_record_ptr -> nx_dhcpv6_DNS_name_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_DNS_SERVERS); - - /* Set the time server address. */ - memcpy(&dhcpv6_ptr -> nx_dhcpv6_time_server_address, &client_record_ptr -> nx_dhcpv6_time_server_address, sizeof(NXD_ADDRESS) * NX_DHCPV6_NUM_TIME_SERVERS); - - /* Set the domain name. */ - memcpy(dhcpv6_ptr -> nx_dhcpv6_domain_name, client_record_ptr -> nx_dhcpv6_domain_name, NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE); - - /* Set the time zone. */ - memcpy(dhcpv6_ptr -> nx_dhcpv6_time_zone, client_record_ptr -> nx_dhcpv6_time_zone, NX_DHCPV6_TIME_ZONE_BUFFER_SIZE); - - /* Set the time since client set its IP address. */ - dhcpv6_ptr -> nx_dhcpv6_IP_lifetime_time_accrued = (client_record_ptr -> nx_dhcpv6_IP_lifetime_time_accrued + time_elapsed); - - /* Set the DHCPv6 Client IPv6 addresses. */ - for(ia_index = 0; ia_index < NX_DHCPV6_MAX_IA_ADDRESS; ia_index++) - { - - if(dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_address_status == NX_DHCPV6_IA_ADDRESS_STATE_VALID) - { - - /* Add the address to the IP instance address table. */ - nxd_ipv6_address_set(dhcpv6_ptr -> nx_dhcpv6_ip_ptr, dhcpv6_ptr -> nx_dhcpv6_client_interface_index, - &dhcpv6_ptr -> nx_dhcpv6_ia[ia_index].nx_global_address, 64, &dhcpv6_ptr -> nx_dhcpv6_client_address_index[ia_index]); - } - } - - /* Release the DHCPv6 Client mutex. */ - tx_mutex_put(&(dhcpv6_ptr -> nx_dhcpv6_client_mutex)); - - return NX_SUCCESS; -} -#endif /* NX_DHCPV6_CLIENT_RESTORE_STATE */ -#endif /* FEATURE_NX_IPV6 */ diff --git a/protocol_handlers/dhcp/nxd_dhcpv6_client.h b/protocol_handlers/dhcp/nxd_dhcpv6_client.h deleted file mode 100644 index 8b2a1663..00000000 --- a/protocol_handlers/dhcp/nxd_dhcpv6_client.h +++ /dev/null @@ -1,1060 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_dhcpv6_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Dynamic Host Configuration Protocol over */ -/* IPv6 (DHCPv6) component, including all data types and external */ -/* references. It is assumed that nx_api.h and nx_port.h have already */ -/* been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_DHCPV6_CLIENT_H -#define NXD_DHCPV6_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -/* Enable support for DHCPv6 client state preserved between reboots */ -/* -#define NX_DHCPV6_CLIENT_RESTORE_STATE -*/ - - -/* Define the DHCPv6 ID "DHCPV6" that is used to mark the DHCPv6 structure as created. */ - -#define NX_DHCPV6_ID 0x44484336UL - - -/* Set the Client lease time. An infinate lease time is not recommended by the RFC - unless the Client requires a permanent IP address. Most servers will likely not - grant an infinite IP address lease. */ - -#define NX_DHCPV6_INFINITE_LEASE 0xffffffffUL -#define NX_DHCPV6_MULTICAST_MASK 0xff000000UL - -typedef enum -{ - NX_DHCPV6_DUID_TYPE_LINK_TIME = 1, - NX_DHCPV6_DUID_TYPE_VENDOR_ASSIGNED, - NX_DHCPV6_DUID_TYPE_LINK_ONLY - -} NX_DHCPV6_DUID_TYPE; - - -/* Define the Hardware types. */ -#define NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET 1 -#define NX_DHCPV6_CLIENT_HARDWARE_TYPE_EUI_64 27 - -/* NX_DHCPV6_HW_TYPE_IEEE_802 is defined as 1 to indicate Ethernet hardware type in old releases, for backward compatibility. - - Note: NX_DHCPV6_HW_TYPE_IEEE_802 will be deprecated by NX_DHCPV6_CLIENT_HARDWARE_TYPE_ETHERNET - in future releases, should use above symbols to define hardware types. -*/ -#define NX_DHCPV6_HW_TYPE_IEEE_802 1 - - -/* Define approximate time since Jan 1, 2000 for computing DUID time. This will form the - basis for the DUID time ID field. */ - -#define SECONDS_SINCE_JAN_1_2000_MOD_32 2563729999UL - -/* Define the value for IA address. */ - -#define NX_DHCPV6_REMOVE_ALL_IA_ADDRESS 0xFFFFFFFF - -/* Define the DHCPv6 Message Types. */ - -#define NX_DHCPV6_MESSAGE_TYPE_SOLICIT 1 -#define NX_DHCPV6_MESSAGE_TYPE_ADVERTISE 2 -#define NX_DHCPV6_MESSAGE_TYPE_REQUEST 3 -#define NX_DHCPV6_MESSAGE_TYPE_CONFIRM 4 -#define NX_DHCPV6_MESSAGE_TYPE_RENEW 5 -#define NX_DHCPV6_MESSAGE_TYPE_REBIND 6 -#define NX_DHCPV6_MESSAGE_TYPE_REPLY 7 -#define NX_DHCPV6_MESSAGE_TYPE_RELEASE 8 -#define NX_DHCPV6_MESSAGE_TYPE_DECLINE 9 -#define NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE 10 -#define NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST 11 - -/* Define the DHCPv6 Options, RFC3315, RFC 3646 and RFC 4242,etc. */ - -#define NX_DHCPV6_OP_CLIENT_ID 1 /* Client DUID (DHCP unique identifier) */ -#define NX_DHCPV6_OP_SERVER_ID 2 /* Server DUID (DHCP unique identifier) */ -#define NX_DHCPV6_OP_IA_NA 3 /* Identity association for non temporary addresses */ -#define NX_DHCPV6_OP_IA_TA 4 /* Identity association for temporary addresses */ -#define NX_DHCPV6_OP_IA_ADDRESS 5 /* Address associated with IA_NA or IA_TA */ -#define NX_DHCPV6_OP_OPTION_REQUEST 6 /* Identifies a list of options */ -#define NX_DHCPV6_OP_PREFERENCE 7 /* Server's means of affecting Client choice of servers. */ -#define NX_DHCPV6_OP_ELAPSED_TIME 8 /* Duration of Client exchange with DHCPv6 server */ -#define NX_DHCPV6_OP_RELAY_MESSAGE 9 /* Not in use in NetX DHCPV6 */ -#define NX_DHCPV6_OP_AUTHENTICATION 11 /* Not in use in NetX DHCPV6 */ -#define NX_DHCPV6_OP_SERVER_UNICAST 12 /* Server ok's allowing the client to address it in Unicast */ -#define NX_DHCPV6_OP_STATUS_CODE 13 /* Status option. */ -#define NX_DHCPV6_OP_RAPID_COMMIT 14 /* Rapid commit option. */ -#define NX_DHCPV6_OP_USER_CLASS 15 /* User calss option. */ -#define NX_DHCPV6_OP_VENDOR_CLASS 16 /* Vendor Class option. */ -#define NX_DHCPV6_OP_VENDOR_SPEC_INFO 17 /* Vendor specific information option. */ -#define NX_DHCPV6_OP_INTERFACE_ID 18 /* Interface ID option. */ -#define NX_DHCPV6_OP_RCONF_MESSAGE 19 /* Reconfigure message option. */ -#define NX_DHCPV6_OP_RCONF_ACCEPT 20 /* Reconfigure accept option. */ - -#define NX_DHCPV6_OP_DNS_SERVER 23 /* Dns servers option. */ -#define NX_DHCPV6_OP_DOMAIN_NAME 24 /* Domain names list option. */ - -#define NX_DHCPV6_OP_SNTP_SERVER 31 /* Network time protocol servers option. */ -#define NX_DHCPV6_OP_CLIENT_FQDN 39 /* Client Fully Qualified Domain Name Option. */ -#define NX_DHCPV6_OP_NEW_POSIX_TIMEZONE 41 /* New timezone POSIX string index option. */ -#define NX_DHCPV6_OP_NEW_TZDB_TIMEZONE 42 /* New timezone database string option. */ - -/* Define the Error Status Code Location. */ -#define NX_DHCPV6_ERROR_STATUS_CODE_IN_OPTION_FIELD 0 /* An Error Status Code option appears in options field of DHCP message. */ -#define NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_NA 1 /* An Error Status Code option appears in options field of IA_NA option. */ -#define NX_DHCPV6_ERROR_STATUS_CODE_IN_IA_ADDRESS 2 /* An Error Status Code option appears in options field of IA_ADDRESS option . */ - -/* Define the options included in the reply message. */ - -#define NX_DHCPV6_INCLUDE_CLIENT_ID_OPTION 0x00000001 /* The reply message includes a Client Identifier option. */ -#define NX_DHCPV6_INCLUDE_SERVER_ID_OPTION 0x00000002 /* The reply message includes a Server Identifier option. */ -#define NX_DHCPV6_INCLUDE_IA_NA_OPTION 0x00000004 /* The reply message includes a IA_NA option. */ -#define NX_DHCPV6_INCLUDE_IA_ADDRESS_OPTION 0x00000008 /* The reply message includes a IA address option. */ -#define NX_DHCPV6_INCLUDE_OPTION_REQUEST_OPTION 0x00000010 /* The reply message includes a option request option. */ -#define NX_DHCPV6_INCLUDE_PREFERENCE_OPTION 0x00000020 /* The reply message includes a preference option. */ -#define NX_DHCPV6_INCLUDE_ELAPSED_TIME_OPTION 0x00000040 /* The reply message includes a elapsed time option. */ -#define NX_DHCPV6_INCLUDE_RELAY_MESSAGE_OPTION 0x00000080 /* The reply message includes a relay message option. */ -#define NX_DHCPV6_INCLUDE_AUTHENTICATION_OPTION 0x00000100 /* The reply message includes a authentication option. */ -#define NX_DHCPV6_INCLUDE_SERVER_UNICAST_OPTION 0x00000200 /* The reply message includes a server unicast option. */ -#define NX_DHCPV6_INCLUDE_STATUS_SUCCESS_OPTION 0x00000400 /* The reply message includes a status code option with success. */ -#define NX_DHCPV6_INCLUDE_STATUS_UNSPEC_FAIL_OPTION 0x00000800 /* The reply message includes a status code option with failure. */ -#define NX_DHCPV6_INCLUDE_STATUS_NO_ADDR_AVAIL_OPTION 0x00001000 /* The reply message includes a status code option with no addresses available. */ -#define NX_DHCPV6_INCLUDE_STATUS_NO_BIND_OPTION 0x00002000 /* The reply message includes a status code option with unavailable. */ -#define NX_DHCPV6_INCLUDE_STATUS_NOT_ONLINK_OPTION 0x00004000 /* The reply message includes a status code option with not onlink. */ -#define NX_DHCPV6_INCLUDE_STATUS_USE_MULTICAST_OPTION 0x00008000 /* The reply message includes a status code option with use multicast. */ -#define NX_DHCPV6_INCLUDE_RAPID_COMMIT_OPTION 0x00010000 /* The reply message includes a rapid commit option. */ -#define NX_DHCPV6_INCLUDE_USER_CLASS_OPTION 0x00020000 /* The reply message includes a user class option. */ -#define NX_DHCPV6_INCLUDE_VENDOR_CLASS_OPTION 0x00040000 /* The reply message includes a vendor class option. */ -#define NX_DHCPV6_INCLUDE_VENDOR_SPEC_INFO_OPTION 0x00080000 /* The reply message includes a vendor specifc information option. */ -#define NX_DHCPV6_INCLUDE_INTERFACE_ID_OPTION 0x00100000 /* The reply message includes a interface Id option. */ -#define NX_DHCPV6_INCLUDE_RECONF_MESSAGE_OPTION 0x00200000 /* The reply message includes a reconfigure message option. */ -#define NX_DHCPV6_INCLUDE_RECONF_ACCEPT_OPTION 0x00400000 /* The reply message includes a reconfigure accept option. */ -#define NX_DHCPV6_INCLUDE_DNS_SERVER_OPTION 0x00800000 /* The reply message includes a dns server option. */ -#define NX_DHCPV6_INCLUDE_DOMAIN_NAME_OPTION 0x01000000 /* The reply message includes a domain name option. */ -#define NX_DHCPV6_INCLUDE_SNTP_SERVER_OPTION 0x02000000 /* The reply message includes a network time protocol servers option. */ -#define NX_DHCPV6_INCLUDE_NEW_POSIX_TIIMEZONE_OPTION 0x04000000 /* The reply message includes a new timezone POSIX string index option. */ -#define NX_DHCPV6_INCLUDE_CLIENT_FQDN_OPTION 0x08000000 /* The reply message includes a client FQDN option. */ - - -/* Define internal DHCPv6 option flags. */ - -#define NX_DHCPV6_DNS_SERVER_OPTION 0x00000001UL /* Option code for requesting DNS server IP address */ -#define NX_DHCPV6_DOMAIN_NAME_OPTION 0x00000002UL /* Option code for requesting domain name. */ -#define NX_DHCPV6_SNTP_SERVER_OPTION 0x00000004UL /* Option code for requesting time server IP address. */ -#define NX_DHCPV6_NEW_POSIX_TIMEZONE_OPTION 0x00000008UL /* Option code for requesting Time zone. */ -#define NX_DHCPV6_CLIENT_FQDN_OPTION 0x00000010UL /* Option code for requesting FQDN. */ - - -/* RFC defined DHCPv6 server status codes */ - -#define NX_DHCPV6_SUCCESS 0 /* Server indicates Client DHCPv6 request is granted. */ -#define NX_DHCPV6_UNSPECIFIED_FAILURE 1 /* Unspecified reason e.g. not found in RFC 3315 */ -#define NX_DHCPV6_NO_ADDRESS_AVAILABLE 2 /* Server unable to assign IP address because none are available. */ -#define NX_DHCPV6_NO_BINDING 3 /* Client record (binding) unavailable */ -#define NX_DHCPV6_NOT_ON_LINK 4 /* Client's IPv6 address is not on the Server link */ -#define NX_DHCPV6_USE_MULTICAST 5 /* Server indicates Client must use multicast ALL_SERVERS address to get IP address */ - -/* Internal DHCPv6 Client status codes */ - -#define NX_DHCPV6_STATE_INIT 1 /* Client state with no bound IP address */ -#define NX_DHCPV6_STATE_SENDING_SOLICIT 2 /* Client sends Sollicit to identify a DHCP server */ -#define NX_DHCPV6_STATE_SENDING_REQUEST 3 /* Address requested, Client initiating a request after receiving server advertisement */ -#define NX_DHCPV6_STATE_SENDING_RENEW 4 /* Address established, Client is initiating a renew request */ -#define NX_DHCPV6_STATE_SENDING_REBIND 5 /* Address established, Client is initiating a rebind request */ -#define NX_DHCPV6_STATE_SENDING_DECLINE 6 /* Address was established but Client can't use it e.g. duplicate address check failed. */ -#define NX_DHCPV6_STATE_SENDING_CONFIRM 7 /* Client IP Address is established but Client requires confirmation its still ok */ -#define NX_DHCPV6_STATE_SENDING_INFORM_REQUEST 8 /* Client IP Address is established but Client requests information other than IP address */ -#define NX_DHCPV6_STATE_SENDING_RELEASE 9 /* Requesting an IP address release of a recently assigned IP address. */ -#define NX_DHCPV6_STATE_BOUND_TO_ADDRESS 15 /* Client is bound to an assigned address; DHCP Client task is basically idle. */ - -/* Internal DHCPv6 Client address status codes. */ - -#define NX_DHCPV6_IA_ADDRESS_STATE_INVALID 0 /* The IA does not inlcude IPv6 address. */ -#define NX_DHCPV6_IA_ADDRESS_STATE_INITIAL 1 /* The IA inlcude one IPv6 address,but the DHCPv6 interactive is not complete. */ -#define NX_DHCPV6_IA_ADDRESS_STATE_DAD_TENTATIVE 2 /* After DHCPv6 interactive, NetX pefrome the DAD to check this IPv6 address. */ -#define NX_DHCPV6_IA_ADDRESS_STATE_DAD_FAILURE 3 /* DAD process failure,the DHCPv6 Client should send DECLINE message.*/ -#define NX_DHCPV6_IA_ADDRESS_STATE_VALID 4 /* The global IP address is valid and set it to the IP instance. */ - -/* Internal DHCPv6 event flags. These events are processed by the Client DHCPv6 thread. */ - -#define NX_DHCPV6_ALL_EVENTS 0xFFFFFFFFUL /* All Client DHCPv6 event flags */ -#define NX_DHCPV6_DAD_FAILURE_EVENT 0x00000001UL /* The DHCPv6 Client perform DAD failure. */ -#define NX_DHCPV6_DAD_SUCCESSFUL_EVENT 0x00000002UL /* The DHCPv6 Client perform DAD failure. */ - -/* The behavior of a DHCPv6 client that implements the Client FQDN option. RFC4704, Section5, Page7. */ - -#define NX_DHCPV6_CLIENT_DESIRES_UPDATE_AAAA_RR 0 /* DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client. */ -#define NX_DHCPV6_CLIENT_DESIRES_SERVER_DO_DNS_UPDATE 1 /* DHCPv6 Client choose to updating the FQDN-to-IPv6 address mapping for FQDN and address(es) used by the client to the server. */ -#define NX_DHCPV6_CLIENT_DESIRES_NO_SERVER_DNS_UPDATE 2 /* DHCPv6 Client choose to request that the server perform no DNS updatest on its behalf. */ - - -/* RFC mandated DHCPv6 client and server ports. */ - -#define NX_DHCPV6_SERVER_UDP_PORT 547 -#define NX_DHCPV6_CLIENT_UDP_PORT 546 - - -/* The solicit mode. */ - -#define NX_DHCPV6_SOLICIT_NORMAL 1 -#define NX_DHCPV6_SOLICIT_RAPID 2 - - -/* Define name compression masks. */ - -#define NX_DHCPV6_LABEL_MAX 63 /* Maximum Label (between to dots) size. */ -#define NX_DHCPV6_COMPRESS_MASK 0xc0 -#define NX_DHCPV6_COMPRESS_VALUE 0xc0 -#define NX_DHCPV6_POINTER_MASK 0xc000 - - -/* Internal error codes for DHCPv6 Client services. */ - -#define NX_DHCPV6_TASK_SUSPENDED 0xE90 /* DHCPv6 task suspended by host application. */ -#define NX_DHCPV6_ALREADY_STARTED 0xE91 /* DHCPv6 already started when API called to start it. */ -#define NX_DHCPV6_NOT_STARTED 0xE92 /* DHCPv6 was not started when API was called */ -#define NX_DHCPV6_PARAM_ERROR 0xE93 /* Invalid non pointer input to API */ -#define NX_DHCPV6_NOT_BOUND 0xE94 /* DHCPv6 was not bound when API was called. */ - -#define NX_DHCPV6_INVALID_CLIENT_DUID 0xE95 /* Client DUID received from Server with invalid data or mismatches Client server DUID on record. */ -#define NX_DHCPV6_INVALID_SERVER_DUID 0xE96 /* Server DUID received by Client has bad syntax or missing data*/ -#define NX_DHCPV6_MESSAGE_MISSING_DUID 0xE97 /* Client receives a message type missing server or client DUID. */ -#define NX_DHCPV6_UNSUPPORTED_DUID_TYPE 0xE98 /* Client configuration involves a DUID type not supported by this API. */ -#define NX_DHCPV6_UNSUPPORTED_DUID_HW_TYPE 0xE99 /* Client configuration involves a network hardware type not supported by this API. */ -#define NX_DHCPV6_NO_DUID_OPTION 0xE9A /* The reply message does not include server or client identifier option. */ -#define NX_DHCPV6_NO_RAPID_COMMIT_OPTION 0xE9B /* The reply message does not iclude rapid commit option. */ -#define NX_DHCPV6_EQUAL_OR_LESS_PREF_VALUE 0xE9C /* The current preference value is equal to or less than the recorded preference valude. */ - -#define NX_DHCPV6_INVALID_IANA_TIME 0xEA0 /* Server IA-NA option T1 vs T2 address lease time is invalid. */ -#define NX_DHCPV6_MISSING_IANA_OPTION 0xEA1 /* Client received IA address option not belonging to an IA block */ -#define NX_DHCPV6_BAD_IANA_ID 0xEA2 /* Server IA-NA option does not contain the Client's original IA-NA ID. */ -#define NX_DHCPV6_INVALID_IANA_DATA 0xEA3 /* Server IA-NA option block has bad syntax or missing data */ -#define NX_DHCPV6_INVALID_IA_ADDRESS 0xEA4 /* Client inquiring about an unknown IA address */ -#define NX_DHCPV6_INVALID_IA_DATA 0xEA5 /* Server IA address option block has bad syntax or missing data */ -#define NX_DHCPV6_INVALID_IA_TIME 0xEA6 /* Server IA option preferred vs valid lease time is invalid. */ -#define NX_DHCPV6_INVALID_PREF_DATA 0xEA7 /* Client received Preference block with missing data or bad syntax */ -#define NX_DHCPV6_INCOMPLETE_OPTION_BLOCK 0xEA8 /* Empty option block data; either zero length or zero option parsed. */ -#define NX_DHCPV6_MISSING_REQUIRED_OPTIONS 0xEA9 /* Cannot start the DHCPv6 Client because required options are missing e.g. IANA, DUID etc */ -#define NX_DHCPV6_INVALID_OPTION_DATA 0xEAA /* Client received option data with missing data or bad syntax */ -#define NX_DHCPV6_UNKNOWN_OPTION 0xEAB /* Client received an unknown or unsupported option from server */ -#define NX_DHCPV6_INVALID_SERVER_PACKET 0xEAC /* Server reply invalid e.g. bad port, invalid DHCP header or invalid reply message. */ -#define NX_DHCPV6_IA_ADDRESS_NOT_VALID 0xEAD /* Client not assigned an IP address from the DHCPv6 Server */ -#define NX_DHCPV6_REACHED_MAX_IA_ADDRESS 0xEAE /* IA address exceeds the maximum IAs specified by NX_DHCPV6_MAX_IA_ADDRESS. */ -#define NX_DHCPV6_IA_ADDRESS_ALREADY_EXIST 0xEAF /* The IA address already added to the Client. */ - -#define NX_DHCPV6_UNKNOWN_PROCESS_STATE 0xEB0 /* Internal DHCPv6 state machine in an unknown state */ -#define NX_DHCPV6_ILLEGAL_MESSAGE_TYPE 0xEB1 /* Client receives a message type intended for a DHCPv6 server e.g. REQUEST or CONFIRM */ -#define NX_DHCPV6_UNKNOWN_MSG_TYPE 0xEB2 /* NetX DHCPv6 receives an unknown message type */ -#define NX_DHCPV6_BAD_TRANSACTION_ID 0xEB3 /* Client received message with bad transaction ID */ -#define NX_DHCPV6_BAD_IPADDRESS_ERROR 0xEB4 /* Unable to parse a valid IPv6 address from specified data buffer */ -#define NX_DHCPV6_PROCESSING_ERROR 0xEB5 /* Server packet size received out of synch with NetX packet length - no assignment of blame */ -#define NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD 0xEB6 /* Client DHCPv6 message will not fit in Client packet pool packet buffer. */ -#define NX_DHCPV6_INVALID_DATA_SIZE 0xEB7 /* Attempting to parse too large a data object to/from DHCPv6 request. */ -#define NX_DHCPV6_ADDRESS_MISMATCH 0xEB8 /* Client IPv6 address index into the IP table is incorrect (addresses do not match). */ - -#define NX_DHCPV6_REACHED_MAX_RETRANSMISSION_COUNT 0xEC0 /* No response from server after maximum number of retries. */ -#define NX_DHCPV6_REACHED_MAX_RETRANSMISSION_TIMEOUT 0xEC1 /* No response from server after maximum retry timeout. */ - - -/* Define DHCPv6 timeout for checking DHCPv6 flag status. */ -#define NX_DHCPV6_TIME_INTERVAL (NX_IP_PERIODIC_RATE) - - -/* Define the conversion between timer ticks and seconds (processor dependent). */ -#define NX_DHCPV6_TICKS_PER_SECOND (NX_IP_PERIODIC_RATE) - - -/* Define the max name size. RFC1035, Section 3.1. */ -#define NX_DHCPV6_MAX_NAME_SIZE 255 - - -/* Define the DHCP stack priority. */ - -#ifndef NX_DHCPV6_THREAD_PRIORITY -#define NX_DHCPV6_THREAD_PRIORITY 2 -#endif - - -/* Define the time out option to obtain a DHCPv6 Client mutex lock. If the - the Client appears to be locking up, this can be set to a finite value - for debugging as well as restore responsiveness to the Client */ - -#ifndef NX_DHCPV6_MUTEX_WAIT -#define NX_DHCPV6_MUTEX_WAIT TX_WAIT_FOREVER -#endif - - -/* Define DHCPv6 Client record parameters */ - -/* Define the timer interval for the IP lifetime timer in seconds. */ - -#ifndef NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL -#define NX_DHCPV6_IP_LIFETIME_TIMER_INTERVAL 1 -#endif - - -/* Define the timer interval for the session duration timer in seconds. */ - -#ifndef NX_DHCPV6_SESSION_TIMER_INTERVAL -#define NX_DHCPV6_SESSION_TIMER_INTERVAL 1 -#endif - - -/* Define the number of DNS name servers the Client will store. */ - -#ifndef NX_DHCPV6_NUM_DNS_SERVERS -#define NX_DHCPV6_NUM_DNS_SERVERS 2 -#endif - - -/* Define the number of time servers the Client will store. */ - -#ifndef NX_DHCPV6_NUM_TIME_SERVERS -#define NX_DHCPV6_NUM_TIME_SERVERS 1 -#endif - - -/* Define the buffer size for storing the DHCPv6 Client domain name. */ - -#ifndef NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE -#define NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE 32 -#endif - - -/* Define the buffer size for storing the DHCPv6 Client time zone e.g. CET, PST etc. */ - -#ifndef NX_DHCPV6_TIME_ZONE_BUFFER_SIZE -#define NX_DHCPV6_TIME_ZONE_BUFFER_SIZE 16 -#endif - -/* Define the amount of packet payload to store DHCPv6 server messages. */ - -#ifndef NX_DHCPV6_MAX_MESSAGE_SIZE -#define NX_DHCPV6_MAX_MESSAGE_SIZE 100 -#endif - -/* Define the amount of IA addresses to store IPv6 addresses. */ - -#ifndef NX_DHCPV6_MAX_IA_ADDRESS -#define NX_DHCPV6_MAX_IA_ADDRESS 1 -#endif - - -/* DHCPv6 Client Network Configuration */ - -/* Define the generic time out option for NetX operations (packet allocate, packet send. */ - -#ifndef NX_DHCPV6_PACKET_TIME_OUT -#define NX_DHCPV6_PACKET_TIME_OUT (3 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - - -/* Define UDP socket type of service. */ - -#ifndef NX_DHCPV6_TYPE_OF_SERVICE -#define NX_DHCPV6_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - - -/* Define the number of routers a UDP packet passes before it is discarded. */ - -#ifndef NX_DHCPV6_TIME_TO_LIVE -#define NX_DHCPV6_TIME_TO_LIVE 0x80 -#endif - -/* Define the stored packets in the UDP socket queue. */ - -#ifndef NX_DHCPV6_QUEUE_DEPTH -#define NX_DHCPV6_QUEUE_DEPTH 5 -#endif - - -/* Define the initial retransmission timeout in timer ticks for DHCPv6 messages. - For no limit on the retransmission timeout set to 0, for no limit - on the retries, set to 0. - - Note that regardless of length of timeout or number of retries, when the IP address - valid lifetime expires, the Client can no longer use its global IP address - assigned by the DHCPv6 Server. */ - -#ifndef NX_DHCPV6_FIRST_SOL_MAX_DELAY -#define NX_DHCPV6_FIRST_SOL_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_SOL_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_TIMEOUT (120 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_COUNT 0 -#endif - -#ifndef NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_SOL_RETRANSMISSION_DURATION 0 -#endif - -#ifndef NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_REQ_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_TIMEOUT (30 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_COUNT 10 -#endif - - -#ifndef NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_REQ_RETRANSMISSION_DURATION 0 -#endif - -#ifndef NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_RENEW_TRANSMISSION_TIMEOUT (10 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_RENEW_RETRANSMISSION_TIMEOUT (600 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_RENEW_RETRANSMISSION_COUNT 0 -#endif - -#ifndef NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_REBIND_TRANSMISSION_TIMEOUT (10 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_REBIND_RETRANSMISSION_TIMEOUT (600 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_REBIND_RETRANSMISSION_COUNT 0 -#endif - -#ifndef NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_RELEASE_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_TIMEOUT 0 -#endif - -#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_COUNT 5 -#endif - -#ifndef NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_RELEASE_RETRANSMISSION_DURATION 0 -#endif - -#ifndef NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_DECLINE_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_TIMEOUT 0 -#endif - -#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_COUNT 5 -#endif - -#ifndef NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_DECLINE_RETRANSMISSION_DURATION 0 -#endif - -#ifndef NX_DHCPV6_FIRST_CONFIRM_MAX_DELAY -#define NX_DHCPV6_FIRST_CONFIRM_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_CONFIRM_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_TIMEOUT (4 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_COUNT 0 -#endif - -#ifndef NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_CONFIRM_RETRANSMISSION_DURATION 10 -#endif - -#ifndef NX_DHCPV6_FIRST_INFORM_MAX_DELAY -#define NX_DHCPV6_FIRST_INFORM_MAX_DELAY (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT -#define NX_DHCPV6_INIT_INFORM_TRANSMISSION_TIMEOUT (1 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT -#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_TIMEOUT (120 * NX_DHCPV6_TICKS_PER_SECOND) -#endif - -#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT -#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_COUNT 0 -#endif - -#ifndef NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION -#define NX_DHCPV6_MAX_INFORM_RETRANSMISSION_DURATION 0 -#endif - - -/* Define the Identity Association Internet Address option structure */ -typedef struct NX_DHCPV6_IA_ADDRESS_STRUCT -{ - - USHORT nx_op_code; /* IA internet address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ - NXD_ADDRESS nx_global_address; /* Assigned Host IPv6 address */ - ULONG nx_preferred_lifetime; /* Server's preference for IPv6 address T1 life time for itself */ - ULONG nx_valid_lifetime; /* Server's assigned valid time for T2 for any server */ - UINT nx_address_status; /* Indicates if the global address is registered and validated. */ - UINT nx_address_map; /* Map the IPv6 address with client, indicates if the IPv6 address already exists or not. */ - -} NX_DHCPV6_IA_ADDRESS; - -/* Define the Option status structure */ -typedef struct NX_DHCPV6_OP_STATUS_STRUCT -{ - - USHORT nx_op_code; /* IA address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ -} NX_DHCPV6_OP_STATUS; - - -/* Define the Preference Option structure */ -typedef struct NX_DHCPV6_PREFERENCE_STRUCT -{ - - USHORT nx_op_code; /* IA address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ - USHORT nx_pref_value; /* Assigned Host IPv6 address */ - -} NX_DHCPV6_PREFERENCE; - - -/* Define the Identity Association for Permanent ("Non Temporary" in RFC) address */ - -typedef struct NX_DHCPV6_IA_NA_STRUCT -{ - - USHORT nx_op_code; /* IA NA address option code is 3 */ - USHORT nx_option_length; /* 12 + length of variable length fields in IA_NA option . */ - ULONG nx_IA_NA_id; /* IANA identifier; must be unique among all client IANA's. Must be the same on restart per IANA */ - ULONG nx_T1; /* Time client can extend time before address lifetime expires from the server it got it from; applies to all addresses in IA_NA. */ - ULONG nx_T2; /* Same as T1 except this is when the client will request REBIND from another server. */ - -} NX_DHCPV6_IA_NA; - - -/* Define DHCPv6 Unique Identifier (DUID); both Client and Server must send messages with their own DUID. */ - -typedef struct NX_DHCPV6_DUID_STRUCT -{ - - USHORT nx_op_code; /* Client DUID option code is 1; Server DUID code is 2 */ - USHORT nx_option_length; /* Option length = 14 not including length and op code field; */ - USHORT nx_duid_type; /* 3 main types: hw; hw + time; vendor assigned ID (not supported here); requires DUID be stored in non volatile storage */ - USHORT nx_hardware_type; /* Only if LL/LLT type. Hardware type specified by IANA/RFC 826 e.g. IEEE 802; network byte order */ - ULONG nx_duid_time; /* Only if LLT type. Time based on when DUID generated; network byte order. */ - ULONG nx_link_layer_address_msw; /* Only if LL/LLT type. Pointer to Unique link layer address - most significant word (2/4 bytes)*/ - ULONG nx_link_layer_address_lsw; /* Only if LL/LLT type. Pointer to Unique link layer address - least significant word (4 bytes) */ - -} NX_DHCPV6_DUID; - - -/* Define the elapsed time option structure. This contains the length of the Client Server session. */ - -typedef struct NX_DHCPV6_ELAPSED_TIME_STRUCT -{ - - USHORT nx_op_code; /* Elapsed time option code = 8 not including length and op code field. */ - USHORT nx_op_length; /* Length of time data = 2. */ - USHORT nx_session_time; /* Time of DHCP session e.g. first msg elapsed time is zero. */ - -} NX_DHCPV6_ELAPSED_TIME; - - -/* Define the Message Option structure. Each message from the Client must have a unique message ID. */ - -typedef struct NX_DHCPV6_MESSAGE_HDR_STRUCT -{ - - USHORT nx_message_type; /* Message type (1 byte) */ - USHORT nx_reserved; /* Reserved. */ - ULONG nx_message_xid; /* Message transaction ID (3 bytes)*/ -} NX_DHCPV6_MESSAGE_HDR; - -/* Define the option request structure. This is how the Client requests information other than global IP address. - It can ask for domain name, DNS server, time zone, time server and other options. */ - -typedef struct NX_DHCPV6_OPTIONREQUEST_STRUCT -{ - USHORT nx_op_code; /* Option Request code = 6*/ - USHORT nx_option_length; /* Length in bytes of option data = 2 * number of requests */ - USHORT nx_op_request; /* e.g. DNS server = 23, ... */ - -} NX_DHCPV6_OPTIONREQUEST; - -/* Define the DHCPv6 Client FQDN Option structure, */ - -typedef struct NX_DHCPV6_CLIENT_FQDN_STRUCT -{ - USHORT nx_op_code; /* Option Client FQDN code = 39*/ - USHORT nx_op_length; /* 1 + length of domain name. */ - UCHAR nx_flags; /* Flag bits used between client and server to negotiate who performs which updates. */ - UCHAR nx_reserved[3]; /* Reserved. */ - CHAR *nx_domain_name; /* The partial or fully qualified domain name. */ - -} NX_DHCPV6_CLIENT_FQDN; - - -/* Define the Client DHCPv6 structure containind the DHCPv6 Client record (DHCPv6 status, server DUID etc). */ - -typedef struct NX_DHCPV6_STRUCT -{ - ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ - CHAR *nx_dhcpv6_name; /* DHCPv6 name supplied at create */ - UINT nx_dhcpv6_client_address_index[NX_DHCPV6_MAX_IA_ADDRESS]; - /* Index in IP address table where the Client assigned address is located. */ - UINT nx_dhcpv6_client_interface_index; /* DHCPv6 outgoing network interface index */ - TX_THREAD nx_dhcpv6_thread; /* Client processing thread */ - TX_EVENT_FLAGS_GROUP nx_dhcpv6_events; /* DHCPv6 Client event flags. */ - TX_MUTEX nx_dhcpv6_client_mutex; /* Mutex for exclusive access to the DHCP Client instance */ - TX_TIMER nx_dhcpv6_IP_lifetime_timer; /* Client IP lifetime timeout timer. */ - TX_TIMER nx_dhcpv6_session_timer; /* Client session duration timer. */ - NX_IP *nx_dhcpv6_ip_ptr; /* The associated IP pointer for this DHCPV6 instance */ - NX_PACKET_POOL *nx_dhcpv6_pool_ptr; /* Pointer to packet pool for sending DHCPV6 messages */ - NX_UDP_SOCKET nx_dhcpv6_socket; /* UDP socket for communicating with DHCPv6 server */ - UCHAR nx_dhcpv6_started; /* DHCPv6 client task has been started */ - UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ - USHORT nx_status_code; /* Status of current option received by Client */ - UINT nx_dhcpv6_sleep_flag; /* If true, the DHCPv6 client is in a position where it can be stopped */ - NX_DHCPV6_MESSAGE_HDR nx_dhcpv6_message_hdr; /* Message Header for all client messages to DHCPv6 Servers */ - NX_DHCPV6_DUID nx_dhcpv6_client_duid; /* Client DUID; ID by which Client and Server identify each other's DUID */ - NX_DHCPV6_DUID nx_dhcpv6_server_duid; /* Server DUID; ID by which Client and Server identify each other's DUID */ - NX_DHCPV6_ELAPSED_TIME nx_dhcpv6_elapsed_time; /* Time duration of the current DHCP msg exchange between Client and Server. */ - NX_DHCPV6_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ - NX_DHCPV6_IA_ADDRESS nx_dhcpv6_ia[NX_DHCPV6_MAX_IA_ADDRESS]; /* Client internet address option */ - NX_DHCPV6_PREFERENCE nx_dhcpv6_preference; /* Server's preference affecting the Client's DHCPv6 server selection. */ - NX_DHCPV6_OPTIONREQUEST nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ - NX_DHCPV6_CLIENT_FQDN nx_dhcpv6_client_FQDN; /* Set of Client options in Solicit, Request, Renew, or Rebind message types. */ - ULONG nx_dhcpv6_IP_lifetime_time_accrued; /* Time since Client set received or renewed its IP address with the DHCPv6 server. */ - UCHAR nx_status_message[NX_DHCPV6_MAX_MESSAGE_SIZE]; /* Server's message in its Option status to client. */ - NXD_ADDRESS nx_dhcpv6_server_address; /* DHCPv6 server address. */ - NXD_ADDRESS nx_dhcpv6_DNS_name_server_address[NX_DHCPV6_NUM_DNS_SERVERS]; /* DNS name server IP address */ - NXD_ADDRESS nx_dhcpv6_time_server_address[NX_DHCPV6_NUM_TIME_SERVERS]; /* time server IP address */ - NXD_ADDRESS nx_dhcpv6_client_destination_address; /* The destination address where DHCP message should be sent, by default All_DHCP_Relay_Agents_and_Servers(FF02::1:2). */ - UCHAR nx_dhcpv6_domain_name[NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE]; /* Buffer for holding domain name. */ - UCHAR nx_dhcpv6_time_zone[NX_DHCPV6_TIME_ZONE_BUFFER_SIZE]; /* Buffer for holding time zone. */ - ULONG nx_dhcpv6_solicitations_sent; /* The number of Solicit messages sent */ - ULONG nx_dhcpv6_solicitation_responses; /* The number of solicitations server responded to */ - ULONG nx_dhcpv6_requests_sent; /* The number of Request messages sent */ - ULONG nx_dhcpv6_request_responses; /* The number of requests server responded to */ - ULONG nx_dhcpv6_renews_sent; /* The number of renew messages sent */ - ULONG nx_dhcpv6_renew_responses; /* The number of renews server responded to */ - ULONG nx_dhcpv6_rebinds_sent; /* The number of Rebind messages sent */ - ULONG nx_dhcpv6_rebind_responses; /* The number of Rebind requests Server responded to */ - ULONG nx_dhcpv6_releases_sent; /* The number of Release messages sent */ - ULONG nx_dhcpv6_release_responses; /* The number of Releases server responded to */ - ULONG nx_dhcpv6_confirms_sent; /* The number of confirmations sent */ - ULONG nx_dhcpv6_confirm_responses; /* The number of confirmations server responded to */ - ULONG nx_dhcpv6_declines_sent; /* The number of declines sent */ - ULONG nx_dhcpv6_decline_responses; /* The number of declines server responded to */ - ULONG nx_dhcpv6_inform_req_sent; /* The number of Inform (option requests) sent */ - ULONG nx_dhcpv6_inform_req_responses; /* The number of Inform server responsed to */ - ULONG nx_dhcpv6_transmission_timeout; /* Timeout on Client messages before resending a request to the server. */ - ULONG nx_dhcpv6_retransmission_count; /* The number of request retransmissions to the server. */ - ULONG nx_dhcpv6_init_retransmission_timeout; /* The initial retransmission time. */ - ULONG nx_dhcpv6_max_retransmission_count; /* The maximum retransmission count. */ - ULONG nx_dhcpv6_max_retransmission_timeout; /* The maximum retransmission time. */ - ULONG nx_dhcpv6_max_retransmission_duration; /* The maximum retransmissions duration. */ - UINT nx_dhcpv6_request_solicit_mode; /* The mode of sending the solicit message with rapid commit option. */ - UINT nx_dhcpv6_reply_option_flags; /* The flags indicate options the reply messages included. */ - USHORT nx_dhcpv6_reply_option_current_pref_value; /* The preference value of current advertise message. */ - UCHAR nx_dhcpv6_received_message_type; /* The type of received message */ - UCHAR nx_dhcpv6_reserved; /* Reserved. */ - - /* Define the callback function for DHCP state change notification. If specified - by the application, this function is called whenever a state change occurs for - the DHCP associated with this IP instance. */ - VOID (*nx_dhcpv6_state_change_callback)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT old_state, UINT new_state); - - /* Define the callback function for receiving a non successful status from the Server. The - context of the status/error is defined by the message type is was received in and what - option the status is referring to e.g. IA Address. */ - VOID (*nx_dhcpv6_server_error_handler)(struct NX_DHCPV6_STRUCT *dhcpv6_ptr, UINT op_code, UINT status_code, UINT message_type); - -} NX_DHCPV6; - - - -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -/* Define the DHCPv6 Client record structure for restore the DHCPv6 Client state from non volatile memory/across reboots. */ - -typedef struct NX_DHCPV6_CLIENT_RECORD_STRUCT -{ - UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ - UCHAR nx_dhcpv6_reserved[3]; /* Reserved. */ - UINT nx_dhcpv6_client_interface_index; /* DHCPv6 outgoing network interface index */ - UINT nx_dhcpv6_client_address_index[NX_DHCPV6_MAX_IA_ADDRESS]; - /* Index in IP address table where the Client assigned address is located. */ - ULONG nx_dhcpv6_IP_lifetime_time_accrued; /* Time since Client set received or renewed its IP address with the DHCPv6 server. */ - NX_DHCPV6_DUID nx_dhcpv6_client_duid; /* Client DUID; ID by which Client and Server identify each other's DUID */ - NX_DHCPV6_DUID nx_dhcpv6_server_duid; /* Server DUID; ID by which Client and Server identify each other's DUID */ - NX_DHCPV6_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ - NX_DHCPV6_IA_ADDRESS nx_dhcpv6_ia[NX_DHCPV6_MAX_IA_ADDRESS]; /* Client internet address option */ - NX_DHCPV6_OPTIONREQUEST nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ - NX_DHCPV6_CLIENT_FQDN nx_dhcpv6_client_FQDN; /* Set of Client options in Solicit, Request, Renew, or Rebind message types. */ - NXD_ADDRESS nx_dhcpv6_DNS_name_server_address[NX_DHCPV6_NUM_DNS_SERVERS]; /* DNS name server IP address */ - NXD_ADDRESS nx_dhcpv6_time_server_address[NX_DHCPV6_NUM_TIME_SERVERS]; /* time server IP address */ - UCHAR nx_dhcpv6_domain_name[NX_DHCPV6_DOMAIN_NAME_BUFFER_SIZE]; /* Buffer for holding domain name. */ - UCHAR nx_dhcpv6_time_zone[NX_DHCPV6_TIME_ZONE_BUFFER_SIZE]; /* Buffer for holding time zone. */ -} NX_DHCPV6_CLIENT_RECORD; -#endif - -#ifndef NX_DHCPV6_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map DHCP API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_dhcpv6_client_create _nx_dhcpv6_client_create -#define nx_dhcpv6_client_delete _nx_dhcpv6_client_delete -#define nx_dhcpv6_create_client_duid _nx_dhcpv6_create_client_duid -#define nx_dhcpv6_create_client_iana _nx_dhcpv6_create_client_iana -#define nx_dhcpv6_create_client_ia _nx_dhcpv6_add_client_ia -#define nx_dhcpv6_add_client_ia _nx_dhcpv6_add_client_ia -#define nx_dhcpv6_client_set_interface _nx_dhcpv6_client_set_interface -#define nx_dhcpv6_client_set_destination_address _nx_dhcpv6_client_set_destination_address -#define nx_dhcpv6_set_time_accrued _nx_dhcpv6_set_time_accrued -#define nx_dhcpv6_get_client_duid_time_id _nx_dhcpv6_get_client_duid_time_id -#define nx_dhcpv6_get_IP_address _nx_dhcpv6_get_IP_address -#define nx_dhcpv6_get_lease_time_data _nx_dhcpv6_get_lease_time_data -#define nx_dhcpv6_get_other_option_data _nx_dhcpv6_get_other_option_data -#define nx_dhcpv6_get_DNS_server_address _nx_dhcpv6_get_DNS_server_address -#define nx_dhcpv6_get_time_server_address _nx_dhcpv6_get_time_server_address -#define nx_dhcpv6_get_time_accrued _nx_dhcpv6_get_time_accrued -#define nx_dhcpv6_get_iana_lease_time _nx_dhcpv6_get_iana_lease_time -#define nx_dhcpv6_get_valid_ip_address_count _nx_dhcpv6_get_valid_ip_address_count -#define nx_dhcpv6_get_valid_ip_address_lease_time _nx_dhcpv6_get_valid_ip_address_lease_time -#define nx_dhcpv6_reinitialize _nx_dhcpv6_reinitialize -#define nx_dhcpv6_request_solicit _nx_dhcpv6_request_solicit -#define nx_dhcpv6_request_solicit_rapid _nx_dhcpv6_request_solicit_rapid -#define nx_dhcpv6_request_confirm _nx_dhcpv6_request_confirm -#define nx_dhcpv6_request_release _nx_dhcpv6_request_release -#define nx_dhcpv6_request_inform_request _nx_dhcpv6_request_inform_request -#define nx_dhcpv6_request_option_DNS_server _nx_dhcpv6_request_option_DNS_server -#define nx_dhcpv6_request_option_domain_name _nx_dhcpv6_request_option_domain_name -#define nx_dhcpv6_request_option_time_server _nx_dhcpv6_request_option_time_server -#define nx_dhcpv6_request_option_timezone _nx_dhcpv6_request_option_timezone -#define nx_dhcpv6_request_option_FQDN _nx_dhcpv6_request_option_FQDN -#define nx_dhcpv6_start _nx_dhcpv6_start -#define nx_dhcpv6_stop _nx_dhcpv6_stop -#define nx_dhcpv6_suspend _nx_dhcpv6_suspend -#define nx_dhcpv6_resume _nx_dhcpv6_resume -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -#define nx_dhcpv6_client_get_record _nx_dhcpv6_client_get_record -#define nx_dhcpv6_client_restore_record _nx_dhcpv6_client_restore_record -#endif - -#else - -/* Services with error checking. */ - -#define nx_dhcpv6_client_create _nxe_dhcpv6_client_create -#define nx_dhcpv6_client_delete _nxe_dhcpv6_client_delete -#define nx_dhcpv6_create_client_duid _nxe_dhcpv6_create_client_duid -#define nx_dhcpv6_create_client_iana _nxe_dhcpv6_create_client_iana -#define nx_dhcpv6_create_client_ia _nxe_dhcpv6_add_client_ia -#define nx_dhcpv6_add_client_ia _nxe_dhcpv6_add_client_ia -#define nx_dhcpv6_client_set_interface _nxe_dhcpv6_client_set_interface -#define nx_dhcpv6_client_set_destination_address _nxe_dhcpv6_client_set_destination_address -#define nx_dhcpv6_set_time_accrued _nxe_dhcpv6_set_time_accrued -#define nx_dhcpv6_get_client_duid_time_id _nxe_dhcpv6_get_client_duid_time_id -#define nx_dhcpv6_get_IP_address _nxe_dhcpv6_get_IP_address -#define nx_dhcpv6_get_lease_time_data _nxe_dhcpv6_get_lease_time_data -#define nx_dhcpv6_get_other_option_data _nxe_dhcpv6_get_other_option_data -#define nx_dhcpv6_get_DNS_server_address _nxe_dhcpv6_get_DNS_server_address -#define nx_dhcpv6_get_time_server_address _nxe_dhcpv6_get_time_server_address -#define nx_dhcpv6_get_time_accrued _nxe_dhcpv6_get_time_accrued -#define nx_dhcpv6_get_iana_lease_time _nxe_dhcpv6_get_iana_lease_time -#define nx_dhcpv6_get_valid_ip_address_count _nxe_dhcpv6_get_valid_ip_address_count -#define nx_dhcpv6_get_valid_ip_address_lease_time _nxe_dhcpv6_get_valid_ip_address_lease_time -#define nx_dhcpv6_reinitialize _nxe_dhcpv6_reinitialize -#define nx_dhcpv6_request_solicit _nxe_dhcpv6_request_solicit -#define nx_dhcpv6_request_solicit_rapid _nxe_dhcpv6_request_solicit_rapid -#define nx_dhcpv6_request_confirm _nxe_dhcpv6_request_confirm -#define nx_dhcpv6_request_release _nxe_dhcpv6_request_release -#define nx_dhcpv6_request_inform_request _nxe_dhcpv6_request_inform_request -#define nx_dhcpv6_request_option_DNS_server _nxe_dhcpv6_request_option_DNS_server -#define nx_dhcpv6_request_option_domain_name _nxe_dhcpv6_request_option_domain_name -#define nx_dhcpv6_request_option_time_server _nxe_dhcpv6_request_option_time_server -#define nx_dhcpv6_request_option_timezone _nxe_dhcpv6_request_option_timezone -#define nx_dhcpv6_request_option_FQDN _nxe_dhcpv6_request_option_FQDN -#define nx_dhcpv6_start _nxe_dhcpv6_start -#define nx_dhcpv6_stop _nxe_dhcpv6_stop -#define nx_dhcpv6_suspend _nxe_dhcpv6_suspend -#define nx_dhcpv6_resume _nxe_dhcpv6_resume -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -#define nx_dhcpv6_client_get_record _nxe_dhcpv6_client_get_record -#define nx_dhcpv6_client_restore_record _nxe_dhcpv6_client_restore_record -#endif - -#endif - -/* Define the prototypes accessible to the application software. */ -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 nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); -UINT nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); -UINT nx_dhcpv6_create_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); -UINT nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); -UINT nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); -UINT nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); -UINT nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); -UINT nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); -UINT nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); -UINT nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); -UINT nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); -UINT nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); -UINT nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); -UINT nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); -UINT nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); -UINT nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -UINT nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); -UINT nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); -#endif - - -#else - -/* DHCP source code is being compiled, do not perform any API mapping. */ - -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 _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 _nxe_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_client_delete(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); -UINT _nx_dhcpv6_create_client_duid(NX_DHCPV6 *dhcpv6_ptr, UINT duid_type, UINT hardware_type, ULONG time); -UINT _nxe_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); -UINT _nx_dhcpv6_create_client_iana(NX_DHCPV6 *dhcpv6_ptr, UINT IA_ident, ULONG T1, ULONG T2); -UINT _nxe_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); -UINT _nx_dhcpv6_add_client_ia(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ipv6_address, ULONG preferred_lifetime, ULONG valid_lifetime); -UINT _nxe_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); -UINT _nx_dhcpv6_client_set_interface(NX_DHCPV6 *dhcpv6_ptr, UINT interface_index); -UINT _nxe_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); -UINT _nx_dhcpv6_client_set_destination_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *destination_address); -UINT _nxe_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); -UINT _nx_dhcpv6_set_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG time_accrued); -UINT _nxe_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); -UINT _nx_dhcpv6_get_client_duid_time_id(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_id); -UINT _nxe_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); -UINT _nx_dhcpv6_get_IP_address(NX_DHCPV6 *dhcpv6_ptr, NXD_ADDRESS *ip_address); -UINT _nxe_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT _nx_dhcpv6_get_lease_time_data(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT _nxe_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); -UINT _nx_dhcpv6_get_other_option_data(NX_DHCPV6 *dhcpv6_ptr, UINT option_code, UCHAR *buffer, UINT buffer_length); -UINT _nxe_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT _nx_dhcpv6_get_DNS_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT _nxe_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT _nx_dhcpv6_get_time_server_address(NX_DHCPV6 *dhcpv6_ptr, UINT index, NXD_ADDRESS *server_address); -UINT _nxe_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); -UINT _nx_dhcpv6_get_time_accrued(NX_DHCPV6 *dhcpv6_ptr, ULONG *time_accrued); -UINT _nxe_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); -UINT _nx_dhcpv6_get_iana_lease_time(NX_DHCPV6 *dhcpv6_ptr, ULONG *T1, ULONG *T2); -UINT _nxe_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); -UINT _nx_dhcpv6_get_valid_ip_address_count(NX_DHCPV6 *dhcpv6_ptr, UINT *address_count); -UINT _nxe_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT _nx_dhcpv6_get_valid_ip_address_lease_time(NX_DHCPV6 *dhcpv6_ptr, UINT address_index, NXD_ADDRESS *ip_address, ULONG *preferred_lifetime, ULONG *valid_lifetime); -UINT _nxe_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_reinitialize(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_solicit(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_solicit_rapid(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_confirm(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_release(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_inform_request(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nx_dhcpv6_request_option_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nxe_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nx_dhcpv6_request_option_domain_name(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nxe_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nx_dhcpv6_request_option_time_server(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nxe_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nx_dhcpv6_request_option_timezone(NX_DHCPV6 *dhcpv6_ptr, UINT enable); -UINT _nxe_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); -UINT _nx_dhcpv6_request_option_FQDN(NX_DHCPV6 *dhcpv6_ptr, CHAR *domain_name, UINT op); -UINT _nxe_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_start(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_stop(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_suspend(NX_DHCPV6 *dhcpv6_ptr); -UINT _nxe_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_resume(NX_DHCPV6 *dhcpv6_ptr); -#ifdef NX_DHCPV6_CLIENT_RESTORE_STATE -UINT _nxe_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); -UINT _nx_dhcpv6_client_get_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr); -UINT _nxe_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); -UINT _nx_dhcpv6_client_restore_record(NX_DHCPV6 *dhcpv6_ptr, NX_DHCPV6_CLIENT_RECORD *client_record_ptr, ULONG time_elapsed); -#endif - -#endif - - -/* Define DHCPv6 Client internal functions. */ - -VOID _nx_dhcpv6_thread_entry(ULONG info); -VOID _nx_dhcpv6_process(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request(NX_DHCPV6 *dhcpv6_ptr, UINT dhcpv6_state); -UINT _nx_dhcpv6_request_renew(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_rebind(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_request_decline(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_send_request(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_add_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_elapsed_time(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_option_request(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_ia_address(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index, UINT ia_index); -UINT _nx_dhcpv6_add_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_client_FQDN(NX_DHCPV6 *dhcpv6_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_waiting_on_reply(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_packet_process(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); -UINT _nx_dhcpv6_scan_packet_options(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); -UINT _nx_dhcpv6_preprocess_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); -UINT _nx_dhcpv6_extract_packet_information(NX_DHCPV6 *dhcpv6_ptr, NX_PACKET *packet_ptr); -VOID _nx_dhcpv6_flush_queue_packets(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_process_client_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_DNS_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_domain_name(NX_DHCPV6 *dhcpv6_ptr, UCHAR *packet_start, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_ia(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length, UINT ia_index); -UINT _nx_dhcpv6_process_iana(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_preference(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_server_duid(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_status(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_time_zone(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_time_server(NX_DHCPV6 *dhcpv6_ptr, UCHAR *received_buffer, UINT length); -VOID _nx_dhcpv6_IP_lifetime_timeout_entry(ULONG dhcpv6_ptr_value); -VOID _nx_dhcpv6_session_timeout_entry(ULONG dhcpv6_ptr_value); -UINT _nx_dhcpv6_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length); -UINT _nx_dhcpv6_utility_get_data(UCHAR *buffer, UINT size, ULONG *value); -INT _nx_dhcpv6_utility_time_randomize(void); -UINT _nx_dhcpv6_update_retransmit_info(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_register_IP_address(NX_DHCPV6 *dhcpv6_ptr); -UINT _nx_dhcpv6_remove_assigned_address(NX_DHCPV6 *dhcpv6_ptr, UINT ia_index); -UINT _nx_dhcpv6_name_string_encode(UCHAR *ptr, UCHAR *name); -UINT _nx_dhcpv6_name_string_unencode(UCHAR *data, UINT start, UCHAR *buffer, UINT size); -#if !defined (NX_DISABLE_IPV6_DAD) && defined (NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY) -VOID _nx_dhcpv6_ipv6_address_DAD_notify(NX_IP *ip_ptr, UINT status, UINT interface_index, UINT ipv6_addr_index, ULONG *ipv6_address); -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_DHCPV6_CLIENT_H */ - - diff --git a/protocol_handlers/dhcp/nxd_dhcpv6_server.c b/protocol_handlers/dhcp/nxd_dhcpv6_server.c deleted file mode 100644 index 49fc0be7..00000000 --- a/protocol_handlers/dhcp/nxd_dhcpv6_server.c +++ /dev/null @@ -1,7281 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6 Server) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_DHCPV6_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include -#include "nx_api.h" -#include "nx_system.h" -#include "nx_ip.h" -#include "nx_ipv6.h" -#include "nx_udp.h" -#include "nxd_dhcpv6_server.h" -#include "tx_timer.h" - -#ifdef FEATURE_NX_IPV6 - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX create dhcpv6 */ -/* server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* ip_ptr Pointer to server IP instance */ -/* name_ptr DHCPV6 name pointer */ -/* packet_pool_ptr Pointer to server packet pool */ -/* stack_ptr Pointer to free memory */ -/* stack_size Size of server stack memory */ -/* dhcpv6_address_declined_handler Declined address request handler*/ -/* dhcpv6_option_request_handler Option request handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_create DHCPV6 server create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, - NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, - VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), - VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_server_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 server create service. */ - status = _nx_dhcpv6_server_create(dhcpv6_server_ptr, ip_ptr, name_ptr, packet_pool_ptr, stack_ptr, stack_size, - dhcpv6_address_declined_handler, dhcpv6_option_request_handler); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the DHCPv6 Client instance with a Netx packet */ -/* pool, processing thread, and various flag event queues, timers and */ -/* mutexes necessary for DHCPv6 Client operations. */ -/* */ -/* Note: User is encouraged to call nx_dhcpv6_server_option_request */ -/* _handler_set to set the option request handler. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* ip_ptr Pointer to Server IP instance */ -/* name_ptr DHCPV6 name pointer */ -/* packet_pool_ptr Pointer to Server packet pool */ -/* stack_ptr Pointer to free memory */ -/* stack_size Size of server stack memory */ -/* dhcpv6_address_declined_handler Declined address request handler*/ -/* dhcpv6_option_request_handler Option request handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_create Create ThreadX flag event queue*/ -/* tx_mutex_create Create mutex lock on resource */ -/* nx_packet_pool_delete Delete the DHCPV6 packet pool */ -/* nx_udp_socket_create Create the DHCPV6 UDP socket */ -/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ -/* tx_mutex_create Create DHCPV6 mutex */ -/* tx_mutex_delete Delete DHCPV6 mutex */ -/* tx_thread_create Create DHCPV6 processing thread*/ -/* tx_thread_delete Delete DHCPV6 processing thread*/ -/* tx_timer_create Create DHCPV6 timer */ -/* tx_timer_delete Delete DHCPV6 timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, - NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, - VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), - VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)) -{ - -UINT i, status; -NX_DHCPV6_CLIENT *dhcpv6_client_ptr; - - - /* Initialize the DHCPV6 control block to zero. */ - memset((void *) dhcpv6_server_ptr, 0, sizeof(NX_DHCPV6_SERVER)); - - /* Default the server global index to index 1. If otherwise, the host - application must set the DHCPv6 interface before it can start - the Server (nx_dhcpv6_server_interface_set). */ - dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = 1; - - /* Link the DHCPv6 server with the IP instance. */ - dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr = ip_ptr; - - /* Set the DHCPV6 name. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_name = name_ptr; - - /* Set the server packet pool. */ - dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr = packet_pool_ptr; - - /* Create the IP timer event flag instance. */ - status = tx_event_flags_create(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, "DHCPv6 Server Timer Events Queue"); - - /* Check for error. */ - if (status != TX_SUCCESS) - { - - return status; - } - - /* Create the DHCPV6 mutex for the Server instance. */ - status = tx_mutex_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), "DHCPV6 Server Mutex", TX_NO_INHERIT); - - /* Determine if the mutexes creation was successful. */ - if (status) - { - - /* Delete the flag queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - - /* No, return error status. */ - return status; - } - - /* Create the DHCPV6 processing thread. */ - status = tx_thread_create(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), "NetX DHCPV6 Server", _nx_dhcpv6_server_thread_entry, - (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, stack_ptr, stack_size, - NX_DHCPV6_SERVER_THREAD_PRIORITY, NX_DHCPV6_SERVER_THREAD_PRIORITY, 1, TX_DONT_START); - - NX_THREAD_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread), dhcpv6_server_ptr) - - /* Determine if the thread creation was successful. */ - if (status) - { - - /* Delete the server protection mutex. */ - tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Delete the flag queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - - /* No, return error status. */ - return status; - } - - /* Create the DHCPV6 timer for keeping track of IP lease time expiration. */ - status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), "NetX DHCPV6 Server Lease timer", - _nx_dhcpv6_server_lease_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, - (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND) , - (NX_DHCPV6_IP_LEASE_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), - TX_NO_ACTIVATE); - - NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer), dhcpv6_server_ptr) - - if (status != NX_SUCCESS) - { - - /* Delete the DHCPv6 Server thread. */ - tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Delete the server protection mutex. */ - tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Delete the flag queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - } - - /* Create the DHCPV6 timer for keeping track of the DHCPv6 Client session time. */ - status = tx_timer_create(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), "NetX DHCPV6 Session Duration timer", - _nx_dhcpv6_server_session_timeout_entry, (ULONG)(ALIGN_TYPE)dhcpv6_server_ptr, - (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), - (NX_DHCPV6_SESSION_TIMER_INTERVAL * NX_DHCPV6_SERVER_TICKS_PER_SECOND), - TX_NO_ACTIVATE); - - NX_TIMER_EXTENSION_PTR_SET(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer), dhcpv6_server_ptr) - - if (status != NX_SUCCESS) - { - - /* Delete the server lease timer. */ - tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); - - /* Delete the DHCPv6 Server thread. */ - tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Delete the server protection mutex. */ - tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Delete the flag queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - } - - /* Initialize the DHCPv6 client control blocks */ - for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) - { - - /* Set a local pointer for convenience. */ - dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; - - /* Clear the client record. */ - memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT)); - } - - /* Determine if the timers creation were successful. */ - if (status) - { - - /* Delete the server lease timer. */ - tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); - - /* Delete the server serssion timer. */ - tx_timer_delete( &(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); - - /* Delete the DHCPv6 Server thread. */ - tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Delete the server protection mutex. */ - tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Delete the flag queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - - /* Return error status. */ - return status; - } - - /* Save the DHCPV6 instance pointer in the socket. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr; - - /* Set the DHCPv6 Client ID. */ - dhcpv6_server_ptr -> nx_dhcpv6_id = NX_DHCPV6_SERVER_ID; - - /* Set the server preference for clients using multicast only for all request message types. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_multicast_only = NX_TRUE; - - /* Assign the various handlers (server error messages, state change and expired/deprecated addresses). */ - dhcpv6_server_ptr -> nx_dhcpv6_IP_address_declined_handler = dhcpv6_address_declined_handler; - dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler = dhcpv6_option_request_handler; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_option_request_handler_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX set dhcpv6 server */ -/* option request callback service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* dhcpv6_option_request_handler_extended */ -/* Extended option request handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_option_request_handler_set */ -/* DHCPV6 server create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, - UCHAR *buffer_ptr, UINT *index, UINT available_payload)) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((!dhcpv6_server_ptr) || (!dhcpv6_option_request_handler_extended)) - { - return NX_PTR_ERROR; - } - - /* Call actual DHCPV6 server option request handler set service. */ - status = _nx_dhcpv6_server_option_request_handler_set(dhcpv6_server_ptr, dhcpv6_option_request_handler_extended); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_option_request_handler_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DHCPv6 option request handler. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* dhcpv6_option_request_handler_extended */ -/* Extended option request handler */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, - UCHAR *buffer_ptr, UINT *index, UINT available_payload)) -{ - - - /* Set the extended handler callback. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended = dhcpv6_option_request_handler_extended; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_add_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the copy client data */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store client data */ -/* message_xid Client transaction ID */ -/* client_address IP address leased to client */ -/* client_state Client DHCPv6 state e.g. bound */ -/* IP_lease_time_accrued Time expired on current IP lease */ -/* valid_lifetime When address becomes invalid */ -/* duid_type Type of Client DUID */ -/* duid_hardware DUID hardware (usually ethernet) */ -/* physical_address_msw MSB of client mac address */ -/* physical_address_lsw LSB of client mac address */ -/* duid_time Time for link layer time DUID */ -/* duid_vendor_number Enterprise ID for Vendor DUID */ -/* duid_vendor_private Pointer to private ID for DUID */ -/* duid_private_length Vendor Duid private ID length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* NX_DHCPV6_TABLE_FULL No empty slot for client data */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_add_client_record Actual copy client data service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, - ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, - ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if ((dhcpv6_server_ptr == NX_NULL) || (client_address == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - /* Check for missing transaction ID or DUID type. */ - if ((message_xid == 0) || (duid_type == 0)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for missing time expired on the lease (if client in a bound state). */ - if ((IP_lease_time_accrued == 0) && (client_state == NX_DHCPV6_STATE_BOUND)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for invalid enterprise DUID data if type is enterprise. */ - if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) - { - - if ((duid_private_length == 0) || (duid_vendor_private == NX_NULL)) - { - - return NX_INVALID_PARAMETERS; - } - } - /* Check for invalid LINK LAYER duid data. */ - else if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) || (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY)) - { - - if ((physical_address_msw == 0) && (physical_address_lsw == 0)) - { - return NX_INVALID_PARAMETERS; - } - - if ((duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) && (duid_time == 0)) - { - return NX_INVALID_PARAMETERS; - } - } - - /* Call the actual service and return completion status. */ - status = _nx_dhcpv6_add_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state, - IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw, physical_address_lsw, - duid_time, duid_vendor_number, duid_vendor_private, duid_private_length); - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies the input data into a DHCPv6 Client record and */ -/* stored in the server's Client table. It then uses the Client IP */ -/* address to find the matching record in the server IP lease table to */ -/* cross link the tables. */ -/* */ -/* This is intended to satisfy the DHCPv6 protocol requirement that a */ -/* DHPCv6 Server be able to store and retrieve lease data from */ -/* nonvolatile memory e..g between reboots. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store client data */ -/* message_xid Client transaction ID */ -/* client_address IP address leased to client */ -/* client_state Client DHCPv6 state e.g. bound */ -/* IP_lease_time_accrued Time expired on current IP lease */ -/* valid_lifetime When address becomes invalid */ -/* duid_type Type of Client DUID */ -/* duid_hardware DUID hardware (usually ethernet) */ -/* physical_address_msw MSB of client mac address */ -/* physical_address_lsw LSB of client mac address */ -/* duid_time Time for link layer time DUID */ -/* duid_vendor_number Enterprise ID for Vendor DUID */ -/* duid_vendor_private Pointer to private ID for DUID */ -/* duid_private_length Vendor Duid private ID length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* NX_DHCPV6_TABLE_FULL No empty slot for client data */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copy data to specified memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, - ULONG IP_lease_time_accrued, ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, - ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length) -{ - -UINT i; -UINT found = NX_FALSE; -NX_DHCPV6_CLIENT *dhcpv6_client_ptr; - - - /* Check if a table index was specified. */ - if (table_index != 0xFFFFFFFF) - { - - /* Check if it is a valid index. */ - if (table_index >= NX_DHCPV6_MAX_CLIENTS) - { - - /* No, return a parameter error. */ - return NX_INVALID_PARAMETERS; - } - - /* Check if it is actually empty. */ - if (dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index].nx_dhcpv6_message_xid != 0) - { - - /* Not empty. Indicate we'll have to find an empty slot. */ - table_index = 0xFFFFFFFF; - } - } - - /* Check if we still need to find a slot. */ - if (table_index == 0xFFFFFFFF) - { - - /* We do, so loop through client records to find one. */ - for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) - { - - /* Is this an empty slot? */ - if (dhcpv6_server_ptr -> nx_dhcpv6_clients[i].nx_dhcpv6_message_xid == 0) - { - - /* This is available. */ - table_index = i; - break; - } - } - - /* Do we have a slot? */ - if (i == NX_DHCPV6_MAX_CLIENTS) - { - - /* No, Indicate the table is full. */ - return NX_DHCPV6_TABLE_FULL; - } - } - - /* Create the table entry. */ - - /* Fill in the generic client information. */ - dhcpv6_client_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_clients[table_index]); - dhcpv6_client_ptr -> nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID; - dhcpv6_client_ptr -> nx_dhcpv6_message_xid = message_xid; - dhcpv6_client_ptr -> nx_dhcpv6_state = (UCHAR)client_state; - dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued = IP_lease_time_accrued; - memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_server_duid), &(dhcpv6_server_ptr -> nx_dhcpv6_server_duid), sizeof(NX_DHCPV6_SVR_DUID)); - - /*Fill in the Client DUID information. */ - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code = NX_DHCPV6_OP_DUID_CLIENT; - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type = (USHORT)duid_hardware; - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type = (USHORT)duid_type; - - /* Determine DUID type to fill in the rest of the DUID fields. */ - if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) - { - - /* Validate the DUID private length. */ - if (duid_private_length > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH) - { - return NX_DHCPV6_INVALID_DUID; - } - - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number = duid_vendor_number; - memcpy(&(dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), duid_vendor_private, duid_private_length); - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = (USHORT)(duid_private_length + 6); - } - else - { - - /* Either link layer or link layer plus time. */ - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw = (USHORT)physical_address_msw; - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw = physical_address_lsw; - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 10; - - if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_option_length = 14; - dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_time = duid_time; - } - } - - /* Fill in the necessary IA-NA and IA Address option fields. */ - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = 24; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = valid_lifetime; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; /* Don't care */ - COPY_NXD_ADDRESS(client_address, &(dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address)); - - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_op_code = NX_DHCPV6_OP_OPTION_STATUS; - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_option_length = 2; /* No message */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; - - /* Now access the server lease table to find this client's lease. */ - for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) - { - - /* Compare our client's assigned IP address with this lease table entry. */ - if(CHECK_IPV6_ADDRESSES_SAME(&(client_address -> nxd_ip_address.v6[0]), - &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0]))) - { - - /* They match! Cross link the tables. */ - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; - found = NX_TRUE; - break; - } - } - - if (!found) - { - - /* This client apparently does not have a valid IP lease. Ok to keep in the tables, - but they will need to request an IP address! */ - return NX_DHCPV6_ADDRESS_NOT_FOUND; - } - - return NX_SUCCESS; - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_retrieve_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the retrieve DHCPv6 Client */ -/* record service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store client data */ -/* message_xid Client transaction ID */ -/* client_address IP address leased to client */ -/* client_state Client DHCPv6 state e.g. bound */ -/* IP_lease_time_accrued Time expired on current IP lease */ -/* valid_lifetime When address becomes invalid */ -/* duid_type Type of Client DUID */ -/* duid_hardware DUID hardware (usually ethernet) */ -/* physical_address_msw MSB of client mac address */ -/* physical_address_lsw LSB of client mac address */ -/* duid_time Time for link layer time DUID */ -/* duid_vendor_number Enterprise ID for Vendor DUID */ -/* duid_vendor_private Pointer to private ID for DUID */ -/* duid_private_length Vendor Duid private ID length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_retrieve_client_record Actual retrieve client data */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, - ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, - ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length) -{ - -UINT status; - - - /* Check for invalid parameters. */ - if (table_index >= NX_DHCPV6_MAX_CLIENTS) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for invalid pointer input. */ - if ((dhcpv6_server_ptr == NX_NULL) || (message_xid == NX_NULL) || (client_address == NX_NULL) || (client_state == NX_NULL) || - (IP_lease_time_accrued == NX_NULL) || (valid_lifetime == NX_NULL) || (duid_type == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - - /* Call the actual service. */ - status = _nx_dhcpv6_retrieve_client_record(dhcpv6_server_ptr, table_index, message_xid, client_address, client_state, - IP_lease_time_accrued, valid_lifetime, duid_type, duid_hardware, physical_address_msw, - physical_address_lsw, duid_time, duid_vendor_number, duid_vendor_private, duid_private_length); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_retrieve_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns DHCPv6 Client record data at the specified */ -/* index into the server table to the caller. Note that if a slot in */ -/* the server's client table is empty, evidenced by a zero transaction */ -/* ID, the service returns null data in all parameters with a successful*/ -/* completion status. */ -/* */ -/* This is intended to satisfy the DHCPv6 protocol requirement that a */ -/* DHPCv6 Server be able to store and retrieve IP lease data from */ -/* nonvolatile memory e..g between reboots. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store client data */ -/* message_xid Client transaction ID */ -/* client_address IP address leased to client */ -/* client_state Client DHCPv6 state e.g. bound */ -/* IP_lease_time_accrued Time expired on current IP lease */ -/* valid_lifetime When address becomes invalid */ -/* duid_type Type of Client DUID */ -/* duid_hardware DUID hardware (usually ethernet) */ -/* physical_address_msw MSB of client mac address */ -/* physical_address_lsw LSB of client mac address */ -/* duid_time Time for link layer time DUID */ -/* duid_vendor_number Enterprise ID for Vendor DUID */ -/* duid_vendor_private Pointer to private ID for DUID */ -/* duid_private_length Vendor Duid private ID length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* NX_DHCPV6_INVALID_DUID Malformed DUID retrieved */ -/* */ -/* CALLS */ -/* */ -/* COPY_NXD_ADDRESS Copy IPv6 address to specified */ -/* memory (holding an IPv6 address*/ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, - ULONG *IP_lease_time_accrued, ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, - ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length) -{ - -NX_DHCPV6_CLIENT *client_ptr; -INT length; - - - /* Get a local pointer for convenience. */ - client_ptr = &(dhcpv6_server_ptr ->nx_dhcpv6_clients[table_index]); - - /* Load the generic client data. */ - *message_xid = client_ptr -> nx_dhcpv6_message_xid; - - /* Is this an empty record? */ - if (*message_xid == 0) - { - - /* Yes so return null data. */ - memset(client_address, 0, sizeof(NXD_ADDRESS)); - *client_state = 0; - *IP_lease_time_accrued = 0; - *valid_lifetime = 0; - *duid_type = 0; - if (duid_hardware) - *duid_hardware = 0; - if (physical_address_msw) - *physical_address_msw = 0; - if (physical_address_lsw) - *physical_address_lsw = 0; - if (duid_time) - *duid_time = 0; - if (duid_vendor_number) - *duid_vendor_number = 0; - if (duid_private_length) - *duid_private_length = 0; - - return NX_SUCCESS; - } - - /* Not an empty record. Extract the data! */ - COPY_NXD_ADDRESS(&(client_ptr -> nx_dhcpv6_ia.nx_global_address), client_address); - *client_state = client_ptr -> nx_dhcpv6_state; - *IP_lease_time_accrued = client_ptr -> nx_dhcpv6_IP_lease_time_accrued; - *valid_lifetime = client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime; - *duid_type = client_ptr -> nx_dhcpv6_client_duid.nx_duid_type; - - /* If this is a LINK LAYER Duid type, load the appropriate data. */ - if ((*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY) || (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME)) - { - - /* Check for invalid pointer input for DUID of the link layer type. */ - if ((duid_hardware == NX_NULL) || (physical_address_msw == NX_NULL) || (physical_address_lsw == NX_NULL)) - { - return NX_PTR_ERROR; - } - - *duid_hardware = client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type; - *physical_address_msw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_msw; - *physical_address_lsw = client_ptr -> nx_dhcpv6_client_duid.nx_link_layer_address_lsw; - - if (*duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - if (duid_time == NX_NULL) - { - return NX_PTR_ERROR; - } - - *duid_time = client_ptr -> nx_dhcpv6_client_duid.nx_duid_time; - } - } - else - { - - /* Client DUID type is vendor assigned. */ - - /* Check for valid pointer input for enterprise ID data */ - if ((duid_vendor_number == NX_NULL) || (duid_vendor_private == NX_NULL) || (duid_private_length == NX_NULL)) - { - return NX_PTR_ERROR; - } - - *duid_vendor_number = client_ptr -> nx_dhcpv6_client_duid.nx_duid_enterprise_number; - length = client_ptr -> nx_dhcpv6_client_duid.nx_option_length - 4; - if (length < 0) - { - - return NX_DHCPV6_INVALID_DUID; - } - - memcpy(duid_vendor_private, &(client_ptr -> nx_dhcpv6_client_duid.nx_duid_private_identifier[0]), (UINT)length); - *duid_private_length = (UINT)length; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_add_ip_address_lease PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the copy lease service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store data */ -/* lease_IP_address Lease IP address */ -/* T1 T1 lifetime (when to renew) */ -/* T2 T2 lifetime (when to rebind) */ -/* preferred_lifetime When address becomes deprecated */ -/* valid_lifetime When address becomes invalid */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_DHCPV6_PARAM_ERROR Invalid non pointer input */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ -/* Address not onlink with Server */ -/* DHCPv6 network interface */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_add_ip_address_lease Actual copy lease data service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, - ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - /* Check for invalid non pointer input. */ - if (CHECK_UNSPECIFIED_ADDRESS(&(lease_IP_address -> nxd_ip_address.v6[0]))) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - /* Check for invalid lease time data. */ - if ((T1 == 0) || (T2 == 0) || (valid_lifetime == 0) || (preferred_lifetime == 0)) - { - - return NX_DHCPV6_PARAM_ERROR; - } - - /* Call the actual service and return completion status. */ - status = _nx_dhcpv6_add_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address, - T1, T2, valid_lifetime, preferred_lifetime); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_ip_address_lease PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies lease data into the Server IP lease table. */ -/* The caller can specify which slot with a index value up to the size */ -/* of the lease table, (NX_DHCPV6_MAX_LEASES - 1), or the DHCPv6 server */ -/* will find an empty slot to store the lease data if the table index is*/ -/* set to 'infinity' e.g. 0xFFFFFFFF. */ -/* */ -/* This is intended to satisfy the DHCPv6 protocol requirement that a */ -/* DHPCv6 Server be able to store and retrieve IP lease data from */ -/* nonvolatile memory e..g between reboots. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to store data */ -/* lease_IP_address Lease IP address */ -/* T1 T1 lifetime (when to renew) */ -/* T2 T2 lifetime (when to rebind) */ -/* preferred_lifetime When address becomes deprecated */ -/* valid_lifetime When address becomes invalid */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_DHCPV6_PARAM_ERROR Invalid table index */ -/* NX_DHCPV6_TABLE_FULL No empty entries for lease data */ -/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ -/* Address not onlink with Server */ -/* DHCPv6 network interface */ -/* CALLS */ -/* */ -/* memcpy Copy memory to specified area */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, - ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime) -{ - -UINT i; -NX_DHCPV6_ADDRESS_LEASE *lease_ptr; -UINT ga_address_index; -UINT prefix_length; - - - /* Get the DHCPv6 server address interface index. */ - ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; - - prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; - - /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the - network masked addresses should be equal). */ - - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &lease_IP_address -> nxd_ip_address.v6[0], prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - /* Is there a table index specified? */ - if (table_index == 0xFFFFFFFF) - { - - /* No, so lets search the server table and find an available slot. */ - for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) - { - - /* Get a local pointer for convenience. */ - lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]); - - /* Does this slot have an address already? */ - if (CHECK_UNSPECIFIED_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0]))) - { - - /* This one looks empty. */ - table_index = i; - break; - } - } - - if (table_index == 0xFFFFFFFF) - { - return NX_DHCPV6_TABLE_FULL; - } - } - else - { - /* Check for valid table index. */ - if (table_index >= NX_DHCPV6_MAX_LEASES) - { - - /* No good. Exceeds the size of the table. */ - return NX_DHCPV6_PARAM_ERROR; - } - } - - /* Copy the supplied IP data into the lease entry. */ - lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]); - - COPY_NXD_ADDRESS(lease_IP_address, &(lease_ptr -> nx_dhcpv6_lease_IP_address)); - lease_ptr -> nx_dhcpv6_lease_T1_lifetime = T1; - lease_ptr -> nx_dhcpv6_lease_T2_lifetime = T2; - lease_ptr -> nx_dhcpv6_lease_valid_lifetime = valid_lifetime; - lease_ptr -> nx_dhcpv6_lease_preferred_lifetime =preferred_lifetime; - - dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses++; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_retrieve_ip_address_lease PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the actual retrieve lease */ -/* service. */ -/* */ -/* This is intended to satisfy the DHCPv6 protocol requirement that a */ -/* DHPCv6 Server be able to store and retrieve lease data from */ -/* nonvolatile memory e..g between reboots. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to obtain data */ -/* lease_IP_address Lease IP address */ -/* T1 T1 lifetime (when to renew) */ -/* T2 T2 lifetime (when to rebind) */ -/* preferred_lifetime When address becomes deprecated */ -/* valid_lifetime When address becomes invalid */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_retrieve_ip_address_lease */ -/* Actual retrieve data service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, - ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dhcpv6_server_ptr == NX_NULL) || (lease_IP_address == NX_NULL) || (T1 == NX_NULL) || - (T2 == NX_NULL) || (valid_lifetime == NX_NULL) || (preferred_lifetime == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - status = _nx_dhcpv6_retrieve_ip_address_lease(dhcpv6_server_ptr, table_index, lease_IP_address, - T1, T2, valid_lifetime, preferred_lifetime); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_retrieve_ip_address_lease PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves lease data from the Server IP lease table. */ -/* The caller must specify which slot with a index value up to the size */ -/* of the lease table, (NX_DHCPV6_MAX_LEASES - 1). */ -/* */ -/* This is intended to satisfy the DHCPv6 protocol requirement that a */ -/* DHPCv6 Server be able to store and retrieve lease data from */ -/* nonvolatile memory e..g between reboots. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* table_index Table index to obtain data */ -/* lease_IP_address Lease IP address */ -/* T1 T1 lifetime (when to renew) */ -/* T2 T2 lifetime (when to rebind) */ -/* preferred_lifetime When address becomes deprecated */ -/* valid_lifetime When address becomes invalid */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address copy */ -/* NX_DHCPV6_PARAM_ERROR Invalid table index */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copy memory to specified area */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, - ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime) -{ - -NX_DHCPV6_ADDRESS_LEASE *lease_ptr; - - - /* Check for valid table index. */ - if (table_index >= NX_DHCPV6_MAX_LEASES) - { - - /* No good. Exceeds the size of the table. */ - return NX_DHCPV6_PARAM_ERROR; - } - - /* Get a local pointer for convenience. */ - lease_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[table_index]); - - /* Copy the lease data into the input pointer buffers. */ - COPY_NXD_ADDRESS(&(lease_ptr -> nx_dhcpv6_lease_IP_address), lease_IP_address); - *T1 = lease_ptr -> nx_dhcpv6_lease_T1_lifetime; - *T2 = lease_ptr -> nx_dhcpv6_lease_T2_lifetime; - *valid_lifetime = lease_ptr -> nx_dhcpv6_lease_valid_lifetime; - *preferred_lifetime = lease_ptr -> nx_dhcpv6_lease_preferred_lifetime; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX delete dhcpv6 */ -/* server service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* */ -/* OUTPUT */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_delete Actual DHCPV6 delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 server delete service. */ - status = _nx_dhcpv6_server_delete(dhcpv6_server_ptr); - - /* Return commpletion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DHCPV6 Client instance and releases all of*/ -/* NetX and ThreadX resources. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Release DHCPV6 UDP socket port*/ -/* nx_udp_socket_delete Delete the DHCPV6 UDP socket */ -/* tx_thread_terminate Terminate DHCPV6 thread */ -/* tx_thread_delete Delete DHCPV6 thread */ -/* tx_timer_delete Delete DHCPV6 timers */ -/* tx_mutex_delete Delete DHCPV6 mutexes */ -/* tx_event_flags_delete Delete DHCPV6 flag queue */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - - /* Terminate the DHCPV6 processing thread. */ - tx_thread_terminate(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Delete the DHCPV6 processing thread. */ - tx_thread_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Delete the flag event queue. */ - tx_event_flags_delete(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events); - - /* Delete the timers */ - tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_lease_timer)); - tx_timer_delete(&(dhcpv6_server_ptr->nx_dhcpv6_session_timer)); - - /* Delete the mutexes. */ - tx_mutex_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Release the UDP socket port. */ - nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Clear the dhcpv6 structure ID. */ - dhcpv6_server_ptr -> nx_dhcpv6_id = 0; - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_create_ip_address_range PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create address list */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* start_ipv6_address Start of IP address in list. */ -/* end_ipv6_address End of IP address in list. */ -/* addresses_added Number of addresses added to list*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP list creation */ -/* */ -/* CALLS */ -/* */ -/* nx_dhcpv6_create_ip_address_range Actual list create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, - UINT *addresses_added) -{ - -UINT status; - - - /* Check for invalid input. */ - if ((dhcpv6_server_ptr == NX_NULL) || - (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) || - (addresses_added == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) || - (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0]))) - { - - return(NX_DHCPV6_INVALID_IP_ADDRESS); - } - - /* Check for an invalid address range. */ - if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3]) - { - - return(NX_DHCPV6_INVALID_IP_ADDRESS); - } - - status = _nx_dhcpv6_create_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_added); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_create_ip_address_range PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a list of IPv6 addresses the DHCPv6 server */ -/* may assign to clients, using a start and end address. It returns the*/ -/* number of addresses actually added, which may be limited by the size */ -/* of the server address table. */ -/* */ -/* Note: The NetX Duo DHCPv6 server accomodates up to 256 assignable */ -/* address ranges in the current release. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* start_ipv6_address Start of IP address in list. */ -/* end_ipv6_address End of IP address in list. */ -/* addresses_added Number of addresses added to list*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP list creation */ -/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ -/* Supplied address not reachable */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, - UINT *addresses_added) -{ - -UINT i; -NX_IP *ip_ptr; -UINT prefix_length; -NXD_ADDRESS next_ipv6_address; -UINT ga_address_index; - - - *addresses_added = 0; - - COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address); - - /* Set up a local variable for convenience. */ - ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; - ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; - prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; - - /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the - network masked addresses should be equal). */ - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - /* Set the server ip address based on the specified interface. */ - - /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ - i = 0; - - /* Fit as many IP addresses in the specified range as will fit in the table. */ - while (i < NX_DHCPV6_MAX_LEASES) - { - - NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr; - - /* Set local pointer to the next entry for convenience. */ - ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; - - /* Initialize each entry before adding data. */ - memset(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i], 0, sizeof(NX_DHCPV6_ADDRESS_LEASE)); - - /* Add the IP address into this slot. */ - COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address); - - /* Update the number of addresses added. */ - (*addresses_added)++; - - /* Increase the address low word by one. */ - next_ipv6_address.nxd_ip_address.v6[3]++; - - /* Check if we are overflowing the last word. */ - if (next_ipv6_address.nxd_ip_address.v6[3] == 0xFFFFFFFF) - { - - /* We are. Let's stop here. */ - break; - } - - if (CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0])) - { - break; - } - - i++; - } - - /* Indicate how many addresses were actually added to the server list. */ - dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses = *addresses_added; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_reserve_ip_address_range PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the reserve address list */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* start_ipv6_address Start of IP address to reserve */ -/* end_ipv6_address End of IP address to reserve */ -/* addresses_reserved Number of addresses reserved */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP list creation */ -/* NX_DHCPV6_INVALID_IP_ADDRESS Invalid address supplied */ -/* */ -/* CALLS */ -/* */ -/* nx_dhcpv6_reserve_ip_address_range Actual list create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, - UINT *addresses_reserved) -{ - -UINT status; - - - /* Check for invalid input. */ - if ((dhcpv6_server_ptr == NX_NULL) || - (start_ipv6_address == NX_NULL)|| (end_ipv6_address == NX_NULL) || - (addresses_reserved == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (start_ipv6_address -> nxd_ip_address.v6[3] > end_ipv6_address -> nxd_ip_address.v6[3]) - { - - return(NX_DHCPV6_INVALID_IP_ADDRESS); - } - - if ((CHECK_UNSPECIFIED_ADDRESS(&start_ipv6_address -> nxd_ip_address.v6[0])) || - (CHECK_UNSPECIFIED_ADDRESS(&end_ipv6_address -> nxd_ip_address.v6[0]))) - { - return(NX_DHCPV6_INVALID_IP_ADDRESS); - } - - status = _nx_dhcpv6_reserve_ip_address_range(dhcpv6_server_ptr, start_ipv6_address, end_ipv6_address, addresses_reserved); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_reserve_ip_address_range PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reserves a range of IPv6 addresses not to assign to */ -/* Clients, using a start and end address. It returns the number of */ -/* addresses actually reserved, depending on the size of the server */ -/* address table. To reserve a single address, start and end address */ -/* are the same. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* start_ipv6_address Start of IP address in list. */ -/* end_ipv6_address End of IP address in list. */ -/* addresses_reserved Number of addresses reserved */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful IP address reservation*/ -/* NX_DHCPV6_INVALID_IP_ADDRESS Reserved addresses out of range */ -/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ -/* Supplied address is unreachable */ -/* */ -/* CALLS */ -/* */ -/* CHECK_IP_ADDRESSES_BY_PREFIX Confirm addresses match the */ -/* server domain by matching prefix*/ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, - UINT *addresses_reserved) -{ - -UINT i; -NX_IP *ip_ptr; -UINT prefix_length; -NXD_ADDRESS next_ipv6_address; -NX_DHCPV6_ADDRESS_LEASE *ip_lease_ptr = NX_NULL; -UINT ga_address_index; - - - /* Initialize local and input variables. */ - *addresses_reserved = 0; - - COPY_NXD_ADDRESS(start_ipv6_address, &next_ipv6_address); - - /* Set up a local variable for convenience. */ - ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; - ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; - prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; - - /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the - network masked addresses should be equal). */ - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &start_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &end_ipv6_address -> nxd_ip_address.v6[0], prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - /* Clear out existing entries and start adding IP addresses at the beginning of the list. */ - i = 0; - - /* Match on start-end addresses for which leases to reserve. */ - while (i < NX_DHCPV6_MAX_LEASES) - { - - /* Set local pointer to the entry for convenience. */ - ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; - - /* Add the IP address into this slot. */ - COPY_NXD_ADDRESS(&next_ipv6_address, &ip_lease_ptr -> nx_dhcpv6_lease_IP_address); - - /* Check if we found the starting address. */ - if (CHECK_IPV6_ADDRESSES_SAME(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], &start_ipv6_address -> nxd_ip_address.v6[0])) - { - break; - } - } - - if (i == NX_DHCPV6_MAX_LEASES) - { - - /* No starting address found in the server IP address list. */ - return NX_DHCPV6_INVALID_IP_ADDRESS; - } - - /* Set the lease times of this entry to infinity. */ - ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF; - - /* Update the number of addresses reserved. */ - (*addresses_reserved)++; - - /* Process the next entry. */ - - /* We found the starting address, so start reserving the rest of the address(es). */ - while ((!CHECK_IPV6_ADDRESSES_SAME(&next_ipv6_address.nxd_ip_address.v6[0], &end_ipv6_address -> nxd_ip_address.v6[0])) && - (i < NX_DHCPV6_MAX_LEASES)) - { - - i++; - - /* Set local pointer to the next entry for convenience. */ - ip_lease_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; - - /* Set the lease times of this entry to infinity. */ - ip_lease_ptr -> nx_dhcpv6_lease_T1_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_T2_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_valid_lifetime = NX_DHCPV6_INFINTY_LEASE; - ip_lease_ptr -> nx_dhcpv6_lease_preferred_lifetime = NX_DHCPV6_INFINTY_LEASE; - - /* Set the number of addresses actually reserved. */ - (*addresses_reserved)++; - - /* Return a pointer to the beginning of non reserved addresses.*/ - COPY_NXD_ADDRESS(&ip_lease_ptr -> nx_dhcpv6_lease_IP_address, &next_ipv6_address); - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_create_dns_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function does error checking for the add dns address service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* dns_ipv6_address DNS server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCPV6_PARAM_ERROR Invalid input */ -/* status Actual add dns address status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_create_dns_address */ -/* Add DNS server address service */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (!dhcpv6_server_ptr || !dns_ipv6_address) - { - return NX_PTR_ERROR; - } - - /* Check for invalid parameters and null address. */ - if ((dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID) || - (CHECK_UNSPECIFIED_ADDRESS(&dns_ipv6_address -> nxd_ip_address.v6[0]))) - - { - return NX_DHCPV6_PARAM_ERROR; - } - - status = _nx_dhcpv6_create_dns_address(dhcpv6_server_ptr, dns_ipv6_address); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_create_dns_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function the DNS server address to the DHCPv6 server for when */ -/* clients request the DNS server address. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* dns_ipv6_address DNS server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successfully added dns address */ -/* NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS */ -/* DNS prefix does not match */ -/* DHCPv6 server interface */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address) -{ - -NX_IP *ip_ptr; -UINT prefix_length; -UINT ga_address_index; - - - /* Set up local variables for convenience. */ - ip_ptr = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr; - ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; - prefix_length = ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; - - /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the - network masked addresses should be equal). */ - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &dns_ipv6_address -> nxd_ip_address.v6[0], - prefix_length)) - { - - return NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS; - } - - /* Set the dns server for this interface. */ - COPY_NXD_ADDRESS(dns_ipv6_address, &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_set_server_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the create server DUID */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server instance */ -/* duid_type Type of DUID, e.g. LL or LLT */ -/* hardware_type Network hardware type e.g IEEE 802*/ -/* mac_address_msw Mac address most significant bit */ -/* mac_address_lsw Mac address least significant bit */ -/* time Time data for link layer DUIDs */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_set_server_duid Actual create server duid service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, - ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time) -{ -UINT status; - - - /* Check for invalid pointer input. */ - if (dhcpv6_server_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* For link layer time DUIDs, the time input must be non zero. */ - if (duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - if (time == 0) - { - return NX_PTR_ERROR; - - } - } - - /* Check for invalid non pointer input. */ - if ((duid_type == 0) || (hardware_type == 0) || (mac_address_msw == 0) || (mac_address_lsw == 0)) - { - return NX_INVALID_PARAMETERS; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_set_server_duid(dhcpv6_server_ptr, duid_type, hardware_type, mac_address_msw, mac_address_lsw, time); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_set_server_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the server DUID with the input data. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server instance */ -/* duid_type Type of DUID, e.g. LL or LLT */ -/* hardware_type Network hardware type e.g IEEE 802*/ -/* mac_address_msw Mac address most significant bit */ -/* mac_address_lsw Mac address least significant bit */ -/* time Time data for link layer DUIDs */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_BAD_SERVER_DUID Unknown or invalid DUID type */ -/* NX_DHCPV6_INVALID_VENDOR_DATA Invalid Vendor ID supplied */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* memcpy Copy data to specified location */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, - ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time) -{ - -NX_DHCPV6_SVR_DUID *duid_ptr; - - - duid_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_server_duid; - - /* Initialize the DUID to null. */ - memset(duid_ptr, 0, sizeof(NX_DHCPV6_SVR_DUID)); - - /* Assign the DUID op code. */ - duid_ptr -> nx_op_code = NX_DHCPV6_OP_DUID_SERVER; - - /* Set the DUID type. */ - duid_ptr -> nx_duid_type = (USHORT)duid_type; - - /* Set the DUID data for a non vendor DUID. */ - if (duid_ptr -> nx_duid_type != NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) - { - - /* Server has a valid link local address. Add this to the server DUID fields - if not a vendor assigned DUID type. */ - duid_ptr-> nx_link_layer_address_msw = (USHORT)mac_address_msw; - duid_ptr -> nx_link_layer_address_lsw = mac_address_lsw; - - /* Set the hardware type. */ - duid_ptr -> nx_hardware_type = (USHORT)hardware_type; - } - else - { - /* This is a private vendor DUID with private vendor ID. */ - duid_ptr -> nx_duid_enterprise_number = NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID; - - /* Check that the server vendor ID size. */ - if (sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID) > NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH) - { - return NX_DHCPV6_INVALID_VENDOR_DATA; - } - - memcpy(&duid_ptr -> nx_duid_private_identifier[0], NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID, sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID)); - } - - /* Now set the server DUID length. This will depend on DUID type. */ - if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY) - { - - /* Set the length to include the duid type, hardware type, msw and lsw fields. */ - duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + sizeof(ULONG); - } - else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - /* Set the length to include the duid type, hardware type, time, and msw and lsw fields. */ - duid_ptr -> nx_option_length = 3 * sizeof(USHORT) + 2 * sizeof(ULONG); - - /* Set the DUID time. */ - duid_ptr -> nx_duid_time = time; - - } - else if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) - { - - /* Set the length to include the duid type, hardware type, enterprise number and - variable length private identifier. */ - duid_ptr -> nx_option_length = sizeof(USHORT) + sizeof(ULONG) + sizeof(NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID); - } - else - { - - /* Undefined or unknown DUID type. Return error status. */ - return NX_DHCPV6_BAD_SERVER_DUID; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_prepare_iana_status PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the IANA status option. If the flag input is */ -/* set, the standard server status message is added to the */ -/* message buffer, and the option length updated. If the flag is false,*/ -/* no message is sent with the status option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_status_ptr Pointer to IANA status to add */ -/* flag 0 to clear; 1 to add message */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copy specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_response_to_client Send server response to client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS *dhcpv6_status_ptr, UINT flag) -{ - - - /* Make sure the basic header fields are filled in. No need to check the status code has been set; it is - part of the decision to send a response. */ - dhcpv6_status_ptr -> nx_op_code = NX_DHCPV6_OP_OPTION_STATUS; - dhcpv6_status_ptr -> nx_option_length = sizeof(USHORT); - - /* Check if we are adding or clearing a message. */ - if (flag == NX_FALSE) - { - - /* Clear the message. */ - memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX); - - /*We're done! */ - return NX_SUCCESS; - } - - /* Flag is set so we are adding a message into the packet. */ - - /* Clear the message before adding anything into the message buffer. */ - memset(&dhcpv6_status_ptr -> nx_status_message[0], 0, NX_DHCPV6_STATUS_MESSAGE_MAX); - - /* Fill in message according to status code. */ - switch (dhcpv6_status_ptr -> nx_status_code) - { - - case NX_DHCPV6_STATUS_SUCCESS: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_SUCCESS, sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_SUCCESS)); - - /* We're done! */ - break; - - case NX_DHCPV6_STATUS_UNSPECIFIED: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED, sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED)); - - /* We're done! */ - break; - - case NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE)); - - /* We're done! */ - break; - - case NX_DHCPV6_STATUS_NO_BINDING: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NO_BINDING, sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NO_BINDING)); - - /* We're done! */ - break; - - case NX_DHCPV6_STATUS_NOT_ON_LINK: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK, sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK)); - - /* We're done! */ - break; - - case NX_DHCPV6_STATUS_USE_MULTICAST: - - /* Copy the standard server reply to message buffer. */ - memcpy(&dhcpv6_status_ptr -> nx_status_message[0], NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST, sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST)); - - /* Update the option length. */ - dhcpv6_status_ptr -> nx_option_length = (USHORT)(dhcpv6_status_ptr -> nx_option_length + sizeof(NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST)); - - /* We're done! */ - break; - - - default: - break; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_preference PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a DHCPv6 preference option to the server reply. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 Server instance */ -/* dhcpv6_client_ptr Pointer to DHCPv6 Client instance */ -/* index Location where to write the data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Data too large for packet payload */ -/* */ -/* CALLS */ -/* */ -/* memcpy Copy specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_response_to_client Send server response to client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_preference(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -UINT available_payload; -ULONG message_word; - - - /* Fill in option code and length. */ - dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code = NX_DHCPV6_OP_PREFERENCE; - dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length = 1; - dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value = NX_DHCPV6_PREFERENCE_VALUE; - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - /* Check if the DUID will fit in the packet buffer. */ - if (available_payload < (UINT)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length + 4)) - { - - /* It won't! */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Create the word to write to the buffer. */ - message_word = (ULONG)dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_op_code << 16; - message_word |= dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy first half of the DUID option to packet buffer. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); - - *index += (ULONG)sizeof(ULONG); - - /* Set the preference value. */ - *(buffer_ptr + *index) = (UCHAR)(dhcpv6_client_ptr -> nx_dhcpv6_preference.nx_pref_value); - - (*index)++; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_option_requests PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the 'option request' option to the server reply */ -/* packet based on the options requested from the client, and what */ -/* options the DHCPv6 server is configured to supply. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ -/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ -/* buffer_ptr Pointer to packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Not enough room for the option */ -/* request in the packet payload */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the server */ -/* DHCPv6 response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, - UCHAR *buffer_ptr, UINT *index) -{ - -USHORT i, j; -ULONG message_word; -UINT available_payload; -NXD_ADDRESS *dns_server_address; -NX_DHCPV6_SERVER_OPTIONREQUEST *dhcpv6_option_ptr; - - - dhcpv6_option_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_option_request; - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - /* Process up to the maximum allowed options. */ - for(i = 0; i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS; i++) - { - - /* Check for the end of the list. */ - if (dhcpv6_option_ptr -> nx_op_request[i] == 0) - { - - /* No more options. */ - break; - } - - /* Is this the DNS server option? */ - if (dhcpv6_option_ptr -> nx_op_request[i] == NX_DHCPV6_RFC_DNS_SERVER_OPTION) - { - - /* Create an option containing a single DNS server address. */ - dhcpv6_option_ptr -> nx_option_length = 4 * sizeof(ULONG); - - /* Check if the option request option will fit in the packet buffer. */ - if (available_payload < (UINT)(dhcpv6_option_ptr -> nx_option_length + 4)) - { - - /* It won't. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - message_word = (ULONG)dhcpv6_option_ptr -> nx_op_request[i] << 16; - message_word |= dhcpv6_option_ptr -> nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the option request option header to the packet. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - dns_server_address = &dhcpv6_server_ptr -> nx_dhcpv6_dns_ip_address; - for (j = 0; j < 4; j++) - { - - message_word = dns_server_address -> nxd_ip_address.v6[j]; - - NX_CHANGE_ULONG_ENDIAN(message_word); - - memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); - - *index += (ULONG)sizeof(ULONG); - } - - /* Update the available payload. */ - available_payload = (UINT)(available_payload - (UINT)(dhcpv6_option_ptr -> nx_option_length + 4)); - } - /* Does the DHCPv6 server have an extended option handler? */ - else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended) - { - - /* Yes, so call it. This handler shall fill the buffer with the requested - option data (if available). - - Note: The handler must update the index pointing to the end of data in the buffer - after it inserts the data. This is done for the DNS server option above. */ - (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler_extended)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index, available_payload); - - /* Check if exceed the payload. */ - if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size) - { - - /* Update the available payload. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - } - else - { - return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); - } - } - /* Does the DHCPv6 server have an option handler? */ - else if (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler) - { - - /* Yes, so call it. This handler shall fill the buffer with the requested - option data (if available). - - Note: The handler must update the index pointing to the end of data in the buffer - after it inserts the data. This is done for the DNS server option above. */ - (dhcpv6_server_ptr -> nx_dhcpv6_server_option_request_handler)(dhcpv6_server_ptr, dhcpv6_option_ptr -> nx_op_request[i], buffer_ptr, index); - - /* Check if exceed the payload. */ - if ((NX_IPv6_UDP_PACKET + *index) <= dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size) - { - - /* Update the available payload. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - } - else - { - return (NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); - } - - } - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_interface_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the set interface service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to the DHCPV6 Server */ -/* iface_index Physical interface index for */ -/* DHCP communication */ -/* ga_address_index Global address index on DHCPv6*/ -/* interface */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index */ -/* NX_NO_INTERFACE_ADDRESS Invalid global address index */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_interface_set Actual set interfaces service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (dhcpv6_server_ptr == NX_NULL) - { - - return NX_PTR_ERROR; - } - - /* Check for invalid parameters. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_INVALID_INTERFACE; - } - - if (ga_address_index >= NX_MAX_IPV6_ADDRESSES) - { - return NX_NO_INTERFACE_ADDRESS; - } - - /* Call the actual service. */ - status = _nx_dhcpv6_server_interface_set(dhcpv6_server_ptr, iface_index, ga_address_index); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_interface_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the physical network interface for DHCPv6 */ -/* communications and the address index of the IP instance for the */ -/* primary global address on that interface. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to the DHCPV6 Server */ -/* iface_index Physical interface index for */ -/* DHCP communication */ -/* ga_address_index Global address index on DHCPv6*/ -/* interface */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Indexes successfully set */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index) -{ - - dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index = iface_index; - dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index = ga_address_index; - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_lease_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is scheduled by the ThreadX scheduler on a user */ -/* configurable time interval. It sets a flag for the DHCPv6 server */ -/* thread task to check the lease expiration on its leased IP address. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr_value Pointer to the DHCPV6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Adds a periodic event to the */ -/* ThreadX event queue */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value) -{ - -NX_DHCPV6_SERVER *dhcpv6_server_ptr; - - - /* Setup DHCPv6 Server pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value) - - /* Signal the DHCPv6 Server it is time to do check the lease time remaining on - clients it has leased IP addresses to. */ - tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the resume NetX DHCPv6 */ -/* server task service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_resume Actual DHCPV6 resume function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 stop service. */ - status = _nx_dhcpv6_server_resume(dhcpv6_server_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resumes DHCPV6 processing thread, activates the */ -/* timers, and sets the running status of the DHCPv6 Server back to */ -/* running. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_ALREADY_STARTED DHPCv6 Server already running */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_resume Resumes DHCPV6 thread task */ -/* tx_timer_activate Activates DHCPv6 timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; - - - /* Is the DHCPv6 Client already running? */ - if (dhcpv6_server_ptr -> nx_dhcpv6_server_running) - { - - /* Return a (benign) error status. */ - return NX_DHCPV6_ALREADY_STARTED; - } - - /* Set the DHCPV6 running flag to indicate DHCPV6 is running. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE; - - /* Start the lease timer. */ - status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); - - /* Check for invalid activate status. */ - if (status != TX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Start the session timer. */ - status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); - - /* Check for invalid activate status. */ - if (status != TX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Resume the Server thread as well. */ - status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Check for invalid resume status. */ - if (status != TX_SUCCESS && status != TX_SUSPEND_LIFTED) - { - - /* Return threadx error status. */ - return status; - } - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_session_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is scheduled by the ThreadX scheduler on a user */ -/* configurable time interval. It sets a flag which the DHCPv6 server */ -/* thread task updates all active client session times and checks if */ -/* any have exceeded the session timeout without sending a response */ -/* back to the server. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr_value Pointer to the DHCPV6 server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Adds a periodic event to the */ -/* ThreadX event queue */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value) -{ - -NX_DHCPV6_SERVER *dhcpv6_server_ptr; - - - /* Setup DHCPv6 Server pointer. */ - NX_TIMER_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, dhcpv6_server_ptr_value) - - /* Signal the DHCPv6 server it's time to do more session time keeping! */ - tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the NetX start the dhcpv6 */ -/* client service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_start Actual DHCPV6 start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 start service. */ - status = _nx_dhcpv6_server_start(dhcpv6_server_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the DHCPV6 processing thread and prepares the */ -/* DHCPv6 Server to receive DHCPv6 client requests. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCPV6_ALREADY_STARTED DHCPv6 server already started */ -/* NX_DHCPV6_MISSING_REQUIRED_OPTIONS Server missing required options */ -/* NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES No addresses available to assign*/ -/* */ -/* CALLS */ -/* */ -/* nxd_ipv6_linklocal_address_set Obtain MAC address for DUID */ -/* nx_udp_socket_create Create the Server UDP socket */ -/* nx_udp_socket_bind Bind the Server socket */ -/* nx_udp_socket_unbind Unbind the Server socket */ -/* tx_timer_activate Activate Server lease timer */ -/* tx_timer_deactivate Deactivate Server lease timer */ -/* tx_thread_resume Resume Server thread task */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; -#ifdef NETXDUO_MULTI_HOME -UINT if_index; -#endif - - - /* Determine if the DHCPV6 server has already started. */ - if (dhcpv6_server_ptr -> nx_dhcpv6_server_running) - { - - /* Yes, it has. */ - return(NX_DHCPV6_ALREADY_STARTED); - } - - /* Check if the server has assignable addresses. */ - if (dhcpv6_server_ptr -> nx_dhcpv6_assignable_addresses == 0) - { - return NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES; - } - - /* Check that the global address is valid. */ - if (dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index >= NX_MAX_IPV6_ADDRESSES) - { - return NX_DHCPV6_INVALID_GLOBAL_INDEX; - } - - /* Create the Socket and check the status */ - status = nx_udp_socket_create(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr, - &(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), (CHAR *)"NetX DHCPV6 Server", - NX_DHCPV6_TYPE_OF_SERVICE, NX_DHCPV6_FRAGMENT_OPTION, - NX_DHCPV6_TIME_TO_LIVE, NX_DHCPV6_QUEUE_DEPTH); - - /* Was the socket creation successful? */ - if (status != NX_SUCCESS) - { - - /* No, return error status. */ - return status; - } - - /* Save the DHCP instance pointer in the socket. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_socket.nx_udp_socket_reserved_ptr = (void *) dhcpv6_server_ptr; - - /* Set the DHCPv6 request handler for packets received on the DHCPv6 server socket. */ - status = nx_udp_socket_receive_notify(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), _nx_dhcpv6_server_socket_receive_notify); - - /* Was the socket receive_notify set successful? */ - if (status != NX_SUCCESS) - { - - /* No, return error status. */ - return status; - } - - /* Check if the host application has created or retrieved a previously created server DUID. */ - if (dhcpv6_server_ptr -> nx_dhcpv6_server_duid.nx_duid_type == 0) - { - - /* No valid server DUID detected. Server cannot run yet!*/ - return NX_DHCPV6_NO_SERVER_DUID; - } - - /* Bind the UDP socket to the DHCPV6 Server port. */ - status = nx_udp_socket_bind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), NX_DHCPV6_SERVER_UDP_PORT, TX_WAIT_FOREVER); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - return status; - } - - /* Activate the DHCPv6 timers. */ - status = tx_timer_activate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer); - - /* Determine if the timer activate call was successful. */ - if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR)) - { - - /* No it was not; unbind the DHCPV6 socket. */ - nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Return the error status. */ - return status; - } - - /* Start the session timer. */ - status = tx_timer_activate(&(dhcpv6_server_ptr -> nx_dhcpv6_session_timer)); - - /* Check for invalid activate status. */ - if ((status != TX_SUCCESS) && (status != TX_ACTIVATE_ERROR)) - { - - /* No it was not; unbind the DHCPV6 socket. */ - nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Return error status. */ - return status; - } - - /* Ready to resume the DHCPV6 server thread. */ - status = tx_thread_resume(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Determine if the resume was successful. */ - if (status != NX_SUCCESS) - { - - /* Deactivate the timer. */ - tx_timer_deactivate(&dhcpv6_server_ptr -> nx_dhcpv6_lease_timer); - - /* Unbind the DHCPV6 socket. */ - nx_udp_socket_unbind(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket)); - - return status; - } - - /* Set the DHCPV6 started flag to indicate the DHCPV6 server is now running. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_TRUE; - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_socket_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is notified by NetX Duo when a packet arrives in the */ -/* server socket. It sets a flag which the DHCPv6 server thread */ -/* detect so it will know to process the incoming packet . */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to Server Socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Threads */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - -NX_DHCPV6_SERVER *dhcpv6_server_ptr; - - - /* Get a pointer to the DHCPv6 server. */ - dhcpv6_server_ptr = (NX_DHCPV6_SERVER *) socket_ptr -> nx_udp_socket_reserved_ptr; - - /* Signal the DHCPv6 Server it has a UDP packet on its socket receive queue. */ - tx_event_flags_set(&(dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events), NX_DHCPV6_SERVER_RECEIVE_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dhcpv6_server_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the suspend NetX DHCPv6 */ -/* Server task service. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_suspend Actual DHCPV6 suspend function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if ((dhcpv6_server_ptr == NX_NULL) || (dhcpv6_server_ptr -> nx_dhcpv6_id != NX_DHCPV6_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DHCPV6 stop service. */ - status = _nx_dhcpv6_server_suspend(dhcpv6_server_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends DHCPV6 processing thread, deactivates the */ -/* timers, and sets the running status of the DHCPv6 Server to not */ -/* running. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_NOT_STARTED Task not running; can't be */ -/* suspended */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend DHCPV6 thread task */ -/* tx_timer_deactivate Deactivate timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - - - /* Determine if the DHCPV6 server thread is running. */ - if (!dhcpv6_server_ptr -> nx_dhcpv6_server_running) - { - - /* DHCPV6 has not been started so we cannot 'suspend' it. */ - return(NX_DHCPV6_NOT_STARTED); - } - - /* Clear the DHCPV6 running flag to indicate DHCPV6 is not running. */ - dhcpv6_server_ptr -> nx_dhcpv6_server_running = NX_FALSE; - - /* Stop the timer. */ - tx_timer_deactivate(&(dhcpv6_server_ptr -> nx_dhcpv6_lease_timer)); - - /* Suspend the Server thread as well. */ - tx_thread_suspend(&(dhcpv6_server_ptr -> nx_dhcpv6_server_thread)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the background processing thread for the DHCPV6 */ -/* Client. It waits to be notified by ThreadX event flags when to */ -/* perform certain actions. These include updating the time remaining */ -/* on the Client IP address lease time, and maintaining the duration of*/ -/* the current Client Server session (if Client has made a request). */ -/* It will terminate if a host application handler is called and */ -/* indicates the Client should abort. */ -/* */ -/* INPUT */ -/* */ -/* info Pointer to DHCPV6 Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Receive notice of event flags set */ -/* tx_mutex_get Obtain lock on Client resource */ -/* tx_mutex_put Release lock on Client resource */ -/* nx_dhcpv6_deprecated_IP_address_handler */ -/* Callback function for handling an */ -/* IP address at the end of its */ -/* preferred life time */ -/* nx_dhcpv6_expired_IP_address_handler */ -/* Callback function for handling an */ -/* IP address at the end of its */ -/* valid life time */ -/* _nx_dhcpv6_request_renew Initiate the RENEW request */ -/* _nx_dhcpv6_request_rebind Initiate the REBIND request */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_dhcpv6_server_thread_entry(ULONG info) -{ - -UINT i; -NX_DHCPV6_SERVER *dhcpv6_server_ptr; -NX_DHCPV6_CLIENT *dhcpv6_client_ptr; -ULONG dhcpv6_events; -NXD_ADDRESS client_address; - - - /* Setup the DHCPV6 server pointer. */ - NX_THREAD_EXTENSION_PTR_GET(dhcpv6_server_ptr, NX_DHCPV6_SERVER, info) - - /* Continue processing periodic tasks till this internal flag is cleared. */ - while (1) - { - - - /* Pick up IP event flags. */ - tx_event_flags_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_timer_events, NX_DHCPV6_ALL_EVENTS, - TX_OR_CLEAR, &dhcpv6_events, TX_WAIT_FOREVER); - - if (dhcpv6_events & NX_DHCPV6_SERVER_RECEIVE_EVENT) - { - - /* Listen for new Client DHCP service request e.g. DISCOVERY messages. */ - _nx_dhcpv6_listen_for_messages(dhcpv6_server_ptr); - } - - if (dhcpv6_events & NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT) - { - /* Check the active clients whose sessions that have timed out. */ - for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) - { - - /* Set a local pointer for convenience. */ - dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; - - tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); - - /* Is this client in session with the server? */ - if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time) - { - - /* Update the Client session time. */ - dhcpv6_client_ptr -> nx_dhcpv6_client_session_time += NX_DHCPV6_SESSION_TIMER_INTERVAL; - - if (dhcpv6_client_ptr -> nx_dhcpv6_client_session_time >= NX_DHCPV6_SESSION_TIMEOUT) - { - - /* The session has timed out without a response from the Client. Invalidate - the client entry. */ - - /* First get the assigned address. */ - COPY_IPV6_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], - &client_address.nxd_ip_address.v6[0]); - - /* Clear the client record. */ - _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); - } - } - - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - } - } - - /* Check for a periodic DHCP server task. */ - if (dhcpv6_events & NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT) - { - - /* Check the active clients for the time remaining in their leased IP address. */ - for (i = 0; i < NX_DHCPV6_MAX_CLIENTS; i++) - { - - /* Set a local pointer for convenience. */ - dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; - - tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); - - /* Skip those clients who do not have a lease assigned yet. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued == 0) - { - - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - continue; - } - - /* Update the time accrued on the client's current IP address lease. */ - dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued += NX_DHCPV6_IP_LEASE_TIMER_INTERVAL; - - /* Has this address become obsolete? */ - if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >= dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime) - { - - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - /* Clear the client record. */ - _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); - } - else if (dhcpv6_client_ptr -> nx_dhcpv6_IP_lease_time_accrued >= - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime) - { - - /* Address is deprecated! Client *should* not use it but no action taken by the server yet. */ - } - - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - } - } - - /* Relinquish control before another cycle.*/ - tx_thread_sleep(1); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts data from DHCPv6 Client request packets. A */ -/* request is checked for valid message type and required DHCPv6 data. */ -/* A client record is created if one does not exist for the client and */ -/* the data updated into it. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* dhcpv6_client_ptr Pointer to DHCPv6 client */ -/* packet_ptr Pointer to received packet */ -/* iface_index Interface packet received on */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_ILLEGAL_MESSAGE_TYPE Packet message type illegal */ -/* NX_DHCPV6_BAD_TRANSACTION_ID Message ID fails to match up */ -/* NX_DHCPV6_PROCESSING_ERROR Packet length is different than */ -/* expected */ -/* NX_DHCPV6_UNKNOWN_OPTION Unknown option in message */ -/* NX_DHCPV6_INVALID_HW_ADDRESS Missing or invalid MAC address */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data Extract data from reply packet */ -/* _nx_dhcpv6_server_utility_get_block_option_length */ -/* Extract option header data */ -/* _nx_dhcpv6_process_duid Extract DUID from Client message*/ -/* _nx_dhcpv6_process_DNS_server Extract DNS server from message */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Waits to receive client message*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, - UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address) -{ - -UINT status; -UINT add_on; -UINT record_index; -ULONG op_code; -ULONG option_length; -UCHAR *buffer_ptr; -UINT index; -ULONG returned_xid; -NX_DHCPV6_SVR_DUID client_duid, server_duid; -UINT client_duid_received; -UINT server_duid_received; -NX_DHCPV6_CLIENT temp_client_rec; -ULONG received_message_type; -UINT matching; - - NX_PARAMETER_NOT_USED(iface_index); - - *dhcpv6_client_ptr = NX_NULL; - - /* Create a scratch record for this client so we can qualify it before adding it to the server table. */ - memset(&temp_client_rec, 0, sizeof(NX_DHCPV6_CLIENT)); - - /* Initialize the record with the DHCPv6 Client ID. */ - temp_client_rec.nx_dhcpv6_id = NX_DHCPV6_CLIENT_ID; - - /* Assume the Client is not bound to an IP address yet. */ - temp_client_rec.nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; - - /* Set a pointer to the start of DHCPv6 data. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Initialize local variables. */ - index = 0; - client_duid_received = NX_FALSE; - server_duid_received = NX_FALSE; - - /* Extract the message type which should be the first byte. */ - _nx_dhcpv6_server_utility_get_data(buffer_ptr, 1, &received_message_type); - - /* Check for an illegal message type. */ - if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) || - (received_message_type == NX_DHCPV6_MESSAGE_TYPE_REPLY) || - (received_message_type == NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE) || - (received_message_type > NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) - { - - /* These should only be sent to DHCPv6 clients! The Inform Request is actually - legal to receive but should NOT be used to add clients to the server table. */ - return NX_DHCPV6_ILLEGAL_MESSAGE_TYPE; - } - - /* Copy the source address to the Client record. */ - COPY_IPV6_ADDRESS(&source_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); - temp_client_rec.nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* Copy the destination address to the Client record. */ - COPY_IPV6_ADDRESS(&destination_address.nxd_ip_address.v6[0], &temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); - temp_client_rec.nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* Advance to the data pointer. */ - buffer_ptr++; - - /* Parse the transaction ID. */ - _nx_dhcpv6_server_utility_get_data(buffer_ptr, 3, &returned_xid); - - temp_client_rec.nx_dhcpv6_message_type = received_message_type; - - /* Set the message ID. The server will need this to reply to the Client. */ - temp_client_rec.nx_dhcpv6_message_xid = returned_xid; - - buffer_ptr += 3; - - /* Now parse all the DHCPv6 option blocks in the packet buffer. */ - /* 4 bytes is data pointer offset, and 4 bytes for option code and option length. */ - while (index <= packet_ptr -> nx_packet_length - 4 - 4) - { - - /* Get the option code and length of data of the current option block. */ - status = _nx_dhcpv6_server_utility_get_block_option_length(buffer_ptr, &op_code, &option_length); - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - - /* This is a double check to verify we haven't gone off the end of the packet buffer. */ - if (index > packet_ptr -> nx_packet_length - 4) - { - - /* Reported length of the packet may be incorrect. At any rate, we don't know - exactly what the end of the message is, so abort. */ - return NX_DHCPV6_PROCESSING_ERROR; - } - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Process the option code with an option specific API. */ - switch (op_code) - { - /* Note - these 'process' functions will not move the buffer pointer. */ - - case NX_DHCPV6_OP_DUID_CLIENT: - - client_duid.nx_op_code = (USHORT)op_code; - client_duid.nx_option_length = (USHORT)option_length; - - status = _nx_dhcpv6_process_duid(&client_duid, NX_DHCPV6_CLIENT_DUID_TYPE, buffer_ptr, option_length); - - if (status != NX_SUCCESS) - { - - return status; - } - - /* Copy to the temporary client record. */ - memcpy(&temp_client_rec.nx_dhcpv6_client_duid, &client_duid, sizeof(NX_DHCPV6_SVR_DUID)); - - /* Indicate the message contained the required Client DUID. */ - client_duid_received = NX_TRUE; - - break; - - case NX_DHCPV6_OP_DUID_SERVER: - - server_duid.nx_op_code = (USHORT)op_code; - server_duid.nx_option_length = (USHORT)option_length; - - status = _nx_dhcpv6_process_duid(&server_duid, NX_DHCPV6_SERVER_DUID_TYPE, buffer_ptr, option_length); - - if (status != NX_SUCCESS) - { - - return status; - } - - /* Copy to the temporary client record. */ - memcpy(&temp_client_rec.nx_dhcpv6_server_duid, &server_duid, sizeof(NX_DHCPV6_SVR_DUID)); - - /* Indicate the message contained the required Server DUID. */ - server_duid_received = NX_TRUE; - - break; - - - case NX_DHCPV6_OP_IA_NA: - - status = _nx_dhcpv6_server_process_iana(&temp_client_rec, buffer_ptr, option_length); - - if (status != NX_SUCCESS) - { - return status; - } - - break; - - /* This should not happen. The IA address option must be embedded in the IANA option. */ - case NX_DHCPV6_OP_IA_ADDRESS: - - /* Don't process an IA address option outside of an address association (IANA). */ - status = NX_DHCPV6_IANA_OPTION_MISSING; - - break; - - case NX_DHCPV6_OP_OPTION_REQUEST: - - /* Option request option contains request usually for network configuration parameters - such as the DNS server. */ - status = _nx_dhcpv6_process_option_request(&temp_client_rec, buffer_ptr, option_length); - - if (status != NX_SUCCESS) - { - - return status; - } - - break; - - case NX_DHCPV6_OP_ELAPSED_TIME: - - /* The elapsed time is time elapsed since the client initiated the IP lease request. */ - status = _nx_dhcpv6_process_elapsed_time(&temp_client_rec, buffer_ptr, option_length); - - if (status != NX_SUCCESS) - { - - return status; - } - - break; - - - default: - break; - } - - /* Check for errors from option block processing. */ - if (status != NX_SUCCESS) - { - - - return status; - } - - /* Move to the next top level option. */ - buffer_ptr += option_length + 4; - - } - - /* Check for an improperly formatted packet. */ - if (index != packet_ptr -> nx_packet_length - 4) - { - - /* If we get here if we are not at the expected end of the buffer. Oops */ - return NX_DHCPV6_PROCESSING_ERROR; - } - - /* Check if the message is missing the required DUID(s). */ - if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) - { - - if (!client_duid_received) - { - - return NX_DHCPV6_MESSAGE_DUID_MISSING; - } - } - /* The following message types must include a client and server DUID. */ - else if ((temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE)) - { - - if (!server_duid_received || !client_duid_received) - { - - return NX_DHCPV6_MESSAGE_DUID_MISSING; - } - } - /* An inform request only requires a server DUID. */ - else if (temp_client_rec.nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) - { - - /* The Inform request message should NOT include an IA. */ - if (temp_client_rec.nx_dhcpv6_ia.nx_op_code != 0) - { - return NX_DHCPV6_INVALID_IA_DATA; - } - } - - /* Validate the client message, and determine how (if) the server should respond to it. */ - status = _nx_dhcpv6_validate_client_message(dhcpv6_server_ptr, &temp_client_rec); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Return all other errors as completion status. Do not send a message to the client. */ - return(status); - } - - if (temp_client_rec.nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) - { - - /* Not responding to client. So do not assign an IP address or update - the client record with invalid message. */ - return NX_SUCCESS; - } - - /* Look up the client record in the server table. If not found, or this is - a new request e.g. a SOLICIT message, create a new client entry in the table and - fill in the extracted information. */ - add_on = NX_FALSE; - - if ((received_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (received_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) || - (received_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) - { - - /* Check first if the validation process indicates we do not reply to this message. */ - if (temp_client_rec.nx_dhcpv6_response_back_from_server != NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT) - { - - /* Ok to update or create a new record. */ - add_on = NX_TRUE; - } - } - - /* Check if the client is already in the server table. */ - status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &client_duid, &record_index, - add_on, temp_client_rec.nx_dhcpv6_message_xid, &matching); - - /* Check for error during search. */ - if (status != NX_SUCCESS) - { - - return(status); - } - - /* Set a local pointer to the client record in the server table. */ - *dhcpv6_client_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[record_index]; - - /* Was a match was found? */ - if (!matching) - { - - /* No, this is a new record. Create a new client record. */ - status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr); - } - else - { - - /* A match was found. Check if this is a different message request than the previous client request. */ - if ((temp_client_rec.nx_dhcpv6_message_type != (*dhcpv6_client_ptr) -> nx_dhcpv6_message_type) && - (received_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) - { - - /* This is a different message from the Client. Before updating the record check the client global address - to be the same as what the server assigned or is offering to assign. */ - if (!CHECK_IPV6_ADDRESSES_SAME(&temp_client_rec.nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], - &(*dhcpv6_client_ptr )-> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) - { - - /* This is a different address. Disregard this message. */ - (*dhcpv6_client_ptr) -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return NX_SUCCESS; - } - - /* This is a valid request. Update the client record with the new data. */ - status = _nx_dhcpv6_update_client_record(dhcpv6_server_ptr, &temp_client_rec, *dhcpv6_client_ptr); - } - } - - /* Yes we're done with no processing errors detected. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_validate_client_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function validates the client DHCPv6 request, determines if an */ -/* IP address need to be assigned, what state the DHCPv6 Client */ -/* should be advanced to, and what the server response type should be. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 server */ -/* dhcpv6_client_ptr Pointer to DHCPv6 client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Table searched successfully */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_update_assignable_ip_address Update IP address status in */ -/* the server database */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Listen for, process and respond*/ -/* to DHCPV6 Client messages */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) -{ - -UINT status; -UINT matching_clients; -UINT matching_server_duids; -UINT record_index; -UINT dest_address_type; -UINT ga_address_index; -UINT if_index; -UINT prefix_length; - - - /* Clear the Server response to the Client. We will decide that below. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = 0; - - ga_address_index = dhcpv6_server_ptr -> nx_dhcpv6_server_ga_address_index; - - /* Initialize the response to the client. If the client request is invalid, ignore the request (no response - from server) or indicate the problem in the IANA status option. */ - - /* Initialize the IANA status for the SOLICIT request as successfully granted. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) - { - - /* Respond to a valid Solicit request with an Advertise message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_ADVERTISE; - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; - } - else - { - - /* Respond to a valid Request request with a Reply message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY; - - /* Set the expected IANA status. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) - { - - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_SUCCESS; - } - } - - /* Never accept a packet without a DHCP ID. */ - if (!dhcpv6_client_ptr -> nx_dhcpv6_message_xid) - { - - /* Don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return(NX_SUCCESS); - } - - /* Determine if destination address type (unicast or multicast). */ - dest_address_type = IPv6_Address_Type(&dhcpv6_client_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); - - /* Do validation specific for message type. This section will also - advance the DHCPv6 Client state and set the server response message type. */ - switch (dhcpv6_client_ptr -> nx_dhcpv6_message_type) - { - - case NX_DHCPV6_MESSAGE_TYPE_SOLICIT: - { - - /* Check for missing required fields. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0)) - { - - /* Don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return(NX_SUCCESS); - } - - /* Check for presence of a server DUID. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != 0) - { - - /* Don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return(NX_SUCCESS); - } - - /* The Solicit message should never be unicast. Check if the destination is unicast. */ - if (IPV6_ADDRESS_UNICAST & dest_address_type) - { - - /* Don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return NX_SUCCESS; - } - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_REQUEST: - case NX_DHCPV6_MESSAGE_TYPE_RENEW: - case NX_DHCPV6_MESSAGE_TYPE_REBIND: - case NX_DHCPV6_MESSAGE_TYPE_RELEASE: - case NX_DHCPV6_MESSAGE_TYPE_DECLINE: - { - - /* Check for missing required fields. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_duid_type == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_hardware_type == 0)) - { - - /* Don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return(NX_SUCCESS); - } - - /* Check for an invalid unicast destination address type. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_REBIND) - { - - /* The DHCPv6 server does not support unicast. Check for unicast client destination. */ - if (IPV6_ADDRESS_UNICAST & dest_address_type) - { - - /* It is unicast. Set the use multicast error status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_USE_MULTICAST; - - return NX_SUCCESS; - } - } - - /* This client message is not valid if an matching client record does not exist with the server. */ - status = _nx_dhcpv6_find_client_record_by_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, - &record_index, NX_FALSE, - dhcpv6_client_ptr -> nx_dhcpv6_message_xid, - &matching_clients); - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Check for matching client record. */ - if (!matching_clients) - { - - /* No matching client record found. */ - - /* For Release and Decline messages let the client know using the IANA status code that - the server has no record of the assigned or requested address for this client. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) - { - - /* Set the non-binding error status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; - - /* Set the lifetimes to zero. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - } - else - { - - /* Otherwise don't respond, just discard the message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return(NX_SUCCESS); - } - } - - /* Handle Rebind a little differently. It should not specify a server DUID. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) - { - /* Is there a server DUID in the client message? */ - if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_option_length > 0) - { - - /* Yes; don't respond, just discard the message. . */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - } - - break; - } - else - { - - /* With all other IA addresses the server DUID must match the server DUID. */ - status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid, - &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, &matching_server_duids); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return status; - } - - /* Do the two server DUIDs match? */ - if (!matching_server_duids) - { - - /* No; don't respond, just discard the message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return NX_SUCCESS; - } - } - break; - } - /* The Client wished to confirm its IP address is on link. */ - case NX_DHCPV6_MESSAGE_TYPE_CONFIRM: - { - - /* Check for missing IA option. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length == 0) - { - - /* No IA option, so don't respond, just discard the message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return NX_SUCCESS; - } - - /* Verify the input addresses match the server interface address prefix (in IPv4 terms, the - network masked addresses should be equal). */ - prefix_length = dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address_prefix_length; - - if (!CHECK_IP_ADDRESSES_BY_PREFIX(&(dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ipv6_address[ga_address_index].nxd_ipv6_address[0]), - &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0], - prefix_length)) - { - - - /* Inform the client their IA address is not on link. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_REPLY; - - /* Set the IA-NA error status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NOT_ON_LINK; - - return(NX_SUCCESS); - } - - /* More checks will be done when the client rebind address is searched in the server - address table. For now we are ok. */ - - break; - } - - case NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST: - { - - /* Verify Client's server duid matches the server DUID. Note that if the server DUID type is a - link layer time type (LLT), this comparison should ignore the time field because this is an 'asynchronous' request - from the client, so just match on the LL data. */ - - /* Temporarily set the server DUID type to LL if it was LLT. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) || - (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY)) - { - - /* Now verify the physical address matches what the server has for this client. */ - if_index = dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index; - if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_msw != - dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_msw) - { - - /* Inform the client their physical address is not on record. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - } - else if (dhcpv6_client_ptr -> nx_dhcpv6_server_duid.nx_link_layer_address_lsw != - dhcpv6_server_ptr -> nx_dhcpv6_ip_ptr -> nx_ip_interface[if_index].nx_interface_physical_address_lsw) - { - /* Inform the client their physical address is not on record. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - } - } - else - { - - /* Verify the client inform request was intended for this server. If the Client did not - include a server DUID, which is acceptable in DHCPv6 protocol, it will 'pass' this check. */ - status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_server_duid, - &dhcpv6_client_ptr -> nx_dhcpv6_server_duid, &matching_server_duids); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return status; - } - - /* Do the two server DUIDs match? */ - if (!matching_server_duids) - { - - /* Don't respond, just discard the message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return NX_SUCCESS; - } - } - - /* Check for missing options request. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length == 0) - { - - /* Don't respond, just discard the message. */ - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - return NX_SUCCESS; - } - - break; - } - - default: - { - - dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server = NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT; - - /* Clear the success status. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_UNSPECIFIED; - - return(NX_SUCCESS); - - /* No further processing to do. Leave the client state unchanged, whatever it was/is. */ - } - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_utility_get_block_option_length PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the input buffer (assuming to be an option */ -/* block in a server reply) for option code and length. It assumes the */ -/* buffer pointer is pointed to the first byte of the option buffer. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ Pointer to DHCPv6 Client */ -/* option Option code of requested data */ -/* buffer_ptr Buffer to copy data to */ -/* length Size of buffer */ -/* valid */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_DHCPV6_OPTION_BLOCK_INCOMPLETE Unknown option specified */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data Parses a specific data from the */ -/* DHCPv6 option */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_utility_get_block_option_length */ -/* Parses option code and length */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Parses each option from server */ -/* reply and updates Client record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length) -{ - - /* Initialize to zero. */ - *option = 0; - *length = 0; - - /* First byte should be the op code. */ - _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, option); - - buffer_ptr += 2; - - /* Next byte should be the option length. */ - _nx_dhcpv6_server_utility_get_data(buffer_ptr, 2, length); - - /* Buffer is now pointed at the data (past the length field). */ - buffer_ptr += 2; - - /* Check for null data. */ - if (*option == 0 || *length == 0) - { - - return NX_DHCPV6_OPTION_BLOCK_INCOMPLETE; - } - - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_utility_get_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the input buffer and returns numeric data */ -/* specified by the size argument, up to 4 bytes long. Note that if */ -/* caller is using this utility to extract bytes from a DHCPv6 packet */ -/* there is no need for byte swapping, as compared to using memcpy in */ -/* which case there is for little endian processors. */ -/* */ -/* INPUT */ -/* */ -/* buffer Pointer to data buffer */ -/* value Pointer to data parsed from buffer*/ -/* size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DHCPV6_INVALID_DATA_SIZE Requested data size too large */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* _nx_dhcpv6_process_server_duid Process server duid in server reply*/ -/* _nx_dhcpv6_process_client_duid Process server duid in server reply*/ -/* _nx_dhcpv6_server_utility_get_block_option_length */ -/* Parses option code and length */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Parses each option from server */ -/* reply and updates Client record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_utility_get_data(UCHAR *buffer, UINT size, ULONG *value) -{ - - - /* Check that the size of the data fits in a ULONG. */ - if (size > sizeof(ULONG)) - { - return NX_DHCPV6_INVALID_DATA_SIZE; - } - - *value = 0; - - /* Process the data retrieval request. */ - while (size-- > 0) - { - - /* Build return value. */ - *value = (*value << 8) | *buffer++; - } - - /* Return value. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_utility_time_randomize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns a value of between -1 seconds and 1 second */ -/* in system ticks. It is used to randomize timeouts as required by */ -/* the RFC's so as to not overload a network server after power out. */ -/* */ -/* INPUT */ -/* */ -/* None */ -/* */ -/* OUTPUT */ -/* */ -/* ticks Number of ticks between 1 & -1*/ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_convert_delay_to_ticks Convert seconds to ticks */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -INT _nx_dhcpv6_server_utility_time_randomize(void) -{ - -INT temp; -UINT sign; - - - temp = (INT)(NX_RAND() & 0x001F); - sign = temp & 0x8; - - /* Try for a number between 0 and 0x1F. */ - if (sign) - { - temp = -temp; - } - - return temp; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_listen_for_messages PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function listens for DHCPv6 client messages. It validates and */ -/* extracts information for creating or updating the client record. It */ -/* also responds to the Client pending valid request is received, and */ -/* updates its client records. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPv6 Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Message handled successfully */ -/* NO_PACKET No packet received */ -/* NX_DHCP_BAD_INTERFACE_INDEX Packet interface not recognized*/ -/* status Actual completion outcome */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release DHCP packet */ -/* nx_udp_socket_receive Receive DHCP packet */ -/* _nx_dhcpv6_extract_information Extract DHCP packet info */ -/* _nx_dhcpv6_validate_client_message Process the Client message */ -/* _nx_dhcpv6_server_assign_ip_address Assign IP address to Client */ -/* _nx_dhcpv6_respond_to_client_message Create and send response back */ -/* _nx_dhcpv6_clear_client_session Clears client session data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_thread_entry DHCPv6 Server thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER *dhcpv6_server_ptr) -{ - -UINT status; -UINT iface_index; -NXD_ADDRESS source_address; -NXD_ADDRESS destination_address; -NX_IPV6_HEADER *ipv6_header_ptr; -NX_PACKET *packet_ptr; -NX_DHCPV6_CLIENT *dhcpv6_client_ptr; -NX_DHCPV6_ADDRESS_LEASE *dhcpv6_interface_list_ptr; -NX_PACKET *new_packet_ptr; -ULONG bytes_copied = 0; - - - /* Check for an incoming DHCPv6 packet with non blocking option. */ - status = nx_udp_socket_receive(&dhcpv6_server_ptr -> nx_dhcpv6_server_socket, &packet_ptr, NX_DHCPV6_PACKET_WAIT_OPTION); - - /* Check for packet receive errors. */ - if (status != NX_SUCCESS) - { - - /* Return the packet receive status. */ - return(status); - } - - /* Check for valid packet length (message type and ID). */ - if (packet_ptr -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_DHCPV6_INVALID_DATA_SIZE); - } - - /* Get the interface index. */ - nxd_udp_packet_info_extract(packet_ptr, NX_NULL, NX_NULL, NX_NULL, &iface_index); - - /* Does the DHCP server have a table for this packet interface? */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - /* No; Release the packet. */ - nx_packet_release(packet_ptr); - - /* No, return the error status. */ - return(NX_DHCPV6_INVALID_INTERFACE_INDEX); - } - - /* Set a pointer to the IPv6 header to obtain source and destination address. */ - ipv6_header_ptr = (NX_IPV6_HEADER*)(packet_ptr -> nx_packet_ip_header); - - /* Get the source address. */ - COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_source_ip[0], &source_address.nxd_ip_address.v6[0]); - source_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* Get the destination address. */ - COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_destination_ip[0], &destination_address.nxd_ip_address.v6[0]); - destination_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* We will copy the received packet (datagram) over to a packet from the DHCP Server pool and release - the packet from the receive packet pool as soon as possible. */ - status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &new_packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); - - /* Check status. */ - if (status != NX_SUCCESS) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Error allocating packet, return error status. */ - return(status); - } - - /* Verify the incoming packet does not exceed our DHCP Server packet payload. */ - if ((ULONG)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < (packet_ptr -> nx_packet_length)) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the newly allocated packet and return an error. */ - nx_packet_release(new_packet_ptr); - - return(NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD); - } - - /* Use a packet from the DHCP Server as a buffer to store the received packet data. - Then we can release the received packet back to its packet pool. */ - status = nx_packet_data_extract_offset(packet_ptr, 0, (VOID *)new_packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length, &bytes_copied); - - /* Check status. */ - if ((status != NX_SUCCESS) || (bytes_copied == 0)) - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the allocated packet we'll never send. */ - nx_packet_release(new_packet_ptr); - - /* Error extracting packet buffer, return error status. */ - return(status); - } - - /* Update the new packet with the bytes copied. For chained packets, this will reflect the total - 'datagram' length. */ - new_packet_ptr -> nx_packet_length = bytes_copied; - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + bytes_copied; - - /* Now we can release the original packet. */ - nx_packet_release(packet_ptr); - - /* Get the DHCPv6 Server Mutex. */ - tx_mutex_get(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex, NX_WAIT_FOREVER); - - /* Extract the DHCPv6 specific information from the packet. This will create new Client record or update existing - client record in the server table. */ - status = _nx_dhcpv6_server_extract_packet_information(dhcpv6_server_ptr, &dhcpv6_client_ptr, new_packet_ptr, iface_index, source_address, destination_address); - - /* We are done with this packet now regardless of the success of the above operations. */ - nx_packet_release(new_packet_ptr); - - /* Check if we have extracted a valid client record. */ - if (status != NX_SUCCESS) - { - - /* Not valid; is there a client record we need to clean up? */ - if (dhcpv6_client_ptr) - { - - /* Yes; clear the client record completely. */ - _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); - } - else - { - - /* No record created; return the error status and abort. */ - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - /* Return the error from extracting packet data. */ - return(status); - } - } - - /* Determine if the server will respond to the message. */ - if ((dhcpv6_client_ptr == NX_NULL) || - (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT)) - { - - /* Release the mutex. */ - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - /* No, no further processing necessary. */ - return NX_SUCCESS; - } - - /* Check if the server status indicates it will grant the client request. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS) - { - - /* Yes it will. Check if the client is requesting an IP address, or renewing or rebinding a - previously assigned one. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) - { - - /* Yes, it is. This will (re)assign an IP address. */ - status = _nx_dhcpv6_assign_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &dhcpv6_interface_list_ptr); - - /* Check for errors or no address assigned. */ - if (status != NX_SUCCESS) - { - - /* Release the mutex. */ - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - /* Return all other errors as completion status. Do not send a message to the client. - The server will otherwise wait for the client to try again. Do not clear client record. */ - return(status); - } - - /* Check if a valid IP address is available. */ - if (dhcpv6_interface_list_ptr) - { - - /* There is. DHCPv6 client has been assigned an IP address. */ - - /* Now ensure we are sending valid lease time parameters with the IP address. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) - { - - /* Ignore invalid preferred or valid lifetimes from the client by setting to zero. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - } - /* Check for invalid T1 or T2 values; if out of range, set to zero). */ - - if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime && - (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime)) - { - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - } - else if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime && - (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime)) - { - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - } - else if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) - { - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - } - } - /* For a solicit message, ignore the preferred and valid lifetimes and check for - valid T1 and T2 times. */ - else if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) - { - - if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) - { - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - } - } - - /* If lifetime values are zero, or exceed the server default time, set to the default lease times. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime > NX_DHCPV6_DEFAULT_PREFERRED_TIME)) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME; - } - if ((dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime > NX_DHCPV6_DEFAULT_VALID_TIME)) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = NX_DHCPV6_DEFAULT_VALID_TIME; - } - - if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > NX_DHCPV6_DEFAULT_T1_TIME)) - { - - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = NX_DHCPV6_DEFAULT_T1_TIME; - } - - if ((dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 == 0) || - (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 > NX_DHCPV6_DEFAULT_T2_TIME)) - { - - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = NX_DHCPV6_DEFAULT_T2_TIME; - } - - /* Update the lease length in the server lease table. */ - dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_preferred_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime; - dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_valid_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime; - dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T1_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1; - dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_T2_lifetime = dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2; - - /* Ok to copy this address into the client record. */ - COPY_NXD_ADDRESS(&dhcpv6_interface_list_ptr -> nx_dhcpv6_lease_IP_address, - &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address); - } - } - } - - /* Send the server reply back to the client. */ - status = _nx_dhcpv6_send_response_to_client(dhcpv6_server_ptr, dhcpv6_client_ptr); - - /* Check if we need to remove the client record e.g. if the Client sent a Decline message. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) - { - - /* This will clear the client record and in the case of - a release message, return the IP address lease status to available. */ - status = _nx_dhcpv6_clear_client_record(dhcpv6_server_ptr, dhcpv6_client_ptr); - - } - - tx_mutex_put(&dhcpv6_server_ptr -> nx_dhcpv6_server_mutex); - - /* Return actual outcome status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_send_response_to_client PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function prepares DHCPv6 messages to send back to the Client. */ -/* Most of the information is obtained from the client session record. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ -/* dhcpv6_client_ptr Pointer to DHCPv6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a DHCPv6 packet */ -/* nx_packet_release Release DHCPv6 packet */ -/* nxd_udp_socket_send Send DHCPv6 packets */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer; -UINT status; -UINT buffer_index; -ULONG message_word; - - - /* Allocate a UDP packet from the DHCPv6 server packet pool. */ - status = nx_packet_allocate(dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_DHCPV6_PACKET_TIME_OUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Indicate this is an IPv6 packet. */ - packet_ptr -> nx_packet_ip_version = NX_IP_VERSION_V6; - - /* Setup the packet buffer pointer. */ - buffer = packet_ptr -> nx_packet_prepend_ptr; - - /* Clear the payload and packet interface field before preparing the packet for transmission. */ - memset(buffer, 0, (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)); - - /* Now reduce it to three bytes. */ - dhcpv6_client_ptr -> nx_dhcpv6_message_xid = dhcpv6_client_ptr -> nx_dhcpv6_message_xid & 0x0ffffff; - - /* Clear memory to make the message header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Add the server message type and matching client transaction ID as the DHCPv6 header fields. */ - message_word = (ULONG)((dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server << 24) | - (0x0FFFFFF & dhcpv6_client_ptr -> nx_dhcpv6_message_xid)); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the message header to the packet buffer. */ - memcpy(buffer, &message_word, sizeof(ULONG)); - - /* Update the buffer 'pointer'. */ - buffer_index = sizeof(ULONG); - - /* Handle the special case of an Inform Request which does not include a Client identifier. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) - { - - status = NX_SUCCESS; - - /* Only add the Client DUID if the client included one. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_client_duid.nx_op_code != 0) - { - - /* Add the Client DUID to the packet buffer. */ - status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer, - &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE); - } - } - else - { - - /* Add the Client DUID to the packet buffer. */ - status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_client_duid, buffer, - &buffer_index, NX_DHCPV6_CLIENT_DUID_TYPE); - } - - /* Check for error. */ - if (status != NX_SUCCESS) - { - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - return status; - } - - /* Now add to the server DUID to the message. */ - status = _nx_dhcpv6_add_duid(dhcpv6_server_ptr, &dhcpv6_server_ptr -> nx_dhcpv6_server_duid, buffer, - &buffer_index, NX_DHCPV6_SERVER_DUID_TYPE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - return status; - } - - /* Handle the special case of the Confirm request where we need only - send a status option. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM) - { - - /* Update the IANA status message. */ - status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE); - - if (status != NX_SUCCESS) - { - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - return status; - } - - /* Ok to just send a status option without the IANA option. */ - status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer, &buffer_index); - - /* Update the IANA status message. */ - status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE); - - if (status != NX_SUCCESS) - { - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - return status; - } - } - - /* Exclude IANA options from Confirm and Inform Request messages. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) && - (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) - { - - /* Add the client IANA to the packet buffer. */ - status = _nx_dhcpv6_server_add_iana(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - return status; - } - } - - /* Only an Advertise response should include a preference. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_response_back_from_server == NX_DHCPV6_MESSAGE_TYPE_ADVERTISE) - - { - - status = _nx_dhcpv6_add_preference(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); - } - - /* Check if the message type requires the server to add option request data. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST)) - { - - /* It does. Did the Client ask for a requested option? Only provide information - if there are no status errors from the server. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request) && - (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS)) - { - - /* Add the option request. */ - status = _nx_dhcpv6_add_option_requests(dhcpv6_server_ptr, dhcpv6_client_ptr, buffer, &buffer_index); - - /* Check for internal error. */ - if (status != NX_SUCCESS) - { - - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - - /* Return the error status and abort. */ - return status; - } - } - } - - /* Adjust the packet length for the DHCPv6 data. */ - packet_ptr -> nx_packet_length = buffer_index; - - /* Update the packet pointer marking the end of the payload (DHCP) data. */ - packet_ptr -> nx_packet_append_ptr += buffer_index; - - /* Send the response packet to the client. */ - status = nxd_udp_socket_interface_send(&(dhcpv6_server_ptr -> nx_dhcpv6_server_socket), packet_ptr, - &dhcpv6_client_ptr -> nx_dhcp_source_ip_address, NX_DHCPV6_CLIENT_UDP_PORT, - dhcpv6_server_ptr -> nx_dhcpv6_server_interface_index); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - /* Release the allocated back to the DHCPv6 Server packet pool. */ - nx_packet_release(packet_ptr); - } - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpc6_server_assign_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service finds an available IP address for the client if none is */ -/* provided, and updates the client's record with the new IP address. It */ -/* updates the server IP address lease table with the assigned lease */ -/* status */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* dhcpv6_client_ptr Pointer to DHCPV6client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* NX_DHCPV6_NO_AVAILABLE_IP_ADDRESSES No available address to assign*/ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_find_interface_table_ip_address */ -/* Look up IP address in */ -/* server interface table */ -/* _nx_dhcp_find_ip_address_owner Look up owner of an IP address*/ -/* in server interfce table */ -/* _nx_dhcp_record_ip_address_owner Set the client as IP address */ -/* owner in interface table */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Process Client DHCPv6 messages*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, - NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr) -{ -UINT status; -UINT i; -NX_DHCPV6_ADDRESS_LEASE *temp_interface_address_ptr; -UINT matching; - - - /* Initialize outcome to no address assigned. */ - *interface_address_ptr = NX_NULL; - - /* Does the Client have a IP address already assigned? */ - if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) - { - - /* Yes; The client has an IP address. */ - - /* Check if this address exists in the Server IP address list. */ - status = _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &temp_interface_address_ptr); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Was the address found in the server table? */ - if (temp_interface_address_ptr) - { - - matching = NX_FALSE; - - /* Verify the server has assigned this address. */ - if (temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to) - { - /* It has; now werify it is assigned to this client. */ - status = _nx_dhcpv6_check_duids_same(&dhcpv6_client_ptr -> nx_dhcpv6_client_duid, - &(temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to -> nx_dhcpv6_client_duid), - &matching); - - /* Check for internal errors. */ - if (status != NX_SUCCESS) - { - - return status; - } - } - else - { - /* It has not (so it is available). Assign it to this client. */ - - /* Set the lease address entry in the server table. */ - *interface_address_ptr = temp_interface_address_ptr; - - /* Mark the owner of the lease as this client. */ - temp_interface_address_ptr -> nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; - - /* We are all done. */ - return NX_SUCCESS; - } - - /* Was the address assigned to this client previously? */ - if (matching) - { - - /* Yes, return a pointer to the IP lease in the server table. */ - *interface_address_ptr = temp_interface_address_ptr; - - /* We will (re)assign this IP address to the client. */ - return NX_SUCCESS; - } - else - { - /* No this address is not available. */ - - /* Is it Ok to assign another IP address only if this is a Solicit request? */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT) - { - - /* No; Reply back the client request can not be granted. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; - - /* Because the server can not validate the IP address to assign, - set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - - dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; - - return NX_SUCCESS; - } - } - } - else - { - - /* Client address not found in table. */ - - /* Ok to assign another IP address only if this is a Solicit request? */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type != NX_DHCPV6_MESSAGE_TYPE_SOLICIT) - { - - /* No; reply backthe client request can not be granted. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_BINDING; - - /* Because the server can not validate the IP address to assign, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - - dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; - - return NX_SUCCESS; - } - } - } - - /* If we reach this point, we need to find an available address for the client. */ - for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) - { - - if (!dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to) - { - break; - } - } - - /* Check if we found anything. */ - if (i == NX_DHCPV6_MAX_LEASES) - { - - /* No; reply back there are no addresses available. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code = NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE; - - /* Because the server can not assign the IP address, set the lifetimes to zero RFC 3315 Sect 18.2.3, 18.2.4. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - - dhcpv6_client_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_UNBOUND; - } - else - { - - /* Found an empty slot; assign it to this client. */ - - /* Mark the owner of the lease as this client. */ - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = dhcpv6_client_ptr; - - /* Return the lease address entry in the server table. */ - *interface_address_ptr = &(dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]); - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcp_find_client_record_by_chaddr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function looks up a client record by the client hardware mac */ -/* address. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ -/* dhcpv6_duid _ptr Pointer to client DUID */ -/* record_index Index of client record found */ -/* in server table */ -/* add_on Option to add if not found */ -/* message_xid Message transaction ID */ -/* matching Indicates if client existed in*/ -/* server records already */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Message handled successfully */ -/* NX_DHCPV6_TABLE_FULL Client record table is full */ -/* */ -/* CALLS */ -/* _nx_dhcpv6_check_duids_same Checks if DUIDs are the same */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Extract DHCPv6 info from */ -/* Client message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *duid_ptr, - UINT *record_index, UINT add_on, ULONG message_xid, UINT *matching) -{ - -UINT i; -UINT status; -UINT available_index; -NX_DHCPV6_CLIENT *client_record_ptr; - - - /* Initialize result to not found. */ - *matching = NX_FALSE; - - /* Initialize an available slot in the table as outside the boundary (e.g. no slots available). */ - available_index = NX_DHCPV6_MAX_CLIENTS; - - /* Records are not necessarily added and deleted sequentially, - so search the whole table until a match is found. */ - i = 0; - status = NX_SUCCESS; - - while (i < NX_DHCPV6_MAX_CLIENTS) - { - - /* Set local pointer for convenience. */ - client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[i]; - - /* Skip empty records. */ - if (!client_record_ptr -> nx_dhcpv6_id) - { - - /* Flag the first empty record in case we need to add the current client to the table. */ - if (i < available_index) - available_index = i; - - i++; - - continue; - } - - status = _nx_dhcpv6_check_duids_same(&client_record_ptr -> nx_dhcpv6_client_duid, duid_ptr, matching); - - /* Check the DUID in the received client request against the server record. */ - if ((status == NX_SUCCESS) && *matching) - { - - client_record_ptr -> nx_dhcpv6_message_xid = message_xid; - - - /* Reset the client session time every time we hear from a client. */ - client_record_ptr -> nx_dhcpv6_client_session_time = 1; - - /* Got a match! Return the client record location. */ - *record_index = i; - - /* Set the result to client located. */ - *matching = NX_TRUE; - - return(NX_SUCCESS); - } - - /* No match. Check the next client in the server table. */ - i++; - } - - /* Not found. Create a record for this client? */ - if (!add_on) - { - - /* Do not create a record and handle as an error. */ - return(NX_DHCPV6_CLIENT_RECORD_NOT_FOUND); - } - - /* Check if there is available room in the table for a new client. */ - if (available_index >= NX_DHCPV6_MAX_CLIENTS) - { - - /* No, we cannot add this client so the server's table. */ - return(NX_DHCPV6_TABLE_FULL); - } - - /* Set local pointer to an available slot. */ - client_record_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_clients[available_index]; - - /* Return the location of the newly created client record. */ - *record_index = available_index; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_find_ip_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function looks up a client DHCPv6 message IP address in the */ -/* appropriate server IP address table, based on the client network */ -/* interface index. For single homed hosts, this defaults to zero. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPv6 Server */ -/* dhcpv6_client_ptr Pointer to DHCPv6 client */ -/* interface_address_ptr Pointer to matching entry */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Search completes successfully */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcp_clear_client_record Removes client record from */ -/* server table */ -/* */ -/* CALLED BY */ -/* */ -/* CHECK_IPV6_ADDRESSES_SAME Does IPv6 address comparison */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, - NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr) -{ - -UINT i; -NXD_ADDRESS server_table_address; - - - /* Initialize to not found. */ - *interface_address_ptr = NX_NULL; - - /* Search through the interface specific address table. For single homed hosts, there is only one address table. */ - for (i = 0; i < NX_DHCPV6_MAX_LEASES; i++) - { - - /* Get a pointer to the address, using the client's interface index to access the correct IP address table. */ - server_table_address = dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address; - - /* Check for a match. */ - if (CHECK_IPV6_ADDRESSES_SAME(&server_table_address.nxd_ip_address.v6[0], - &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) - { - - /* Set the location of the matching server entry, to indicate we found a match. */ - *interface_address_ptr = &dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i]; - break; - } - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_clear_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the entire client record from the server table.*/ -/* It also frees up the client's IP address in the server IP address */ -/* table. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_ptr Pointer to DHCPV6 Server */ -/* dhcpv6_client_ptr Pointer to DHCPV6 Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful outcome */ -/* NX_DHCP_BAD_INTERFACE_INDEX Invalid client interface index */ -/* CALLS */ -/* */ -/* tx_mutex_get Get server protection mutex */ -/* tx_mutex_put Release server protection mutex*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Listen for client requests */ -/* _nx_dhcpv6_find_client_record_by_chaddr */ -/* Find client in server table */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr) -{ - -UINT i; - - - if (!dhcpv6_client_ptr) - { - - /* Benign error. Return success. */ - return(NX_SUCCESS); - } - - i = 0; - - /* Does the client have an assigned IP address? */ - if (!CHECK_UNSPECIFIED_ADDRESS(&dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) - { - - /* Yes, We need to free up the Client's assigned IP address in the server database. */ - while (i < NX_DHCPV6_MAX_LEASES) - { - - tx_mutex_get(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex), NX_WAIT_FOREVER); - - /* Find the interface table entry by matching IP address. */ - if (CHECK_IPV6_ADDRESSES_SAME(&dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], - &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0])) - { - - /* Clear the IP address list item properties. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) - { - - /* Apparently another client has this address so do not clear the assignment status. */ - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = (NX_DHCPV6_CLIENT *)(ALIGN_TYPE)0xFFFFFFFF; - } - else - { - - /* Restore availability by clearing the owner. */ - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_assigned_to = NX_NULL; - } - - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T1_lifetime = 0; - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_T2_lifetime = 0; - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_valid_lifetime = 0; - dhcpv6_server_ptr -> nx_dhcpv6_lease_list[i].nx_dhcpv6_lease_preferred_lifetime = 0; - - tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - /* Address now available for DHCP client. */ - break; - } - i++; - - tx_mutex_put(&(dhcpv6_server_ptr -> nx_dhcpv6_server_mutex)); - - } - } - - /* Ok to clear the Client record. */ - memset(dhcpv6_client_ptr, 0, sizeof(NX_DHCPV6_CLIENT)); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_update_client_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the client record based on the most recent */ -/* message received from the client. A typical example is after a */ -/* Solicit message is received the server gets a Request message which */ -/* it will add to the client record it has in its table. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 Server */ -/* to_server_ptr Pointer to client to update */ -/* from_client_ptr Pointer to client updated from */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful outcome */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Process DHCPv6 data in packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - NX_DHCPV6_CLIENT *from_extracted_client_data_ptr, - NX_DHCPV6_CLIENT *to_client_data_on_record_ptr) -{ - - NX_PARAMETER_NOT_USED(dhcpv6_server_ptr); - - /* If this is a solicit message update the entire copy into the specified record. */ - if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_SOLICIT) - { - - /* Ok to copy the whole record over. */ - memcpy(to_client_data_on_record_ptr, from_extracted_client_data_ptr, sizeof(NX_DHCPV6_CLIENT)); - - /* Update various fields now that the client is in a DHCPv6 session with the server. */ - to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 1; - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); - } - else if (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST) - { - - /* Update selected fields for an INFORM REQUEST. */ - to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id; - to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid; - to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type; - to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server; - - COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0], - &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); - to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0], - &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); - to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); - - } - /* If this is not a solicit message, update the selected fields into the specified record. */ - else if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_CONFIRM)) - { - - - /* Ok to update the existing client record. - - Note: if this is a duplicate client request we update the client record just - the same. */ - to_client_data_on_record_ptr -> nx_dhcpv6_id = from_extracted_client_data_ptr -> nx_dhcpv6_id; - to_client_data_on_record_ptr -> nx_dhcpv6_message_xid = from_extracted_client_data_ptr -> nx_dhcpv6_message_xid; - to_client_data_on_record_ptr -> nx_dhcpv6_message_type = from_extracted_client_data_ptr -> nx_dhcpv6_message_type; - to_client_data_on_record_ptr -> nx_dhcpv6_response_back_from_server = from_extracted_client_data_ptr -> nx_dhcpv6_response_back_from_server; - - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_client_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_client_duid, sizeof(NX_DHCPV6_SVR_DUID)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_server_duid, &from_extracted_client_data_ptr -> nx_dhcpv6_server_duid, sizeof(NX_DHCPV6_SVR_DUID)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_elapsed_time, &from_extracted_client_data_ptr -> nx_dhcpv6_elapsed_time, sizeof(NX_DHCPV6_SERVER_ELAPSED_TIME)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_iana, &from_extracted_client_data_ptr -> nx_dhcpv6_iana, sizeof(NX_DHCPV6_SERVER_IA_NA)); - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_ia, &from_extracted_client_data_ptr -> nx_dhcpv6_ia, sizeof(NX_DHCPV6_SERVER_IA_ADDRESS)); - - /* Update the IANA status option code, length and status message. The DHCPv6 server - will figure out the actual lenght with the status message text added in later. */ - to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_status_code = from_extracted_client_data_ptr -> nx_dhcpv6_iana_status.nx_status_code; - to_client_data_on_record_ptr -> nx_dhcpv6_iana_status.nx_option_length = sizeof(USHORT); - - COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0], - &to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_address.v6[0]); - - to_client_data_on_record_ptr -> nx_dhcp_source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - COPY_IPV6_ADDRESS(&from_extracted_client_data_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0], - &to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_address.v6[0]); - - to_client_data_on_record_ptr -> nx_dhcp_destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - memcpy(&to_client_data_on_record_ptr -> nx_dhcpv6_option_request, &from_extracted_client_data_ptr -> nx_dhcpv6_option_request, sizeof(NX_DHCPV6_SERVER_OPTIONREQUEST)); - - /* Update fields based on the state of the client. At this point the client is bound to a - valid IP address to the session is 'over'. Set timeout fields to stop the session timer - and begin the lease life timer. */ - to_client_data_on_record_ptr -> nx_dhcpv6_client_session_time = 0; - - /* Start the lease timer if we have just (re)assigned an IP lease. */ - if ((from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REQUEST) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RENEW) || - (from_extracted_client_data_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_REBIND)) - { - - to_client_data_on_record_ptr -> nx_dhcpv6_IP_lease_time_accrued = 1; - to_client_data_on_record_ptr -> nx_dhcpv6_state = NX_DHCPV6_STATE_BOUND; - } - - /* No need to set the client state to unbound. We will remove the client record and restore the - IP address status back to available after sending the server reply. */ - } - /* else - Confirm, Inform Request and other messages should not change the client record. */ - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_process_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the IANA option from a client DHCPv6 message.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */ -/* received_buffer Pointer to client packet buffer */ -/* length Size of client packet buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_INVALID_IANA_DATA IANA option is missing data or */ -/* improperly formatted */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data */ -/* Parses data from packet buffer */ -/* _nx_dhcpv6_server_utility_get_block_option_length */ -/* Parses option header from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Extracts DHCPV6 data from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) -{ - -UINT status; -ULONG data; -UINT index; -ULONG opcode, option_length; -UINT process_ia_option; - - - /* Initialize local variables. */ - process_ia_option = NX_TRUE; - index = 0; - - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(USHORT), &data); - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_op_code = (USHORT)data; - - index = 2; - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(USHORT), &data); - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_option_length = (USHORT)data; - - /* Set up the location of the read pointer past option header. */ - index = 4; - - /* The first word should contain the IANA ID. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - - /* Process the IANA ID. */ - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_IA_NA_id = data; - - /* Update the write location index. */ - index += 4; - - /* Copy T1 and T2 from the buffer into IANA. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 = data; - - index += (ULONG)sizeof(ULONG); - - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - index += (ULONG)sizeof(ULONG); - - dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2 = data; - - /* Check for invalid T1/T2 lifetimes. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T1 > dhcpv6_client_ptr -> nx_dhcpv6_iana.nx_T2) - { - - /* Reject the server DHCPv6 response. */ - return NX_DHCPV6_INVALID_IANA_TIME; - } - - /* Check if we're at the end of option data yet. */ - if ((index - 4) == length) - { - - /* Yes, all done. */ - return NX_SUCCESS; - } - - /* Now we recurse into the options embedded in the IANA option. We do it here - because this is part of the IANA option data length. */ - do - { - - /* Get the next option code and length. */ - status = _nx_dhcpv6_server_utility_get_block_option_length(received_buffer + index, &opcode, &option_length); - - /* Check that the block data is valid. */ - if (status != NX_SUCCESS) - { - - /* No, return the error status. */ - return status; - } - - /* Check if this is an IA address option request, and if we have already - processed an IA in this message (the DHCPv6 server is limited to - one IA per client message). */ - if (opcode == NX_DHCPV6_OP_IA_ADDRESS) - { - - /* Yes it is, so process it. */ - status = _nx_dhcpv6_server_process_ia(dhcpv6_client_ptr, (received_buffer + index), option_length, process_ia_option); - - /* Check for errors processing the DHCPv6 message. */ - if (status != NX_SUCCESS) - { - - /* Abort further processing. Return error status. */ - return status; - } - - /* Indicate we already have an IA option if the client request contains multiple IAs. */ - process_ia_option = NX_FALSE; - - /* Keep track of how far into the packet we have parsed. */ - index += option_length + 4; - } - - - } while (index - 4 < length); - - /* Check if we went past the reported size of IA-NA data. */ - if (index - 4 > length) - { - - /* Yes return an error status. */ - return NX_DHCPV6_INVALID_IANA_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_option_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the option request from the client packet. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ -/* received_buffer Pointer to packet buffer */ -/* length Size of packet buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data */ -/* Parses data from specified buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Extracts DHCPv6 data from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) -{ - -ULONG data; -UINT i; -UINT index; -UINT option_length; - - NX_PARAMETER_NOT_USED(length); - - index = 0; - - /* Extract the option code which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - - dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_code = (USHORT)data; - - index += 2; - - /* Extract the option length which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length = (USHORT)data; - - index += 2; - - option_length = dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_option_length; - - i = 0; - - while (option_length && (i < NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS)) - { - - /* Clear out existing data. */ - dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request[i] = 0; - - /* Extract the option request which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - - dhcpv6_client_ptr -> nx_dhcpv6_option_request.nx_op_request[i] = (USHORT)data; - - /* Update all the length and index counters.*/ - option_length -= 2; - index += 2; - i++; - - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_elapsed_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the elapsed time option in the client packet.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ -/* received_buffer Pointer to packet buffer */ -/* length Size of packet buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_OPTION_DATA Elapsed time is missing data */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data */ -/* Parses data from specified buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Extracts DHCPv6 data from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length) -{ - -ULONG data; -UINT index; - - index = 0; - - /* Extract the option code which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_op_code = (USHORT)data; - - index += 2; - - /* Extract the option length which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_option_length = (USHORT)data; - - index += 2; - - /* Extract the elapsed session time which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - dhcpv6_client_ptr -> nx_dhcpv6_elapsed_time.nx_session_time = (USHORT)data; - - index += 2; - - /* Are we past the end of the buffer, subtracting for the toplevel opcode and - length of the IANA option? */ - if ((index - 4) > length || (index - 4) < length) - { - - /* Yes, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_OPTION_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_process_ia PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the IA address option from the client packet.*/ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_client_ptr Pointer to DHCPV6 Client instance */ -/* buffer_ptr Pointer to client packet buffer */ -/* length Size of client packet buffer */ -/* process_ia If true, write IA to client record*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_IA_DATA IA option is missing data or */ -/* improperly formatted */ -/* NX_DHCPV6_INVALID_IA_TIME IA option lifetime data is invalid*/ -/* */ -/* CALLS */ -/* */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_process_iana Processes IANA in client request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length, UINT process_ia) -{ - -UINT index, k; -ULONG data; - - - /* Fill in the IA address code and length. Client might already have one on - record, but use the server's data instead. */ - if (process_ia) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (USHORT)length; - } - - /* Set the index for the read pointer past the option header. */ - index = 4; - - for (k = 0; k < sizeof(ULONG); k++) - { - - /* Copy each IPv6 address word into the IA address. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - - if (process_ia) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[k] = data; - } - - /* Move to the next IPv6 address word. */ - index += (ULONG)sizeof(ULONG); - - /* Check if we're going past the end of the option data. */ - if (index - sizeof(ULONG) > length) - { - /* Yes, return an error status.*/ - return NX_DHCPV6_INVALID_IA_DATA; - } - } - - /* Copy the preferred lifetime data from the client buffer to IA.*/ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - - if (process_ia) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = data; - - } - - index += (ULONG)sizeof(ULONG); - - /* Copy the valid lifetime data from the client buffer to IA.*/ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, sizeof(ULONG), &data); - - if (process_ia) - { - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = data; - - } - - index += (ULONG)sizeof(ULONG); - - /* Check if we went past the reported size of IA address data. */ - if (index - 4 > length || index - 4 < length) - { - - /* Return an error status. Cannot accept this reply. */ - return NX_DHCPV6_INVALID_IA_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_process_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the DUID from the client packet. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ -/* duid_type Denotes client or server DUID */ -/* received_buffer Pointer to packet buffer */ -/* length Size of packet buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INVALID_DUID DUID is missing data or does not */ -/* match the DUID on record */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_server_utility_get_data */ -/* Parses data from specified buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_extract_packet_information */ -/* Extracts DHCPv6 data from packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID *duid_ptr, UINT duid_type, UCHAR *received_buffer, UINT length) -{ - -ULONG data; -UINT index; - - NX_PARAMETER_NOT_USED(duid_type); - - /* Set an index past the option code and data length. */ - index = 4; - - /* Extract the DUID type which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - duid_ptr -> nx_duid_type = (USHORT)data; - - index += 2; - - /* Extract the hardware type which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - - duid_ptr -> nx_hardware_type = (USHORT)data; - - index += 2; - - /* IS this a link layer plus time DUID type? */ - if (duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - /* Yes; Extract the time which should be the next 4 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 4, &data); - - duid_ptr -> nx_duid_time = data; - - index += 4; - } - - /* Extract the link local address msw which should be the next 2 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 2, &data); - - index += 2; - - duid_ptr -> nx_link_layer_address_msw = (USHORT)data; - - /* Extract the link local address lsw which should be the next 4 bytes. */ - _nx_dhcpv6_server_utility_get_data(received_buffer + index, 4, &data); - - index += 4; - - duid_ptr -> nx_link_layer_address_lsw = data; - - - /* Are we past the end of the buffer, subtracting for the toplevel opcode and - length of the IANA option? */ - if ((index - 4) > length || (index - 4) < length) - { - - /* Yes, return the error status to reject this packet. */ - return NX_DHCPV6_INVALID_OPTION_DATA; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_check_duids_same PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares the two input DUIDs to match field by field. */ -/* if they match, the match status is returned NX_TRUE. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_duid1_ptr Pointer to first DHCPV6 DUID */ -/* dhcpv6_duid1_ptr Pointer to 2nd DHCPV6 DUID */ -/* matching Flag indicating if DUIDs match */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS No errors doing comparison */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get server protection mutex */ -/* tx_mutex_put Release server protection mutex*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_listen_for_messages Listen for client requests */ -/* _nx_dhcpv6_find_client_record_by_chaddr */ -/* Find client in server table */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID *dhcpv6_duid1_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid2_ptr, UINT *matching) -{ - - - /* Check for invalid input. */ - if (!dhcpv6_duid1_ptr || !dhcpv6_duid2_ptr || !matching) - { - - /* Return invalid input. */ - return(NX_PTR_ERROR); - } - - /* Initialize result to no match. */ - *matching = NX_FALSE; - - /* CHeck field by field starting with the ones most likely to miss. */ - if (dhcpv6_duid1_ptr -> nx_link_layer_address_msw != dhcpv6_duid2_ptr -> nx_link_layer_address_msw) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_link_layer_address_lsw != dhcpv6_duid2_ptr -> nx_link_layer_address_lsw) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_duid_type != dhcpv6_duid2_ptr -> nx_duid_type) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_hardware_type != dhcpv6_duid2_ptr -> nx_hardware_type) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_op_code != dhcpv6_duid2_ptr -> nx_op_code) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_option_length != dhcpv6_duid2_ptr -> nx_option_length) - { - return NX_SUCCESS; - } - else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - if (dhcpv6_duid1_ptr -> nx_duid_time != dhcpv6_duid2_ptr -> nx_duid_time) - { - return NX_SUCCESS; - } - } - else if (dhcpv6_duid1_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED) - { - - /* First compare the enterprise ID. */ - if (dhcpv6_duid1_ptr -> nx_duid_enterprise_number != dhcpv6_duid2_ptr -> nx_duid_enterprise_number) - { - return NX_SUCCESS; - } - - /* Then compare the private ID. */ - if (memcmp(dhcpv6_duid1_ptr -> nx_duid_private_identifier, dhcpv6_duid2_ptr -> nx_duid_private_identifier, - dhcpv6_duid1_ptr -> nx_option_length - sizeof(ULONG))) - { - - /* No match. */ - return NX_SUCCESS; - } - } - - /* It's match! */ - *matching = NX_TRUE; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_duid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a DHCPv6 DUID to the server response packet */ -/* based on the input DUID and the DUID type (client or server). */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ -/* dhcpv6_duid_ptr Pointer to DHCPV6 DUID instance */ -/* buffer Pointer to packet buffer */ -/* index Location where to add DUID */ -/* duid_type Indicate client or serve DUID */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet buffer too small for DUID */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Compiles and sends the Server */ -/* DHCPv6 response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid_ptr, UCHAR *buffer_ptr, UINT *index, UINT duid_type) -{ - -ULONG message_word; -UINT available_payload; - - NX_PARAMETER_NOT_USED(duid_type); - - /* Clear memory to make the message header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Compile the header from the DUID. */ - message_word = (ULONG)(dhcpv6_duid_ptr -> nx_op_code << 16); - message_word |= (dhcpv6_duid_ptr -> nx_option_length); - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - /* Check if the DUID will fit in the packet buffer. */ - if (available_payload < (UINT)(dhcpv6_duid_ptr -> nx_option_length + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy first half of the DUID option to packet buffer. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); - *index += (ULONG)sizeof(UINT); - - memset(&message_word, 0, sizeof(ULONG)); - - /* Set up the rest of the Client DUID header. */ - message_word = (ULONG)(dhcpv6_duid_ptr -> nx_duid_type << 16); - message_word |= dhcpv6_duid_ptr -> nx_hardware_type; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Set up the DUID option. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); - *index += (ULONG)sizeof(UINT); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw); - - /* Include the 'time' field if this is a Link layer time DUID type. */ - if (dhcpv6_duid_ptr -> nx_duid_type == NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME) - { - - memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_duid_time), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - } - - /* Copy the rest of the DUID header. */ - memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_msw), sizeof(USHORT)); - *index += (ULONG)sizeof(USHORT); - - memcpy(buffer_ptr + *index, &(dhcpv6_duid_ptr -> nx_link_layer_address_lsw), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Swap bytes back to original endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_lsw); - NX_CHANGE_USHORT_ENDIAN(dhcpv6_duid_ptr -> nx_link_layer_address_msw); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_duid_ptr -> nx_duid_time); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_server_add_iana PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the IANA option to the server response packet */ -/* using the Client IANA on record. It will also add any 'nested' */ -/* options such as the Client IA(s) and IANA status option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ -/* dhcpv6_client_ptr Pointer to DHCPV6 client instance */ -/* buffer_ptr Pointer to response packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Buffer too small for IANA option */ -/* CALLS */ -/* */ -/* _nx_dhcpv6_add_ia Adds the IA option to buffer */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_send_request Sends server DHCPv6 response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -UINT status; -UINT add_ia; -UINT temp; -UINT temp_index; -ULONG message_word; -UINT available_payload; -NX_DHCPV6_SERVER_IA_NA *iana_ptr; - - - /* Initialize the completion status variable. */ - status = NX_SUCCESS; - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - iana_ptr = &dhcpv6_client_ptr -> nx_dhcpv6_iana; - - /* Check if the client IANA will fit in the packet buffer. */ - if (available_payload < (UINT)(iana_ptr -> nx_option_length + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* For release or decline messages, or a server status indicating no IP address can be - assigned yet, set the IANA IP lease times to expired. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE) || - (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code != NX_DHCPV6_STATUS_SUCCESS)) - { - - iana_ptr -> nx_T1 = 0; - iana_ptr -> nx_T2 = 0; - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = 0; - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime = 0; - } - - /* Clear memory to make the first word of the IA-NA header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Save this location in the buffer. */ - temp_index = *index; - - /* Write the IANA opcode and data length into one word. */ - message_word = (ULONG)((iana_ptr -> nx_op_code) << 16); - - /* Reset the IANA length to just the IANA option fields, (not IA or status options). */ - iana_ptr -> nx_option_length = 3 * sizeof(ULONG); - - message_word |= iana_ptr -> nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the word into the packet buffer going to the server. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); - - /* Update the buffer pointer. */ - *index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id); - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1); - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2); - - memcpy(buffer_ptr + *index, &(iana_ptr -> nx_IA_NA_id), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T1), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(iana_ptr -> nx_T2), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Swap bytes back. */ - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_IA_NA_id); - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T1); - NX_CHANGE_ULONG_ENDIAN(iana_ptr -> nx_T2); - - /* Determine if we include an IA address option. This requires a successful IANA status - and applies only if the client is requesting or confirming an address including renew/rebinding one. */ - add_ia = NX_FALSE; - - /* We include an IA if we intend to assign or confirm an IP address. */ - if (dhcpv6_client_ptr -> nx_dhcpv6_iana_status.nx_status_code == NX_DHCPV6_STATUS_SUCCESS) - { - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type >= NX_DHCPV6_MESSAGE_TYPE_SOLICIT) && - (dhcpv6_client_ptr -> nx_dhcpv6_message_type <= NX_DHCPV6_MESSAGE_TYPE_DECLINE)) - { - - add_ia = NX_TRUE; - } - } - - /* Or if we are confirming the IP address a client is releasing or declining, regardless - if our records show this IP address is bound to this client. Sect 18.2.6-7 RFC 3315. */ - if ((dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_RELEASE) || - (dhcpv6_client_ptr -> nx_dhcpv6_message_type == NX_DHCPV6_MESSAGE_TYPE_DECLINE)) - { - add_ia = NX_TRUE; - } - - if (add_ia) - { - - temp = *index; - - /* Check for a missing IA option (as in the Solicit message did not have one). */ - if (dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code == 0) - { - - NX_DHCPV6_ADDRESS_LEASE *client_address_lease; - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_op_code = NX_DHCPV6_OP_IA_ADDRESS; - - /* Set the length to include option code, lenght (one word), IPv6 address (4 words), and lifetime data (2 words). */ - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_option_length = (2 * sizeof(ULONG))+ (4 * sizeof(ULONG)); - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_preferred_lifetime = NX_DHCPV6_DEFAULT_PREFERRED_TIME; - - dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_valid_lifetime= NX_DHCPV6_DEFAULT_VALID_TIME; - - /* Find the Client's tentatively assigned address in the Server IP address list. */ - _nx_dhcpv6_find_ip_address(dhcpv6_server_ptr, dhcpv6_client_ptr, &client_address_lease); - - if ((status != NX_SUCCESS) || (client_address_lease == NX_NULL)) - { - - return status; - } - - COPY_IPV6_ADDRESS(&client_address_lease -> nx_dhcpv6_lease_IP_address.nxd_ip_address.v6[0], - &dhcpv6_client_ptr -> nx_dhcpv6_ia.nx_global_address.nxd_ip_address.v6[0]); - } - - status = _nx_dhcpv6_add_ia(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_ia, buffer_ptr, &temp); - - if (status != NX_SUCCESS) - { - - return status; - } - - - /* Add the size of the IA(s) to the client IANA. Note that we include the option code - and length field of any nested options. */ - iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr-> nx_dhcpv6_ia.nx_option_length + 4); - - /* Update the index into packet buffer from our temporary variable. */ - *index = temp; - } - - /* Update the IANA status message. */ - status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_TRUE); - - if (status != NX_SUCCESS) - { - - return status; - } - - temp = *index; - - /* Ok to add one to server reply.*/ - status = _nx_dhcpv6_add_iana_status(dhcpv6_server_ptr, &dhcpv6_client_ptr -> nx_dhcpv6_iana_status, buffer_ptr, &temp); - - if (status != NX_SUCCESS) - { - - return status; - } - - /* Update the index into packet buffer from our temporary variable. */ - *index = temp; - - /* Update the IANA option length with the iana status option size. */ - iana_ptr -> nx_option_length = (USHORT)(iana_ptr -> nx_option_length + dhcpv6_client_ptr->nx_dhcpv6_iana_status.nx_option_length + 4); - - /* Rewrite the IANA opcode and update the changed IANA data length with the additional IA address option. */ - message_word = (ULONG)((iana_ptr -> nx_op_code) << 16); - message_word |= (ULONG)(iana_ptr -> nx_option_length); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the updated word into the packet buffer at the saved location. */ - memcpy(buffer_ptr + temp_index, &message_word, sizeof(ULONG)); - - /* Erase the IANA status message. We will add another message on the next (if any) IANA option for the client. */ - status = _nx_dhcpv6_prepare_iana_status(&dhcpv6_client_ptr -> nx_dhcpv6_iana_status, NX_FALSE); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_ia PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the IA address option to the server response */ -/* packet using the input IA option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ -/* dhcpv6_ia_ptr Pointer to IA to add */ -/* buffer_ptr Pointer to response packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Buffer to small for IA option */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_add_iana Adds the IANA to server response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_ia(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IA_ADDRESS *dhcpv6_ia_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG message_word; -UINT available_payload; - - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - /* Check if the client IA address option will fit in the packet buffer. */ - if (available_payload < (UINT)(dhcpv6_ia_ptr -> nx_option_length + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* If the client has created an address option, apply it to the message. */ - - /* Clear memory to make the first word of the IA-Address header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Compile the header from the IA option on the client record. */ - message_word = (ULONG)(dhcpv6_ia_ptr -> nx_op_code << 16); - message_word |= dhcpv6_ia_ptr -> nx_option_length; - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy option header into the packet and update the index into the buffer. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime); - - /* Copy the IPv6 address to the packet. */ - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Copy the Client's preference for lifetimes to packet. */ - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_preferred_lifetime), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - memcpy(buffer_ptr + *index, &(dhcpv6_ia_ptr -> nx_valid_lifetime), sizeof(ULONG)); - *index += (ULONG)sizeof(ULONG); - - /* Swap bytes back. */ - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[0]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[1]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[2]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_global_address.nxd_ip_address.v6[3]); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_preferred_lifetime); - NX_CHANGE_ULONG_ENDIAN(dhcpv6_ia_ptr -> nx_valid_lifetime); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dhcpv6_add_iana_status PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the IANA status option to the server response */ -/* packet using the input IANA status option. */ -/* */ -/* INPUT */ -/* */ -/* dhcpv6_server_ptr Pointer to DHCPV6 server instance */ -/* iana_status_ptr Pointer to IANA status option */ -/* buffer_ptr Pointer to response packet buffer */ -/* index Location into buffer to write data*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD */ -/* Buffer to small for IA option */ -/* CALLS */ -/* */ -/* memset Clears specified area of memory */ -/* memcpy Copies specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dhcpv6_server_add_iana Add IANA status to server response*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IANA_STATUS *iana_status_ptr, UCHAR *buffer_ptr, UINT *index) -{ - -ULONG message_word; -USHORT message_short; -UINT available_payload; -UINT message_length; - - - /* Compute the available payload in the packet buffer. */ - available_payload = dhcpv6_server_ptr -> nx_dhcpv6_packet_pool_ptr -> nx_packet_pool_payload_size - - NX_IPv6_UDP_PACKET - *index; - - /* Check if the status option will fit in the packet buffer. */ - if (available_payload < (UINT)(iana_status_ptr -> nx_option_length + 4)) - { - - /* Hmmm... not enough! Can't do it. */ - return NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Clear memory to make the message header. */ - memset(&message_word, 0, sizeof(ULONG)); - - /* Compile the header for the status option. */ - message_word = (ULONG)(iana_status_ptr -> nx_op_code << 16); - message_word |= (iana_status_ptr -> nx_option_length); - - /* Adjust for endianness. */ - NX_CHANGE_ULONG_ENDIAN(message_word); - - /* Copy the word to packet buffer. */ - memcpy(buffer_ptr + *index, &message_word, sizeof(UINT)); - *index += (ULONG)sizeof(UINT); - - memset(&message_word, 0, sizeof(ULONG)); - - /* Set up the status option code. */ - message_short = iana_status_ptr -> nx_status_code; - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(message_short); - - /* Set up the DUID option. */ - memcpy(buffer_ptr + *index, &message_short, sizeof(USHORT)); - *index += (ULONG)sizeof(USHORT); - - message_length = iana_status_ptr -> nx_option_length - (ULONG)(sizeof(USHORT)); - memcpy(buffer_ptr + *index, &iana_status_ptr -> nx_status_message[0], message_length); - - *index += message_length; - - /* No need to swap the last byte. */ - return NX_SUCCESS; -} -#endif /* FEATURE_NX_IPV6 */ diff --git a/protocol_handlers/dhcp/nxd_dhcpv6_server.h b/protocol_handlers/dhcp/nxd_dhcpv6_server.h deleted file mode 100644 index ee01ba0e..00000000 --- a/protocol_handlers/dhcp/nxd_dhcpv6_server.h +++ /dev/null @@ -1,825 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Dynamic Host Configuration Protocol over IPv6 (DHCPv6) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_dhcpv6_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Dynamic Host Configuration Protocol over */ -/* IPv6 (DHCPv6) component, including all data types and external */ -/* references. It is assumed that nx_api.h and nx_port.h have already */ -/* been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_DHCPV6_SERVER_H -#define NXD_DHCPV6_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the DHCPv6 ID to mark the DHCPV6_CLIENT and DHCPV6_SERVER structures as created. */ - -#define NX_DHCPV6_CLIENT_ID 0x44484336UL -#define NX_DHCPV6_SERVER_ID 0x44484337UL - - -/* Define the conversion between timer ticks and seconds (processor dependent). */ - -#define NX_DHCPV6_SERVER_TICKS_PER_SECOND NX_IP_PERIODIC_RATE - - -/* Set up interface defines for NetX Duo. */ - -#define LINK_LOCAL_INTERFACE 0 -#define GLOBAL_IP_INTERFACE 1 - - -/* Set the Client lease time. An infinate lease time is not recommended by the RFC - unless the Client requires a permanent IP address. Most servers will likely not - grant an infinite IP address lease. */ - -#define NX_DHCPV6_INFINITE_LEASE 0xffffffffUL -#define NX_DHCPV6_MULTICAST_MASK 0xff000000UL - - -/* Define RFC mandated (draft only) option codes. */ - -#define NX_DHCPV6_RFC_DNS_SERVER_OPTION 0x00000017UL /* RFC Option code for requesting DNS server IP address */ -#define NX_DHCPV6_RFC_TIME_SERVER_OPTION 0x0000001FUL /* RFC Option code for requesting tme server IP address. */ -#define NX_DHCPV6_RFC_TIME_ZONE_OPTION 0x00000029UL /* RFC Option code for requesting Time zone. */ -#define NX_DHCPV6_RFC_DOMAIN_NAME 0x00000018UL /* RFC Option code for requesting domain name. */ - - -/* Define the DHCPv6 DUID types supported by the NetX DHCPv6 Server. */ - -typedef enum -{ -NX_DHCPV6_SERVER_DUID_TYPE_LINK_TIME = 1, -NX_DHCPV6_SERVER_DUID_TYPE_VENDOR_ASSIGNED, -NX_DHCPV6_SERVER_DUID_TYPE_LINK_ONLY - -} NX_DHCPV6_DUID_TYPE_SERVER; - -/* Define constants for denoting server vs client DUIDs. */ - -#define NX_DHCPV6_SERVER_DUID_TYPE 1 -#define NX_DHCPV6_CLIENT_DUID_TYPE 2 - -/* Define approximate time since Jan 1, 2000 for computing DUID time. This will form the - basis for the DUID time ID field. */ - -#define SECONDS_SINCE_JAN_1_2000_MOD_32 2563729999UL - - -/* Define the Hardware types. */ -#define NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET 1 -#define NX_DHCPV6_SERVER_HARDWARE_TYPE_EUI_64 27 - -/* NX_DHCPV6_HW_TYPE_IEEE_802 is defined as 1 to indicate Ethernet hardware type in old releases, for backward compatibility. - - Note: NX_DHCPV6_HW_TYPE_IEEE_802 will be deprecated by NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET - in future releases, should use above symbols to define hardware types. -*/ -#define NX_DHCPV6_HW_TYPE_IEEE_802 1 - - -/* Define the symbol for a static IP address lease, e.g. infinity. */ - -#define NX_DHCPV6_INFINTY_LEASE 0xFFFFFFFF - - -/* Define the DHCPv6 Message Types. */ - -#define NX_DHCPV6_MESSAGE_TYPE_DHCPSILENT 0 -#define NX_DHCPV6_MESSAGE_TYPE_SOLICIT 1 -#define NX_DHCPV6_MESSAGE_TYPE_ADVERTISE 2 -#define NX_DHCPV6_MESSAGE_TYPE_REQUEST 3 -#define NX_DHCPV6_MESSAGE_TYPE_CONFIRM 4 -#define NX_DHCPV6_MESSAGE_TYPE_RENEW 5 -#define NX_DHCPV6_MESSAGE_TYPE_REBIND 6 -#define NX_DHCPV6_MESSAGE_TYPE_REPLY 7 -#define NX_DHCPV6_MESSAGE_TYPE_RELEASE 8 -#define NX_DHCPV6_MESSAGE_TYPE_DECLINE 9 -#define NX_DHCPV6_MESSAGE_TYPE_RECONFIGURE 10 -#define NX_DHCPV6_MESSAGE_TYPE_INFORM_REQUEST 11 - - -/* Define the DHCPv6 Options. */ - -#define NX_DHCPV6_OP_DUID_CLIENT 1 /* Client DUID (DHCP unique identifier) */ -#define NX_DHCPV6_OP_DUID_SERVER 2 /* Server DUID (DHCP unique identifier) */ -#define NX_DHCPV6_OP_IA_NA 3 /* Identity association for non temporary addresses */ -#define NX_DHCPV6_OP_IA_TA 4 /* Identity association for temporary addresses */ -#define NX_DHCPV6_OP_IA_ADDRESS 5 /* Address associated with IA_NA or IA_TA */ -#define NX_DHCPV6_OP_OPTION_REQUEST 6 /* Identifies a list of options */ -#define NX_DHCPV6_OP_PREFERENCE 7 /* Server's means of affecting Client choice of servers. */ -#define NX_DHCPV6_OP_ELAPSED_TIME 8 /* Duration of Client exchange with DHCPv6 server */ -#define NX_DHCPV6_OP_RELAY_MESSAGE 9 /* Not in use in NetX DHCPV6 */ -#define NX_DHCPV6_OP_AUTHENTICATION 11 /* Not in use in NetX DHCPV6 */ -#define NX_DHCPV6_OP_SERVER_UNICAST 12 /* Server ok's allowing the client to address it in Unicast */ -#define NX_DHCPV6_OP_OPTION_STATUS 13 /* Option request status. */ -#define NX_DHCPV6_OP_RAPID_COMMIT 14 /* Option requesting exchange of two DHCPv6 packets to assign address */ - - -/* Define the DHCPv6 Client states */ - -#define NX_DHCPV6_STATE_BOUND 1 /* Client not known to be bound to an IP address. */ -#define NX_DHCPV6_STATE_UNBOUND 2 /* Client is bound to an IP address (not necessarily by this server). */ - - -/* Define DHCPv6 event flags. These events are processed by the Server DHCPv6 thread. */ - -#define NX_DHCPV6_ALL_EVENTS 0xFFFFFFFFUL /* All Server DHCPv6 event flags */ -#define NX_DHCPV6_SERVER_RECEIVE_EVENT 0x00000001UL /* Packet received on the DHCPv6 server queue. */ -#define NX_DHCPV6_IP_LEASE_CHECK_PERIODIC_EVENT 0x00000008UL /* Time keeper to check for expiration on leased IP addresses. */ -#define NX_DHCPV6_CHECK_SESSION_PERIODIC_EVENT 0x00000004UL /* Time keeper to check if each session with active client has timed out. */ - - -/* Define DHCPv6 client and server ports. */ - -#define NX_DHCPV6_SERVER_UDP_PORT 547 -#define NX_DHCPV6_CLIENT_UDP_PORT 546 - - -/* Define error codes from DHCPv6 API. */ - -#define NX_DHCPV6_ALREADY_STARTED 0xE91 /* DHCPv6 already started when API called to start it. */ -#define NX_DHCPV6_NOT_STARTED 0xE92 /* DHCPv6 was not started when API was called */ -#define NX_DHCPV6_PARAM_ERROR 0xE93 /* Invalid non pointer input to API */ -#define NX_DHCPV6_INVALID_DEVICE_MAC_ADDRESS 0xE94 /* DHCPv6 server device mac address unknown or undefined */ -#define NX_DHCPV6_INVALID_INTERFACE_IP_ADDRESS 0xE95 /* DHCPv6 server interface global IP address unknown or undefined */ -#define NX_DHCPV6_INVALID_INTERFACE_LL_ADDRESS 0xE96 /* DHCPv6 server interface link local address unknown or undefined */ -#define NX_DHCPV6_INVALID_GLOBAL_INDEX 0xE97 /* DHCPv6 global address index not set */ -#define NX_DHCPV6_BAD_SERVER_DUID 0xE98 /* Invalid or inappropriate server DUID (Should not be in some DHCPv6 message types). */ -#define NX_DHCPV6_MESSAGE_DUID_MISSING 0xE99 /* Received a message type missing server or client DUID. */ -#define NX_DHCPV6_INVALID_INTERFACE_INDEX 0xEBC /* Specified interface does not exist for the DHCPv6 server instance */ -#define NX_DHCPV6_INVALID_IANA_TIME 0xEA0 /* Client IA-NA option T1 vs T2 address lease time is invalid. */ -#define NX_DHCPV6_IANA_OPTION_MISSING 0xEA1 /* Received IA address option not belonging to an IA block */ -#define NX_DHCPV6_NO_SERVER_DUID 0xEA2 /* No server DUID detected; DHCPv6 server cannot start without one */ -#define NX_DHCPV6_INVALID_IANA_DATA 0xEA3 /* Client IA-NA option block has bad syntax or missing data */ -#define NX_DHCPV6_INVALID_IA_DATA 0xEA5 /* Server IA address option block has bad syntax or missing data */ -#define NX_DHCPV6_INVALID_IA_TIME 0xEA6 /* Server IA option preferred vs valid lease time is invalid. */ -#define NX_DHCPV6_NO_ASSIGNABLE_ADDRESSES 0xEA7 /* Server created with no assignable addresses. */ -#define NX_DHCPV6_ADDRESS_NOT_FOUND 0xEA8 /* Client address not found in server lease table. */ -#define NX_DHCPV6_OPTION_BLOCK_INCOMPLETE 0xEA9 /* Empty option block data; either zero length or zero option parsed. */ -#define NX_DHCPV6_INVALID_OPTION_DATA 0xEAA /* Server received option data with missing data or bad syntax */ -#define NX_DHCPV6_ILLEGAL_MESSAGE_TYPE 0xEB1 /* Received invalid message request e.g. RENEW (server should discard), */ -#define NX_DHCPV6_PROCESSING_ERROR 0xEB5 /* Invalid Client packet with DHCPv6 format or packet size */ -#define NX_DHCPV6_INSUFFICIENT_PACKET_PAYLOAD 0xEB6 /* Server DHCPv6 reply will not fit in packet pool packet buffer. */ -#define NX_DHCPV6_INVALID_DATA_SIZE 0xEB7 /* Attempting to parse too large a data object from DHCPv6 request. */ -#define NX_DHCPV6_TABLE_FULL 0xEC4 /* Server table (e.g. Client records or IP address leases) is full. */ -#define NX_DHCPV6_INVALID_IP_ADDRESS 0xECB /* Invalid IP address e.g. null address received or obtained from client record. */ -#define NX_DHCPV6_INVALID_DUID 0xECC /* Invalid DUID received from client or retrieved from memory. */ -#define NX_DHCPV6_CLIENT_RECORD_NOT_FOUND 0xECF /* Unable to find client in Client records table. */ -#define NX_DHCPV6_TIMER_INTERNAL_ERROR 0xED4 /* Problem setting or accessing real time clock server for DUID time field. */ -#define NX_DHCPV6_INVALID_VENDOR_DATA 0xED5 /* Vendor data invalid (ID is too long, null data etc). */ - - -/* Define the DHCPv6 status codes. */ - -#define NX_DHCPV6_STATUS_SUCCESS 0 /* Client request granted. */ -#define NX_DHCPV6_STATUS_UNSPECIFIED 1 /* Failure, reason unspecified; */ -#define NX_DHCPV6_STATUS_NO_ADDRS_AVAILABLE 2 /* Server has no addresses available to assign to the IA(s) */ -#define NX_DHCPV6_STATUS_NO_BINDING 3 /* Client record (binding) unavailable or not possible */ -#define NX_DHCPV6_STATUS_NOT_ON_LINK 4 /* Address prefix not appropriate for client domain */ -#define NX_DHCPV6_STATUS_USE_MULTICAST 5 /* Server informs client to use the All_DHCP_Relay_Agents_and_Servers address. */ - - -/* Define the server messages for IANA status codes. Note that these - messages must be shorter than the NX_DHCPV6_STATUS_MESSAGE_MAX - option defined for the client IANA status option. -*/ -#ifndef NX_DHCPV6_STATUS_MESSAGE_SUCCESS -#define NX_DHCPV6_STATUS_MESSAGE_SUCCESS "IA OPTION GRANTED" -#endif - -#ifndef NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED -#define NX_DHCPV6_STATUS_MESSAGE_UNSPECIFIED "IA OPTION NOT GRANTED-FAILURE UNSPECIFIED" -#endif - -#ifndef NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE -#define NX_DHCPV6_STATUS_MESSAGE_NO_ADDRS_AVAILABLE "IA OPTION NOT GRANTED-NO ADDRESSES AVAILABLE" -#endif - - -#ifndef NX_DHCPV6_STATUS_MESSAGE_NO_BINDING -#define NX_DHCPV6_STATUS_MESSAGE_NO_BINDING "IA OPTION NOT GRANTED-INVALID CLIENT REQUEST" -#endif - - -#ifndef NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK -#define NX_DHCPV6_STATUS_MESSAGE_NOT_ON_LINK "IA OPTION NOT GRANTED-CLIENT NOT ON LINK" -#endif - - -#ifndef NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST -#define NX_DHCPV6_STATUS_MESSAGE_USE_MULTICAST "IA OPTION NOT GRANTED-CLIENT MUST USE MULTICAST" -#endif - - -/* Define the wait option on receiving packets on the DHCPv6 server queue. This - is on a receive notify callback, so there need not be any wait involved. */ - -#ifndef NX_DHCPV6_PACKET_WAIT_OPTION -#define NX_DHCPV6_PACKET_WAIT_OPTION NX_IP_PERIODIC_RATE -#endif - -/* Note the DHCPv6 server only supports the DNS server option in the current release. */ - - - -/* Define the DHCPv6 Server application stack size. This is more than enough - for most DHCPv6 Server applications. */ - -#ifndef NX_DHCPV6_SERVER_THREAD_STACK_SIZE -#define NX_DHCPV6_SERVER_THREAD_STACK_SIZE 4096 -#endif - - -/* Define the DHCPv6 Server thread priority. */ - -#ifndef NX_DHCPV6_SERVER_THREAD_PRIORITY -#define NX_DHCPV6_SERVER_THREAD_PRIORITY 2 -#endif - - -/* Define the timer interval in seconds for checking Client lease time expirations. */ - -#ifndef NX_DHCPV6_IP_LEASE_TIMER_INTERVAL -#define NX_DHCPV6_IP_LEASE_TIMER_INTERVAL (60) -#endif - - -/* Define the timer interval in seconds for the session duration timer. */ - -#ifndef NX_DHCPV6_SESSION_TIMER_INTERVAL -#define NX_DHCPV6_SESSION_TIMER_INTERVAL (3) -#endif - - -/* Define the session time out in seconds. This is the timer for how long the server has not - received a client response. */ - -#ifndef NX_DHCPV6_SESSION_TIMEOUT -#define NX_DHCPV6_SESSION_TIMEOUT (20) -#endif - -/* Define the private ID of the vendor DUID tuple. This is a 32 bit word. */ - -#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID -#define NX_DHCPV6_SERVER_DUID_VENDOR_PRIVATE_ID 0x12345678 -#endif - - -/* Define the size limit on the Vendor ID buffer. */ - -#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH -#define NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH 48 -#endif - - -/* Define the vendor ID. The server must have this data to create its DUID required for sending - responses to the DHCPv6 client. */ - -#ifndef NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID -#define NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_ID "abcdeffghijklmnopqrstuvwxyz" -#endif - - -/* Define parameters for the server DUID */ - -/* Define the server DUID type. The most common are link layer, based on mac address, - and link layer-time which is based on mac address and current time. */ - -#ifndef NX_DHCPV6_SERVER_DUID_TYPE -#define NX_DHCPV6_SERVER_DUID_TYPE NX_DHCPV6_DUID_TYPE_LINK_TIME -#endif - - -/* Default DUID hardware type to Ethernet */ - -#ifndef NX_DHCPV6_SERVER_HW_TYPE -#define NX_DHCPV6_SERVER_HW_TYPE NX_DHCPV6_SERVER_HARDWARE_TYPE_ETHERNET -#endif - - -/* Define the preference option pref-value. When multiple DHCPv6 servers exist, this - enables a server to tell the client which preference to place on this server. The higher - the value the greater the preference. A value of 255 received by a DHCPv6 - client will instruct the client to choose this DHPCv6 server immediately, rather - than wait for the full round trip time out option specified in RFC 3315. RFC 3315 - sect 17.2.2 requires the server set this value to zero by default*/ - -#ifndef NX_DHCPV6_PREFERENCE_VALUE -#define NX_DHCPV6_PREFERENCE_VALUE 0 -#endif - - -/* Define the maximum options to extract from a client message. This makes - no assumptions about the packet size limitations which the host application - must ensure can handle both the client request and the server reply. */ - -#ifndef NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS -#define NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS 6 -#endif - - -/* Set the default T1 time, which is when the Client should begin renewing its IP address, - for leased IP addresses in seconds. RFC 3315 recommends - T1 is 0.5 the value of the preferred lifetime. */ - -#ifndef NX_DHCPV6_DEFAULT_T1_TIME -#define NX_DHCPV6_DEFAULT_T1_TIME (2000) -#endif - - -/* Set the default T2 time, which is when the Client should begin renewing its IP address, - assuming renewal attempts failed, for leased IP addresses in seconds. - T2 must be greater than T2 and less than the value of the preferred lifetime. */ - -#ifndef NX_DHCPV6_DEFAULT_T2_TIME -#define NX_DHCPV6_DEFAULT_T2_TIME (3000) -#endif - - -/* Set the default preferred lifetime for leased IP addresses in seconds, which is - when the Client IP address becomes deprecated. A value of zero in - this field indicates that the server leaves it to the - client discretion to renew its IP address lease. */ - -#ifndef NX_DHCPV6_DEFAULT_PREFERRED_TIME -#define NX_DHCPV6_DEFAULT_PREFERRED_TIME (2 * NX_DHCPV6_DEFAULT_T1_TIME) -#endif - - -/* Set the default valid lifetime in seconds for leased IP addresses in secs, which is when - the Client IP address becomes obsolete. A value of zero in this field indicates - that the server leaves it to the client discretion to renew its IP address lease. - The valid time must be greater than the preferred time. */ - -#ifndef NX_DHCPV6_DEFAULT_VALID_TIME -#define NX_DHCPV6_DEFAULT_VALID_TIME (2 * NX_DHCPV6_DEFAULT_PREFERRED_TIME) -#endif - - - -/* Define maximum size for server messages in status option. */ - -#ifndef NX_DHCPV6_STATUS_MESSAGE_MAX -#define NX_DHCPV6_STATUS_MESSAGE_MAX 100 -#endif - - -/* Define the max number of IPv6 address leases available to lease. */ - -#ifndef NX_DHCPV6_MAX_LEASES -#define NX_DHCPV6_MAX_LEASES 100 -#endif - - -/* Define the max number of clients the server can assign leases to at any given time. - These are clients either already leasing an IPv6 address or currently requesting one. - Note: there are more addresses than clients in the event the client declines an address - or one assigned is already in use. The NetX DHCPv6 server currently only supports - one IP address leased to each client. */ - -#ifndef NX_DHCPV6_MAX_CLIENTS -#define NX_DHCPV6_MAX_CLIENTS 120 -#endif - -/* Define the wait option in timer ticks for DHCPv6 server packet allocations. */ - -#ifndef NX_DHCPV6_PACKET_TIME_OUT -#define NX_DHCPV6_PACKET_TIME_OUT (3 * NX_DHCPV6_SERVER_TICKS_PER_SECOND) -#endif - - -/* Define the DHCPv6 packet size. Should be large enough to hold IP and UDP headers, - plus DHCPv6 data runs about 200 - 300 bytes for a typical exchange. */ - -#ifndef NX_DHCPV6_PACKET_SIZE -#define NX_DHCPV6_PACKET_SIZE 500 -#endif - - -/* Define the DHCPv6 packet memory area. Packet pool size depends on client traffic and - available network bandwidth. */ - -#ifndef NX_DHCPV6_PACKET_POOL_SIZE -#define NX_DHCPV6_PACKET_POOL_SIZE (10 * NX_DHCPV6_PACKET_SIZE) -#endif - - -/* Define UDP socket type of service. */ - -#ifndef NX_DHCPV6_TYPE_OF_SERVICE -#define NX_DHCPV6_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - - -/* Define the UDP socket fragment option. */ - -#ifndef NX_DHCPV6_FRAGMENT_OPTION -#define NX_DHCPV6_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -/* Define the number of routers a UDP packet passes before it is discarded. */ - -#ifndef NX_DHCPV6_TIME_TO_LIVE -#define NX_DHCPV6_TIME_TO_LIVE 0x80 -#endif - -/* Define the stored packets in the UDP server socket queue. */ - -#ifndef NX_DHCPV6_QUEUE_DEPTH -#define NX_DHCPV6_QUEUE_DEPTH 5 -#endif - - -/* Define the Identity Association Internet Address option structure */ -typedef struct NX_DHCPV6_SERVER_IA_ADDRESS_STRUCT -{ - - USHORT nx_op_code; /* IA internet address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ - NXD_ADDRESS nx_global_address; /* Assigned Host IPv6 address */ - ULONG nx_preferred_lifetime; /* Server's preference for IPv6 address T1 life time for itself */ - ULONG nx_valid_lifetime; /* Server's assigned valid time for T2 for any server */ - -} NX_DHCPV6_SERVER_IA_ADDRESS; - -/* Define the Option status structure */ -typedef struct NX_DHCPV6_SERVER_IANA_STATUS_STRUCT -{ - - USHORT nx_op_code; /* IA address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ - USHORT nx_status_code; /* Server status (reply) to client request */ - CHAR nx_status_message[NX_DHCPV6_STATUS_MESSAGE_MAX]; - /* Buffer containing server status messages */ -} NX_DHCPV6_SERVER_IANA_STATUS; - - -/* Define the Preference Option structure */ -typedef struct NX_DHCPV6_SERVER_PREFERENCE_STRUCT -{ - - USHORT nx_op_code; /* IA address option code is 5 */ - USHORT nx_option_length; /* Length of the IA address option data = 24 not including length and op code field*/ - USHORT nx_pref_value; /* Assigned Host IPv6 address */ - -} NX_DHCPV6_SERVER_PREFERENCE; - - -/* Define the Identity Association for Permanent ("Non Temporary" in RFC) address */ - -typedef struct NX_DHCPV6_SERVER_IA_NA_STRUCT -{ - - USHORT nx_op_code; /* IA NA address option code is 3 */ - USHORT nx_option_length; /* 12 + length of variable length fields in IA_NA option . */ - ULONG nx_IA_NA_id; /* IANA identifier; must be unique among all client IANA's. Must be the same on restart per IANA */ - ULONG nx_T1; /* Time client can extend time before address lifetime expires from the server it got it from; applies to all addresses in IA_NA. */ - ULONG nx_T2; /* Same as T1 except this is when the client will request REBIND from another server. */ - -} NX_DHCPV6_SERVER_IA_NA; - - -/* Define DHCPv6 Unique Identifier (DUID); both Client and Server must send messages with their own DUID. */ - -typedef struct NX_DHCPV6_SVR_DUID_STRUCT -{ - - USHORT nx_op_code; /* Client DUID option code is 1; Server DUID code is 2 */ - USHORT nx_option_length; /* Option length = 14 not including length and op code field; */ - USHORT nx_duid_type; /* 3 main types: hw; hw + time; vendor assigned ID (not supported here); requires DUID be stored in non volatile storage */ - USHORT nx_hardware_type; /* Only if LL/LLT type. Hardware type specified by IANA/RFC 826 e.g. IEEE 802; network byte order */ - ULONG nx_duid_time; /* Only if LLT type. Time based on when DUID generated; network byte order. */ - ULONG nx_duid_enterprise_number; /* Only if vendor assigned (enterprise) DUID */ - UCHAR nx_duid_private_identifier[NX_DHCPV6_SERVER_DUID_VENDOR_ASSIGNED_LENGTH]; - USHORT nx_link_layer_address_msw; /* Only if LL/LLT type. Pointer to Unique link layer address - most significant word (2 bytes)*/ - ULONG nx_link_layer_address_lsw; /* Only if LL/LLT type. Pointer to Unique link layer address - least significant word (4 bytes) */ - -} NX_DHCPV6_SVR_DUID; - - -/* Define the elapsed time option structure. This contains the length of the Client Server session. */ - -typedef struct NX_DHCPV6_SERVER_ELAPSED_TIME_STRUCT -{ - - USHORT nx_op_code; /* Elapsed time option code = 8 not including length and op code field. */ - USHORT nx_option_length; /* Length of time data = 2. */ - USHORT nx_session_time; /* Time of DHCP session e.g. first msg elapsed time is zero. */ - -} NX_DHCPV6_SERVER_ELAPSED_TIME; - - -/* Define the option request structure. This is how the Client requests information other than global IP address. - It can ask for domain name, DNS server, time zone, time server and other options. */ - -typedef struct NX_DHCPV6_SERVER_OPTIONREQUEST_STRUCT -{ - USHORT nx_op_code; /* Option Request code = 6*/ - USHORT nx_option_length; /* Length in bytes of option data = 2 * number of requests */ - USHORT nx_op_request[NX_DHCPV6_MAX_OPTION_REQUEST_OPTIONS]; - /* List of option request options e.g. DNS server */ - -} NX_DHCPV6_SERVER_OPTIONREQUEST; - -/* Define the Client DHCPv6 structure containing the DHCPv6 Client record (DHCPv6 status, server DUID etc). */ - -typedef struct NX_DHCPV6_CLIENT_STRUCT -{ - - ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ - ULONG nx_dhcpv6_message_xid; /* Message transaction ID (3 bytes)*/ - UCHAR nx_dhcpv6_state; /* The current state of the DHCPv6 Client */ - UINT nx_dhcpv6_message_type; /* DHCPv6 message type most recently received from client. */ - UINT nx_dhcpv6_response_back_from_server; /* Response server will send back to client based on previous client message */ - NX_DHCPV6_SVR_DUID nx_dhcpv6_client_duid; /* Client DUID parsed from client DHCPv6 requests */ - NX_DHCPV6_SVR_DUID nx_dhcpv6_server_duid; /* Server DUID parsed from client DHCPv6 requests */ - ULONG nx_dhcpv6_client_session_time; /* Duration of client server session. Used to determine if client quit on the session. */ - UINT nx_dhcpv6_rapid_commit_status; /* Client status on rapid commit (set to true if requests and server approves). */ - NX_DHCPV6_SERVER_ELAPSED_TIME - nx_dhcpv6_elapsed_time; /* Time duration of the current DHCP msg exchange between Client and Server. */ - NX_DHCPV6_SERVER_IA_NA nx_dhcpv6_iana; /* Identity Association for non temp address - must be stored in non volatile memory */ - NX_DHCPV6_SERVER_IA_ADDRESS - nx_dhcpv6_ia; /* Client internet address option */ - NX_DHCPV6_SERVER_OPTIONREQUEST - nx_dhcpv6_option_request; /* Set of request options in Solicit, Renew, Confirm or Rebind message types. */ - NX_DHCPV6_SERVER_IANA_STATUS - nx_dhcpv6_iana_status; /* Status option set by the server for client IANA */ - NX_DHCPV6_SERVER_PREFERENCE - nx_dhcpv6_preference; /* Preference option set by the server */ - ULONG nx_dhcpv6_IP_lease_time_accrued ; /* Time remaining on the Client IP address lease. */ - NXD_ADDRESS nx_dhcp_source_ip_address; /* Source IP of the client DHCP message. */ - NXD_ADDRESS nx_dhcp_destination_ip_address; /* Destination IP of the client DHCP message. */ - -} NX_DHCPV6_CLIENT; - -/* Define the DHCPv6 server interface IP address table. */ - -typedef struct NX_DHCPV6_ADDRESS_LEASE_STRUCT -{ - - NXD_ADDRESS nx_dhcpv6_lease_IP_address; /* Address to assign */ - ULONG nx_dhcpv6_lease_T1_lifetime; /* T1 value set if assigned to client */ - ULONG nx_dhcpv6_lease_T2_lifetime; /* T2 value set if assigned to client */ - ULONG nx_dhcpv6_lease_valid_lifetime; /* valid lifetime set if assigned to client */ - ULONG nx_dhcpv6_lease_preferred_lifetime; /* preferred lifetime set if assigned to client */ - NX_DHCPV6_CLIENT *nx_dhcpv6_lease_assigned_to; /* Client DUID assigned the address */ - -}NX_DHCPV6_ADDRESS_LEASE; - - -/* Define the Server DHCPv6 structure containing the Client tables and assignable IP address tables. */ - -typedef struct NX_DHCPV6_SERVER_STRUCT -{ - ULONG nx_dhcpv6_id; /* DHCPv6 Structure ID */ - CHAR *nx_dhcpv6_server_name; /* DHCPv6 name supplied at create */ - NX_IP *nx_dhcpv6_ip_ptr; /* The associated IP pointer for this DHCPV6 instance */ - UINT nx_dhcpv6_server_interface_index; /* Index indicating interface DHCPv6 requests accepted */ - UINT nx_dhcpv6_server_ga_address_index; /* Global address index of the DHCPv6 server*/ - NX_DHCPV6_SVR_DUID nx_dhcpv6_server_duid; /* DUID by which server identifies itself to clients */ - NX_DHCPV6_CLIENT nx_dhcpv6_clients[NX_DHCPV6_MAX_CLIENTS]; /* list of clients leased an IPv6 address */ - NX_DHCPV6_ADDRESS_LEASE nx_dhcpv6_lease_list[NX_DHCPV6_MAX_LEASES]; /* List of IP addresses available for DHCPv6 Clients */ - UINT nx_dhcpv6_assignable_addresses; /* Number of assignable addresses the server starts with. */ - UINT nx_dhcpv6_server_multicast_only; /* Indicate if the client should send requests using all servers multicast address */ - NX_UDP_SOCKET nx_dhcpv6_server_socket; /* UDP socket for communicating with DHCPv6 clients */ - TX_MUTEX nx_dhcpv6_server_mutex; /* Mutex protection of server control block */ - TX_TIMER nx_dhcpv6_lease_timer; /* Timer for tracking IP lease expiration */ - TX_TIMER nx_dhcpv6_session_timer; /* Server session duration timer */ - TX_THREAD nx_dhcpv6_server_thread; /* DHCPv6 Server processing thread */ - NX_PACKET_POOL *nx_dhcpv6_packet_pool_ptr; /* Pointer to packet pool for sending DHCPV6 messages */ - TX_EVENT_FLAGS_GROUP nx_dhcpv6_server_timer_events; /* Message queue for IP lease and session timer events. */ - UINT nx_dhcpv6_server_running; /* Status of dhcpv6 server; idle (NX_FALSE) or running (NX_TRUE) */ - NXD_ADDRESS nx_dhcpv6_dns_ip_address; /* DHCP server DNS Server Address in message to DHCP Client */ - - /* Define a handler for receiving a DECLINE or RELEASE message. */ - VOID (*nx_dhcpv6_IP_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message_type); - /* Define a handler for Option Request options. */ - VOID (*nx_dhcpv6_server_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index); - - /* Define a extended handler for Option Request options. */ - VOID (*nx_dhcpv6_server_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index, UINT available_payload); - -} NX_DHCPV6_SERVER; - -#ifndef NX_DHCPV6_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map DHCP API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - - -#define nx_dhcpv6_set_server_duid _nx_dhcpv6_set_server_duid -#define nx_dhcpv6_create_dns_address _nx_dhcpv6_create_dns_address -#define nx_dhcpv6_create_ip_address_range _nx_dhcpv6_create_ip_address_range -#define nx_dhcpv6_add_ip_address_lease _nx_dhcpv6_add_ip_address_lease -#define nx_dhcpv6_add_client_record _nx_dhcpv6_add_client_record -#define nx_dhcpv6_retrieve_client_record _nx_dhcpv6_retrieve_client_record -#define nx_dhcpv6_retrieve_ip_address_lease _nx_dhcpv6_retrieve_ip_address_lease -#define nx_dhcpv6_reserve_ip_address_range _nx_dhcpv6_reserve_ip_address_range -#define nx_dhcpv6_server_create _nx_dhcpv6_server_create -#define nx_dhcpv6_server_delete _nx_dhcpv6_server_delete -#define nx_dhcpv6_server_resume _nx_dhcpv6_server_resume -#define nx_dhcpv6_server_suspend _nx_dhcpv6_server_suspend -#define nx_dhcpv6_server_start _nx_dhcpv6_server_start -#define nx_dhcpv6_server_interface_set _nx_dhcpv6_server_interface_set -#define nx_dhcpv6_server_option_request_handler_set _nx_dhcpv6_server_option_request_handler_set - -#else - -/* Services with error checking. */ - -#define nx_dhcpv6_set_server_duid _nxe_dhcpv6_set_server_duid -#define nx_dhcpv6_create_dns_address _nxe_dhcpv6_create_dns_address -#define nx_dhcpv6_create_ip_address_range _nxe_dhcpv6_create_ip_address_range -#define nx_dhcpv6_add_ip_address_lease _nxe_dhcpv6_add_ip_address_lease -#define nx_dhcpv6_add_client_record _nxe_dhcpv6_add_client_record -#define nx_dhcpv6_retrieve_client_record _nxe_dhcpv6_retrieve_client_record -#define nx_dhcpv6_retrieve_ip_address_lease _nxe_dhcpv6_retrieve_ip_address_lease -#define nx_dhcpv6_reserve_ip_address_range _nxe_dhcpv6_reserve_ip_address_range -#define nx_dhcpv6_server_create _nxe_dhcpv6_server_create -#define nx_dhcpv6_server_delete _nxe_dhcpv6_server_delete -#define nx_dhcpv6_server_resume _nxe_dhcpv6_server_resume -#define nx_dhcpv6_server_suspend _nxe_dhcpv6_server_suspend -#define nx_dhcpv6_server_start _nxe_dhcpv6_server_start -#define nx_dhcpv6_server_interface_set _nxe_dhcpv6_server_interface_set -#define nx_dhcpv6_server_option_request_handler_set _nxe_dhcpv6_server_option_request_handler_set -#endif /* NX_DISABLE_ERROR_CHECKING */ - - -/* Define the prototypes accessible to the application software. */ -UINT nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); -UINT nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); -UINT nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); -UINT nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetimeo); -UINT nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, - ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, - ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); -UINT nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, - ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, - ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); -UINT nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); -UINT nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); -UINT nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, - VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), - VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); -UINT nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); -UINT nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, - UCHAR *buffer_ptr, UINT *index, UINT available_payload)); - -#else - -/* DHCP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); -UINT _nx_dhcpv6_set_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw, ULONG time); -UINT _nxe_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); -UINT _nx_dhcpv6_create_dns_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *dns_ipv6_address); -UINT _nxe_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); -UINT _nx_dhcpv6_create_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_added); -UINT _nxe_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); -UINT _nx_dhcpv6_reserve_ip_address_range(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NXD_ADDRESS *start_ipv6_address, NXD_ADDRESS *end_ipv6_address, UINT *addresses_reserved); -UINT _nxe_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime); -UINT _nx_dhcpv6_add_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG T1, ULONG T2, ULONG valid_lifetime, ULONG preferred_lifetime); -UINT _nxe_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, - ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, - ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); -UINT _nx_dhcpv6_add_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG message_xid, NXD_ADDRESS *client_address, UINT client_state, - ULONG IP_lease_time_accrued , ULONG valid_lifetime, UINT duid_type, UINT duid_hardware, ULONG physical_address_msw, - ULONG physical_address_lsw, ULONG duid_time, ULONG duid_vendor_number, UCHAR *duid_vendor_private, UINT duid_private_length); -UINT _nxe_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, - ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, - ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); -UINT _nx_dhcpv6_retrieve_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, ULONG *message_xid, NXD_ADDRESS *client_address, UINT *client_state, - ULONG *IP_lease_time_accrued , ULONG *valid_lifetime, UINT *duid_type, UINT *duid_hardware, ULONG *physical_address_msw, - ULONG *physical_address_lsw, ULONG *duid_time, ULONG *duid_vendor_number, UCHAR *duid_vendor_private, UINT *duid_private_length); -UINT _nxe_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); -UINT _nx_dhcpv6_retrieve_ip_address_lease(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT table_index, NXD_ADDRESS *lease_IP_address, ULONG *T1, ULONG *T2, ULONG *valid_lifetime, ULONG *preferred_lifetime); -UINT _nxe_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, - VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), - VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); -UINT _nx_dhcpv6_server_create(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_IP *ip_ptr, CHAR *name_ptr, NX_PACKET_POOL *packet_pool_ptr, VOID *stack_ptr, ULONG stack_size, - VOID (*dhcpv6_address_declined_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UINT message), - VOID (*dhcpv6_option_request_handler)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, UCHAR *buffer_ptr, UINT *index)); -UINT _nxe_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nx_dhcpv6_server_delete(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nxe_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nx_dhcpv6_server_resume(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nxe_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nx_dhcpv6_server_start(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nxe_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nx_dhcpv6_server_suspend(NX_DHCPV6_SERVER *dhcpv6_server_ptr); -UINT _nxe_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); -UINT _nx_dhcpv6_server_interface_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT iface_index, UINT ga_address_index); -UINT _nxe_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, - UCHAR *buffer_ptr, UINT *index, UINT available_payload)); -UINT _nx_dhcpv6_server_option_request_handler_set(NX_DHCPV6_SERVER *dhcpv6_server_ptr, - VOID (*dhcpv6_option_request_handler_extended)(struct NX_DHCPV6_SERVER_STRUCT *dhcpv6_server_ptr, UINT option_request, - UCHAR *buffer_ptr, UINT *index, UINT available_payload)); - - -#endif /* NX_DHCPV6_SOURCE_CODE */ - - -UINT _nx_dhcpv6_add_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid_ptr, UCHAR *buffer_ptr, UINT *index, UINT duid_type); -UINT _nx_dhcpv6_add_ia(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IA_ADDRESS *dhcpv6_ia_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_server_add_iana(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_iana_status(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SERVER_IANA_STATUS *iana_status_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_option_requests(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_add_preference(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *buffer_ptr, UINT *index); -UINT _nx_dhcpv6_assign_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr); -UINT _nx_dhcpv6_check_duids_same(NX_DHCPV6_SVR_DUID *dhcpv6_duid1_ptr, NX_DHCPV6_SVR_DUID *dhcpv6_duid2_ptr, UINT *matching); -UINT _nx_dhcpv6_clear_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); -UINT _nx_dhcpv6_create_server_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, UINT duid_type, UINT hardware_type, ULONG mac_address_msw, ULONG mac_address_lsw); -UINT _nx_dhcpv6_find_client_record_by_duid(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_SVR_DUID *duid_ptr, UINT *record_index, UINT add_on, ULONG message_xid, UINT *matching); -UINT _nx_dhcpv6_find_ip_address(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr, NX_DHCPV6_ADDRESS_LEASE **interface_address_ptr); -UINT _nx_dhcpv6_server_extract_packet_information(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT **dhcpv6_client_ptr, NX_PACKET *packet_ptr, - UINT iface_index, NXD_ADDRESS source_address, NXD_ADDRESS destination_address); -UINT _nx_dhcpv6_listen_for_messages(NX_DHCPV6_SERVER *dhcpv6_ptr); -UINT _nx_dhcpv6_prepare_iana_status(NX_DHCPV6_SERVER_IANA_STATUS *dhcpv6_status_ptr, UINT flag); -UINT _nx_dhcpv6_process_duid(NX_DHCPV6_SVR_DUID *duid_ptr, UINT duid_type, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_elapsed_time(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_server_process_ia(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length, UINT process_ia); -UINT _nx_dhcpv6_server_process_iana(NX_DHCPV6_CLIENT *dhcpv6_client_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_process_option_request(NX_DHCPV6_CLIENT *client_ptr, UCHAR *received_buffer, UINT length); -UINT _nx_dhcpv6_send_response_to_client(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); -VOID _nx_dhcpv6_server_lease_timeout_entry(ULONG dhcpv6_server_ptr_value); -VOID _nx_dhcpv6_server_thread_entry(ULONG ip_instance); -VOID _nx_dhcpv6_server_socket_receive_notify(NX_UDP_SOCKET *socket_ptr); -VOID _nx_dhcpv6_server_session_timeout_entry(ULONG dhcpv6_server_ptr_value); -UINT _nx_dhcpv6_update_client_record(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *from_client_ptr, NX_DHCPV6_CLIENT *to_client_ptr); -UINT _nx_dhcpv6_validate_client_message(NX_DHCPV6_SERVER *dhcpv6_server_ptr, NX_DHCPV6_CLIENT *dhcpv6_client_ptr); -UINT _nx_dhcpv6_server_utility_get_block_option_length(UCHAR *buffer_ptr, ULONG *option, ULONG *length); -UINT _nx_dhcpv6_server_utility_get_data(UCHAR *data, UINT size, ULONG *value); -INT _nx_dhcpv6_server_utility_time_randomize(void); - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_DHCPV6_SERVER_H */ - - diff --git a/protocol_handlers/dns/nxd_dns.c b/protocol_handlers/dns/nxd_dns.c deleted file mode 100644 index d5866bd2..00000000 --- a/protocol_handlers/dns/nxd_dns.c +++ /dev/null @@ -1,9907 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Domain Name System (DNS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_DNS_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_dns.h" -#include "stdio.h" -#include "string.h" -#include "nx_system.h" - -/* Define the resource record section. */ -#define NX_DNS_RR_ANSWER_SECTION 1 -#define NX_DNS_RR_AUTHORITY_SECTION 2 -#define NX_DNS_RR_ADDITIONAL_SECTION 3 - -/* Internal DNS functions. */ -static UINT _nx_dns_header_create(UCHAR *buffer_ptr, USHORT id, USHORT flags); -static UINT _nx_dns_new_packet_create(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, USHORT id, UCHAR *name, USHORT type); -static UINT _nx_dns_name_size_calculate(UCHAR *name); -static UINT _nx_dns_name_string_encode(UCHAR *ptr, UCHAR *name); -static UINT _nx_dns_name_string_unencode(NX_PACKET *packet_ptr, UCHAR *data, UCHAR *buffer, UINT buffer_size); -static USHORT _nx_dns_network_to_short_convert(UCHAR *ptr); -static ULONG _nx_dns_network_to_long_convert(UCHAR *ptr); -static UINT _nx_dns_question_add(NX_PACKET *packet_ptr, UCHAR *name, USHORT type); -static UCHAR * _nx_dns_resource_data_address_get(UCHAR *resource); -static UINT _nx_dns_resource_data_length_get(UCHAR *resource); -static UINT _nx_dns_resource_type_get(UCHAR *resource); -static UINT _nx_dns_resource_size_get(UCHAR *resource); -static VOID _nx_dns_short_to_network_convert(UCHAR *ptr, USHORT value); -#ifndef NX_DISABLE_IPV4 -static UINT _nx_dns_number_to_ascii_convert(UINT number, CHAR *buffstring); -#endif /* NX_DISABLE_IPV4 */ -static UINT _nx_dns_host_resource_data_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, - UINT *record_count, UINT lookup_type, ULONG wait_option); -static UINT _nx_dns_response_process(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); -static UINT _nx_dns_process_a_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count, UINT rr_location); -static UINT _nx_dns_process_aaaa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count, UINT rr_location); - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -static UINT _nx_dns_resource_name_real_size_calculate(UCHAR *data, UINT start); -static UINT _nx_dns_process_cname_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); -static UINT _nx_dns_process_txt_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); -static UINT _nx_dns_process_ns_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); -static UINT _nx_dns_process_mx_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); -static UINT _nx_dns_process_srv_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, UINT *record_count); -static UINT _nx_dns_process_soa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR *record_buffer, UINT buffer_size, UINT *record_count); -#endif - -#ifdef NX_DNS_CACHE_ENABLE -static UINT _nx_dns_name_match(UCHAR *src, UCHAR *dst, UINT length); -static UINT _nx_dns_cache_add_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr, NX_DNS_RR **insert_ptr); -static UINT _nx_dns_cache_find_answer(NX_DNS *dns_ptr, VOID *cache_ptr, UCHAR *query_name, USHORT query_type, UCHAR *buffer, UINT buffer_size, UINT *record_count); -static UINT _nx_dns_cache_delete_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr); -static UINT _nx_dns_cache_delete_rr_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr); -static UINT _nx_dns_cache_add_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_size, VOID **insert_ptr); -static UINT _nx_dns_cache_delete_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_len); -static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource); -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef FEATURE_NX_IPV6 -static VOID _nxd_dns_build_an_ipv6_question_string(NXD_ADDRESS *ip_address, UCHAR *buffer, UINT len); -#endif -static UINT _nx_dns_server_add_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -static UINT _nx_dns_server_remove_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -static UINT _nx_dns_server_get_internal(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *server_address); -static UINT _nx_dns_host_by_address_get_internal(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, - UINT host_name_buffer_size, ULONG wait_option); -static UINT _nx_dns_send_query_by_address(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server, UCHAR *ip_question, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -static UINT _nx_dns_send_query_get_rdata_by_name(NX_DNS *dns_ptr, NXD_ADDRESS *server_address, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, UINT *record_count, UINT dns_record_type, ULONG wait_option); - -/* static VOID _nx_dns_long_to_network_convert(UCHAR *ptr, ULONG value); */ -/* static UINT _nx_dns_resource_class_get(UCHAR *resource); */ -/* static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource); */ -/* static UINT _nx_dns_resource_name_get(UCHAR *buffer, UINT start, UCHAR *destination, UINT size); */ - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - -UCHAR lookup_end[] = "IN-ADDR.ARPA"; - -#ifdef NX_DNS_CACHE_ENABLE -static NX_DNS_RR temp_rr; -#endif /* NX_DNS_CACHE_ENABLE */ - -#if defined(NX_DNS_ENABLE_EXTENDED_RR_TYPES) || defined(NX_DNS_CACHE_ENABLE) -static UCHAR temp_string_buffer[NX_DNS_NAME_MAX + 1]; -#endif - -/* Record the temp host name,*/ -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -#define TEMP_SRV_BUFFER_SIZE (NX_DNS_NAME_MAX + 1 + sizeof (NX_DNS_SRV_ENTRY)) -#endif - -NX_DNS *_nx_dns_instance_ptr; - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS create function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* ip_ptr Pointer to IP instance */ -/* domain_name DNS name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_create Actual DNS create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id == NX_DNS_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS create service. */ - status = _nx_dns_create(dns_ptr, ip_ptr, domain_name); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a DNS instance for the specified IP. This */ -/* involves creating a UDP DNS socket, and a mutex for mutual exclusion*/ -/* of DNS requests, and binding the DNS socket to the appropriate port.*/ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* ip_ptr Pointer to IP instance */ -/* domain_name DNS name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_create Create DNS UDP socket */ -/* nx_udp_socket_delete Delete DNS UDP socket */ -/* nx_udp_socket_bind Bind DNS UDP socket to port */ -/* nx_udp_socket_unbind Unbind DNS UDP socket */ -/* tx_mutex_create Create a ThreadX mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name) -{ - -UINT status; - - /* If the host does intend to supply their own packet pool, create one here. */ -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - - /* Create the DNS packet pool. */ - status = nx_packet_pool_create(&(dns_ptr -> nx_dns_pool), "DNS Pool", NX_DNS_PACKET_PAYLOAD, - dns_ptr -> nx_dns_pool_area, NX_DNS_PACKET_POOL_SIZE); - - /* Check status of packet pool create. */ - if (status != NX_SUCCESS) - { - - /* Return an error. */ - return(NX_DNS_ERROR); - } - - /* Set an internal packet pool pointer to the newly created packet pool. */ - dns_ptr -> nx_dns_packet_pool_ptr = &dns_ptr -> nx_dns_pool; - -#endif - - /* Create the DNS UDP socket. */ - status = nx_udp_socket_create(ip_ptr, &(dns_ptr -> nx_dns_socket), "DNS Socket", - NX_DNS_TYPE_OF_SERVICE, NX_DNS_FRAGMENT_OPTION, NX_DNS_TIME_TO_LIVE, NX_DNS_QUEUE_DEPTH); - - /* Check status of socket create. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - - /* Delete the packet pool. */ - nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); -#endif - - /* Return the NetX error. */ - return(status); - } - - /* Bind the UDP socket to the DNS Client port. */ - status = nx_udp_socket_bind(&(dns_ptr -> nx_dns_socket), NX_ANY_PORT, TX_WAIT_FOREVER); - - /* Check status of socket bind. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - - /* Delete the packet pool. */ - nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); -#endif - - /* Delete the socket. */ - nx_udp_socket_delete(&(dns_ptr -> nx_dns_socket)); - - /* Return the NetX error. */ - return(status); - } - - /* Create a DNS mutex for multi-thread access protection. */ - status = tx_mutex_create(&dns_ptr -> nx_dns_mutex, "DNS Mutex", TX_NO_INHERIT); - - /* Check status of mutex create. */ - if (status != TX_SUCCESS) - { - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - - /* Delete the packet pool. */ - nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); -#endif - - /* Unbind the socket. */ - nx_udp_socket_unbind(&(dns_ptr -> nx_dns_socket)); - - /* Delete the socket. */ - nx_udp_socket_delete(&(dns_ptr -> nx_dns_socket)); - - /* Return the threadx error. */ - return(status); - } - - /* Save the IP structure pointer. */ - dns_ptr -> nx_dns_ip_ptr = ip_ptr; - dns_ptr -> nx_dns_domain = domain_name; - - /* Initialize the rest of the DNS structure. */ - dns_ptr -> nx_dns_id = NX_DNS_ID; - - /* Clear memory except for client DNS server array. */ - memset(&dns_ptr -> nx_dns_server_ip_array[0], 0, NX_DNS_MAX_SERVERS * sizeof(NXD_ADDRESS)); - - /* Setup the maximum retry. */ - dns_ptr -> nx_dns_retries = NX_DNS_MAX_RETRIES; - - /* Is the client's network gateway also the primary DNS server? */ -#if defined(NX_DNS_IP_GATEWAY_AND_DNS_SERVER) && !defined(NX_DISABLE_IPV4) - - /* Verify we have a non zero gateway IP address. */ - if(ip_ptr -> nx_ip_gateway_address != 0) - { - - /* Yes; Assign the IP's gateway address to the first entry in the Client DNS server list. */ - dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version = NX_IP_VERSION_V4; - dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_address.v4 = ip_ptr -> nx_ip_gateway_address; - } - -#endif /* defined(NX_DNS_IP_GATEWAY_AND_DNS_SERVER) && !defined(NX_DISABLE_IPV4) */ - - _nx_dns_instance_ptr = dns_ptr; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the set the DNS Client */ -/* packet pool service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_NOT_ENABLED DNS client not enabled for */ -/* user create packet pool */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_packet_pool_set Actual set packet pool service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr) -{ - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - - /* Client not configured for the user creating the packet pool. Return an error status. */ - return NX_NOT_ENABLED; -#else - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dns_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - status = _nx_dns_packet_pool_set(dns_ptr, packet_pool_ptr); - - return status; -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DNS Client packet pool by passing in a */ -/* packet pool pointer to packet pool already create. The */ -/* NX_DNS_CLIENT_USER_CREATE_PACKET_POOL must be set. For guidelines on*/ -/* packet payload and packet pool size, see the */ -/* nx_packet_pool_create call in nx_dns_create. */ -/* */ -/* Note that the DNS Client nx_dns_delete service will delete this */ -/* packet pool when the DNS Client is deleted. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_NOT_ENABLED Setting DNS Client packet */ -/* pool not enabled */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr) -{ - - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - - /* No, return the error status. */ - return NX_NOT_ENABLED; -#else - /* Check the payload size. */ - if (packet_pool_ptr -> nx_packet_pool_payload_size < NX_DNS_PACKET_PAYLOAD) - return(NX_DNS_PARAM_ERROR); - - /* Set the Client packet pool to the supplied packet pool. */ - dns_ptr -> nx_dns_packet_pool_ptr = packet_pool_ptr; - - return NX_SUCCESS; -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS delete function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_delete Actual DNS delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_delete(NX_DNS *dns_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS delete service. */ - status = _nx_dns_delete(dns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created DNS instance for the */ -/* specified IP. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_delete Delete DNS UDP socket */ -/* nx_udp_socket_unbind Unbind DNS UDP socket */ -/* tx_mutex_delete Delete DNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_delete(NX_DNS *dns_ptr) -{ - -UINT status; - - - /* Unbind the UDP socket. */ - status = nx_udp_socket_unbind(&dns_ptr -> nx_dns_socket); - - if (status != NX_SUCCESS) - { - /* Return the socket unbind error. */ - return status; - } - /* Delete the DNS UDP socket. */ - status = nx_udp_socket_delete(&dns_ptr -> nx_dns_socket); - - if (status != NX_SUCCESS) - { - /* Return the socket delete error. */ - return status; - } - -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - - /* Delete the DNS packet pool. */ - status = nx_packet_pool_delete(dns_ptr -> nx_dns_packet_pool_ptr); - - if (status != NX_SUCCESS) - { - /* Return the packet pool delete error. */ - return status; - } -#endif - - /* Delete the DNS mutex. */ - status = tx_mutex_delete(&dns_ptr -> nx_dns_mutex); - - if (status != NX_SUCCESS) - { - /* Return the mutex delete error. */ - return status; - } - - /* Cleanup entries in the DNS structure. */ - dns_ptr -> nx_dns_id = 0; - dns_ptr -> nx_dns_ip_ptr = NX_NULL; - - /* Return successful completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_server_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS add server function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_add Actual DNS add server function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_server_add(NX_DNS *dns_ptr, ULONG server_address) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - { - - return(NX_PTR_ERROR); - } - - /* Check for invalid server IP address. */ - if (server_address == 0) - { - - return(NX_DNS_BAD_ADDRESS_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS server add service. */ - status = _nx_dns_server_add(dns_ptr, server_address); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls the actual service to add DNS server address. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_add_internal Actual add DNS server service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address) -{ - -#ifndef NX_DISABLE_IPV4 -NXD_ADDRESS dns_server_address; - - - memset(&dns_server_address, 0, sizeof(NXD_ADDRESS)); - - /* Construct an IP address structure, and fill in IPv4 address information. */ - dns_server_address.nxd_ip_version = NX_IP_VERSION_V4; - dns_server_address.nxd_ip_address.v4 = server_address; - - /* Invoke the real function. */ - return (_nx_dns_server_add_internal(dns_ptr, &dns_server_address)); -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_server_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS add server function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_dns_server_add Actual DNS add server function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((dns_ptr == NX_NULL)|| (server_address == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input or invalid server attributes. */ - if ((dns_ptr -> nx_dns_id != NX_DNS_ID) || (server_address -> nxd_ip_version == NX_NULL)) - { - - return NX_DNS_PARAM_ERROR; - } - - /* Check for an invalid address type. */ - if ((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && - (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) - { - - return NX_DNS_INVALID_ADDRESS_TYPE; - } - - /* Check if the server address is unspecified (::). */ - if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - - /* Check for invalid or null address input*/ -#ifdef FEATURE_NX_IPV6 - if(CHECK_UNSPECIFIED_ADDRESS(&server_address -> nxd_ip_address.v6[0])) - { - - /* Null address input. */ - return NX_DNS_BAD_ADDRESS_ERROR; - } -#else - - /* Unsupported address type. */ - return NX_DNS_INVALID_ADDRESS_TYPE; -#endif - - } - else if (server_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* Check for null address. */ - if(server_address -> nxd_ip_address.v4 == 0) - { - - return NX_DNS_BAD_ADDRESS_ERROR; - } -#else - - /* Unsupported address type. */ - return NX_DNS_INVALID_ADDRESS_TYPE; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS add server service. */ - status = _nxd_dns_server_add(dns_ptr, server_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_server_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the specified DNS server to this DNS (client) */ -/* instance's list of DNS server. DNS servers can be IPv4 or IPv6 */ -/* servers. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* dns_server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_add_internal Actual add DNS server service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address) -{ - - - /* Invoke the real function. */ - return (_nx_dns_server_add_internal(dns_ptr, dns_server_address)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_add_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the specified DNS server to this DNS (client) */ -/* instance's list of DNS server. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* dns_server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_server_add_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) -{ - -UINT status; -UINT i; - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Determine if there was an error getting the mutex. */ - if (status != TX_SUCCESS) - { - - /* Return the completion status error. */ - return(status); - } - - /* Check for a duplicate entry. */ - i = 0; - - /* Check all entries for a either a matching entry or an empty slot is found. */ - while (i < NX_DNS_MAX_SERVERS) - { - - /* The dns server IP is IPv4 address. */ - if (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* Is there a match? */ - if ((server_address -> nxd_ip_version == NX_IP_VERSION_V4) && - (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v4 == server_address -> nxd_ip_address.v4)) - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Yes, no need to add to the table, just return the 'error' status. */ - return NX_DNS_DUPLICATE_ENTRY; - } -#else - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_PARAM_ERROR; -#endif /* NX_DISABLE_IPV4 */ - } - - /* The dns server IP is IPv6 address. */ - else if (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifdef FEATURE_NX_IPV6 - /* Is there a match? */ - if ((server_address -> nxd_ip_version == NX_IP_VERSION_V6) && - CHECK_IPV6_ADDRESSES_SAME(&dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v6[0], - &(server_address -> nxd_ip_address.v6[0]))) - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Yes, no need to add to the table, just return the 'error' status. */ - return NX_DNS_DUPLICATE_ENTRY; - } -#else - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_PARAM_ERROR; -#endif - } - - else - { - /* Yes, find one empty slot in the DNS server array. */ - break; - } - - i++; - } - - if(i == NX_DNS_MAX_SERVERS) - { - - /* Can not find one empty slot. Release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return(NX_NO_MORE_ENTRIES); - } - - /* Add the new entry here. */ - if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifdef FEATURE_NX_IPV6 - COPY_NXD_ADDRESS(server_address, &dns_ptr -> nx_dns_server_ip_array[i]); -#else - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_IPV6_NOT_SUPPORTED; -#endif - } - else - { - -#ifndef NX_DISABLE_IPV4 - dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_address.v4 = server_address -> nxd_ip_address.v4; - dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version = NX_IP_VERSION_V4; -#else - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_INVALID_ADDRESS_TYPE; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Success, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_server_remove PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS remove server function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_remove Actual DNS remove server */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server IP address. */ - if (server_address == 0) - { - return(NX_DNS_BAD_ADDRESS_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS remove server service. */ - status = _nx_dns_server_remove(dns_ptr, server_address); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_remove PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls actual service to remove specified DNS Server. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_remove_internal Actual DNS server remove */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address) -{ - -#ifndef NX_DISABLE_IPV4 -NXD_ADDRESS dns_server_address; - - /* Construct an IP address structure, and fill in IPv4 address information. */ - dns_server_address.nxd_ip_version = NX_IP_VERSION_V4; - dns_server_address.nxd_ip_address.v4 = server_address; - - /* Invoke the real function. */ - return (_nx_dns_server_remove_internal(dns_ptr, &dns_server_address)); -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_server_remove PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS remove server function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* server_address DNS Server NXD_ADDRESS instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_remove Actual DNS remove server */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (server_address == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for an invalid address type. */ - if ((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && - (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) - { - - return NX_DNS_INVALID_ADDRESS_TYPE; - } - - /* Check if the server address is unspecified (::). */ - if (server_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - - /* Check for invalid or null address input*/ -#ifdef FEATURE_NX_IPV6 - if(CHECK_UNSPECIFIED_ADDRESS(&server_address -> nxd_ip_address.v6[0])) - { - - /* Null address input. */ - return NX_DNS_BAD_ADDRESS_ERROR; - } -#else - - /* Unsupported address type. */ - return NX_DNS_INVALID_ADDRESS_TYPE; -#endif - - } - else if (server_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* Check for null address. */ - if(server_address -> nxd_ip_address.v4 == 0) - { - - return NX_DNS_BAD_ADDRESS_ERROR; - } -#else - - /* Unsupported address type. */ - return NX_DNS_INVALID_ADDRESS_TYPE; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS remove server service. */ - status = _nxd_dns_server_remove(dns_ptr, server_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_server_remove PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes the specified DNS server to this DNS */ -/* instance. If the server is not found among the client list of DNS */ -/* servers, the function returns an error. When a server is removed, */ -/* the servers above the removed server's index are moved down one to */ -/* fill the empty slot. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* server_address DNS Server NXD_ADDRESS isntance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) -{ - - - /* Invoke the real function. */ - return (_nx_dns_server_remove_internal(dns_ptr, server_address)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_remove_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes the specified DNS server to this DNS */ -/* instance. If the server is not found among the client list of DNS */ -/* servers, the function returns an error. When a server is removed, */ -/* the servers above the removed server's index are moved down one to */ -/* fill the empty slot. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* server_address DNS Server address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_server_remove_internal(NX_DNS *dns_ptr, NXD_ADDRESS *server_address) -{ - -NXD_ADDRESS *DNSserver_array; -UINT status; -UINT i; -UINT found_match; - - /* Initialize local variables. */ - found_match = NX_FALSE; - i = 0; - - /* Calculate the start of the DNS server array. */ - DNSserver_array = dns_ptr -> nx_dns_server_ip_array; - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Determine if there was an error getting the mutex. */ - if (status != TX_SUCCESS) - { - - /* Return an error. */ - return(status); - } - - /* Search through the array to see if we can find the server address. */ - do - { - - /* Is there an IPv6 address in this slot? */ - if (DNSserver_array[i].nxd_ip_version == NX_IP_VERSION_V6) -#ifndef FEATURE_NX_IPV6 - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_IPV6_NOT_SUPPORTED; - } -#else - { - /* Check for a null address. */ - if (!CHECK_UNSPECIFIED_ADDRESS(&DNSserver_array[i].nxd_ip_address.v6[0])) - { - - /* No null; Determine if this entry matches the specified DNS server. */ - if (CHECK_IPV6_ADDRESSES_SAME(&DNSserver_array[i].nxd_ip_address.v6[0], &(server_address -> nxd_ip_address.v6[0]))) - { - - found_match = NX_TRUE; - break; - } - } - /* Check for a null address. */ - else - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - return NX_DNS_BAD_ADDRESS_ERROR; - } - } -#endif - else if (DNSserver_array[i].nxd_ip_version == NX_IP_VERSION_V4) -#ifndef NX_DISABLE_IPV4 - { - - /* Check for a null address. */ - if (DNSserver_array[i].nxd_ip_address.v4 != IP_ADDRESS(0, 0, 0, 0)) - { - - /* Determine if this entry matches the specified DNS server. */ - if (DNSserver_array[i].nxd_ip_address.v4 == server_address -> nxd_ip_address.v4) - { - - found_match = NX_TRUE; - break; - } - } - else - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - return NX_DNS_INVALID_ADDRESS_TYPE; - } - } -#else - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_IPV6_NOT_SUPPORTED; - } -#endif /* NX_DISABLE_IPV4 */ - - /* Check the next slot. */ - i++; - - } while (i < NX_DNS_MAX_SERVERS); - - if (!found_match) - { - - /* Release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Return the error. */ - return(NX_DNS_SERVER_NOT_FOUND); - } - - /* We found the DNS server entry. Remove it from the table. */ - while (i < NX_DNS_MAX_SERVERS - 1) - { - - /* Move them up one slot. */ - -#ifdef FEATURE_NX_IPV6 - /* This will handle IPv6 and IPv4 addresses if IPv6 enabled in NetX Duo. */ - COPY_NXD_ADDRESS(&DNSserver_array[i+1], &DNSserver_array[i]); -#else - /* IPv6 is not enabled, so first verify this is not an IPv6 address. */ - if (DNSserver_array[i+1].nxd_ip_version == NX_IP_VERSION_V6) - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* This should not happen. return an error. */ - return NX_DNS_IPV6_NOT_SUPPORTED; - } - - /* This is an IPv4 address. Copy to the slot above directly. */ - DNSserver_array[i].nxd_ip_version = DNSserver_array[i+1].nxd_ip_version; - DNSserver_array[i].nxd_ip_address.v4 = DNSserver_array[i+1].nxd_ip_address.v4; -#endif - - i++; - } - - /* Terminate the last slot. */ - memset(&dns_ptr -> nx_dns_server_ip_array[NX_DNS_MAX_SERVERS - 1], 0, sizeof(NXD_ADDRESS)); - - /* Release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_server_remove_all PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS remove all */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_remove_all Actual DNS remove all function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_server_remove_all(NX_DNS *dns_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS remove server service. */ - status = _nx_dns_server_remove_all(dns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_remove_all PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes all DNS servers. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_server_remove_all(NX_DNS *dns_ptr) -{ - -UINT status; - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Determine if there was an error getting the mutex. */ - if (status != TX_SUCCESS) - { - /* Return an error. */ - return(NX_DNS_ERROR); - } - - /* Remove all DNS servers. */ - memset(&dns_ptr -> nx_dns_server_ip_array[0], 0, NX_DNS_MAX_SERVERS * sizeof(NXD_ADDRESS)); - - /* Release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_get_serverlist_size PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the get DNS server list size */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* size Pointer to server size */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_get_serverlist_size Actual get DNS server list size*/ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *size) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || (size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get server size service. */ - status = _nx_dns_get_serverlist_size(dns_ptr, size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_get_serverlist_size PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the number of DNS servers in the Client list. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* size Pointer to server list size */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *size) -{ - - /* Initialize the list size to zero. */ - *size = 0; - - /* Loop through the list till we hit the first empty slot. */ - while (*size < NX_DNS_MAX_SERVERS) - { - - /* Is this a valid IP address entry in this slot? */ - if (dns_ptr -> nx_dns_server_ip_array[*size].nxd_ip_version == 0) - { - - /* This is an empty slot, so we're at the end of the list. */ - break; - } - - (*size)++; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the get DNS server service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* index Index into server list */ -/* dns_server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_get Actual get DNS server service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || (dns_server_address == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual get DNS server service. */ - status = _nx_dns_server_get(dns_ptr, index, dns_server_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls actual service to get the DNS Server address. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* index Index into server list */ -/* dns_server_address DNS Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_get Get DNS server service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_address; - - - /* Initialize to not found. */ - *dns_server_address = 0x0; - - /* Invoke the real function. */ - status = _nx_dns_server_get_internal(dns_ptr, index, &server_address); - - if (status != NX_SUCCESS) - { - return status; - } - - /* Verify this is an IPv4 address. */ - if (server_address.nxd_ip_version != NX_IP_VERSION_V4) - { - return NX_DNS_INVALID_ADDRESS_TYPE; - } - - /* Return the IPv4 address information. */ - *dns_server_address = server_address.nxd_ip_address.v4; - - return NX_SUCCESS; -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(index); - NX_PARAMETER_NOT_USED(dns_server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the get DNS server service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* index Index into server list */ -/* dns_server_address Pointer to Server address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_server_remove Actual DNS return server */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_server_address == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual get DNS server service. */ - status = _nxd_dns_server_get(dns_ptr, index, dns_server_address); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retreives the DNS server at the specified index into */ -/* the DNS server list. If the index exceeds the size of the list or */ -/* an empty slot is at that index, the function returns an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* index Index into server list */ -/* dns_server_address Pointer to Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address) -{ - - /* Invoke the real function. */ - return(_nx_dns_server_get_internal(dns_ptr, index, dns_server_address)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_server_get_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retreives the DNS server at the specified index into */ -/* the DNS server list. If the index exceeds the size of the list or */ -/* an empty slot is at that index, the function returns an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS client */ -/* index Index into server list */ -/* dns_server_address Pointer to Server IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_server_get_internal(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *server_address) -{ - -UINT status; - - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Determine if there was an error getting the mutex. */ - if (status != TX_SUCCESS) - { - - /* Return an error. */ - return(status); - } - - /* Check for an invalid index. The max list size is NX_DNS_MAX_SERVERS. */ - if (index >= NX_DNS_MAX_SERVERS) - { - - return NX_DNS_PARAM_ERROR; - } - - /* Is there a valid IP address entry in this slot? */ - if (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == 0) - { - - /* No, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_SERVER_NOT_FOUND; - } -#ifndef NX_DISABLE_IPV4 - /* Check for a null IPv4 address if this is an IPv4 type. */ - else if ((dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == NX_IP_VERSION_V4) && - (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_address.v4 == 0)) - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_BAD_ADDRESS_ERROR; - } -#endif /* NX_DISABLE_IPV4 */ - else if (dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_version == NX_IP_VERSION_V6) -#ifndef FEATURE_NX_IPV6 - { - - /* IPv6 not enabled, return an error status. */ - - /* Release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_INVALID_ADDRESS_TYPE; - } -#else - { - - /* Check for unspecified (null) IPv6 address. */ - if (CHECK_UNSPECIFIED_ADDRESS(&(dns_ptr -> nx_dns_server_ip_array[index].nxd_ip_address.v6[0]))) - { - - /* Error, release the mutex and return. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return NX_DNS_BAD_ADDRESS_ERROR; - } - } -#endif - - /* Set a pointer to the DNS server in the list. */ - *server_address = (dns_ptr -> nx_dns_server_ip_array[index]); - - /* Release the mutex. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_host_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up host IP address */ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to DNS host IP address*/ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_by_name_get Actual DNS host IP address */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (host_name == NX_NULL) || (host_address_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host by name service. */ - status = _nx_dns_host_by_name_get(dns_ptr, host_name, host_address_ptr, wait_option); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_host_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls service to get the host address by name service */ -/* as an A record (IPv4) lookup query. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to DNS host IP address*/ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get host address */ -/* by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option) -{ - -UINT status; -UINT record_count = 0; - - /* Keep the API consistency. Invoke the real DNS query call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (VOID*)host_address_ptr, sizeof(ULONG), &record_count, NX_DNS_RR_TYPE_A, wait_option); - - /* Record_count set to 1 indicates the call is successful. */ - if(record_count == 1) - { - /* Set the return value. */ - status = NX_SUCCESS; - } - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_host_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS get host by name */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to destination of */ -/* host IP address */ -/* wait_option Timeout value */ -/* lookup_type Lookup for which IP version */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_dns_host_by_name_get Actual DNS get host by name */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, - ULONG wait_option, UINT lookup_type) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if ((dns_ptr == NX_NULL) || (host_name == NX_NULL) || (host_address_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if ((dns_ptr -> nx_dns_id != NX_DNS_ID) || (lookup_type == 0)) - { - return NX_DNS_PARAM_ERROR; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host by name service. */ - status = _nxd_dns_host_by_name_get(dns_ptr, host_name, host_address_ptr, wait_option, lookup_type); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_host_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS get host by name */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to host IP address */ -/* wait_option Timeout value */ -/* lookup_type Lookup for which IP version */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get host by name */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, - ULONG wait_option, UINT lookup_type) -{ - -UINT status; -UINT record_count = 0; - - - /* Is this a AAAA record lookup (e.g. expect an IPv6 address)? If no type is specified default to AAAA type. */ - if((lookup_type == NX_IP_VERSION_V6) || (lookup_type == 0)) - { - -#ifdef FEATURE_NX_IPV6 - /* Send AAAA type message, and keep the API consistency. Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (UCHAR *)&host_address_ptr -> nxd_ip_address.v6[0], 16, &record_count, NX_DNS_RR_TYPE_AAAA, wait_option); - - /* Record_count being set indicates the query gets a valid answer. */ - if (record_count) - { - - /* Have recorded the IPv6 address, set the IP version. */ - host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V6; - - /* Modify the return status.*/ - status = NX_SUCCESS; - } -#else - return NX_DNS_IPV6_NOT_SUPPORTED; -#endif - } - else if(lookup_type == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* Keep the API consistency. Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, (UCHAR *)&host_address_ptr -> nxd_ip_address.v4, sizeof(ULONG), &record_count, NX_DNS_RR_TYPE_A, wait_option); - - /* Record_count being set indicates the query gets a valid answer. */ - if (record_count) - { - - /* Have recorded the IPv4 address, set the IP version. */ - host_address_ptr -> nxd_ip_version = NX_IP_VERSION_V4; - - /* Modify the return status.*/ - status = NX_SUCCESS; - } -#else - return NX_DNS_BAD_ADDRESS_ERROR; -#endif - } - - else - { - return NX_DNS_BAD_ADDRESS_ERROR; - } - - /* Return status. */ - return(status); -} - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_info_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS get info by name */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to destination of */ -/* host IP address */ -/* host_port_ptr Pointer to destination of host*/ -/* source port */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_info_by_name_get Actual DNS get info by name */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT *host_port_ptr, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (dns_ptr -> nx_dns_id != NX_DNS_ID) || - (host_name == NX_NULL) || (host_address_ptr == NX_NULL) || (host_port_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host by name service. */ - status = _nx_dns_info_by_name_get(dns_ptr, host_name, host_address_ptr, host_port_ptr, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_info_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the Service record associated with the*/ -/* specified host name. If a service rec cannot be found, this */ -/* routine returns a zero IP address in the input address pointer and a*/ -/* non zero error status return to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* host_address_ptr Pointer to destination of */ -/* host IP address */ -/* host_port_ptr Pointer to destination of */ -/* host port */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, - USHORT *host_port_ptr, ULONG wait_option) -{ - -NX_DNS_SRV_ENTRY *dns_srv_entry; -UINT record_count; -UINT status; -UCHAR temp_buffer[TEMP_SRV_BUFFER_SIZE]; - - /* Call the service get function to get information. */ - status = _nx_dns_domain_service_get(dns_ptr, host_name, (VOID *)temp_buffer, TEMP_SRV_BUFFER_SIZE, &record_count, wait_option); - - /* Check erros. */ - if(status) - { - return status; - } - - /* Set the srv pointer. */ - dns_srv_entry = (NX_DNS_SRV_ENTRY *)temp_buffer; - - /* record the info returned to user. */ - *host_address_ptr = dns_srv_entry -> nx_dns_srv_ipv4_address; - *host_port_ptr = dns_srv_entry -> nx_dns_srv_port_number; - - return NX_SUCCESS; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_ipv4_address_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up host IP address */ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name_ptr Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* IPv4 addresses */ -/* buffer_size Size of the record_buffer */ -/* record_count The count of IPv4 addresses */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_ipv4_address_by_name_get Actual DNS host IP address */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!dns_ptr) || (!host_name_ptr) || (!record_buffer) || (!record_count)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host ipv4 address by name service. */ - status = _nx_dns_ipv4_address_by_name_get(dns_ptr, host_name_ptr, record_buffer, buffer_size, record_count, wait_option); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_ipv4_address_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calls service to get the host address by name service */ -/* as an A record (IPv4) lookup query. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing */ -/* IPv4 addresses */ -/* buffer_size Size of the record_buffer */ -/* record_count The count of IPv4 addresses */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get host rdata */ -/* by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name_ptr, buffer, buffer_size, record_count, NX_DNS_RR_TYPE_A, wait_option); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_ipv6_address_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up host IPv6 address*/ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name_ptr Name of host to search on */ -/* record_buffer Buffer space for storing IPv6 */ -/* addresses. */ -/* buffer_size Size of record_buffer */ -/* record_count The count of IPv6 addresses */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_ipv6_address_by_name_get Actual DNS host IPv6 address */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!dns_ptr) || (!host_name_ptr) || (!record_buffer) || (!record_count)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host ipv6 address by name service. */ - status = _nxd_dns_ipv6_address_by_name_get(dns_ptr, host_name_ptr, record_buffer, buffer_size, record_count, wait_option); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_ipv6_address_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an NXD_ADDRESS instance from the specified */ -/* IPv6 address and submits it to the actual get host by name service */ -/* as an AAAA record (IPv6) lookup query. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing IPv6 */ -/* addresses. */ -/* buffer_size Size of record_buffer */ -/* record_count The count of IPv6 addresses */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual NetX Duo DNS get */ -/* host rdata by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name_ptr, VOID *buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name_ptr, buffer, buffer_size, record_count, NX_DNS_RR_TYPE_AAAA, wait_option); - - /* Return completion status. */ - return status; -} - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_cname_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up host cname */ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* cname response. */ -/* buffer_size Size of record_buffer */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_cname_get Actual DNS host cname */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_cname_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if (!dns_ptr || !host_name || !record_buffer) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host by name service. */ - status = _nx_dns_cname_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cname_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the host cname associated with */ -/* the specified host name. If host cname cannot be found, this */ -/* routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing */ -/* cname response. */ -/* buffer_size Size of record_buffer */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get host cname */ -/* by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_cname_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; -UINT record_count = 0; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, - &record_count, NX_DNS_RR_TYPE_CNAME, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_domain_name_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up the authoritative*/ -/* name servers in a given domain. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* the data structure that */ -/* holds name server information*/ -/* buffer_size Size of the record_buffer */ -/* record_count The number of records stored */ -/* in the record_buffer */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_domain_name_server_get Actual DNS host NS */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get the authoritative name server by name service. */ - status = _nx_dns_domain_name_server_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_domain_name_server_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the authoritative name server */ -/* associated with the specified host name. If host cname cannot */ -/* be found, this routine returns zero for the string size to */ -/* signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* the data structure that */ -/* holds name server information*/ -/* buffer_size Size of the record_buffer */ -/* record_count The number of records stored */ -/* in the record_buffer */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get the */ -/* authoritaive name server */ -/* by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, NX_DNS_RR_TYPE_NS, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_host_text_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up the text strings */ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* the host text string */ -/* buffer_size Size of record_buffer. */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* _nx_dns_host_text_get Actual DNS host text strings */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if (!dns_ptr || !host_name || !record_buffer) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get the text strings by name service. */ - status = _nx_dns_host_text_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_host_text_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the text strings associated with */ -/* the specified host name. If host cname cannot be found, */ -/* this routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing */ -/* the host text string */ -/* buffer_size Size of record_buffer. */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get the text */ -/* strings by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; -UINT record_count = 0; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, &record_count, NX_DNS_RR_TYPE_TXT, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_domain_mail_exchange_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up the mail */ -/* exchange by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for recording */ -/* data structure that holds */ -/* the mail exchange information*/ -/* buffer_size Size of record_buffer. */ -/* record_count The count of mail exchange */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_domain_mail_exchange_get */ -/* Actual DNS host MX lookup */ -/* by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get the mail exchange by name service. */ - status = _nx_dns_domain_mail_exchange_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_domain_mail_exchange_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the mail exchange associated with */ -/* the specified host name. If host cname cannot be found, */ -/* this routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for recording */ -/* data structure that holds */ -/* the mail exchange information*/ -/* buffer_size Size of record_buffer. */ -/* record_count The count of mail exchange */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_get */ -/* Actual DNS get the mail */ -/* exchange by name service */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, - record_count, NX_DNS_RR_TYPE_MX, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_domain_service_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up the service */ -/* by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing the */ -/* the data structures that */ -/* hold the service information */ -/* buffer_size size of record_buffer */ -/* record_count The count of services stored */ -/* in record_buffer */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_domain_service_get */ -/* Actual DNS host SRV */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!dns_ptr) || (!host_name) || (!record_buffer) || (!record_count)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get the service by name service. */ - status = _nx_dns_domain_service_get(dns_ptr, host_name, record_buffer, buffer_size, record_count, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_domain_service_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the service associated with */ -/* the specified host name. If host cname cannot be found, */ -/* this routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing the */ -/* the data structures that */ -/* hold the service information */ -/* buffer_size size of record_buffer */ -/* record_count The count of services stored */ -/* in record_buffer */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Route that sends out the */ -/* query and process response. */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, - UINT buffer_size, UINT *record_count, ULONG wait_option) -{ - -UINT status; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, - record_count, NX_DNS_RR_TYPE_SRV, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_authority_zone_start_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS look up the start of */ -/* a zone of authority by name service. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to search on */ -/* record_buffer Buffer space for storing */ -/* the data structures that */ -/* hold the SOA information */ -/* buffer_size Size of record_buffer. */ -/* wait_option Time to wait on server response*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* _nx_dns_authority_zone_start_get Actual DNS host text strings */ -/* lookup by host name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_authority_zone_start_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if (!dns_ptr || !host_name || !record_buffer) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if(((ALIGN_TYPE)record_buffer & 0x3) != 0) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get the start of zone authority by name service. */ - status = _nx_dns_authority_zone_start_get(dns_ptr, host_name, record_buffer, buffer_size, wait_option); - - /* Return status. */ - return(status); -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_authority_zone_start_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the start of a zone of authority */ -/* associated with the specified host name. If it cannot be found, */ -/* this routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer space for storing */ -/* the data structures that */ -/* hold the SOA information */ -/* buffer_size Size of record_buffer. */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Actual DNS get the authority */ -/* zone by name service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_authority_zone_start_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, - UINT buffer_size, ULONG wait_option) -{ - -UINT status; -UINT record_count = 0; - - /* Invoke the real connection call. */ - status = _nx_dns_host_resource_data_by_name_get(dns_ptr, host_name, record_buffer, buffer_size, &record_count, NX_DNS_RR_TYPE_SOA, wait_option); - - /* Return completion status. */ - return status; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_host_resource_data_by_name_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to find the IP address associated with the */ -/* specified host name. If a DNS server responds but does not have */ -/* the IP address, this function skips to the next server in the */ -/* DNS client list. Otherwise it will resend the same query up to the */ -/* DNS client's max retry times before skipping to the next server. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_name Name of host to resolve */ -/* record_buffer Buffer for record ipv4 address*/ -/* buffer_size Buffer size for ipv4 adress */ -/* record_count The count of ipv4 address */ -/* wait_option Timeout value */ -/* lookup_type Lookup for which IP version */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_send_query_get_rdata_by_name */ -/* Creates and transmits a DNS */ -/* query on supplied host name */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_host_resource_data_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, - UCHAR *buffer, UINT buffer_size, - UINT *record_count, UINT lookup_type, ULONG wait_option) -{ - -UINT status; -UINT retries; -UINT i; - - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), wait_option); - - /* Check status. */ - if (status != TX_SUCCESS) - { - - /* The mutex was not granted in the time specified. Return the threadx error. */ - return(status); - } - - /* Clear the record name buffer and record count. This way - if the query fails, the API returns zero record. */ - memset(buffer, 0, buffer_size); - - /* Initialize the record count. */ - *record_count = 0; - -#ifdef NX_DNS_CACHE_ENABLE - - /* Find the answer in local cache. */ - if(_nx_dns_cache_find_answer(dns_ptr, dns_ptr -> nx_dns_cache, host_name, (USHORT)lookup_type, buffer, buffer_size, record_count) == NX_DNS_SUCCESS) - { - - /* Put the DNS mutex. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - return (NX_DNS_SUCCESS); - } -#endif /*NX_DNS_CACHE_ENABLE. */ - - /* Determine if there is at least one DNS server. Is there anything in the first slot? */ - if (dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version == 0) - { - - /* No, this means the list is empty. Release the DNS Client lock. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - /* At least one DNS server is required - return an error. */ - return(NX_DNS_NO_SERVER); - } - - /* Keep sending queries to all DNS Servers till the retry count expires. */ - for (retries = 0; retries < dns_ptr -> nx_dns_retries; retries++) - { - - /* The client should try other servers and server addresses before repeating a query to a specific address of a server. - RFC1035, Section4.2.1 UDP usage, Page32. */ - /* Attempt host name resolution from each DNS server till one if found. */ - for (i = 0; (i < NX_DNS_MAX_SERVERS) && (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version != 0); i ++) - { - - /* Send the DNS query. */ - status = _nx_dns_send_query_get_rdata_by_name(dns_ptr, &dns_ptr -> nx_dns_server_ip_array[i], host_name, - buffer, buffer_size, record_count, lookup_type, wait_option); - - /* Check the status. */ - if (status == NX_SUCCESS) - { - - /* Release the mutex */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - /* Yes, have done, just return success. */ - return NX_SUCCESS; - } - } - - /* Timed out for querying all DNS servers in this cycle, double the timeout, limited to NX_DNS_MAX_RETRANS_TIMEOUT. */ - if ((2 * wait_option) <= NX_DNS_MAX_RETRANS_TIMEOUT) - wait_option = wait_option * 2; - else - wait_option = NX_DNS_MAX_RETRANS_TIMEOUT; - } - - /* Release protection. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - /* Failed on all servers, return DNS lookup failed status. */ - return(NX_DNS_QUERY_FAILED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_send_query_by_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the name of a host from the specified */ -/* IP address associated. If the IP address cannot be found, this */ -/* routine returns a NULL host name . */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* dns_server Pointer to DNS server to use */ -/* ip_question Buffer pointer to IP address */ -/* in ascii to lookup */ -/* host_name_ptr Buffer pointer to host name */ -/* host_name_buffer_size Buffer size for host name */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* _nx_dns_network_to_long_convert Convert to unsigned long */ -/* _nx_dns_network_to_short_convert Convert to unsigned short */ -/* _nx_dns_new_packet_create Create new DNS packet */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_resource_data_length_get Get length of resource */ -/* _nx_dns_resource_type_get Get resource type */ -/* nx_packet_copy Copy packet */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_receive Receive DNS UDP packet */ -/* nxd_udp_socket_send Send DNS UDP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_send_query_by_address(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server, UCHAR *ip_question, UCHAR *host_name_ptr, - UINT host_name_buffer_size, ULONG wait_option) -{ - -UINT status; -USHORT answerCount; -UCHAR *data_ptr; -NX_PACKET *packet_ptr; -NX_PACKET *receive_packet_ptr; -USHORT id; -UINT ip_question_size; -UINT name_size; -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE -ULONG start_time; -ULONG current_time; -ULONG elapsed_time; -ULONG time_remaining; -#endif -#ifdef NX_DNS_CACHE_ENABLE -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - - - - /* Check for IP question. */ - if (_nx_utility_string_length_check((CHAR *)ip_question, &ip_question_size, NX_DNS_IP_LOOKUP_SIZE)) - { - return(NX_DNS_SIZE_ERROR); - } - - /* Create a random DNS query ID based on the first word of an IP address (or only - word for IPv4 addresses). */ - if (dns_server -> nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifdef FEATURE_NX_IPV6 - id = (USHORT)(dns_server -> nxd_ip_address.v6[0] ^ tx_time_get()); -#else - return NX_DNS_IPV6_NOT_SUPPORTED; -#endif - } - else - { -#ifndef NX_DISABLE_IPV4 - id = (USHORT)(dns_server -> nxd_ip_address.v4 ^ tx_time_get()); -#else - return NX_DNS_BAD_ADDRESS_ERROR; -#endif - } - - /* Allocate a packet. */ - status = nx_packet_allocate(dns_ptr -> nx_dns_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_DNS_PACKET_ALLOCATE_TIMEOUT); - - /* Check the allocate status. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Create a request */ - status = _nx_dns_new_packet_create(dns_ptr, packet_ptr, id, ip_question, NX_DNS_RR_TYPE_PTR); - - /* Check the DNS packet create status. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return(status); - } - - /* First clear off any 'old' DNS packets. */ - -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE - - /* We will use the time spent sleeping to clear broadcast DNS packets from a previous query - from the DNS receive queue. This will prevent ensure the most recent DNS response is - processed and avoid the situation of valid DNS response packets overflowing the DNS socket - queue. */ - - receive_packet_ptr = NX_NULL; - - - /* Remove all packets from the DNS Client receive queue. */ - status = NX_SUCCESS;; - do - { - - /* Is there any packets on the queue? */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, 1 ); - - /* Yes, we received a packet on the DNS port! */ - if (status == NX_SUCCESS) - { - - /* But we don't want it. Release it! */ - nx_packet_release(receive_packet_ptr); - } - - /* Keep checking till the queue becomes empty. */ - - } while(status == NX_SUCCESS); - -#endif - - /* Send the DNS packet out. */ - status = nxd_udp_socket_send(&dns_ptr -> nx_dns_socket, packet_ptr, dns_server, NX_DNS_PORT); - - - /* Check the completion of the send. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful, release the packet. */ - nx_packet_release(packet_ptr); - - return status; - } - -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE - - /* Initialize the value. */ - elapsed_time = 0; - time_remaining = wait_option; - - /* If waiting for the DNS 'sleep' interval, check for packets arriving on the queue. */ - while(time_remaining > 0) - { - - start_time = tx_time_get(); - - /* Check if some of these packet are intended for other hosts. */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, time_remaining); - - /* Determine if this one is for us. */ - if (status == NX_SUCCESS) - { - - /* Check the ID from the Client query matches the ID in the received DNS packet. */ - if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) == id) - { - /* They do. We can stop receiving packets and process this one. */ - break; - } - else - { - /* They do not. Discard the packet! */ - nx_packet_release(receive_packet_ptr); - } - } - - /* Get the current time. */ - current_time = tx_time_get(); - - /* Has the time wrapped? */ - if (current_time >= start_time) - { - /* No, simply subtract to get the elapsed time. */ - elapsed_time = current_time - start_time; - } - else - { - /* Yes it has. Time has rolled over the 32-bit boundary. */ - elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; - } - - /* Update the time remaining by subtracting the elapsed time. */ - if (time_remaining > elapsed_time) - { - time_remaining -= elapsed_time; - } - else - { - time_remaining = 0; - } - } - -#else - - /* Otherwise, wait for a DNS response UDP packet. */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, wait_option); -#endif - - /* Check status. */ - if (status == NX_SUCCESS) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - if (receive_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(receive_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We received a response. First, check that there is a valid header. */ - if (receive_packet_ptr -> nx_packet_length <= NX_DNS_QDSECT_OFFSET) - { - /* No; Release the new packet. */ - nx_packet_release(receive_packet_ptr); - - /* Return error status. */ - return NX_DNS_MALFORMED_PACKET; - } - - /* Packet is long enough. Check the IDs in the DNS header match. */ - if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) != id) - { - - /* No; Release the packet. */ - nx_packet_release(receive_packet_ptr); - - /* Return error status. */ - return NX_DNS_BAD_ID_ERROR; - } - - /* We have a response with matching ID, check that it is a response - and is successful and has a response record. */ - status = _nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_FLAGS_OFFSET); - - /* Check for indication of DNS server error (cannot authenticate answer or authority portion - of the DNS data. */ - if ((status & NX_DNS_ERROR_MASK) == NX_DNS_ERROR_MASK) - { - - /* No; Release the packet. */ - nx_packet_release(receive_packet_ptr); - - return NX_DNS_SERVER_AUTH_ERROR; - } - - answerCount = _nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ANCOUNT_OFFSET); - - /* Is it for our question? */ - if (((status & NX_DNS_QUERY_MASK) == NX_DNS_RESPONSE_FLAG) - && ((status & NX_DNS_RCODE_MASK) == NX_DNS_RCODE_SUCCESS) - && (answerCount >= 1)) - { - - /* Yes, set a point to the start of the question to find the response record. */ - data_ptr = receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDSECT_OFFSET; - - /* Determine if there is a question still in the server's response. */ - if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET) == 1) - { - - /* Yes, the question is present in the response, skip it! */ - data_ptr += _nx_dns_name_size_calculate(data_ptr) + 4; - } - - /* Check all the response records */ - while (answerCount-- > 0) - { - - /* Check for valid data_ptr. */ - if (data_ptr >= receive_packet_ptr -> nx_packet_append_ptr) - { - - /* Release the packet. */ - nx_packet_release(receive_packet_ptr); - - /* NULL-terminate the host name string. */ - *host_name_ptr = NX_NULL; - - /* Return an error! */ - return(NX_DNS_SIZE_ERROR); - } - - /* Check that the answer has a name and there is space for it. */ - if (_nx_dns_resource_type_get(data_ptr) == NX_DNS_RR_TYPE_PTR) - { - -#ifdef NX_DNS_CACHE_ENABLE - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Update the pointer to point at the response data and get the name. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Determine if there is room for the name - one less for NULL termination. */ - name_size = _nx_dns_name_string_unencode(receive_packet_ptr, data_ptr, host_name_ptr, host_name_buffer_size - 1); - if (name_size) - { - - /* Yes; We're done! */ - - /* Need to release the packet. */ - nx_packet_release(receive_packet_ptr); - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_PTR; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, ip_question, ip_question_size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the PTR string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, host_name_ptr, name_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Return success! */ - return(NX_SUCCESS); - } - else - { - - /* Nope, Our destination string is too small. Release the packet. */ - nx_packet_release(receive_packet_ptr); - - /* NULL-terminate the host name string. */ - *host_name_ptr = NX_NULL; - - /* Return an error! */ - return(NX_DNS_SIZE_ERROR); - } - } - else - { - /* This response isn't a name, just skip it. */ - data_ptr += _nx_dns_resource_size_get(data_ptr); - } - - } /* and check the next answer record */ - } - - /* We got a packet, but did it supply name resolution? */ - if (answerCount == 0) - { - - /* No, set the failed query status. */ - status = NX_DNS_QUERY_FAILED; - } - - /* Release the packet. */ - nx_packet_release(receive_packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_send_query_get_rdata_by_name PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates and sends a new DNS query on the specific */ -/* information. On receiving a response, this function also invokes */ -/* a process function to parse the resposne. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* server_address The DNS server address */ -/* record_buffer Buffer for resource data */ -/* buffer_size Buffer size for resource data */ -/* record_count The count of resource data */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a new packet */ -/* _nx_dns_new_packet_create Create new DNS packet */ -/* nx_packet_release Release packet */ -/* nxd_udp_socket_send Send DNS UDP packet */ -/* nx_udp_socket_receive Receive DNS UDP packet */ -/* _nx_dns_response_process Process the DNS respondse */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_resource_data_by_name_get */ -/* Get the resource data by name */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_send_query_get_rdata_by_name(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address, - UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, - UINT *record_count, UINT dns_record_type, ULONG wait_option) -{ - -UINT status; -NX_PACKET *packet_ptr; -NX_PACKET *receive_packet_ptr; -USHORT id; -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE -ULONG start_time; -ULONG current_time; -ULONG elapsed_time; -ULONG time_remaining; -#endif - - /* Generate a random ID based on host name. */ - id = (USHORT)((ALIGN_TYPE) host_name ^ tx_time_get()); - - /* Allocate a packet. */ - status = nx_packet_allocate(dns_ptr -> nx_dns_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_DNS_PACKET_ALLOCATE_TIMEOUT); - - /* Check the allocate status. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Create a request */ - status = _nx_dns_new_packet_create(dns_ptr, packet_ptr, id, host_name, (USHORT)dns_record_type); - - /* Check the DNS packet create status. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return error status. */ - return(status); - } - - /* First clear off any 'old' DNS packets. */ -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE - - /* Initialize the value */ - receive_packet_ptr = NX_NULL; - - /* Remove all packets from the DNS Client receive queue. */ - status = NX_SUCCESS;; - do - { - - start_time = tx_time_get(); - - /* Is there any packets on the queue? */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, 1 ); - - /* Yes, we received a packet on the DNS port! */ - if (status == NX_SUCCESS) - { - - /* But we don't want it. Release it! */ - nx_packet_release(receive_packet_ptr); - } - - /* Keep checking till the queue becomes empty. */ - - } while(status == NX_SUCCESS); -#endif - - /* Send the DNS packet out. */ - status = nxd_udp_socket_send(&dns_ptr -> nx_dns_socket, packet_ptr, dns_server_address, NX_DNS_PORT); - - /* Check the completion of the send. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful, release the packet. */ - nx_packet_release(packet_ptr); - - return status; - } - -#ifdef NX_DNS_CLIENT_CLEAR_QUEUE - - /* Initialize the value. */ - elapsed_time = 0; - time_remaining = wait_option; - - /* If waiting for the DNS 'sleep' interval, check for packets arriving on the queue. */ - while(time_remaining > 0) - { - - start_time = tx_time_get(); - - /* Check if some of these packet are intended for other hosts. */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, time_remaining); - - /* Determine if this one is for us. */ - if (status == NX_SUCCESS) - { - - /* Check the IDs in the DNS header match. */ - if (_nx_dns_network_to_short_convert(receive_packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) == id) - { - - /* They do. We can stop receiving packets and process this one. */ - break; - } - else - { - - /* They do not. Discard the packet! */ - nx_packet_release(receive_packet_ptr); - } - } - - /* Get the current time. */ - current_time = tx_time_get(); - - /* Has the time wrapped? */ - if (current_time >= start_time) - { - /* No, simply subtract to get the elapsed time. */ - elapsed_time = current_time - start_time; - } - else - { - - /* Yes it has. Time has rolled over the 32-bit boundary. */ - elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; - } - - /* Update the time remaining with the elapsed time. */ - if (time_remaining > elapsed_time) - { - time_remaining -= elapsed_time; - } - else - time_remaining = 0; - - } - -#else - - /* Otherwise, wait for a DNS response UDP packet. */ - status = nx_udp_socket_receive(&(dns_ptr -> nx_dns_socket), &receive_packet_ptr, wait_option); -#endif - - /* Check status. */ - if (status == NX_SUCCESS) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - if (receive_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(receive_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Call the function to process the DNS packet. */ - status = _nx_dns_response_process(dns_ptr, receive_packet_ptr, record_buffer, buffer_size, record_count); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_response_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a DNS respond packet. If the reply packet */ -/* includes multiple answers. this service records as many answers */ -/* into the record_buffer. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* record_buffer Buffer for resource data */ -/* buffer_size Buffer size for resource data */ -/* record_count The count of resource data */ -/* lookup_type The DNS query type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* _nx_dns_network_to_short_convert Convert to unsigned short */ -/* _nx_dns_resource_type_get Get the value of the resource */ -/* type. */ -/* _nx_dns_process_cname_type Process the CNAME type record */ -/* _nx_dns_process_txt_type Process the TXT type record */ -/* _nx_dns_process_ns_type Process the NS type record */ -/* _nx_dns_process_mx_type Process the MX type record */ -/* _nx_dns_process_srv_type Process the SRV type record */ -/* _nx_dns_process_a_type Process the A type record */ -/* _nx_dns_process_aaaa_type Process the AAAA type record */ -/* _nx_dns_process_soa_type Process the SOA type record */ -/* nx_packet_release Release the packet. */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_response_process(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *record_buffer, - UINT buffer_size, UINT *record_count) -{ - -UINT status; -USHORT answerCount; -USHORT answerRRCount; -USHORT authorityRRCount; -USHORT additionalRRCount; -UCHAR *data_ptr; -UINT response_type; -UCHAR *buffer_prepend_ptr; -UCHAR *buffer_append_ptr; -UINT rrIndex; -UINT rr_location; -UINT answer_found = NX_FALSE; - - /* Set the buffer pointer. */ - buffer_prepend_ptr = record_buffer; - buffer_append_ptr = record_buffer + buffer_size; - - /* We received a response. Is there a valid header? */ - if (packet_ptr -> nx_packet_length <= NX_DNS_QDSECT_OFFSET) - { - - /* No; Release the new packet. */ - nx_packet_release(packet_ptr); - - /* Return error status. */ - return NX_DNS_MALFORMED_PACKET; - } - - /* Does the incoming DNS header ID match the query ID we sent out? */ - if (_nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ID_OFFSET) != dns_ptr -> nx_dns_transmit_id) - { - - /* No; Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error status. */ - return NX_DNS_BAD_ID_ERROR; - } - - /* Check that the packet has a valid response record. */ - status = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_FLAGS_OFFSET); - - /* Check for indication of DNS server error (cannot authenticate answer or authority portion - of the DNS data. */ - if ((status & NX_DNS_ERROR_MASK) == NX_DNS_ERROR_MASK) - { - - /* Release the source packet. */ - nx_packet_release(packet_ptr); - - return NX_DNS_SERVER_AUTH_ERROR; - } - - /* Determine if we have any 'answers' to our DNS query. */ - answerRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ANCOUNT_OFFSET); - answerCount = answerRRCount; - - /* Also check if there are any 'hints' from the Authoritative nameserver. */ - authorityRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_NSCOUNT_OFFSET); - answerCount = (USHORT)(answerCount + authorityRRCount); - - /* Include Additional section as well */ - additionalRRCount = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_ARCOUNT_OFFSET); - answerCount = (USHORT)(answerCount + additionalRRCount); - - /* Are there answers in this resposne? */ - if (((status & NX_DNS_QUERY_MASK) == NX_DNS_RESPONSE_FLAG) - && ((status & NX_DNS_RCODE_MASK) == NX_DNS_RCODE_SUCCESS) - && (answerCount >= 1)) - { - - - /* This looks like the response to our question, now find the response record. */ - /* Point at the start of the question. */ - data_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDSECT_OFFSET; - - /* Determine if there is a question still in the server's response. */ - if (_nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET) == 1) - { - /* Yes, the question is present in the response, skip it! */ - data_ptr += _nx_dns_name_size_calculate(data_ptr) + 4; - } - - /* Set the status. */ - status = NX_SUCCESS; - - /* Check all the response records */ - for(rrIndex = 0; rrIndex < answerCount; rrIndex++) - { - - /* Set the section class. */ - if(answerRRCount && (rrIndex < answerRRCount)) - rr_location = NX_DNS_RR_ANSWER_SECTION; - else if(authorityRRCount && (rrIndex < (UINT)(answerRRCount + authorityRRCount))) - rr_location = NX_DNS_RR_AUTHORITY_SECTION; - else - rr_location = NX_DNS_RR_ADDITIONAL_SECTION; - - /* Check for valid data_ptr. */ - if (data_ptr >= packet_ptr -> nx_packet_append_ptr) - { - - /* Process error. */ - break; - } - - /* Process the server response. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Is this an A Type? */ - if(response_type == NX_DNS_RR_TYPE_A) - { - - /* Call the function process the A type message. */ - status = _nx_dns_process_a_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count, rr_location); - - } - - /* Is this an AAAA Type? */ - else if(response_type == NX_DNS_RR_TYPE_AAAA) - { - - /* Call the function process the AAAA type message. */ - status = _nx_dns_process_aaaa_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count, rr_location); - - } - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - - /* Is this a Type NX_DNS_RR_TYPE_CNAME? */ - else if(response_type == NX_DNS_RR_TYPE_CNAME) - { - - /* Call the function process the CNAME type message. */ - status = _nx_dns_process_cname_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); - - } - - /* Is this a Type NX_DNS_RR_TYPE_TXT? */ - else if(response_type == NX_DNS_RR_TYPE_TXT) - { - - /* Call the function process the TXT type message. */ - status = _nx_dns_process_txt_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); - } - - /* Is this a Type NX_DNS_RR_TYPE_NS? */ - else if(response_type == NX_DNS_RR_TYPE_NS) - { - - /* Call the function process the NS type message. */ - status = _nx_dns_process_ns_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); - } - - - /* Is this a Type NX_DNS_RR_TYPE_MX? */ - else if(response_type == NX_DNS_RR_TYPE_MX) - { - - /* Call the function process the MX type message. */ - status = _nx_dns_process_mx_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); - } - - /* Is this a Type NX_DNS_RR_TYPE_SRV? */ - else if(response_type == NX_DNS_RR_TYPE_SRV) - { - - /* Call the function process the SRV type message. */ - status = _nx_dns_process_srv_type(dns_ptr, packet_ptr, data_ptr, &buffer_prepend_ptr, &buffer_append_ptr, record_count); - } - - /* Is this a Type NX_DNS_RR_TYPE_SOA? */ - else if(response_type == NX_DNS_RR_TYPE_SOA) - { - - /* Call the function process the SOA type message. */ - status = _nx_dns_process_soa_type(dns_ptr, packet_ptr, data_ptr, record_buffer, buffer_size, record_count); - - } -#endif - - /* Check the process status. */ - if(status != NX_SUCCESS) - { - - /* Process error. */ - break; - } - else - { - - /* Did we get a correct answer? */ - if ((answer_found == NX_FALSE) && - (response_type == dns_ptr -> nx_dns_lookup_type)) - { - answer_found = NX_TRUE; - } - } - - data_ptr += _nx_dns_resource_size_get(data_ptr); - } - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Check the answer found flag. */ - if (answer_found) - status = NX_SUCCESS; - else - status = NX_DNS_QUERY_FAILED; - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_a_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the A record type. If the DNS look up type */ -/* was NS, MX, or SRV type, this function also parses the additional */ -/* section looking for A type information. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* buffer_prepend_ptr Pointer to the starting */ -/* address of available buffer */ -/* buffer_append_ptr Pointer to the ending address */ -/* of available buffer */ -/* record_count The count of the IPv4 address */ -/* rr_location The DNS resource data section */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_a_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, - UINT *record_count, UINT rr_location) -{ - -UINT response_type; -ULONG ipv4_address; - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -UCHAR *buffer_header_ptr; -#endif -#ifdef NX_DNS_CACHE_ENABLE -UINT size; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#if !defined(NX_DNS_CACHE_ENABLE) && !defined(NX_DNS_ENABLE_EXTENDED_RR_TYPES) - NX_PARAMETER_NOT_USED(packet_ptr); -#endif - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Process the A type message in the answer section.*/ - if((rr_location == NX_DNS_RR_ANSWER_SECTION)|| - (rr_location == NX_DNS_RR_AUTHORITY_SECTION)) - { - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Yes, make sure it has the correct data size. */ - if (_nx_dns_resource_data_length_get(data_ptr) == 4) - { - - /* Finally, get the address!!! */ - ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); - - /* Check the buffer space. */ - - if (*buffer_prepend_ptr + 4 > *buffer_append_ptr) - { - - /* The buffer space is not enough. */ - return(NX_DNS_NEED_MORE_RECORD_BUFFER); - } - - /* Set the return IP address. */ - memcpy(*buffer_prepend_ptr,&ipv4_address,4); - - /* Update the record buffer pointer. */ - *buffer_prepend_ptr +=4; - - /* Update the count of ipv4 address. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_A; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the IPv4 address. */ - temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_a.nx_dns_rr_a_address = ipv4_address; - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Success! Return success to caller! */ - return(NX_SUCCESS); - } - else - { - - /* Return.*/ - return(NX_DNS_MALFORMED_PACKET); - } - } - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - /* Process the A type message in the additional section. */ - else if(rr_location == NX_DNS_RR_ADDITIONAL_SECTION) - { - if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_NS) - { - NX_DNS_NS_ENTRY *ns_entry; - UINT entry_index; - UINT name_size; - - /* Processing NS query, and encountered A type in the additional section. */ - /* This means the record_buffer should already contain name server information, - and the name server IP address is in this resource record. */ - - /* First obtain the string. */ - temp_string_buffer[0] = 0; - name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!name_size) - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the first address of record buffer. */ - buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_NS_ENTRY)); - - /* Go through all the records and match the string. */ - for(entry_index = 0; entry_index < *record_count; entry_index++) - { - - /* Set the NS entry. */ - ns_entry = (NX_DNS_NS_ENTRY*)(buffer_header_ptr); - - /* Check the ipv4 address.*/ - if( ns_entry -> nx_dns_ns_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) - { - - /* Update the buffer prepend pointer, and match the next NS entry. */ - buffer_header_ptr += sizeof(NX_DNS_NS_ENTRY); - - continue; - } - - if((memcmp(ns_entry -> nx_dns_ns_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) - { - - /* This A type record contains the IPv4 address for the NS entry. */ - - /* Yes, make sure it has the correct data size. */ - if (_nx_dns_resource_data_length_get(data_ptr) == 4) - { - - /* Finally, get the address!!! */ - ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); - - /* Record the NS entry ipv4 address . */ - ns_entry -> nx_dns_ns_ipv4_address = ipv4_address; - - /* Success! Return success to caller! */ - return(NX_SUCCESS); - } - } - else - { - - /* Update the buffer prepend pointer, and match the next NS entry. */ - buffer_header_ptr += sizeof(NX_DNS_NS_ENTRY); - } - } - } - - else if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_MX) - { - NX_DNS_MX_ENTRY *mx_entry; - UINT entry_index; - UINT name_size; - - /* Processing MX query, and encountered A type in the additional section. */ - /* This means the record_buffer should already contain mail exchange information, - and the mail server IP address is in this resource record. */ - - /* First obtain the string. */ - temp_string_buffer[0] = 0; - name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!name_size) - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Set the record buffer prepend. */ - buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_MX_ENTRY)); - - /* Go through all the records and match the string. */ - for(entry_index = 0; entry_index < *record_count; entry_index++) - { - - /* Set the MX entry pointer. */ - mx_entry = (NX_DNS_MX_ENTRY*)(buffer_header_ptr); - - /* Check the ipv4 address, If the ipv4 address has been set, skip it..*/ - if( mx_entry -> nx_dns_mx_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) - { - - /* Update the buffer prepend pointer, and match the next MX entry. */ - buffer_header_ptr += sizeof(NX_DNS_MX_ENTRY); - continue; - } - - if((memcmp(mx_entry -> nx_dns_mx_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) - { - - /* This A type record contains the IPv4 address for the MX entry. */ - - /* Yes, make sure it has the correct data size. */ - if (_nx_dns_resource_data_length_get(data_ptr) == 4) - { - - /* Finally, get the address!!! */ - ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); - - /* Record the MX entry ipv4 address . */ - mx_entry -> nx_dns_mx_ipv4_address = ipv4_address; - - /* Success! Return success to caller! */ - return(NX_SUCCESS); - } - } - else - { - - /* Update the buffer prepend pointer, and match the next MX entry. */ - buffer_header_ptr += sizeof(NX_DNS_MX_ENTRY); - } - } - } - else if(dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_SRV) - { - NX_DNS_SRV_ENTRY *srv_entry; - UINT entry_index; - UINT name_size; - - /* Processing SRV query, and encountered A type in the additional section. */ - /* This means the record_buffer should already contain SRV information, - and the mail server IP address is in this resource record. */ - - /* First obtain the string. */ - temp_string_buffer[0] = 0; - name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!name_size) - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Set the record buffer prepend. */ - buffer_header_ptr = *buffer_prepend_ptr - ((*record_count) * sizeof(NX_DNS_SRV_ENTRY)); - - /* Go through all the records and match the string. */ - for(entry_index = 0; entry_index < *record_count; entry_index++) - { - - /* Set the MX entry pointer. */ - srv_entry = (NX_DNS_SRV_ENTRY*)(buffer_header_ptr); - - /* Check the ipv4 address, If the ipv4 address has been set, skip it..*/ - if( srv_entry -> nx_dns_srv_ipv4_address != IP_ADDRESS(0, 0, 0, 0)) - { - - /* Update the buffer prepend pointer, and match the next MX entry. */ - buffer_header_ptr += sizeof(NX_DNS_SRV_ENTRY); - continue; - } - - if((memcmp(srv_entry -> nx_dns_srv_hostname_ptr, &temp_string_buffer[0], name_size)) == 0) - { - - /* This A type record contains the IPv4 address for the MX entry. */ - - /* Yes, make sure it has the correct data size. */ - if (_nx_dns_resource_data_length_get(data_ptr) == 4) - { - - /* Finally, get the address!!! */ - ipv4_address = _nx_dns_network_to_long_convert(_nx_dns_resource_data_address_get(data_ptr)); - - /* Record the SRV entry ipv4 address . */ - srv_entry -> nx_dns_srv_ipv4_address = ipv4_address; - - /* Success! Return success to caller! */ - return(NX_SUCCESS); - } - } - else - { - - /* Update the buffer prepend pointer, and match the next MX entry. */ - buffer_header_ptr += sizeof(NX_DNS_SRV_ENTRY); - } - } - } - } -#endif - - /* Return.*/ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_aaaa_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the AAAA record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* buffer_prepend_ptr Pointer to the starting */ -/* address of available buffer */ -/* buffer_append_ptr Pointer to the ending address */ -/* of available buffer */ -/* record_count The count of the IPv6 address */ -/* rr_location The DNS resource data section */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_aaaa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, - UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, - UCHAR **buffer_append_ptr, UINT *record_count, - UINT rr_location) -{ - -UINT response_type; -UINT i; -ULONG ipv6_address; -NX_DNS_IPV6_ADDRESS *ipv6_address_ptr; -#ifdef NX_DNS_CACHE_ENABLE -UINT size; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifndef NX_DNS_CACHE_ENABLE - NX_PARAMETER_NOT_USED(packet_ptr); -#endif - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Process the A type message in the answer section.*/ - if((rr_location == NX_DNS_RR_ANSWER_SECTION)|| - (rr_location == NX_DNS_RR_AUTHORITY_SECTION)) - { - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Yes, make sure it has the correct data size. */ - if (_nx_dns_resource_data_length_get(data_ptr) == 16) - { - - /* Check the buffer space. */ - if ((*buffer_prepend_ptr + sizeof(NX_DNS_IPV6_ADDRESS)) > *buffer_append_ptr) - { - - /* The buffer space is not enough. */ - return(NX_DNS_NEED_MORE_RECORD_BUFFER); - } - - /* Update the pointer to the ipv6 address. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - ipv6_address_ptr = (NX_DNS_IPV6_ADDRESS*)(*buffer_prepend_ptr); - - /* Finally, Record the ipv6 address to record buffer. */ - for(i = 0; i < 4; i++) - { - - ipv6_address = _nx_dns_network_to_long_convert(data_ptr); - - ipv6_address_ptr -> ipv6_address[i] = ipv6_address; - - data_ptr +=4; - - } - - *buffer_prepend_ptr = *buffer_prepend_ptr + sizeof(NX_DNS_IPV6_ADDRESS); - - /* Update the count of ipv6 address. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_AAAA; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the IPv6 address string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, ipv6_address_ptr, 16, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Success! */ - return(NX_SUCCESS); - } - else - { - - /* Return.*/ - return(NX_DNS_MALFORMED_PACKET); - } - - } - - /* Return.*/ - return(NX_SUCCESS); - -} - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_cname_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the CNAME record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* record_buffer Buffer space for storing */ -/* the host cname */ -/* buffer_size Size of record_buffer. */ -/* record_count Record count */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_cname_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR *record_buffer, UINT buffer_size, UINT *record_count) -{ -UINT response_type; -UINT name_size; -#ifdef NX_DNS_CACHE_ENABLE -UINT size; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if(response_type == dns_ptr -> nx_dns_lookup_type) - { - - /* Update the pointer to point at the resource data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Determine if there is room for the name - one less for NULL termination. */ - name_size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, record_buffer, buffer_size - 1); - if (name_size) - { - - /* Yes, got the canonical name successfully,and record the information! */ - - /* Update the count. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_CNAME; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the cname string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, record_buffer, name_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_cname.nx_dns_rr_cname_name))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - return(NX_SUCCESS); - } - else - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - } - - /* If send A type query, should also process the CNAME + A type response. - RFC1034, section3.6.2, page15 and RFC10.5 section 3.3.1, page14. */ - else if (dns_ptr -> nx_dns_lookup_type == NX_DNS_RR_TYPE_A) - { - - /* Only get the A type message, skip the CNAME answer process, - and return success to process next A type answer. - The CNAME record to be implemented. */ - return(NX_SUCCESS); - } - - /* Error lookup response*/ - else - { - /* Return error status. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_txt_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the TXT DNS type packet and record text string*/ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* record_buffer Buffer space for storing */ -/* the host text string */ -/* buffer_size Size of record_buffer. */ -/* record_count Record count */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_txt_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR *record_buffer, UINT buffer_size, UINT *record_count) -{ -UINT response_type; -UINT text_data_length; -#ifdef NX_DNS_CACHE_ENABLE -UINT size; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#else - NX_PARAMETER_NOT_USED(packet_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Update the pointer to point at the response data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Get the text resource data length. */ - text_data_length = (UINT) (*data_ptr++); - - /* Judge the resource data buffer space. */ - if(text_data_length > buffer_size - 1) - { - - /* Return error, and release the packet in repsonse*/ - return(NX_DNS_MALFORMED_PACKET); - - } - else - { - - /* Record the text string to the buffer. */ - memcpy(&record_buffer[0],data_ptr,text_data_length); - - /* Null terminate text. */ - record_buffer[text_data_length] = '\0'; - - /* Update the count. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_TXT; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the txt string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, record_buffer, text_data_length, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_txt.nx_dns_rr_txt_data))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Yes; We're done! Return success! */ - return(NX_SUCCESS); - } -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_ns_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the NS record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* buffer_prepend_ptr Pointer to the starting */ -/* address of available buffer */ -/* buffer_append_ptr Pointer to the ending address */ -/* of available buffer */ -/* record_count The count of the name server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* _nx_dns_resource_name_real_size_calculate */ -/* Calculate real size of name */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_ns_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, - UINT *record_count) -{ -NX_DNS_NS_ENTRY *nx_dns_ns_entry_ptr; -UINT response_type; -UINT name_buffer_size; -#ifdef NX_DNS_CACHE_ENABLE -UINT size; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Update the pointer to point at the resource data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Get the real size of the name, and set the name buffer size.*/ - name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the buffer space. */ - if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_NS_ENTRY))) - { - - /* The buffer space is not enough. */ - return(NX_DNS_NEED_MORE_RECORD_BUFFER); - } - - /* Set the ns entry pointer. */ - nx_dns_ns_entry_ptr = (NX_DNS_NS_ENTRY *)(*buffer_prepend_ptr); - - /* Initialize the variables to NULL. */ - memset(nx_dns_ns_entry_ptr, 0, sizeof(NX_DNS_NS_ENTRY)); - - /* Update the buffer pointer.*/ - *buffer_prepend_ptr += sizeof(NX_DNS_NS_ENTRY); - - /* Update the store pointer. include the null flag '\0'. */ - *buffer_append_ptr -= (name_buffer_size + 1); - - /* Determine if there is room for the name - one less for NULL termination. */ - if (_nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size)) - { - - /* Yes,record the name server successfully. */ - - /* Update the name server pointer. */ - nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr = *buffer_append_ptr; - - /* Update the count of ns. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_NS; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Add the ns string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr, name_buffer_size, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - return(NX_SUCCESS); - } - else - { - /* Ruturn. */ - return(NX_DNS_MALFORMED_PACKET); - } -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_mx_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the MX record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* buffer_prepend_ptr Pointer to the starting */ -/* address of available buffer */ -/* buffer_append_ptr Pointer to the ending address */ -/* of available buffer */ -/* record_count The count of the mail exchange*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* _nx_dns_resource_name_real_size_calculate */ -/* Calculate real size of name */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_mx_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR **buffer_prepend_ptr, UCHAR **buffer_append_ptr, - UINT *record_count) -{ -NX_DNS_MX_ENTRY *nx_dns_mx_entry_ptr; -UINT response_type; -UINT name_buffer_size; -USHORT mx_preference; -UINT name_length; -#ifdef NX_DNS_CACHE_ENABLE -UINT status; -ULONG rr_ttl; -UINT size; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Update the pointer to point at the resource data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Get the preference data of the resource data. */ - mx_preference = _nx_dns_network_to_short_convert(data_ptr); - - /* Skip the MX preference, and update the pointer to point at the mail exchange data. */ - data_ptr += 2; - - /* Get the real size of the name, and set the name buffer size.*/ - name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the buffer space. */ - if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_MX_ENTRY))) - { - - /* The buffer space is not enough. */ - return(NX_DNS_NEED_MORE_RECORD_BUFFER); - } - - /* Set the ns entry pointer. */ - nx_dns_mx_entry_ptr = (NX_DNS_MX_ENTRY *)(*buffer_prepend_ptr); - - /* Initialize the variables to NULL. */ - memset(nx_dns_mx_entry_ptr, 0, sizeof(NX_DNS_MX_ENTRY)); - - /* Record the MX preference. */ - nx_dns_mx_entry_ptr -> nx_dns_mx_preference = mx_preference; - - /* Update the buffer pointer.*/ - *buffer_prepend_ptr += sizeof(NX_DNS_MX_ENTRY); - - /* Update the store pointer. include the null flag '\0'. */ - *buffer_append_ptr -= (name_buffer_size + 1); - - /* Determine if there is room for the name - one less for NULL termination. */ - name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size); - - /* Check the length. */ - if (name_length) - { - - /* Yes,record the name server successfully. */ - - /* Update the name server pointer. */ - nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr = *buffer_append_ptr; - - /* Update the count of mx. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - - /* Check the temp buffer size. */ - if (name_length + 2 > NX_DNS_NAME_MAX + 1) - return (NX_SUCCESS); - - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_MX; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Set the MX rdata preference string. */ - *(USHORT *)(&temp_string_buffer[0]) = mx_preference; - - /* Set the MX rdata string. */ - memcpy((char*)&temp_string_buffer[2], (const char*)nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr, name_length); - - /* Add the MX string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length + 2, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - return(NX_SUCCESS); - } - else - { - - /* Return. */ - return(NX_DNS_MALFORMED_PACKET); - } -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_srv_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the DNS SRV record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* buffer_prepend_ptr Pointer to the starting */ -/* address of available buffer */ -/* buffer_append_ptr Pointer to the ending address */ -/* of available buffer */ -/* record_count The count of the services */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* _nx_dns_resource_name_real_size_calculate */ -/* Calculate real size of name */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_srv_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UCHAR **buffer_prepend_ptr, - UCHAR **buffer_append_ptr, UINT *record_count) -{ -NX_DNS_SRV_ENTRY *nx_dns_srv_entry_ptr; -UINT response_type; -UINT name_buffer_size; -USHORT srv_priority; -USHORT srv_weight; -USHORT srv_port_number; -UINT name_length; -#ifdef NX_DNS_CACHE_ENABLE -UINT status; -ULONG rr_ttl; -UINT size; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - size = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!size) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Update the pointer to point at the resource data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Get the priority data of the resource data. */ - srv_priority = _nx_dns_network_to_short_convert(data_ptr); - - /* Skip the SRV preference, and update the pointer to point at the weight data. */ - data_ptr += 2; - - /* Get the weight data of the resource data. */ - srv_weight = _nx_dns_network_to_short_convert(data_ptr); - - /* Skip the SRV weight, and update the pointer to point at the port data. */ - data_ptr += 2; - - /* Get the port data of the resource data. */ - srv_port_number = _nx_dns_network_to_short_convert(data_ptr); - - /* Skip the SRV port, and update the pointer to point at the target data. */ - data_ptr += 2; - - /* Get the real size of the name, and set the name buffer size.*/ - name_buffer_size = _nx_dns_resource_name_real_size_calculate(packet_ptr -> nx_packet_prepend_ptr, (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the buffer space. */ - if ((*buffer_append_ptr - name_buffer_size - 1 ) < (*buffer_prepend_ptr + sizeof(NX_DNS_MX_ENTRY))) - { - - /* The buffer space is not enough. */ - return(NX_DNS_NEED_MORE_RECORD_BUFFER); - } - - /* Set the SRV entry pointer. */ - nx_dns_srv_entry_ptr = (NX_DNS_SRV_ENTRY *)(*buffer_prepend_ptr); - - /* Initialize the variables to NULL. */ - memset(nx_dns_srv_entry_ptr, 0, sizeof(NX_DNS_SRV_ENTRY)); - - /* Record the SRV options data. */ - nx_dns_srv_entry_ptr -> nx_dns_srv_priority = srv_priority; - nx_dns_srv_entry_ptr -> nx_dns_srv_weight = srv_weight; - nx_dns_srv_entry_ptr -> nx_dns_srv_port_number = srv_port_number; - - /* Update the buffer pointer.*/ - *buffer_prepend_ptr += sizeof(NX_DNS_SRV_ENTRY); - - /* Update the store pointer. include the null flag '\0'. */ - *buffer_append_ptr -= (name_buffer_size + 1); - - /* Determine if there is room for the name - one less for NULL termination. */ - name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, *buffer_append_ptr, name_buffer_size); - - /* Check the length. */ - if (name_length) - { - - /* Yes,record the name server successfully. */ - - /* Update the name server pointer. */ - nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr = *buffer_append_ptr; - - /* Update the count of srv. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - - /* Check the temp buffer size. */ - if (name_length + 6 > NX_DNS_NAME_MAX + 1) - return (NX_SUCCESS); - - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_SRV; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, size, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Set the SRV priority, weight and port number. */ - *(USHORT *)(&temp_string_buffer[0]) = srv_priority; - *(USHORT *)(&temp_string_buffer[2]) = srv_weight; - *(USHORT *)(&temp_string_buffer[4]) = srv_port_number; - - /* Set the SRV rdata string. */ - memcpy((char*)&temp_string_buffer[6], (const char*)nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr, name_length); - - /* Add the srv string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length + 6, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - return(NX_SUCCESS); - } - else - { - - /* Return. */ - return(NX_DNS_MALFORMED_PACKET); - } -} -#endif - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_process_soa_type PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the SOA record type. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Pointer to received packet */ -/* data_ptr Pointer to resource data */ -/* section */ -/* record_buffer Buffer space for storing */ -/* the data structures that */ -/* hold the SOA information */ -/* buffer_size Size of record_buffer. */ -/* record_count Record count */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_resource_type_get Get resource type */ -/* _nx_dns_resource_data_address_get Get address of data */ -/* _nx_dns_name_string_unencode Unencode the name and get it. */ -/* _nx_dns_name_size_calculate Calculate size of name field */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_response_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_process_soa_type(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, - UCHAR *record_buffer, UINT buffer_size, UINT *record_count) -{ -NX_DNS_SOA_ENTRY *nx_dns_soa_entry_ptr; -UINT response_type; -ULONG mname_length; -ULONG rname_length; -UCHAR *buffer_start; -#ifdef NX_DNS_CACHE_ENABLE -ULONG name_length; -UINT status; -ULONG rr_ttl; -#endif /* NX_DNS_CACHE_ENABLE */ - -#ifdef NX_DNS_CACHE_ENABLE - /* Initialize the value. */ - memset(temp_string_buffer, 0, NX_DNS_NAME_MAX + 1); - memset(&temp_rr, 0, sizeof (NX_DNS_RR)); - - /* First obtain the string. */ - name_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, temp_string_buffer, NX_DNS_NAME_MAX); - - /* Check the string correct. */ - if(!name_length) - { - - /* Return! */ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the resource record ttl. */ - rr_ttl = _nx_dns_resource_time_to_live_get(data_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - - /* Process the server response and get it. */ - response_type = _nx_dns_resource_type_get(data_ptr); - - /* Verify this is what the DNS Client was requesting. */ - if (response_type != dns_ptr -> nx_dns_lookup_type) - { - - /* No, this was not what the Client requested. Return error status. - This should not happen so return error to the host application, - might be a problem with the query or the server. */ - return NX_DNS_MISMATCHED_RESPONSE; - } - - /* Set the SRV entry pointer. */ - nx_dns_soa_entry_ptr = (NX_DNS_SOA_ENTRY *)(record_buffer); - - /* Update the start address of available buffer and the buffer size. */ - buffer_start = record_buffer + sizeof(NX_DNS_SOA_ENTRY); - buffer_size -= sizeof(NX_DNS_SOA_ENTRY); - - /* Update the pointer to point at the resource data. */ - data_ptr = _nx_dns_resource_data_address_get(data_ptr); - - /* Get the primary name server and record it in buffer. */ - mname_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, buffer_start, buffer_size - 1); - - /* Check the name length. */ - if (mname_length) - { - - /* Yes, got the primary name server successfully. set the mname ptr pointer. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr = buffer_start; - - /* Update the pointer to point at the rname data. */ - data_ptr += _nx_dns_name_size_calculate(data_ptr); - - /* Update the start address of available buffer and the buffer size. 1 is the Null terminate. */ - buffer_start += mname_length + 1; - buffer_size -= mname_length + 1; - } - else - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the responsible mail address and record it in buffer. */ - rname_length = _nx_dns_name_string_unencode(packet_ptr, data_ptr, buffer_start, buffer_size - 1); - - if (rname_length) - { - - /* Yes, got the primary name server successfully. set the mname ptr pointer. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr = buffer_start; - - /* Update the pointer to point at the rname data. */ - data_ptr += _nx_dns_name_size_calculate(data_ptr); - - /* Update the start address of available buffer and the buffer size.1 is the Null terminate. */ - buffer_start += rname_length + 1; - buffer_size -= rname_length + 1; - } - else - { - - /* Return !*/ - return(NX_DNS_MALFORMED_PACKET); - } - - /* Get the serial number of the resource data. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_serial = _nx_dns_network_to_long_convert(data_ptr); - - /* Skip the serial number, and update the pointer to point at the refresh data. */ - data_ptr += 4; - - /* Get the refresh number of the resource data. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_refresh = _nx_dns_network_to_long_convert(data_ptr); - - /* Skip the refresh number, and update the pointer to point at the retry data. */ - data_ptr += 4; - - /* Get the retry number of the resource data. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_retry = _nx_dns_network_to_long_convert(data_ptr); - - /* Skip the retry number, and update the pointer to point at the expire data. */ - data_ptr += 4; - - /* Get the expire number of the resource data. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_expire = _nx_dns_network_to_long_convert(data_ptr); - - /* Skip the expire number, and update the pointer to point at the minmum data. */ - data_ptr += 4; - - /* Get the minmum number of the resource data. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_minmum = _nx_dns_network_to_long_convert(data_ptr); - - /* Skip the serial number, and update the pointer to point at the refresh data. */ - data_ptr += 4; - - /* Update the count. */ - (*record_count) ++; - -#ifdef NX_DNS_CACHE_ENABLE - - /* Check the temp buffer size. */ - if (mname_length + rname_length + 22 > NX_DNS_NAME_MAX + 1) - return (NX_SUCCESS); - - /* Set the resource record type. */ - temp_rr.nx_dns_rr_type = NX_DNS_RR_TYPE_SOA; - - /* Set the resource record ttl. */ - temp_rr.nx_dns_rr_ttl = rr_ttl; - - /* Add the name string. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, name_length, (VOID **)(&(temp_rr.nx_dns_rr_name))); - - /* Check the status. */ - if(status) - return (NX_SUCCESS); - - /* Set the SOA MNAME. */ - memcpy((char*)&temp_string_buffer[0], (char*)nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr, mname_length); - temp_string_buffer[mname_length] = '\0'; - - /* Set the SOA RNAME. */ - memcpy((char*)&temp_string_buffer[mname_length + 1], (char*)nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr, rname_length); - temp_string_buffer[mname_length + 1 + rname_length] = '\0'; - - /* Set the SOA Serial, Refresh, Retry, Expire, Minmum. */ - *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 2]) = nx_dns_soa_entry_ptr -> nx_dns_soa_serial; - *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 6]) = nx_dns_soa_entry_ptr -> nx_dns_soa_refresh; - *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 10]) = nx_dns_soa_entry_ptr -> nx_dns_soa_retry; - *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 14]) = nx_dns_soa_entry_ptr -> nx_dns_soa_expire; - *(ULONG *)(&temp_string_buffer[mname_length + rname_length + 18]) = nx_dns_soa_entry_ptr -> nx_dns_soa_minmum; - - /* Add the SOA string, mname length, '\0', rname length, '\0', Refresh, Retry, Expire, Minmum. */ - status = _nx_dns_cache_add_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_string_buffer, mname_length + rname_length + 22, (VOID **)(&(temp_rr.nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata))); - - /* Check the status. */ - if(status) - { - _nx_dns_cache_delete_string(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, temp_rr.nx_dns_rr_name, 0); - return (NX_SUCCESS); - } - - /* Add the resource record. */ - status = _nx_dns_cache_add_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr, NX_NULL); - - /* Check the status. */ - if(status) - { - - /* Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, &temp_rr); - } -#endif /* NX_DNS_CACHE_ENABLE */ - - return (NX_SUCCESS); -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_host_by_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS get host by address */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* ip_address IP address to get host name */ -/* host_name Destination for host name */ -/* host_name_buffer_size Buffer size of host name */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_by_address_get Actual DNS get host by address*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG host_address, UCHAR *host_name, UINT host_name_buffer_size, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (host_name == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid non pointer input. */ - if (!host_address || dns_ptr -> nx_dns_id != NX_DNS_ID || (host_name_buffer_size == 0)) - return(NX_DNS_PARAM_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS get host by address service. */ - status = _nx_dns_host_by_address_get(dns_ptr, host_address, host_name, host_name_buffer_size, wait_option); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_host_by_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the host name associated with the */ -/* specified IP address. If a host name cannot be found, this */ -/* routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* dns_address DNS server IP address */ -/* host_name Destination for host name */ -/* host_name_buffer_size Buffer size for host name */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_host_by_address_get_internal Actual host address */ -/* get service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG dns_address, UCHAR *host_name, UINT host_name_buffer_size, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -NXD_ADDRESS host_address; - - - /* Check for null address input. */ - if (dns_address == 0) - { - return NX_DNS_BAD_ADDRESS_ERROR; - } - - /* Construct an IP address structure, and fill in IPv4 address information. */ - host_address.nxd_ip_version = NX_IP_VERSION_V4; - host_address.nxd_ip_address.v4 = dns_address; - - /* Invoke the real function. */ - return(_nx_dns_host_by_address_get_internal(dns_ptr, &host_address, host_name, host_name_buffer_size, wait_option)); -#else - NX_PARAMETER_NOT_USED(dns_ptr); - NX_PARAMETER_NOT_USED(dns_address); - NX_PARAMETER_NOT_USED(host_name); - NX_PARAMETER_NOT_USED(host_name_buffer_size); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_dns_host_by_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the NetX duo compatible DNS get */ -/* host by address function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* ip_address IP address to get host name */ -/* host_name_ptr Destination for host name */ -/* host_name_buffer_size Size of host name buffer */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_dns_host_by_address_get Actual DNS get host by address*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((dns_ptr == NX_NULL) || (host_name_ptr == NX_NULL) || (host_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid host name size. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID || (host_name_buffer_size == 0)) - return(NX_DNS_PARAM_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DNS service get host IP address by host name. */ - status = _nxd_dns_host_by_address_get(dns_ptr, host_address, host_name_ptr, host_name_buffer_size, wait_option); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_host_by_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the host name associated with the */ -/* specified IP address. If a host name cannot be found, this */ -/* routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_address_ptr NXD_ADDRESS instance with the */ -/* IP address to search for */ -/* host name */ -/* host_name_ptr Destination for host name */ -/* host_name_buffer_size Buffer size for host name */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_dns_build_an_ipv6_question_string Create the DNS query */ -/* _nx_dns_send_query_by_address Create and transmit the DNS */ -/* query packet */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, - UINT host_name_buffer_size, ULONG wait_option) -{ - - - /* Invoke the real function. */ - return(_nx_dns_host_by_address_get_internal(dns_ptr, host_address_ptr, host_name_ptr, host_name_buffer_size, wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_host_by_address_get_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses DNS to get the host name associated with the */ -/* specified IP address. If a host name cannot be found, this */ -/* routine returns zero for the string size to signal an error. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* host_address_ptr Pointer to host address */ -/* host_name_ptr Destination for host name */ -/* host_name_buffer_size Buffer size for host name */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_dns_build_an_ipv6_question_string Create the DNS query */ -/* _nx_dns_send_query_by_address Create and transmit the DNS */ -/* query packet */ -/* tx_mutex_get Get DNS protection mutex */ -/* tx_mutex_put Release DNS protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_host_by_address_get_internal(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, - UINT host_name_buffer_size, ULONG wait_option) -{ - -UINT retries; -UINT status; -UCHAR ip_question[NX_DNS_IP_LOOKUP_SIZE + 1]; -UINT i; -#ifndef NX_DISABLE_IPV4 -UCHAR dot = '.'; -UINT value; -UINT length, index; -#endif /* NX_DISABLE_IPV4 */ - - - /* Check for an invalid address type. */ - if ((host_address_ptr -> nxd_ip_version != NX_IP_VERSION_V4) && - (host_address_ptr -> nxd_ip_version != NX_IP_VERSION_V6)) - { - - return NX_DNS_INVALID_ADDRESS_TYPE; - } - - if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V6) -#ifdef FEATURE_NX_IPV6 - { - - /* Check for Null address input. */ - if (CHECK_UNSPECIFIED_ADDRESS(&(host_address_ptr ->nxd_ip_address.v6[0]))) - { - return NX_DNS_BAD_ADDRESS_ERROR; - } - } -#else - { - /* IPv6 not supported. */ - return NX_DNS_INVALID_ADDRESS_TYPE; - } -#endif - else if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* Check for Null address input. */ - if (host_address_ptr -> nxd_ip_address.v4== 0) -#endif /* NX_DISABLE_IPV4 */ - { - - return NX_DNS_BAD_ADDRESS_ERROR; - } - } - else - { - return NX_DNS_INVALID_ADDRESS_TYPE; - } - - /* Check for an invalid buffer size. */ - if (host_name_buffer_size == 0) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Clear the host name buffer. */ - memset(host_name_ptr, 0, sizeof(host_name_buffer_size)); - - /* Get the protection mutex to make sure no other thread interferes. */ - status = tx_mutex_get(&(dns_ptr -> nx_dns_mutex), wait_option); - - /* Check status. */ - if (status != TX_SUCCESS) - { - - /* The mutex was not granted in the time specified. Return an error. */ - return(NX_DNS_TIMEOUT); - } - - /* Determine if there is at least one DNS server. Is the first slot empty? */ - if (dns_ptr -> nx_dns_server_ip_array[0].nxd_ip_version == 0) - { - - /* No, this means the list is empty. Release the DNS Client lock. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - /* At least one DNS server is required - return an error. */ - return(NX_DNS_NO_SERVER); - } - - /* Is this an IPv6 address we are looking up? */ - if (host_address_ptr -> nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - /* Release the mutex and return. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - return NX_DNS_IPV6_NOT_SUPPORTED; -#else - /* Yes; build the PTR query string containing an IPv6 address. */ - _nxd_dns_build_an_ipv6_question_string(host_address_ptr, &ip_question[0], NX_DNS_IP_LOOKUP_SIZE); -#endif - } - else - { - -#ifndef NX_DISABLE_IPV4 - memset(ip_question, 0, NX_DNS_IP_LOOKUP_SIZE); - value = host_address_ptr -> nxd_ip_address.v4 & 0xff; - length = _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[0]); - ip_question[length++] = dot; - index = length; - - value = (host_address_ptr -> nxd_ip_address.v4 >> 8) & 0xff; - length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]); - ip_question[length++] = dot; - index = length; - - value = (host_address_ptr -> nxd_ip_address.v4 >> 16) & 0xff; - length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]) ; - ip_question[length++] = dot; - index = length; - - value = (host_address_ptr -> nxd_ip_address.v4 >> 24) & 0xff; - length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]); - ip_question[length++] = dot; - index = length; - - memcpy(&ip_question[length], &lookup_end[0], 12); -#else - /* Release the mutex and return. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - return NX_DNS_BAD_ADDRESS_ERROR; -#endif /* NX_DISABLE_IPV4 */ - } - -#ifdef NX_DNS_CACHE_ENABLE - - /* Find the answer in local cache. */ - if(_nx_dns_cache_find_answer(dns_ptr, dns_ptr -> nx_dns_cache, ip_question, NX_DNS_RR_TYPE_PTR, host_name_ptr, host_name_buffer_size, NX_NULL) == NX_DNS_SUCCESS) - { - - /* Release the mutex. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - return (NX_DNS_SUCCESS); - } -#endif /*NX_DNS_CACHE_ENABLE. */ - - /* Keep sending queries to all DNS Servers till the retry count expires. */ - for (retries = 0; retries < dns_ptr -> nx_dns_retries; retries++) - { - - /* The client should try other servers and server addresses before repeating a query to a specific address of a server. - RFC1035, Section4.2.1 UDP usage, Page32. */ - /* Attempt host name resolution from each DNS server till one if found. */ - for (i = 0; (i < NX_DNS_MAX_SERVERS) && (dns_ptr -> nx_dns_server_ip_array[i].nxd_ip_version != 0); i ++) - { - - /* Send the PTR/reverse lookup query. */ - status = _nx_dns_send_query_by_address(dns_ptr, &dns_ptr -> nx_dns_server_ip_array[i], &ip_question[0], - host_name_ptr, host_name_buffer_size, wait_option); - - /* Check the status. */ - if (status == NX_SUCCESS) - { - - /* Release the mutex */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - /* Yes, have done, just return success. */ - return NX_SUCCESS; - } - } - - /* Timed out for querying all DNS servers in this cycle, double the timeout, limited to NX_DNS_MAX_RETRANS_TIMEOUT. */ - if ((2 * wait_option) <= NX_DNS_MAX_RETRANS_TIMEOUT) - wait_option = wait_option * 2; - else - wait_option = NX_DNS_MAX_RETRANS_TIMEOUT; - } - - /* Release protection. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - /* Failed on all servers, return DNS lookup failed status. */ - return(NX_DNS_QUERY_FAILED); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_new_packet_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This routine fills in the header and question in a DNS queyr packet,*/ -/* and updates the size and the question count fields in the header. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* packet_ptr Packet allocated for message */ -/* id DNS Client Identification */ -/* name Question e.g. host name */ -/* type DNS message type e.g. A, AAAA */ -/* */ -/* OUTPUT */ -/* */ -/* NX_DNS_PACKET_CREATE_ERROR Error creating header or query*/ -/* NX_SUCCESS Successful compltion */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_header_create Create a DNS header */ -/* _nx_dns_question_add Add the DNS question to packet*/ -/* nx_packet_allocate Allocate a new DNS packet */ -/* nx_packet_release Release DNS packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_name_get Get IP address with name */ -/* _nx_host_by_address_get Get name from IP address */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_new_packet_create(NX_DNS *dns_ptr, NX_PACKET *packet_ptr, USHORT id, UCHAR *name, USHORT type) -{ - -UINT size; - - /* Add the DNS header. */ - size = _nx_dns_header_create(packet_ptr -> nx_packet_append_ptr, id, NX_DNS_QUERY_FLAGS); - - /* Determine if there was an error. */ - if (size == 0) - { - - /* Return error status. */ - return NX_DNS_PACKET_CREATE_ERROR; - } - - /* Save the DNS transmit id and lookup type. */ - dns_ptr -> nx_dns_transmit_id = id; - dns_ptr -> nx_dns_lookup_type = type; - - /* Setup the packet pointers. */ - packet_ptr -> nx_packet_append_ptr += size; - packet_ptr -> nx_packet_length += size; - - /* Add the DNS question. */ - size = _nx_dns_question_add(packet_ptr, name, type); - - /* Determine if there was an error. */ - if (size == 0) - { - - /* Return the error status. */ - return NX_DNS_PACKET_CREATE_ERROR; - } - - /* Successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_header_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a standard DNS header and returns the size of */ -/* header. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to header area */ -/* id Identification */ -/* flags Flags */ -/* */ -/* OUTPUT */ -/* */ -/* size Size of DNS header */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_short_to_network_convert Convert from short to network */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_new_packet_create Create new DNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_header_create(UCHAR *buffer_ptr, USHORT id, USHORT flags) -{ - - /* Transaction ID. */ - _nx_dns_short_to_network_convert(buffer_ptr + NX_DNS_ID_OFFSET, id); - - /* Flags and Command. */ - _nx_dns_short_to_network_convert(buffer_ptr + NX_DNS_FLAGS_OFFSET, flags); - - /* Initialize counts to 0. */ - memset(buffer_ptr + NX_DNS_QDCOUNT_OFFSET, 0, 8); - - /* Return the size of the DNS header. */ - return(NX_DNS_QDSECT_OFFSET); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_question_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a question to the packet buffer at the end of */ -/* the current data and updates the size and the question count */ -/* (assuming that there is a dns header at the start if the packet */ -/* buffer). The question class is assumed to be INET. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to header area */ -/* name Host name or IP address that */ -/* is target of the DNS query */ -/* type DNS record type (e.g. A, AAAA)*/ -/* */ -/* OUTPUT */ -/* */ -/* size Total size of packet */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_string_encode Encode the supplied string */ -/* _nx_dns_network_to_short_convert Convert from network to short */ -/* _nx_dns_short_to_network_convert Convert from short to network */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_new_packet_create Create new DNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_question_add(NX_PACKET *packet_ptr, UCHAR *name, USHORT type) -{ - -UINT name_size; -UINT size; -USHORT value; - - - /* Check for name. */ - if (_nx_utility_string_length_check((CHAR *)name, &name_size, NX_DNS_NAME_MAX)) - { - - /* Name error, release the packet. */ - nx_packet_release(packet_ptr); - - /* Return a size of 0 to indicate an error. */ - return(0); - } - - /* The question will take the size of the string plus 6 bytes, is there space? */ - if ((name_size + 6) > (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr)) - { - - /* Size error, release the packet. */ - nx_packet_release(packet_ptr); - - /* Return a size of 0 to indicate an error. */ - return(0); - } - - /* Encode and add the name. */ - size = _nx_dns_name_string_encode(packet_ptr -> nx_packet_append_ptr, name); - - /* Add the type and class. */ - _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_append_ptr + size, type); - size += 2; - _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_append_ptr + size, NX_DNS_RR_CLASS_IN); - size += 2; - - /* Update the packet size and end. */ - packet_ptr -> nx_packet_length += size; - packet_ptr -> nx_packet_append_ptr += size; - - /* Get the question count. */ - value = _nx_dns_network_to_short_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET); - - /* Increment question count by one. */ - value++; - _nx_dns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_DNS_QDCOUNT_OFFSET, value); - - /* Return the size. */ - return(packet_ptr -> nx_packet_length); -} - - -#ifdef FEATURE_NX_IPV6 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_dns_build_an_ipv6_question_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the IP address in text form to go into the DNS*/ -/* lookup query ("Name"), including the ip6.arpa tag on the end. */ -/* */ -/* INPUT */ -/* */ -/* ip_address NXD_ADDRESS instance with the */ -/* IP address to search for */ -/* host name */ -/* buffer Pointer to host name to lookup*/ -/* len Buffer size for host name */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_dns_host_by_address_get Lookup host by address service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_dns_build_an_ipv6_question_string(NXD_ADDRESS *ip_address, UCHAR *buffer, UINT len) -{ -INT i, j; -ULONG temp; - - memset(buffer, 0, len); - for (j = 3; j >= 0; j--) - { - i = 0; - while (i <= 7) - { - - temp = ip_address -> nxd_ip_address.v6[j]; - temp = temp >> (4 * i++); - temp = (USHORT)temp & 0xf; - if(temp >= 10) - *buffer = (UCHAR)('a' + ((UCHAR)temp - 10)); - else - *buffer = (UCHAR)('0' + (UCHAR)temp); - buffer ++; - *buffer = '.'; - buffer++; - } - } - - memcpy(buffer, "ip6.arpa", sizeof("ip6.arpa")); - - return; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_name_string_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a string containing the name as a list of */ -/* labels separated by dots to the encoded list of labels specified */ -/* in RFC1035 for DNS servers. This conversion doesn't handle */ -/* compression and doesn't check on the lengths of the labels or the */ -/* entire name. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* count Count of characters encoded */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_question_add Add question to DNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_name_string_encode(UCHAR *ptr, UCHAR *name) -{ - -UCHAR *length; -UINT count = 1; - - - /* Point to the first character position in the buffer. This will point - to the length of the following name. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - - /* Move through string, copying bytes and updating length. - Whenever a "." is found, start a new string by updating the - pointer to the length and setting the length to zero. */ - while (*name) - { - - /* Is a dot been found? */ - if (*name == '.') - { - - /* Yes, setup a new length pointer. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - name++; - } - else - { - - /* Copy a character to the destination. */ - *ptr++ = *name++; - - /* Adjust the length of the current segment. */ - (*length)++; - } - - /* Increment the total count here. */ - count++; - } - - /* Add the final zero length, like a NULL terminator. */ - *ptr = 0; - - /* Increment the total count. */ - count++; - - /* Return the count. */ - return(count); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_name_string_unencode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts from the encoded list of labels as specified */ -/* in RFC 1035 to a string containing the name as a list of labels */ -/* separated by dots. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer to decode */ -/* start Location of start of data */ -/* buffer Pointer to decoded data */ -/* buffer_size Size of data buffer to decode */ -/* */ -/* OUTPUT */ -/* */ -/* Size of decoded data */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_send_query_by_address Send reverse lookup query */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_name_string_unencode(NX_PACKET *packet_ptr, UCHAR *data, UCHAR *buffer, UINT buffer_size) -{ - -UCHAR *character; -UCHAR *message_start; -UINT label_size; -UINT offset; -UINT length; - - - /* Initialize the value. */ - character = data; - message_start = packet_ptr -> nx_packet_prepend_ptr; - length = 0; - - /* As long as there is space in the buffer and we haven't - found a zero terminating label */ - while (*character != '\0') - { - - /* Check the buffer size. */ - if (buffer_size > length) - { - - /* Get the label size. */ - label_size = *character++; - - /* Is this a compression pointer or a count. */ - if (label_size <= NX_DNS_LABEL_MAX) - { - - /* Simple count, check for space and copy the label. */ - while ((buffer_size > length) && (label_size > 0)) - { - - *buffer++ = *character++; - length++; - label_size--; - } - - /* Now add the '.' */ - *buffer++ = '.'; - length++; - } - else if ((label_size & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) - { - - /* Message compression. */ - - /* Get the offset. */ - offset = ((label_size & NX_DNS_LABEL_MAX) << 8) + *character; - - /* Check the offset. */ - if (offset >= packet_ptr -> nx_packet_length) - { - - /* This is malformed packet. */ - return(0); - } - else - { - - /* This is a pointer, just adjust the source. */ - character = message_start + offset; - } - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - else - { - - /* Size error , just fail */ - return(0); - } - } - - /* Check for invalid length. */ - if (length == 0) - return(length); - - /* Done copying the data, set the last . to a trailing null */ - if (*(buffer - 1) == '.') - { - - buffer--; - length --; - } - - /* Null terminate name. */ - *buffer = '\0'; - - /* Return name size. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_name_size_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the size of the name. */ -/* */ -/* INPUT */ -/* */ -/* name Pointer to the name */ -/* */ -/* OUTPUT */ -/* */ -/* UINT Size of name */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_name_get Get IP address with name */ -/* _nx_host_by_address_get Get name from IP address */ -/* _nx_dns_resource_type_get Get resource type */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_name_size_calculate(UCHAR *name) -{ - -UINT size = 0; - - - /* As long as we haven't found a zero length terminating label */ - while (*name != '\0') - { - - UINT labelSize = *name++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_DNS_LABEL_MAX) - { - - /* Simple count, adjust size and skip the label. */ - size += labelSize + 1; - name += labelSize; - } - else if ((labelSize & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) - { - - /* This is a pointer size is 2 bytes and this is the end of this name */ - return(size + 2); - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - - /* Adjust size for the final NULL. */ - return(size + 1); -} - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_name_real_size_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the real size of the resouce name. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer to decode */ -/* start Location of start of data */ -/* */ -/* OUTPUT */ -/* */ -/* Real size of a string */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_send_query_by_name Send reverse lookup query */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_resource_name_real_size_calculate(UCHAR *data, UINT start) -{ - -UCHAR *character = data + start; -UINT length = 0; - - - /* As long as there is space in the buffer and we haven't - found a zero terminating label */ - while (*character != '\0') - { - - UINT labelSize = *character++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_DNS_LABEL_MAX) - { - - /* Simple count, check for space and copy the label. */ - while (labelSize > 0) - { - character++; - length++; - labelSize--; - } - - /* Now add the '.' space */ - length++; - } - else if ((labelSize & NX_DNS_COMPRESS_MASK) == NX_DNS_COMPRESS_VALUE) - { - - /* This is a pointer, just adjust the source. */ - character = data + ((labelSize & NX_DNS_LABEL_MAX) << 8) + *character; - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - - /* Reduce the last '.' string, update the length. */ - length --; - - /* Return name size. */ - return(length); -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource type. It is a wrapper for the */ -/* actual internal function that retrieves the name to maintain */ -/* compatibility with the previous version of DNS Client, e.g. NetX DNS*/ -/* Client. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* resource type */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate name's size */ -/* _nx_dns_network_to_short_convert Actual get resource type */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_name_get Get IP address with name */ -/* _nx_host_by_address_get Get name from IP address */ -/* _nx_dns_name_size_calculate Calculate name's size */ -/* _nx_dns_network_to_short_convert Convert network to short */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_resource_type_get(UCHAR *resource) -{ - - return(_nx_dns_network_to_short_convert(resource + _nx_dns_name_size_calculate(resource))); -} - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_time_to_live_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource time to live. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* resource type */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dns_resource_time_to_live_get(UCHAR *resource) -{ - - return(_nx_dns_network_to_long_convert(resource + _nx_dns_name_size_calculate(resource) + 4)); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_data_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource data length. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* data length */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate name's size */ -/* _nx_dns_network_to_short_convert Convert from network to short */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_name_get Get IP address with name */ -/* _nx_host_by_address_get Get name from IP address */ -/* _nx_dns_resource_size_get Get size of resource */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_resource_data_length_get(UCHAR *resource) -{ - - return(_nx_dns_network_to_short_convert(resource + _nx_dns_name_size_calculate(resource) + 8)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_data_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource data address. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* pointer to address */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate name's size */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_name_get Get IP address with name */ -/* _nx_host_by_address_get Get name from IP address */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UCHAR *_nx_dns_resource_data_address_get(UCHAR *resource) -{ - - return(resource + _nx_dns_name_size_calculate(resource) + 10); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_resource_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource data size. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* size of data */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_name_size_calculate Calculate name's size */ -/* _nx_dns_resource_data_length_get Get resource data length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_host_by_address_get Get name from IP address */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_resource_size_get(UCHAR *resource) -{ - - /* Resource size is - name size + data size + 2 bytes for type, 2 for class, 4 for time to live and 2 for data length - i.e. name size + data size + 10 bytes overhead - */ - return(_nx_dns_name_size_calculate(resource) + _nx_dns_resource_data_length_get(resource) + 10); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_short_to_network_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an unsigned short to network byte order, */ -/* which is big endian. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to the destination */ -/* value Source value */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* DNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static void _nx_dns_short_to_network_convert(UCHAR *ptr, USHORT value) -{ - - *ptr++ = (UCHAR)(value >> 8); - *ptr = (UCHAR)value; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_network_to_short_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an unsigned short in network format, which */ -/* big endian, to an unsigned short. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to the source */ -/* */ -/* OUTPUT */ -/* */ -/* return value */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* DNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static USHORT _nx_dns_network_to_short_convert(UCHAR *ptr) -{ - -USHORT value = *ptr++; - - value = (USHORT)((value << 8) | *ptr); - - return(value); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_network_to_long_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an unsigned long in network format, which */ -/* big endian, to an unsigned long. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to the source */ -/* */ -/* OUTPUT */ -/* */ -/* return value */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* DNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_dns_network_to_long_convert(UCHAR *ptr) -{ - -ULONG value = *ptr++; - - value = (value << 8) | *ptr++; - value = (value << 8) | *ptr++; - value = (value << 8) | *ptr; - - return(value); -} - - -#ifndef NX_DISABLE_IPV4 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_number_to_ascii_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts single digits into an ASCII character in an */ -/* NULL terminated string. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* buffstring Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_dns_host_by_address_get Send PTR query to DNS server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_number_to_ascii_convert(UINT number, CHAR *buffstring) -{ -UINT value; -UINT digit; -UINT index = 0; - - value = number; - - /* Is the value in the range of 100 and 255? */ - if(value >= 200) - { - buffstring[index++] = '2'; - value -= 200; - } - else if(value >= 100) - { - buffstring[index++] = '1'; - value -= 100; - } - - digit = value % 10; - value = value / 10; - - if(value == 0) - { - /* The 10s is zero. However if we already recorded the hundreds, - we need to insert 0 here. */ - if(index != 0) - buffstring[index++] = '0'; - } - else - buffstring[index++] = (CHAR)('0' + value); - - /* Last print the digit. */ - buffstring[index++] = (CHAR)('0' + digit); - - return index; -} -#endif /* NX_DISABLE_IPV4 */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_cache_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS cache initialize */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* cache_ptr Pointer to cache memory */ -/* cache_size The size of cache */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_cache_initialize Actual cache initialize function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!dns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Check for invalid input pointers. */ - if (!cache_ptr) - { - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure peer cache is 4-byte aligned. */ - if ((((ALIGN_TYPE)cache_ptr & 0x3) != 0) || - ((cache_size & 0x3) != 0)) - { - return(NX_DNS_ERROR); - } - - /* Call actual DNS cache initialize service. */ - status = _nx_dns_cache_initialize(dns_ptr, cache_ptr, cache_size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the DNS cache. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* cache_ptr Pointer to cache memory */ -/* cache_size The size of cache */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DNS mutex */ -/* tx_mutex_put Put the DNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size) -{ - -ALIGN_TYPE *head; -ALIGN_TYPE *tail; - - - /* Get the mutex. */ - tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Zero out the cache. */ - memset(cache_ptr, 0, cache_size); - - /* Set the head. */ - head = (ALIGN_TYPE*)cache_ptr; - *head = (ALIGN_TYPE)((ALIGN_TYPE*)cache_ptr + 1); - - /* Set the tail. */ - tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; - *tail = (ALIGN_TYPE)tail; - - /* Record the info. */ - dns_ptr -> nx_dns_cache = (UCHAR*)cache_ptr; - dns_ptr -> nx_dns_cache_size = cache_size; - - /* Clear the count. */ - dns_ptr -> nx_dns_rr_count = 0; - dns_ptr -> nx_dns_string_count = 0; - dns_ptr -> nx_dns_string_bytes = 0; - - /* Put the DNS mutex. */ - tx_mutex_put(&dns_ptr -> nx_dns_mutex); - - return(NX_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS cache full notify */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_cache_notify_set Actual cache notify set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!dns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Call actual DNS cache notify set function. */ - status = _nx_dns_cache_notify_set(dns_ptr, cache_full_notify_cb); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the cache full notify function. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DNS mutex */ -/* tx_mutex_put Put the DNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)) -{ - - - /* Get the DNS mutex. */ - tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Set the cache notify. */ - dns_ptr -> nx_dns_cache_full_notify = cache_full_notify_cb; - - /* Release the DNS mutex. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return(NX_DNS_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_dns_cache_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS cache full notify clear */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_dns_cache_notify_clear Actual cache notify clear function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_dns_cache_notify_clear(NX_DNS *dns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!dns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (dns_ptr -> nx_dns_id != NX_DNS_ID) - { - return(NX_DNS_PARAM_ERROR); - } - - /* Call actual DNS cache notify clear function. */ - status = _nx_dns_cache_notify_clear(dns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clear the cache full notify function. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the DNS mutex */ -/* tx_mutex_put Put the DNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_dns_cache_notify_clear(NX_DNS *dns_ptr) -{ - - - /* Get the DNS mutex. */ - tx_mutex_get(&(dns_ptr -> nx_dns_mutex), TX_WAIT_FOREVER); - - /* Clear the cache notify. */ - dns_ptr -> nx_dns_cache_full_notify = NX_NULL; - - /* Release the DNS mutex. */ - tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); - - return(NX_DNS_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_add_rr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the DNS resource record into record buffer. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_add_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr, NX_DNS_RR **insert_ptr) -{ - -ALIGN_TYPE *tail; -ALIGN_TYPE *head; -NX_DNS_RR *p; -NX_DNS_RR *rr; -ULONG elapsed_time; -ULONG current_time; -ULONG max_elapsed_time; - - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Initialize the parameters. */ - max_elapsed_time = 0; - current_time = tx_time_get(); - - /* Get head and tail. */ - tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; - tail = (ALIGN_TYPE*)(*tail); - head = (ALIGN_TYPE*)cache_ptr; - head = (ALIGN_TYPE*)(*head); - - /* Set the pointer. */ - rr = NX_NULL; - - /* Find an empty entry before head. */ - for(p = (NX_DNS_RR*)((ALIGN_TYPE*)cache_ptr + 1); p < (NX_DNS_RR*)head; p++) - { - if(!p -> nx_dns_rr_type) - { - rr = p; - break; - } - } - - /* Check the record ptr. */ - if (!rr) - { - /* Check whether the cache is full. */ - if((ALIGN_TYPE*)((UCHAR*)head + sizeof(NX_DNS_RR)) > tail) - { - - /* Find an aging resource reocrd and repalce it. */ - for(p = (NX_DNS_RR*)((ALIGN_TYPE*)cache_ptr + 1); p < (NX_DNS_RR*)head; p++) - { - - if (!p -> nx_dns_rr_name) - continue; - - /* Calculate the elapsed time. */ - elapsed_time = current_time - p -> nx_dns_rr_last_used_time; - - /* Step1. Find the expired resource record. */ - if ((elapsed_time / NX_IP_PERIODIC_RATE) >= p ->nx_dns_rr_ttl) - { - - /* Yes, find it. */ - rr = p; - break; - } - - /* Step2. Find the aging resource record. */ - if (elapsed_time >= max_elapsed_time) - { - rr = p; - max_elapsed_time = elapsed_time; - } - } - - /* Check the replacement resource record. */ - if (rr) - { - - /* Delete this record. */ - _nx_dns_cache_delete_rr(dns_ptr, cache_ptr, cache_size, rr); - - /* Update the head. */ - head = (ALIGN_TYPE*)cache_ptr; - head = (ALIGN_TYPE*)(*head); - } - else - { - return(NX_DNS_CACHE_ERROR); - } - } - else - { - rr = (NX_DNS_RR*)head; - } - } - - /* Just copy it to cache_ptr. */ - memcpy(rr, record_ptr, sizeof(NX_DNS_RR)); - - /* Update the resource record count. */ - dns_ptr -> nx_dns_rr_count ++; - - /* Get the current time to set the elapsed time. */ - rr -> nx_dns_rr_last_used_time = current_time; - - /* Set the insert ptr. */ - if(insert_ptr != NX_NULL) - *insert_ptr = rr; - - if((ALIGN_TYPE*)rr >= head) - { - - /* Update HEAD when new record is added. */ - head = (ALIGN_TYPE*)cache_ptr; - *head = (ALIGN_TYPE)(rr + 1); - } - - return(NX_DNS_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_find_answer PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the answer of DNS query in record buffer. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance. */ -/* cache_ptr Pointer to the record buffer */ -/* query_name RR Query name */ -/* query_type RR Query type */ -/* buffer Pointer to buffer */ -/* buffer_size The size of record_buffer */ -/* record_count The count of RR stored */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_find_answer(NX_DNS *dns_ptr, VOID *cache_ptr, UCHAR *query_name, USHORT query_type, UCHAR *buffer, UINT buffer_size, UINT *record_count) -{ - -ALIGN_TYPE *head; -NX_DNS_RR *p; -ULONG current_time; -ULONG elasped_ttl; -UINT old_count; -UINT answer_count; -UCHAR *buffer_prepend_ptr; -UINT query_name_length; -UINT name_string_length; -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -UCHAR *buffer_append_ptr; -NX_DNS_NS_ENTRY *nx_dns_ns_entry_ptr; -NX_DNS_MX_ENTRY *nx_dns_mx_entry_ptr; -NX_DNS_SRV_ENTRY *nx_dns_srv_entry_ptr; -NX_DNS_SOA_ENTRY *nx_dns_soa_entry_ptr; -UINT rname_string_length; -UINT mname_string_length; -#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ - - - /* Check the query name string. */ - if (_nx_utility_string_length_check((CHAR *)query_name, &query_name_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Initialize the value. */ - old_count = 0; - answer_count = 0; - if(record_count) - *record_count = 0; - - /* Set the buffer pointer. */ - buffer_prepend_ptr = buffer; -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - buffer_append_ptr = buffer + buffer_size; -#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ - - /* Get the current time. */ - current_time = tx_time_get(); - - /* Get head. */ - head = (ALIGN_TYPE*)cache_ptr; - head = (ALIGN_TYPE*)(*head); - - /* Lookup the cache to delete the expired resource record and find the answer. */ - for(p = (NX_DNS_RR*)((UCHAR*)cache_ptr + sizeof(ALIGN_TYPE)); (ALIGN_TYPE*)p < head; p++) - { - - /* Check whether the resource record is valid. */ - if (!p -> nx_dns_rr_name) - continue; - - /* Calucate the elapsed time. */ - elasped_ttl = (current_time - p -> nx_dns_rr_last_used_time) / NX_IP_PERIODIC_RATE; - - /* Compare the ttl. */ - if (elasped_ttl >= p -> nx_dns_rr_ttl) - { - - /* The resource record is expired, Delete the resource record. */ - _nx_dns_cache_delete_rr(dns_ptr, dns_ptr -> nx_dns_cache, dns_ptr -> nx_dns_cache_size, p); - continue; - } - - /* Check the resource record type. */ - if (p -> nx_dns_rr_type != query_type) - continue; - - /* Check the resource record name. */ - if (_nx_dns_name_match(p -> nx_dns_rr_name, query_name, query_name_length)) - continue; - - /* Update the elasped time and ttl. */ - p -> nx_dns_rr_last_used_time = current_time; - p -> nx_dns_rr_ttl -= elasped_ttl; - - /* Yes, get the answer. */ - - /* Check the type. */ - switch (query_type) - { - - case NX_DNS_RR_TYPE_A: - { - - /* Check the buffer size. */ - if (buffer_size < 4) - break; - - /* Set the IPv4 address. */ - *(ULONG *)buffer_prepend_ptr = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_a.nx_dns_rr_a_address; - - /* Update the count and pointer. */ - answer_count++; - buffer_size -= 4; - buffer_prepend_ptr += 4; - - break; - } - case NX_DNS_RR_TYPE_AAAA: - { - - /* Check the buffer size. */ - if (buffer_size < 16) - break; - - /* Set the IPv6 address. */ - *(ULONG *)buffer_prepend_ptr = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[0]; - *(ULONG *)(buffer_prepend_ptr + 4) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[1]; - *(ULONG *)(buffer_prepend_ptr + 8) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[2]; - *(ULONG *)(buffer_prepend_ptr + 12) = p -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address[3]; - - /* Update the count and pointer. */ - answer_count++; - buffer_size -= 16; - buffer_prepend_ptr += 16; - - break; - } - case NX_DNS_RR_TYPE_PTR: -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - case NX_DNS_RR_TYPE_CNAME: - case NX_DNS_RR_TYPE_TXT: -#endif - { - - /* PTR, CNAME, TXT record should be only one answer, union: ptr name, cname name, and txt data. */ - /* Check the name string. */ - if (_nx_utility_string_length_check((CHAR *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, &name_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure there is enough room to store the name and null-terminator. */ - if (buffer_size < (name_string_length + 1)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Set the cname string. */ - memcpy((char *)buffer_prepend_ptr, (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, name_string_length); - - /* Return success. */ - return (NX_DNS_SUCCESS); - } -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - case NX_DNS_RR_TYPE_NS: - { - - /* Check the name string. */ - if (_nx_utility_string_length_check((CHAR *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name, &name_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure there is enough room to store the name and null-terminator. */ - if (buffer_size < (sizeof(NX_DNS_NS_ENTRY) + name_string_length + 1)) - break; - - /* Set the ns entry pointer. */ - nx_dns_ns_entry_ptr = (NX_DNS_NS_ENTRY *)(buffer_prepend_ptr); - - /* Update the store pointer. include the null flag '\0'. */ - buffer_append_ptr -= (name_string_length + 1); - - /* Set the ns string. */ - memcpy((char *)buffer_append_ptr, (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_ns.nx_dns_rr_ns_name, name_string_length); - nx_dns_ns_entry_ptr -> nx_dns_ns_hostname_ptr = buffer_append_ptr; - - /* Update the count and pointer. */ - answer_count++; - buffer_size -= (sizeof(NX_DNS_NS_ENTRY) + name_string_length + 1); - buffer_prepend_ptr += sizeof(NX_DNS_NS_ENTRY); - - break; - } - case NX_DNS_RR_TYPE_MX: - { - - /* Check the name string. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata + 2), &name_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure there is enough room to store the name and null-terminator. */ - if (buffer_size < (sizeof(NX_DNS_MX_ENTRY) + name_string_length + 1)) - break; - - /* Set the mx entry pointer. */ - nx_dns_mx_entry_ptr = (NX_DNS_MX_ENTRY *)(buffer_prepend_ptr); - - /* Set the mx preference. */ - nx_dns_mx_entry_ptr -> nx_dns_mx_preference = *(USHORT *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata; - - /* Update the store pointer. include the null flag '\0'. */ - buffer_append_ptr -= (name_string_length + 1); - - /* Set the mx string. */ - memcpy((char *)buffer_append_ptr, (char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata + 2), name_string_length); - nx_dns_mx_entry_ptr -> nx_dns_mx_hostname_ptr = buffer_append_ptr; - - /* Update the count and pointer. */ - answer_count++; - buffer_size -= (sizeof(NX_DNS_MX_ENTRY) + name_string_length + 1); - buffer_prepend_ptr += sizeof(NX_DNS_MX_ENTRY); - - break; - } - case NX_DNS_RR_TYPE_SRV: - { - - /* Check the name string. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 6), &name_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure there is enough room to store the name and null-terminator. */ - if (buffer_size < (sizeof(NX_DNS_SRV_ENTRY) + name_string_length + 1)) - break; - - /* Set the srv entry pointer. */ - nx_dns_srv_entry_ptr = (NX_DNS_SRV_ENTRY *)(buffer_prepend_ptr); - - /* Set the priority, weight and port number. */ - nx_dns_srv_entry_ptr -> nx_dns_srv_priority = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata); - nx_dns_srv_entry_ptr -> nx_dns_srv_weight = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 2); - nx_dns_srv_entry_ptr -> nx_dns_srv_port_number = *(USHORT *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 4); - - /* Update the store pointer. include the null flag '\0'. */ - buffer_append_ptr -= (name_string_length + 1); - - /* Set the srv string. */ - memcpy((char *)buffer_append_ptr, (char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata + 6), name_string_length); - nx_dns_srv_entry_ptr -> nx_dns_srv_hostname_ptr = buffer_append_ptr; - - /* Update the count and pointer. */ - answer_count++; - buffer_size -= (sizeof(NX_DNS_SRV_ENTRY) + name_string_length + 1); - buffer_prepend_ptr += sizeof(NX_DNS_SRV_ENTRY); - - break; - } - case NX_DNS_RR_TYPE_SOA: - { - - /* Check the mname string. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata), &mname_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Check the rname string. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + 1), &rname_string_length, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Make sure there is enough room to store the name and null-terminator. */ - if (buffer_size < (sizeof(NX_DNS_SOA_ENTRY) + mname_string_length + rname_string_length + 2)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - - /* Set the soa entry pointer. */ - nx_dns_soa_entry_ptr = (NX_DNS_SOA_ENTRY *)(buffer_prepend_ptr); - - /* Update the store pointer. include the null flag '\0'. */ - buffer_append_ptr -= (mname_string_length + rname_string_length + 2); - - /* Set the soa mname string. */ - memcpy((char *)(buffer_append_ptr), (char *)p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata, mname_string_length); - nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr = buffer_append_ptr; - - /* Set the soa rname string. */ - memcpy((char *)(buffer_append_ptr + mname_string_length + 1), (const char *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + 1), rname_string_length); - nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr = (buffer_append_ptr + mname_string_length + 1); - - /* Set the SOA Serial, Refresh, Retry, Expire, Minmum. */ - nx_dns_soa_entry_ptr -> nx_dns_soa_serial = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 2); - nx_dns_soa_entry_ptr -> nx_dns_soa_refresh = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 6); - nx_dns_soa_entry_ptr -> nx_dns_soa_retry = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 10); - nx_dns_soa_entry_ptr -> nx_dns_soa_expire = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 14); - nx_dns_soa_entry_ptr -> nx_dns_soa_minmum = *(ULONG *)(p -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + mname_string_length + rname_string_length + 18); - - /* Return success. */ - return (NX_DNS_SUCCESS); - } -#endif /* NX_DNS_ENABLE_EXTENDED_RR_TYPES */ - } - - /* Check if the answer count is updated. */ - if (old_count == answer_count) - { - - /* The answer count is not updated, means the buffer is not enough, stop finding. */ - break; - } - else - { - /* Update the old count. */ - old_count = answer_count; - } - } - - /* Check the answer count. */ - if (answer_count) - { - - /* Update the record count. */ - if (record_count) - *record_count = answer_count; - return (NX_DNS_SUCCESS); - } - else - { - return(NX_DNS_ERROR); - } -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_delete_rr PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DNS resource record from cache. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_delete_rr(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr) -{ - -ALIGN_TYPE *head; - - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Delete the resource record strings. */ - _nx_dns_cache_delete_rr_string(dns_ptr, cache_ptr,cache_size, record_ptr); - - /* Zero out the record. */ - memset(record_ptr, 0, sizeof(NX_DNS_RR)); - - /* Update the resource record count. */ - dns_ptr -> nx_dns_rr_count --; - - /* Get head. */ - head = (ALIGN_TYPE*)cache_ptr; - head = (ALIGN_TYPE*)(*head); - - /* Move HEAD if the last RR is deleted. */ - if(record_ptr == ((NX_DNS_RR*)head - 1)) - { - while(!record_ptr -> nx_dns_rr_type) - { - record_ptr--; - if(record_ptr < (NX_DNS_RR*)cache_ptr) - break; - } - *((ALIGN_TYPE*)cache_ptr) = (ALIGN_TYPE)(record_ptr + 1); - } - - return(NX_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_delete_rr_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DNS entry string from the record cache. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_delete_rr_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, NX_DNS_RR *record_ptr) -{ - -UINT string_len; -UINT size; - - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Compare the resource record type. */ - if((record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_PTR) -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - || - (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_TXT) || - (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_CNAME) || - (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_NS) -#endif - ) - { - - /* Delete the rdata name string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_ptr.nx_dns_rr_ptr_name, 0); - } - else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_AAAA) - { - - /* Delete the IPv6 address string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_aaaa.nx_dns_rr_aaaa_address, 16); - } -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_SRV) - { - - /* Compute the SRV rdata length. */ - if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata), &size, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - string_len = (UINT)(size + 6); - - /* Delete the SRV rdata string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_srv.nx_dns_rr_srv_rdata, string_len); - } - else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_MX) - { - - /* Compute the MX rdata length. */ - if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata), &size, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - string_len = (UINT)(size + 2); - - /* Delete the MX rdata string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_mx.nx_dns_rr_mx_rdata, string_len); - } - else if (record_ptr -> nx_dns_rr_type == NX_DNS_RR_TYPE_SOA) - { - - /* Compute the SOA rdata length. */ - if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata), &size, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - string_len = size; /* MNAME */ - string_len += 1; /* '\0' */ - - if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata + string_len), &size, NX_DNS_NAME_MAX)) - { - - /* Return. */ - return(NX_DNS_CACHE_ERROR); - } - string_len += size; /* RNAME */ - string_len += 1; /* '\0' */ - string_len += 20; /* Serial, Refresh, Retry, Expire, Minmum. */ - - /* Delete the SRV rdata string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_rdata.nx_dns_rr_rdata_soa.nx_dns_rr_soa_rdata, string_len); - } -#endif - - /* Delete the name string. */ - _nx_dns_cache_delete_string(dns_ptr, cache_ptr, cache_size, record_ptr -> nx_dns_rr_name, 0); - - return(NX_DNS_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_add_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds or finds the DNS string in the cache. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_add_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_size, VOID **insert_ptr) -{ - -ALIGN_TYPE *tail; -ALIGN_TYPE *head; -UINT string_len; -USHORT len, cnt; -USHORT min_len = 0xFFFF; -UCHAR *p, *available, *start; - - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Get head and tail. */ - tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; - p = (UCHAR*)tail; - tail = (ALIGN_TYPE*)(*tail); - head = (ALIGN_TYPE*)cache_ptr; - head = (ALIGN_TYPE*)(*head); - - /* Calculate the amount of memory needed to store this string, including CNT and LEN fields. */ - - /* Make the length 4 bytes align. */ - string_len = string_size; - - /* Add the length of CNT and LEN fields. */ - string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - available = (UCHAR*)tail; - while(p > (UCHAR*)tail) - { - - /* Get len and cnt. */ - len = *((USHORT*)(p - 2)); - cnt = *((USHORT*)(p - 4)); - start = p - len; - - if((len == string_len) && - (!_nx_dns_name_match(start, string_ptr, string_size))) - { - - /* The same string exists in the string table. */ - if(insert_ptr) - *insert_ptr = start; - - /* Increase the use count CNT. */ - cnt++; - *((USHORT*)(p - 4)) = cnt; - - return(NX_SUCCESS); - } - - /* This slot is not being used. The size of the slot is a smaller - fit for this string. */ - if((cnt == 0) && (len >= string_len) && (len < min_len)) - { - - /* This place is better to insert. */ - available = p; - min_len = len; - } - - /* Move to the next string. */ - p = start; - } - - /* If we reach this point, the string needs to be added to the string table. */ - if(available == (UCHAR*)tail) - { - - /* Make sure the service cache still has room to add this string - (without overwriting the RR area.) */ - if(((UCHAR*)tail - string_len) < (UCHAR*)head) - { - - /* This service cache does not have room for the string table to grow. */ - /* Invoke user-installed cache full notify function .*/ - if(dns_ptr -> nx_dns_cache_full_notify) - { - - /* Call the notify function. */ - (dns_ptr -> nx_dns_cache_full_notify)(dns_ptr); - } - - /* The buffer is full. */ - return(NX_DNS_SIZE_ERROR); - } - - /* Update TAIL. */ - *((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1) = (ALIGN_TYPE)(available - string_len); - - } - else if(string_len < min_len) - { - - /* Set the LEN for remaining space. */ - *((USHORT*)(available - 2 - string_len)) = (USHORT)(min_len - string_len); - } - - /* Set LEN and CNT. */ - *((USHORT*)(available - 2)) = (USHORT)string_len; - *((USHORT*)(available - 4)) = 1; - - /* Clear last 4 bytes. */ - *((ULONG*)(available - 8)) = 0; - - /* Insert string to cache. */ - memcpy(available - string_len, string_ptr, string_size); - - /* Set end character 0. */ - *(available - string_len + string_size) = 0; - - /* Update the string length and count . */ - dns_ptr -> nx_dns_string_count ++; - dns_ptr -> nx_dns_string_bytes += string_len; - - if(insert_ptr) - *insert_ptr = available - string_len; - - return(NX_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_cache_delete_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the DNS string from the record buffer. */ -/* */ -/* INPUT */ -/* */ -/* dns_ptr Pointer to DNS instance. */ -/* cache_ptr Pointer to the record buffer */ -/* cache_size The size of buffer. */ -/* string_ptr Pointer to the string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_cache_delete_string(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size, VOID *string_ptr, UINT string_len) -{ - -ALIGN_TYPE *tail; -ALIGN_TYPE *end; -USHORT cnt; - - - /* Check the cache. */ - if (cache_ptr == NX_NULL) - return(NX_DNS_CACHE_ERROR); - - /* Validate input parameter. */ - if (string_ptr == NX_NULL) - return(NX_DNS_PARAM_ERROR); - - /* Validate string. */ - if (_nx_utility_string_length_check((CHAR *)string_ptr, &string_len, NX_DNS_NAME_MAX)) - return(NX_DNS_SIZE_ERROR); - - /* Add the length of CNT and LEN fields. */ - /* Also make the total length 4 bytes align. */ - string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - end = (ALIGN_TYPE*)((UCHAR*)string_ptr + string_len); - - /* Get tail. */ - - /* Validate the string table. */ - tail = (ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1; - if(end > tail) - { - - /* The end of string exceeds cache_ptr. */ - return(NX_DNS_SIZE_ERROR); - } - tail = (ALIGN_TYPE*)(*tail); - if((UCHAR*)string_ptr < (UCHAR*)tail) - { - - /* The end of string exceeds cache_ptr. */ - return(NX_DNS_SIZE_ERROR); - } - - /* Decrease the usage counter value. */ - cnt = *((USHORT*)((UCHAR*)end - 4)); - cnt--; - *((USHORT*)((UCHAR*)end - 4)) = cnt; - - /* Clear the memory if cnt is zero. */ - if(cnt == 0) - { - memset(string_ptr, 0, string_len - 2); - - /* Update the string length and count . */ - dns_ptr -> nx_dns_string_count --; - dns_ptr -> nx_dns_string_bytes -= string_len; - - /* Update the tail pointer if the string at the tail is deleted. */ - if(string_ptr == tail) - { - tail = end; - - while(end < ((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1)) - { - - /* Set the string pt and string length. */ - string_ptr = end; - - /* Validate string. */ - if (_nx_utility_string_length_check((CHAR *)string_ptr, &string_len, NX_DNS_NAME_MAX)) - return(NX_DNS_SIZE_ERROR); - - /* Check the string length. */ - if(string_len == 0) - { - - /* This slot is cleared. */ - while(*((ULONG*)string_ptr) == 0) - string_ptr = (UCHAR*)string_ptr + 4; - - end = (ALIGN_TYPE*)((UCHAR*)string_ptr + 4); - cnt = *((USHORT*)string_ptr); - } - else - { - - /* Make the length 4 bytes align and add the length of CNT and LEN fields. */ - string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - end = (ALIGN_TYPE*)((UCHAR*)string_ptr + string_len); - cnt = *((USHORT*)((UCHAR*)end - 4)); - } - - /* Check whether this slot is never referenced. */ - if(cnt == 0) - tail = end; - else - break; - } - *((ALIGN_TYPE*)((UCHAR*)cache_ptr + cache_size) - 1) = (ALIGN_TYPE)tail; - } - } - - return(NX_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ - - -#ifdef NX_DNS_CACHE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_dns_name_match PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function name string match, the lowercase letters "a" to "z" */ -/* match their uppercase equivalents "A" to "Z". */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_dns_name_match(UCHAR *src, UCHAR *dst, UINT length) -{ - -UINT index = 0; - - - /* Check the name. */ - while (*dst != '\0') - { - if((*src) != (*dst)) - { - if((((*src) | 0x20) >= 'a') && (((*src) | 0x20) <= 'z')) - { - /* Match the characters, case in-sensitive. */ - if(((*src) | 0x20) != ((*dst) | 0x20)) - return(NX_DNS_NAME_MISMATCH); - } - else - { - return(NX_DNS_NAME_MISMATCH); - } - } - src ++; - dst ++; - index ++; - } - - /* Check the scan length. */ - if (index != length) - { - return (NX_DNS_NAME_MISMATCH); - } - - /* Return success. */ - return(NX_DNS_SUCCESS); -} -#endif /* NX_DNS_CACHE_ENABLE */ diff --git a/protocol_handlers/dns/nxd_dns.h b/protocol_handlers/dns/nxd_dns.h deleted file mode 100644 index e646484d..00000000 --- a/protocol_handlers/dns/nxd_dns.h +++ /dev/null @@ -1,1013 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Domain Name System (DNS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_dns.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Domain Name System Protocol (DNS) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_DNS_H -#define NXD_DNS_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_udp.h" -#include "nx_ipv4.h" -#include "nx_ipv6.h" - -/* Define the DNS ID. */ - -#define NX_DNS_ID 0x444e5320UL - -/* Define message and name limits. */ - -#define NX_DNS_LABEL_MAX 63 /* Maximum Label (between to dots) size */ -#define NX_DNS_NAME_MAX 255 /* Maximum Name size */ -#define NX_DNS_IP_LOOKUP_SIZE 75 /* IPv6 needs 66 characters for the address plus 8 for the ip6.arpa plus null */ - /* IPv4 needs 12 characters max for the address plus 12 for the IN-ADDR.ARPA plus null */ - - -/* Define offsets into the DNS message buffer. */ - -#define NX_DNS_ID_OFFSET 0 /* Offset to ID code in DNS buffer */ -#define NX_DNS_FLAGS_OFFSET 2 /* Offset to flags in DNS buffer */ -#define NX_DNS_QDCOUNT_OFFSET 4 /* Offset to Question Count in DNS buffer */ -#define NX_DNS_ANCOUNT_OFFSET 6 /* Offset to Answer Count in DNS buffer */ -#define NX_DNS_NSCOUNT_OFFSET 8 /* Offset to Authority Count in DNS buffer */ -#define NX_DNS_ARCOUNT_OFFSET 10 /* Offset to Additional Info. Count in DNS buffer */ -#define NX_DNS_QDSECT_OFFSET 12 /* Offset to Question Section in DNS buffer */ - - -/* Define return code constants. */ - -#define NX_DNS_SUCCESS 0x00 /* DNS success */ -#define NX_DNS_ERROR 0xA0 /* DNS internal error */ -#define NX_DNS_NO_SERVER 0xA1 /* No DNS server was specified */ -#define NX_DNS_TIMEOUT 0xA2 /* DNS timeout occurred */ -#define NX_DNS_QUERY_FAILED 0xA3 /* DNS query failed; no DNS server sent an 'answer' */ -#define NX_DNS_BAD_ADDRESS_ERROR 0xA4 /* Improperly formatted IPv4 or IPv6 address */ -#define NX_DNS_SIZE_ERROR 0xA5 /* DNS destination size is too small */ -#define NX_DNS_MALFORMED_PACKET 0xA6 /* Improperly formed or corrupted DNS packet received */ -#define NX_DNS_BAD_ID_ERROR 0xA7 /* DNS packet from server does not match query ID */ -#define NX_DNS_PARAM_ERROR 0xA8 /* Invalid non pointer input to API */ -#define NX_DNS_SERVER_NOT_FOUND 0xA9 /* Server not found in Client list of DNS servers */ -#define NX_DNS_PACKET_CREATE_ERROR 0xAA /* Error creating DNS packet */ -#define NX_DNS_EMPTY_DNS_SERVER_LIST 0xAB /* DNS Client's list of DNS servers is empty */ -#define NX_DNS_SERVER_AUTH_ERROR 0xAC /* Server not able to authenticate answer/authority data*/ -#define NX_DNS_ZERO_GATEWAY_IP_ADDRESS 0xAD /* DNS Client IP instance has a zero gateway IP address */ -#define NX_DNS_MISMATCHED_RESPONSE 0xAE /* Server response type does not match the query request*/ -#define NX_DNS_DUPLICATE_ENTRY 0xAF /* Duplicate entry exists in DNS server table */ -#define NX_DNS_RETRY_A_QUERY 0xB0 /* SOA status returned; web site only exists as IPv4 */ -#define NX_DNS_IPV6_DISABLED_ERROR 0xB1 /* Cannot process AAAA or PTR record with IPv6 disabled */ -#define NX_DNS_INVALID_ADDRESS_TYPE 0xB2 /* IP address type (e.g. IPv6) not supported */ -#define NX_DNS_IPV6_NOT_SUPPORTED 0xB3 /* Cannot process AAAA or PTR record with IPv6 disabled */ -#define NX_DNS_NEED_MORE_RECORD_BUFFER 0xB4 /* The buffer size is not enough. */ -#define NX_DNS_FEATURE_NOT_SUPPORTED 0xB5 /* The requested feature is not supported in this build */ -#define NX_DNS_NAME_MISMATCH 0xB6 /* The name mismatch. */ -#define NX_DNS_CACHE_ERROR 0xB7 /* The Cache size is not enough. */ - - -/* Define constants for the flags word. */ - -#define NX_DNS_QUERY_MASK 0x8000 -#define NX_DNS_RESPONSE_FLAG 0x8000 -#define NX_DNS_ERROR_MASK 0x8002 /* Server response indicates an error or data not authenticated by server */ - - -#define NX_DNS_OPCODE_QUERY (0 << 12) /* Shifted right 12 is still 0 */ -#define NX_DNS_OPCODE_IQUERY (1 << 12) /* 1 shifted right by 12 */ -#define NX_DNS_OPCODE_STATUS (2 << 12) /* 2 shifted right by 12 */ - -#define NX_DNS_AA_FLAG 0x0400 /* Authoritative Answer */ -#define NX_DNS_TC_FLAG 0x0200 /* Truncated */ -#define NX_DNS_RD_FLAG 0x0100 /* Recursive Query */ -#define NX_DNS_RA_FLAG 0x0080 /* Recursion Available */ -#define NX_DNS_FA_FLAG 0x0010 /* Force Authentication */ - -#define NX_DNS_RCODE_MASK 0x000f /* Isolate the Result Code */ -#define NX_DNS_RCODE_SUCCESS 0 -#define NX_DNS_RCODE_FORMAT_ERR 1 -#define NX_DNS_RCODE_SERVER_ERR 2 -#define NX_DNS_RCODE_NAME_ERR 3 -#define NX_DNS_RCODE_NOT_IMPL 4 -#define NX_DNS_RCODE_REFUSED 5 - -#define NX_DNS_QUERY_FLAGS (NX_DNS_OPCODE_QUERY | NX_DNS_RD_FLAG) /* | NX_DNS_FA_FLAG */ - -/* Define name compression masks. */ - -#define NX_DNS_COMPRESS_MASK 0xc0 -#define NX_DNS_COMPRESS_VALUE 0xc0 -#define NX_DNS_POINTER_MASK 0xc000 - -/* Define resource record types. */ - -#define NX_DNS_RR_TYPE_A 1 /* Host address */ -#define NX_DNS_RR_TYPE_NS 2 /* Authoritative name server */ -#define NX_DNS_RR_TYPE_MD 3 /* Mail destination (Obsolete - use MX) */ -#define NX_DNS_RR_TYPE_MF 4 /* Mail forwarder (Obsolete - use MX) */ -#define NX_DNS_RR_TYPE_CNAME 5 /* Canonical name for an alias */ -#define NX_DNS_RR_TYPE_SOA 6 /* Marks the start of a zone of authority */ -#define NX_DNS_RR_TYPE_MB 7 /* Mailbox domain name (EXPERIMENTAL) */ -#define NX_DNS_RR_TYPE_MG 8 /* Mail group member (EXPERIMENTAL) */ -#define NX_DNS_RR_TYPE_MR 9 /* Mail rename domain name (EXPERIMENTAL) */ -#define NX_DNS_RR_TYPE_NULL 10 /* Null RR (EXPERIMENTAL) */ -#define NX_DNS_RR_TYPE_WKS 11 /* Well known service description */ -#define NX_DNS_RR_TYPE_PTR 12 /* Domain name pointer */ -#define NX_DNS_RR_TYPE_HINFO 13 /* Host information */ -#define NX_DNS_RR_TYPE_MINFO 14 /* Mailbox or mail list information */ -#define NX_DNS_RR_TYPE_MX 15 /* Mail exchange */ -#define NX_DNS_RR_TYPE_TXT 16 /* Text strings */ -#define NX_DNS_RR_TYPE_AAAA 28 /* IPv6 Host address */ -#define NX_DNS_RR_TYPE_SRV 33 /* The location of services */ - - -/* Define constants for Qtypes (queries). */ - -#define NX_DNS_RR_TYPE_AXFR 252 /* Request for a transfer of an entire zone */ -#define NX_DNS_RR_TYPE_MAILB 253 /* Request for mailbox-related records (MB, MG or MR) */ -#define NX_DNS_RR_TYPE_MAILA 254 /* Request for mail agent RRs (Obsolete - see MX) */ -#define NX_DNS_RR_TYPE_ALL 255 /* Request for all records */ - -/* Define resource record classes. */ - -#define NX_DNS_RR_CLASS_IN 1 /* Internet */ -#define NX_DNS_RR_CLASS_CS 2 /* CSNET class (Obsolete) */ -#define NX_DNS_RR_CLASS_CH 3 /* CHAOS class */ -#define NX_DNS_RR_CLASS_HS 4 /* Hesiod [Dyer 87] */ - - -/* Define constant valid for Qtypes (queries). */ - -#define NX_DNS_RR_CLASS_ALL 255 /* Any class */ - -/* Define the TCP and UDP port number */ - -#define NX_DNS_PORT 53 /* Port for TX,RX and TCP/UDP */ - - -/* Start of configurable options. */ - -/* Set the IP instance gateway server to be the DNS server if the gateway address is non zero. */ -/* -#define NX_DNS_IP_GATEWAY_AND_DNS_SERVER -*/ - -/* Determine if the Client will create its own packet pool - or let the host application create one. See nx_dns_packet_pool_set - for how to set the DNS packet pool from the host application. */ -/* -#define NX_DNS_CLIENT_USER_CREATE_PACKET_POOL -*/ - -/* Enable the feature to clear off old DNS packets before sending a fresh query. */ -/* -#define NX_DNS_CLIENT_CLEAR_QUEUE -*/ - -/* Enable the feature to send the TXT, CNAME, NS, MX, SRV, SOA DNS types query. */ -/* -#define NX_DNS_ENABLE_EXTENDED_RR_TYPES -*/ - -/* Enable the cache to store the resource record. */ -/* -#define NX_DNS_CACHE_ENABLE -*/ - -/* Define UDP socket create options. */ - -#ifndef NX_DNS_TYPE_OF_SERVICE -#define NX_DNS_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_DNS_FRAGMENT_OPTION -#define NX_DNS_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_DNS_TIME_TO_LIVE -#define NX_DNS_TIME_TO_LIVE 0x80 -#endif - -/* Define the queue depth of the DNS Client socket. */ - -#ifndef NX_DNS_QUEUE_DEPTH -#define NX_DNS_QUEUE_DEPTH 5 -#endif - -/* Define the maximum size of DNS message. 512 is the maximum size defined in RFC 1035 section 2.3.4. */ - -#ifndef NX_DNS_MESSAGE_MAX -#define NX_DNS_MESSAGE_MAX 512 -#endif - -/* Define a payload to include the maximum size DNS message plus the Ethernet, IP and UDP overhead. */ - -#ifndef NX_DNS_PACKET_PAYLOAD_UNALIGNED -#define NX_DNS_PACKET_PAYLOAD_UNALIGNED (NX_UDP_PACKET + NX_DNS_MESSAGE_MAX) -#endif - -/* Round up to a 4 byte aligned packet payload. */ - -#define NX_DNS_PACKET_PAYLOAD (((NX_DNS_PACKET_PAYLOAD_UNALIGNED + sizeof(ULONG) - 1)/sizeof(ULONG)) * sizeof(ULONG)) - -/* Define the size (e.g. number of packets) of the DNS Client - packet pool for sending out DNS messages. */ - -#ifndef NX_DNS_PACKET_POOL_SIZE -#define NX_DNS_PACKET_POOL_SIZE (16 * (NX_DNS_PACKET_PAYLOAD + sizeof(NX_PACKET))) -#endif - - -/* Define the maximum number of retries to a DNS server. */ - -#ifndef NX_DNS_MAX_RETRIES -#define NX_DNS_MAX_RETRIES 3 -#endif - -/* Define size of the DNS server list. Remember to allow for one 'null' terminating - e.g. zero IP address entry for this list. */ - -#ifndef NX_DNS_MAX_SERVERS -#define NX_DNS_MAX_SERVERS 5 -#endif - -/* Define the maximum amount of time to retransmit a DNS query. The default wait time is 64 seconds. - the retransmission policy are recommended in RFC1035 page 32. */ -#ifndef NX_DNS_MAX_RETRANS_TIMEOUT -#define NX_DNS_MAX_RETRANS_TIMEOUT (64 * NX_IP_PERIODIC_RATE) -#endif - -/* Define the timeout option in timer ticks for allocating a packet - from the DNS Client packet pool. */ - -#ifndef NX_DNS_PACKET_ALLOCATE_TIMEOUT -#define NX_DNS_PACKET_ALLOCATE_TIMEOUT NX_IP_PERIODIC_RATE -#endif - - -/* Define the basic DNS data structure. */ - -typedef struct NX_IP_DNS_STRUCT -{ - ULONG nx_dns_id; /* DNS ID */ - UCHAR *nx_dns_domain; /* Pointer to domain name */ - USHORT nx_dns_lookup_type; /* DNS look up type */ - USHORT nx_dns_transmit_id; /* DNS message transmit identifier */ - NX_IP *nx_dns_ip_ptr; /* Pointer to associated IP structure */ - NXD_ADDRESS nx_dns_server_ip_array[NX_DNS_MAX_SERVERS]; /* List of DNS server IP addresses */ - ULONG nx_dns_retries; /* DNS query retries */ -#ifndef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL - NX_PACKET_POOL nx_dns_pool; /* The pool of UDP data packets for DNS messages */ - UCHAR nx_dns_pool_area[NX_DNS_PACKET_POOL_SIZE]; -#endif - NX_PACKET_POOL *nx_dns_packet_pool_ptr; /* Pointer to DNS Client packet pool */ - NX_UDP_SOCKET nx_dns_socket; /* DNS Socket */ - TX_MUTEX nx_dns_mutex; /* DNS Mutex to protect DNS instance */ -#ifdef NX_DNS_CACHE_ENABLE - UCHAR* nx_dns_cache; /* Pointer to the cache. */ - UINT nx_dns_cache_size; /* The size of cache. */ - ULONG nx_dns_rr_count; /* The number of resource records in the cache. */ - ULONG nx_dns_string_count; /* The number of strings in the cache. */ - ULONG nx_dns_string_bytes; /* The number of total bytes in string table in the cache. */ - VOID (*nx_dns_cache_full_notify)(struct NX_IP_DNS_STRUCT *); -#endif /* NX_DNS_CACHE_ENABLE */ -} NX_DNS; - - -/* Define the RDATA structure. */ -/********************************************************************************/ -/* Type A */ -/********************************************************************************/ - -/* A RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - | ADDRESS | - |-------------------------------------------------------------| -*/ -/* The host name may have multiple addresses,so we need a buffer to record the all addresses. - return_buffer must be 4-byte aligned. This return buffer is used to store IP addresses returned from the server. - record_number stores the number of entries in the buffer. If the server returns more entries than the buffer - can hold, the entries exceeding the buffer size are dropped. */ - -/* Layout of the buffer - |-------------------------------------------------------------------------------------| - |ip.address.0|ip.address.1|ip.address.2|....... |ip.address.n| - |-------------------------------------------------------------------------------------| -*/ - -/********************************************************************************/ -/* Type AAAA */ -/********************************************************************************/ -/* AAAA RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - | ADDRESS | - |-------------------------------------------------------------| - | ADDRESS | - |-------------------------------------------------------------| - | ADDRESS | - |-------------------------------------------------------------| - | ADDRESS | - |-------------------------------------------------------------| -*/ - -typedef struct NX_DNS_IPV6_ADDRESS_STRUCT -{ - ULONG ipv6_address[4]; -} NX_DNS_IPV6_ADDRESS; - - -/* The return_buffer must be 4-byte aligned. This return buffer is used to store IP addresses returned from the server. */ -/* The record_number in the query stores the number of entries in the buffer. If the server returns more entries than the buffer - can hold, the entries exceeding the buffer size are dropped. */ - -/* Layout of the buffer - |---------------------------------------------------------------| - |ip.address.0[0]|ip.address.0[1]|ip.address.0[2]|ip.address.0[3]| - |---------------------------------------------------------------| - |ip.address.1[0]|ip.address.1[1]|ip.address.1[2]|ip.address.1[3]| - |---------------------------------------------------------------| - | | - | .......................................... | - | | - |---------------------------------------------------------------| - |ip.address.n[0]|ip.address.n[1]|ip.address.n[2]|ip.address.n[3]| - |---------------------------------------------------------------| - -*/ - -/********************************************************************************/ -/* PTR */ -/********************************************************************************/ -/* PTR RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - / PTRDNAME / - / / - |-------------------------------------------------------------| -*/ - - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES - -/********************************************************************************/ -/* Type NS */ -/********************************************************************************/ -/* NS RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - / NSDNAME / - / / - |-------------------------------------------------------------| -*/ - -typedef struct NX_DNS_NS_ENTRY_STRUCT -{ - ULONG nx_dns_ns_ipv4_address; /* The name server ipv4 address. */ - UCHAR *nx_dns_ns_hostname_ptr; /* The name server. */ -} NX_DNS_NS_ENTRY; - -/* Store the message in one buffer. Layout of the buffer: - - record_buffer |---------------------------------------------------------------| - entry 0 |xx.xx.xx.xx |Pointer to the host name string | - record_buffer + 8 |---------------------------------------------------------------| - entry 1 |xx.xx.xx.xx |Pointer to the host name string | - record_buffer + 16 |---------------------------------------------------------------| - entry 2 |xx.xx.xx.xx |Pointer to the host name string | - record_buffer + 24 |---------------------------------------------------------------| - entry 3 |xx.xx.xx.xx |Pointer to the host name string | - record_buffer + 32 |---------------------------------------------------------------| - entry 4 |xx.xx.xx.xx |Pointer to the host name string | - record_buffer + 40 |---------------------------------------------------------------| - |xx.xx.xx.xx |Pointer to the host name string | - |---------------------------------------------------------------| - | | ns_hostname 4 | - |ns_hostname 3 | ns_hostname 2 | - |ns_hostname 1 | ns_hostname 0 | - record_buffer + max |---------------------------------------------------------------| - */ - -/********************************************************************************/ -/* CNAME */ -/********************************************************************************/ -/* CNAME RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - / CNAME / - / / - |-------------------------------------------------------------| -*/ - - -/********************************************************************************/ -/* MX */ -/********************************************************************************/ -/* MX RDATA format - 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |-----------------------------| - | PREFERECE | - |-----------------------------| - / EXCHANGE / - / / - |-----------------------------| -*/ - -/* Define the mail exchange record type */ -typedef struct NX_DNS_MAIL_EXCHANGE_ENTRY_STRUCT -{ - ULONG nx_dns_mx_ipv4_address; /* The mail exchange server ipv4 address. */ - USHORT nx_dns_mx_preference; /* The preference given to this RR, Lower values are preferred. */ - USHORT nx_dns_mx_reserved0; /* Keep 4-byte aligned. */ - UCHAR *nx_dns_mx_hostname_ptr; /* The mail exchange server host name. */ -} NX_DNS_MX_ENTRY; - -/* Layout of the buffer - record_buffer |---------------------------------------------------------| - entry 0 |xx.xx.xx.xx|preference|res|pointer to host name string | - record_buffer + 12 |---------------------------------------------------------| - entry 1 |xx.xx.xx.xx|preference|res|pointer to host name string | - record_buffer + 24 |---------------------------------------------------------| - entry 2 |xx.xx.xx.xx|preference|res|pointer to host name string | - record_buffer + 36 |---------------------------------------------------------| - entry 3 |xx.xx.xx.xx|preference|res|pointer to host name string | - record_buffer + 48 |---------------------------------------------------------| - entry 4 |xx.xx.xx.xx|preference|res|pointer to host name string | - record_buffer + 60 |---------------------------------------------------------| - |xx.xx.xx.xx|preference|res|pointer to host name string | - |---------------------------------------------------------| - | | mx_hostname 4 | - |mx_hostname 3 | mx_hostname 2 | - |mx_hostname 1 | mx_hostname 0 | - record_buffer + max |---------------------------------------------------------| -*/ - -/********************************************************************************/ -/* SRV */ -/********************************************************************************/ - -/* Define the service record type. */ -typedef struct NX_DNS_SERVICE_ENTRY_STRUCT -{ - ULONG nx_dns_srv_ipv4_address; - USHORT nx_dns_srv_priority; - USHORT nx_dns_srv_weight; - USHORT nx_dns_srv_port_number; - USHORT nx_dns_srv_reserved0; - UCHAR *nx_dns_srv_hostname_ptr; -} NX_DNS_SRV_ENTRY; - -/* Layout of the buffer: - - record_buffer |-------------------------------------------------------------------| - entry 0 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - record_buffer + 16 |-------------------------------------------------------------------| - entry 1 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - record_buffer + 32 |-------------------------------------------------------------------| - entry 2 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - record_buffer + 48 |-------------------------------------------------------------------| - entry 3 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - record_buffer + 64 |-------------------------------------------------------------------| - entry 4 |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - record_buffer + 80 |-------------------------------------------------------------------| - |xx.xx.xx.xx|priority|weight|port|res|pointer to host name string | - | | srv_hostname 4 | - |srv_hostname 3 | srv_hostname 2 | - |srv_hostname 1 | srv_hostname 0 | - record_buffer + max |-------------------------------------------------------------------| - -*/ -/********************************************************************************/ -/* TXT */ -/********************************************************************************/ -/* TXT RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - / TXT-DATA / - / / - |-------------------------------------------------------------| -*/ - -/********************************************************************************/ -/* SOA */ -/********************************************************************************/ -/* SOA RDATA format - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - |-------------------------------------------------------------| - / MNAME / - / / - |-------------------------------------------------------------| - / RNAME / - / / - |-------------------------------------------------------------| - | SERIAL | - |-------------------------------------------------------------| - | REFRESH | - |-------------------------------------------------------------| - | RETRY | - |-------------------------------------------------------------| - | EXPIRE | - |-------------------------------------------------------------| - | MINMUM | - |-------------------------------------------------------------| -*/ - -/* Define the service record type. */ - -typedef struct NX_DNS_SOA_ENTRY_STRUCT -{ - - UCHAR *nx_dns_soa_host_mname_ptr; - UCHAR *nx_dns_soa_host_rname_ptr; - ULONG nx_dns_soa_serial; - ULONG nx_dns_soa_refresh; - ULONG nx_dns_soa_retry; - ULONG nx_dns_soa_expire; - ULONG nx_dns_soa_minmum; -} NX_DNS_SOA_ENTRY; - -/* Layout of the buffer - record_buffer - - |-------------------------------------------------------------------| - | pointer to primary name server| pointer to responsible mailbox | - |-------------------------------------------------------------------| - | serial | refresh | retry | expire | minmum | - |-------------------------------------------------------------------| - | soa_host_mname | soa_host_rname | - |-------------------------------------------------------------------| - */ - -/********************************************************************************/ -/* LOC */ -/********************************************************************************/ -/* To be implemented */ - -/********************************************************************************/ -/* NAPTR */ -/********************************************************************************/ -/* To be implemented */ - -/********************************************************************************/ -/* DNAME */ -/********************************************************************************/ -/* To be implemented */ - -#endif - - -/* Define the RDATA structure. */ - -/* A RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | ADDRESS | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_A_STRUCT -{ - ULONG nx_dns_rr_a_address; -} NX_DNS_RR_A; - -/* AAAA RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | | - | | - | | - | IPv6 ADDRESS | - | | - | | - | | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_AAAA_STRUCT -{ - ULONG* nx_dns_rr_aaaa_address; /* Keep the same resource record structure size, store the rdata information into cache with string. */ -} NX_DNS_RR_AAAA; - - -/* PTR RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / PTRDNAME / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_PTR_STRUCT -{ - UCHAR* nx_dns_rr_ptr_name; -} NX_DNS_RR_PTR; - - -/* NS RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / NSDNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_NS_STRUCT -{ - UCHAR* nx_dns_rr_ns_name; -} NX_DNS_RR_NS; - -/* CNMAE RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / CNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_CNAME_STRUCT -{ - UCHAR* nx_dns_rr_cname_name; -} NX_DNS_RR_CNAME; - - -/* MX RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PREFERENCE | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / NEWNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_MX_STRUCT -{ - UCHAR* nx_dns_rr_mx_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string. "preference, newname" */ -} NX_DNS_RR_MX; - -/* TXT RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / TXT-DATA / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_TXT_STRUCT -{ - UCHAR* nx_dns_rr_txt_data; -} NX_DNS_RR_TXT; - -/* SRV RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PRIORITY | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | WEIGHTS | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PORT | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / TARGET / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_SRV_STRUCT -{ - UCHAR* nx_dns_rr_srv_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string, "priority, weights, port,target". */ -} NX_DNS_RR_SRV; - - -/* SOA RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / RNAME / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | SERIAL | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | REFRESH | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | RETRY | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | EXPIRE | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | MINMUM | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_DNS_RR_SOA_STRUCT -{ - UCHAR* nx_dns_rr_soa_rdata; /* Keep the same resource record structure size, store the rdata information into cache with string. - "Mname, Rname, Serial, Refresh, Retry, Expire, Minmum" */ -} NX_DNS_RR_SOA; - - -/* The following data structure is used to store the resource records(RRs). */ -typedef struct NX_DNS_RR_STRUCT -{ - - UCHAR* nx_dns_rr_name; /* Owner's name,i.e., the name of the node to which this resource record pertains. */ - - USHORT nx_dns_rr_type; /* RR TYPE. */ - - USHORT nx_dns_rr_class; /* RR CLASS. */ - - ULONG nx_dns_rr_ttl; /* The time interval that the RR may be cached before the source of the information should again be consulted. */ - - ULONG nx_dns_rr_last_used_time; /* Define the last used time for the peer RR. */ - - /* Union that holds resource record data. */ - union nx_dns_rr_rdata_union - { - NX_DNS_RR_A nx_dns_rr_rdata_a; - NX_DNS_RR_AAAA nx_dns_rr_rdata_aaaa; - NX_DNS_RR_PTR nx_dns_rr_rdata_ptr; - NX_DNS_RR_SRV nx_dns_rr_rdata_srv; - NX_DNS_RR_TXT nx_dns_rr_rdata_txt; - NX_DNS_RR_CNAME nx_dns_rr_rdata_cname; - NX_DNS_RR_NS nx_dns_rr_rdata_ns; - NX_DNS_RR_MX nx_dns_rr_rdata_mx; - NX_DNS_RR_SOA nx_dns_rr_rdata_soa; - } nx_dns_rr_rdata; - -}NX_DNS_RR; - - -#ifndef NX_DNS_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_dns_create _nx_dns_create -#define nx_dns_delete _nx_dns_delete -#define nx_dns_packet_pool_set _nx_dns_packet_pool_set -#define nx_dns_host_by_address_get _nx_dns_host_by_address_get -#define nx_dns_host_by_name_get _nx_dns_host_by_name_get -#define nx_dns_ipv4_address_by_name_get _nx_dns_ipv4_address_by_name_get - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -#define nx_dns_cname_get _nx_dns_cname_get -#define nx_dns_domain_name_server_get _nx_dns_domain_name_server_get -#define nx_dns_host_text_get _nx_dns_host_text_get -#define nx_dns_domain_mail_exchange_get _nx_dns_domain_mail_exchange_get -#define nx_dns_domain_service_get _nx_dns_domain_service_get -#define nx_dns_authority_zone_start_get _nx_dns_authority_zone_start_get -#define nx_dns_info_by_name_get _nx_dns_info_by_name_get -#endif - -#define nx_dns_server_add _nx_dns_server_add -#define nx_dns_server_remove _nx_dns_server_remove -#define nx_dns_server_remove_all _nx_dns_server_remove_all -#define nx_dns_server_get _nx_dns_server_get -#define nx_dns_get_serverlist_size _nx_dns_get_serverlist_size - -#define nxd_dns_ipv6_address_by_name_get _nxd_dns_ipv6_address_by_name_get -#define nxd_dns_host_by_address_get _nxd_dns_host_by_address_get -#define nxd_dns_host_by_name_get _nxd_dns_host_by_name_get -#define nxd_dns_server_add _nxd_dns_server_add -#define nxd_dns_server_remove _nxd_dns_server_remove -#define nxd_dns_server_get _nxd_dns_server_get - -#ifdef NX_DNS_CACHE_ENABLE -#define nx_dns_cache_initialize _nx_dns_cache_initialize -#define nx_dns_cache_notify_set _nx_dns_cache_notify_set -#define nx_dns_cache_notify_clear _nx_dns_cache_notify_clear -#endif /* NX_DNS_CACHE_ENABLE */ - -#else - -/* Services with error checking. */ - -#define nx_dns_create _nxe_dns_create -#define nx_dns_delete _nxe_dns_delete -#define nx_dns_packet_pool_set _nxe_dns_packet_pool_set -#define nx_dns_host_by_address_get _nxe_dns_host_by_address_get -#define nx_dns_host_by_name_get _nxe_dns_host_by_name_get -#define nx_dns_ipv4_address_by_name_get _nxe_dns_ipv4_address_by_name_get - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -#define nx_dns_cname_get _nxe_dns_cname_get -#define nx_dns_domain_name_server_get _nxe_dns_domain_name_server_get -#define nx_dns_host_text_get _nxe_dns_host_text_get -#define nx_dns_domain_mail_exchange_get _nxe_dns_domain_mail_exchange_get -#define nx_dns_domain_service_get _nxe_dns_domain_service_get -#define nx_dns_authority_zone_start_get _nxe_dns_authority_zone_start_get -#define nx_dns_info_by_name_get _nxe_dns_info_by_name_get -#endif - -#define nx_dns_server_add _nxe_dns_server_add -#define nx_dns_server_remove _nxe_dns_server_remove -#define nx_dns_server_remove_all _nxe_dns_server_remove_all -#define nx_dns_server_get _nxe_dns_server_get -#define nx_dns_get_serverlist_size _nxe_dns_get_serverlist_size - -#define nxd_dns_ipv6_address_by_name_get _nxde_dns_ipv6_address_by_name_get -#define nxd_dns_host_by_address_get _nxde_dns_host_by_address_get -#define nxd_dns_host_by_name_get _nxde_dns_host_by_name_get -#define nxd_dns_server_add _nxde_dns_server_add -#define nxd_dns_server_remove _nxde_dns_server_remove -#define nxd_dns_server_get _nxde_dns_server_get - -#ifdef NX_DNS_CACHE_ENABLE -#define nx_dns_cache_initialize _nxe_dns_cache_initialize -#define nx_dns_cache_notify_set _nxe_dns_cache_notify_set -#define nx_dns_cache_notify_clear _nxe_dns_cache_notify_clear -#endif /* NX_DNS_CACHE_ENABLE */ - -#endif - -/* Define the prototypes accessible to the application software. */ - -UINT nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); -UINT nx_dns_delete(NX_DNS *dns_ptr); -UINT nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); -UINT nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); -UINT nx_dns_server_remove_all(NX_DNS *dns_ptr); -UINT nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); -UINT nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); -UINT nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); -UINT nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -UINT nx_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT nx_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); -#endif - -UINT nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); -UINT nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *dns_server_address); -UINT nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -UINT nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); - -#ifdef NX_DNS_CACHE_ENABLE -UINT nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); -UINT nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); -UINT nx_dns_cache_notify_clear(NX_DNS *dns_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - -#else - -/* DNS source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); -UINT _nx_dns_create(NX_DNS *dns_ptr, NX_IP *ip_ptr, UCHAR *domain_name); -UINT _nxe_dns_delete(NX_DNS *dns_ptr); -UINT _nx_dns_delete(NX_DNS *dns_ptr); -UINT _nxe_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT _nx_dns_packet_pool_set(NX_DNS *dns_ptr, NX_PACKET_POOL *packet_pool_ptr); -UINT _nxe_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT _nx_dns_host_by_address_get(NX_DNS *dns_ptr, ULONG ip_address, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT _nxe_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); -UINT _nx_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, ULONG wait_option); -UINT _nxe_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nx_dns_ipv4_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); - -#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES -UINT _nxe_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size,ULONG wait_option); -UINT _nx_dns_cname_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size,ULONG wait_option); -UINT _nxe_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nx_dns_domain_name_server_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nxe_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT _nx_dns_host_text_get(NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT _nxe_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nx_dns_domain_mail_exchange_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nxe_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nx_dns_domain_service_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nxe_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT _nx_dns_authority_zone_start_get (NX_DNS *dns_ptr, UCHAR *host_name, UCHAR *record_buffer, UINT buffer_size, ULONG wait_option); -UINT _nxe_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); -UINT _nx_dns_info_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, ULONG *host_address_ptr, USHORT* host_port, ULONG wait_option); -#endif - -UINT _nxe_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); -UINT _nx_dns_server_add(NX_DNS *dns_ptr, ULONG server_address); -UINT _nxe_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); -UINT _nx_dns_server_remove(NX_DNS *dns_ptr, ULONG server_address); -UINT _nxe_dns_server_remove_all(NX_DNS *dns_ptr); -UINT _nx_dns_server_remove_all(NX_DNS *dns_ptr); -UINT _nxe_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); -UINT _nx_dns_server_get(NX_DNS *dns_ptr, UINT index, ULONG *dns_server_address); -UINT _nxe_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); -UINT _nx_dns_get_serverlist_size(NX_DNS *dns_ptr, UINT *server_list_size); -UINT _nxde_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nxd_dns_ipv6_address_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, VOID *record_buffer, UINT buffer_size, UINT *record_count, ULONG wait_option); -UINT _nxde_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT _nxd_dns_host_by_address_get(NX_DNS *dns_ptr, NXD_ADDRESS *host_address_ptr, UCHAR *host_name_ptr, UINT host_name_buffer_size, ULONG wait_option); -UINT _nxde_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); -UINT _nxd_dns_host_by_name_get(NX_DNS *dns_ptr, UCHAR *host_name, NXD_ADDRESS *host_address_ptr, ULONG wait_option, UINT lookup_type); -UINT _nxde_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -UINT _nxd_dns_server_add(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -UINT _nxde_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -UINT _nxd_dns_server_remove(NX_DNS *dns_ptr, NXD_ADDRESS *server_address); -UINT _nxde_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); -UINT _nxd_dns_server_get(NX_DNS *dns_ptr, UINT index, NXD_ADDRESS *dns_server_address); - -#ifdef NX_DNS_CACHE_ENABLE -UINT _nxe_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); -UINT _nx_dns_cache_initialize(NX_DNS *dns_ptr, VOID *cache_ptr, UINT cache_size); -UINT _nxe_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); -UINT _nx_dns_cache_notify_set(NX_DNS *dns_ptr, VOID (*cache_full_notify_cb)(NX_DNS *dns_ptr)); -UINT _nxe_dns_cache_notify_clear(NX_DNS *dns_ptr); -UINT _nx_dns_cache_notify_clear(NX_DNS *dns_ptr); -#endif /* NX_DNS_CACHE_ENABLE */ - -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_DNS_H */ - diff --git a/protocol_handlers/ftp/nxd_ftp_client.c b/protocol_handlers/ftp/nxd_ftp_client.c deleted file mode 100644 index e85ed09e..00000000 --- a/protocol_handlers/ftp/nxd_ftp_client.c +++ /dev/null @@ -1,6078 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** File Transfer Protocol (FTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_FTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* If FileX is not used in your application, define this option. Then define the - services declared in filex_stub.h elsewhere. -#define NX_FTP_NO_FILEX -*/ - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_ipv6.h" -#endif /* FEATURE_NX_IPV6 */ -#include "nxd_ftp_client.h" -#include "stdio.h" -#include "string.h" - - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client connect call. */ -/* */ -/* Note: The string lengths of username and password are limited by */ -/* the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* server_ip FTP server IPv4 address */ -/* username Pointer to login username */ -/* password Pointer to login password */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_ftp_client_connect Actual client connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, - CHAR *password, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid server IP address. */ - if (server_ip == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client connect function. */ - status = _nx_ftp_client_connect(ftp_client_ptr, server_ip, username, password, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(ftp_client_ptr); - NX_PARAMETER_NOT_USED(server_ip); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a previously created FTP instance with the */ -/* FTP server at the specified IP address. */ -/* */ -/* Note: The string lengths of username and password are limited by */ -/* the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* server_ip FTP server IPv4 address */ -/* username Pointer to login username */ -/* password Pointer to login password */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_connect_internal Connect to FTP server using */ -/* IP address */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, - CHAR *password, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -NXD_ADDRESS server_ipduo; - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ipduo.nxd_ip_version = NX_IP_VERSION_V4; - server_ipduo.nxd_ip_address.v4 = server_ip; - - - /* Invoke the real connection call. */ - return (_nx_ftp_client_connect_internal(ftp_client_ptr, &server_ipduo, username, password, wait_option)); -#else - NX_PARAMETER_NOT_USED(ftp_client_ptr); - NX_PARAMETER_NOT_USED(server_ip); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_ftp_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client connect call. */ -/* */ -/* Note: The string lengths of username and password are limited by */ -/* the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* server_ip FTP server IP address */ -/* username Pointer to login username */ -/* password Pointer to login password */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_ftp_client_connect Actual client connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, - CHAR *password, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid server IP address. */ - if (!server_ipduo) - return(NX_IP_ADDRESS_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client connect function. */ - status = _nxd_ftp_client_connect(ftp_client_ptr, server_ipduo, username, password, wait_option); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_ftp_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a previously created FTP instance with the */ -/* FTP server at the specified IP address. */ -/* */ -/* Note: The string lengths of username and password are limited by */ -/* the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* server_ip FTP server IP duo address */ -/* username Pointer to login username */ -/* password Pointer to login password */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_connect_internal Acutal connect service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, - CHAR *password, ULONG wait_option) -{ - - /* Invoke the real connection call. */ - return (_nx_ftp_client_connect_internal(ftp_client_ptr, server_ipduo, username, password, wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_connect_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a previously created FTP instance with the */ -/* FTP server at the specified IP address. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* server_ip FTP server IP address */ -/* username Pointer to login username */ -/* password Pointer to login password */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_client_socket_bind Bind client socket to port */ -/* nxd_tcp_client_socket_connect Connect to FTP server */ -/* nx_tcp_client_socket_unbind Unbind client socket from port*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive server response */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_connect_internal(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ip, CHAR *username, - CHAR *password, ULONG wait_option) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT length; -UINT i; -UINT status; - - - /* Determine if the client is still in a not connected state. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_NOT_CONNECTED) - { - - /* Already connected, return an error. */ - return(NX_FTP_NOT_DISCONNECTED); - } - - /* Bind the client control socket. */ - status = nx_tcp_client_socket_bind(&(ftp_client_ptr -> nx_ftp_client_control_socket), NX_FTP_CLIENT_SOURCE_PORT, wait_option); - - /* Check for an error. */ - if ((status != NX_SUCCESS) && (status != NX_ALREADY_BOUND)) - { - - /* Unable to bind socket to port. */ - return(status); - } - - /* Connect the socket to the FTP server. */ - status = nxd_tcp_client_socket_connect(&(ftp_client_ptr -> nx_ftp_client_control_socket), server_ip, NX_FTP_SERVER_CONTROL_PORT, wait_option); - - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* Now wait for the "220 " response from the FTP server to indicate the connection has been - established. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Check to see if no packet was received. */ - if (status) - { - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Return. */ - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - length = packet_ptr -> nx_packet_length; - - /* Check for 220 message. */ - if ((length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2')) - { - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(NX_FTP_EXPECTED_22X_CODE); - } - - memset(buffer_ptr, 0, length); - - /* Check if out of boundary. */ - if (((!username) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 11)) || - ((username) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7))) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Now build the user name message. */ - buffer_ptr[0] = 'U'; - buffer_ptr[1] = 'S'; - buffer_ptr[2] = 'E'; - buffer_ptr[3] = 'R'; - buffer_ptr[4] = ' '; - - /* Determine if a user name was supplied. */ - if (username == NX_NULL) - { - - /* No username specified, use "USER". */ - buffer_ptr[5] = 'U'; - buffer_ptr[6] = 'S'; - buffer_ptr[7] = 'E'; - buffer_ptr[8] = 'R'; - buffer_ptr[9] = 13; - buffer_ptr[10]= 10; - - /* Set the length of the packet. */ - packet_ptr -> nx_packet_length = 11; - } - else - { - - /* A username was supplied, copy it into the buffer. */ - for(i = 0; username[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy byte of the username. */ - buffer_ptr[5+i] = (UCHAR)username[i]; - } - - /* Now insert the CR/LF. */ - buffer_ptr[5+i] = 13; - buffer_ptr[5+i+1] = 10; - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = i + 7; - } - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the username to the FTP server. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Check for unsuccessful send. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* There may be multiple 220 responses from FTP server after establishing connection. - Flush mutiple 220 respones and wait for 331 response from the FTP server. */ - while(1) - { - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Return. */ - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 220 message. */ - if ((packet_ptr -> nx_packet_length >= 3) && (buffer_ptr[0] == '2') && (buffer_ptr[1] == '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - continue; - } - - /* Check to make sure the response is proper. */ - - /* Check for 331 message. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '3') || (buffer_ptr[1] != '3')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(NX_FTP_EXPECTED_33X_CODE); - } - else - { - break; - } - } - - memset(buffer_ptr, 0, length); - - /* Check if out of boundary. */ - if (((!password) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 11)) || - ((password) && ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7))) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Now build the password message. */ - buffer_ptr[0] = 'P'; - buffer_ptr[1] = 'A'; - buffer_ptr[2] = 'S'; - buffer_ptr[3] = 'S'; - buffer_ptr[4] = ' '; - - /* Determine if a password was specified. */ - if (password == NX_NULL) - { - - /* No password was specified, use "PASS". */ - buffer_ptr[5] = 'P'; - buffer_ptr[6] = 'A'; - buffer_ptr[7] = 'S'; - buffer_ptr[8] = 'S'; - buffer_ptr[9] = 13; - buffer_ptr[10]= 10; - - /* Setup the packet length. */ - packet_ptr -> nx_packet_length = 11; - } - else - { - - /* Password was specified, copy it into the buffer. */ - for(i = 0; password[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy byte of password. */ - buffer_ptr[5+i] = (UCHAR)password[i]; - } - - /* Now insert the CR/LF. */ - buffer_ptr[5+i] = 13; - buffer_ptr[5+i+1] = 10; - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = i + 7; - } - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the password to the FTP server. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Check for successful send. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 230 message, signaling successful login. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '3')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Close the socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(NX_FTP_EXPECTED_23X_CODE); - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* If we get here, we have a successful connect with the FTP server. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_CONNECTED; - - ftp_client_ptr -> nx_ftp_client_data_port = ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_port; - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* ftp_client_name Name of this FTP client */ -/* ip_ptr Pointer to IP instance */ -/* window_size Size of TCP receive window */ -/* pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, - ULONG window_size, NX_PACKET_POOL *pool_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id == NXD_FTP_CLIENT_ID) || - (pool_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual client create function. */ - status = _nx_ftp_client_create(ftp_client_ptr, ftp_client_name, ip_ptr, window_size, pool_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an FTP client instance. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* ftp_client_name Name of this FTP client */ -/* ip_ptr Pointer to IP instance */ -/* window_size Size of TCP receive window */ -/* pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create TCP socket */ -/* nx_tcp_socket_delete Delete TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, - ULONG window_size, NX_PACKET_POOL *pool_ptr) -{ - -UINT status; - - - /* Clear the client FTP control block. */ - memset((void *) ftp_client_ptr, 0, sizeof(NX_FTP_CLIENT)); - - /* Create the TCP control socket. */ - status = nx_tcp_socket_create(ip_ptr, &(ftp_client_ptr -> nx_ftp_client_control_socket), ftp_client_name, - NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, window_size, - NX_NULL, NX_NULL); - - /* Check for an error. */ - if (status) - { - - /* Return an error. */ - return(status); - } - - /* Create the TCP data socket. */ - status = nx_tcp_socket_create(ip_ptr, &(ftp_client_ptr -> nx_ftp_client_data_socket), ftp_client_name, - NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, window_size, - NX_NULL, _nx_ftp_client_data_disconnect); - - /* Check for an error. */ - if (status) - { - - /* Delete the control socket. */ - nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Return an error. */ - return(status); - } - - /* Save off the remaining information. */ - - /* Save the client name. */ - ftp_client_ptr -> nx_ftp_client_name = ftp_client_name; - - /* Save the IP pointer. */ - ftp_client_ptr -> nx_ftp_client_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - ftp_client_ptr -> nx_ftp_client_packet_pool_ptr = pool_ptr; - - /* Set the initial client state. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_NOT_CONNECTED; - - /* Set the FTP client id. */ - ftp_client_ptr -> nx_ftp_client_id = NXD_FTP_CLIENT_ID; - - /* Default to active transfer mode. */ - ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled = NX_FALSE; - - /* Default to stream mode. */ - ftp_client_ptr -> nx_ftp_client_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_data_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the disconnect from the server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* data_socket_ptr Pointer to FTP client data */ -/* socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_disconnect Disconnect TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ftp_client_data_disconnect(NX_TCP_SOCKET *data_socket_ptr) -{ - - /* Disconnect FTP client data socket. */ - nx_tcp_socket_disconnect(data_socket_ptr, NX_NO_WAIT); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_delete Actual client delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nx_ftp_client_delete(ftp_client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created FTP client instance. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create TCP socket */ -/* nx_tcp_socket_delete Delete TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr) -{ - - /* Determine if the client is still in a not connected state. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_NOT_CONNECTED) - { - - /* Already connected, return an error. */ - return(NX_FTP_NOT_DISCONNECTED); - } - - /* Delete the control and data sockets. */ - nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - nx_tcp_socket_delete(&(ftp_client_ptr -> nx_ftp_client_data_socket)); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_directory_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client directory */ -/* create call. */ -/* */ -/* Note: The string length of directory_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_name New directory name */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_directory_create Actual client directory */ -/* create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (directory_name == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client directory create function. */ - status = _nx_ftp_client_directory_create(ftp_client_ptr, directory_name, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_directory_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the specified directory name on the FTP */ -/* server. */ -/* */ -/* Note: The string length of directory_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_name New directory name */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive packet from server */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - /* Ensure the client is the proper state for directory create request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Allocate a packet for sending the directory create command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "MKD" message to indicate directory create. */ - buffer_ptr[0] = 'M'; - buffer_ptr[1] = 'K'; - buffer_ptr[2] = 'D'; - buffer_ptr[3] = ' '; - - /* Copy the new directory name into the message. */ - for(i = 0; directory_name[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the directory name. */ - buffer_ptr[4+i] = (UCHAR)directory_name[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+4] = 13; - buffer_ptr[i+5] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+6; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the MKD message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* MKD error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "MKD" was processed successfully. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Create directory error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Yes, the directory was created. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_directory_default_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client directory */ -/* default set. */ -/* */ -/* Note: The string length of directory_path is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_path New default directory path */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_directory_default_set Actual client directory */ -/* default set call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client directory default set function. */ - status = _nx_ftp_client_directory_default_set(ftp_client_ptr, directory_path, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_directory_default_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function changes the default working directory on the FTP */ -/* server. */ -/* */ -/* Note: The string length of directory_path is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_path New default directory path */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive packet from server */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - - /* Ensure the client is the proper state for a default directory request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Allocate a packet for sending the change directory command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "CWD" message to indicate default directory change. */ - buffer_ptr[0] = 'C'; - buffer_ptr[1] = 'W'; - buffer_ptr[2] = 'D'; - buffer_ptr[3] = ' '; - - /* Copy the new default directory into the message. */ - for(i = 0; directory_path[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the directory path. */ - buffer_ptr[4+i] = (UCHAR)directory_path[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+4] = 13; - buffer_ptr[i+5] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+6; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the CWD message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* RNFR file error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "CWD" was processed successfully. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Change directory error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Yes, the default directory was changed. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_directory_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client directory */ -/* delete. */ -/* */ -/* Note: The string length of directory_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_name Directory name to delete */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_directory_delete Actual client directory */ -/* delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client directory delete function. */ - status = _nx_ftp_client_directory_delete(ftp_client_ptr, directory_name, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_directory_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the specified directory on the FTP */ -/* server. */ -/* */ -/* Note: The string length of directory_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_name Directory name to delete */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive packet from server */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - - /* Ensure the client is the proper state for directory delete request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Allocate a packet for sending the directory delete command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "RMD" message to indicate directory delete. */ - buffer_ptr[0] = 'R'; - buffer_ptr[1] = 'M'; - buffer_ptr[2] = 'D'; - buffer_ptr[3] = ' '; - - /* Copy the directory name into the message. */ - for(i = 0; directory_name[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 6) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the directory name. */ - buffer_ptr[4+i] = (UCHAR)directory_name[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+4] = 13; - buffer_ptr[i+5] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+6; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the RMD message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* DELE error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "RMD" was processed successfully. */ - if ((packet_ptr -> nx_packet_length < 3) ||(buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Delete directory error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Yes, the directory was deleted. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_directory_listing_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client directory */ -/* listing get. */ -/* */ -/* Note: The string length of directory_path is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_path Directory to get listing for */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* that contains the listing */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_directory_listing_get Actual client directory */ -/* listing get call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, - NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client directory listing get function. */ - status = _nx_ftp_client_directory_listing_get(ftp_client_ptr, directory_path, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_directory_listing_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets a listing for the specified directory on the */ -/* FTP server. */ -/* */ -/* Note: The string length of directory_path is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* directory_path Directory to get listing for */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* that contains the listing */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_packet_allocate Allocate packet */ -/* _nx_ftp_client_active_transfer_setup Setup active transfer */ -/* _nx_ftp_client_passive_transfer_setup Setup passive transfer */ -/* _nx_ftp_client_block_mode_send Send block mode command */ -/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ -/* nx_packet_release Release packet */ -/* nx_tcp_server_socket_accept Connect data socket to server */ -/* nx_tcp_socket_receive Receive response from server */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, - NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *new_packet_ptr; -UINT status; - - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Ensure the client is the proper state for directory listing request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Divert to passive mode operation if passive mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled) - { - - /* Transfer the data in passive transfer mode. */ - status = _nx_ftp_client_passive_transfer_setup(ftp_client_ptr, wait_option); - } - else - { - - /* Transfer the data in active transfer mode. */ - status = _nx_ftp_client_active_transfer_setup(ftp_client_ptr, wait_option); - } - - /* Determine if set up successful. */ - if (status) - { - return(status); - } - - /* Check if enable block mode. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Send MODE B command to FTP server. */ - status = _nx_ftp_client_block_mode_send(ftp_client_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - return(status); - } - } - - /* Allocate a packet for sending the NLST command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &new_packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr) < 7) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = new_packet_ptr -> nx_packet_prepend_ptr; - - /* Now build the actual NLST request. */ - buffer_ptr[0] = 'N'; - buffer_ptr[1] = 'L'; - buffer_ptr[2] = 'S'; - buffer_ptr[3] = 'T'; - buffer_ptr[4] = ' '; - - /* Copy the directory path into the buffer. */ - for(i = 0; directory_path[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of directory path. */ - buffer_ptr[5+i] = (UCHAR)directory_path[i]; - } - - /* Insert the CR/LF. */ - buffer_ptr[5+i] = 13; - buffer_ptr[5+i+1] = 10; - - /* Setup the length of the packet. */ - new_packet_ptr -> nx_packet_length = i + 7; - - /* Setup the packet append pointer. */ - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_prepend_ptr + new_packet_ptr -> nx_packet_length; - - /* Send the NLST message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), new_packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Return error. */ - return(status); - } - - /* Check if enable passive mode. */ - if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) - { - - /* Now wait for the data connection to connect. */ - status = nx_tcp_server_socket_accept(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); - - /* Determine if the accept was unsuccessful. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Return error. */ - return(status); - } - } - - /* Now wait for response from the FTP server control port. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &new_packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Error in NLST request to FTP server. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = new_packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 1xx message, signaling the data port was connected properly and ready for - transfer. */ - if ((new_packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '1')) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Error in NLST request to FTP server. */ - return(NX_FTP_EXPECTED_1XX_CODE); - } - - /* Release the last packet. */ - nx_packet_release(new_packet_ptr); - - /* Now read a listing packet from the data socket. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); - - /* Determine if an error occurred. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Map all unsuccessful status to error. */ - return(status); - } - - /* Determine if the block mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Retrieve the block header. */ - status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); - - /* Determine if an error occurred. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - } - } - - /* Return staus to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_directory_listing_continue PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client directory */ -/* listing continue. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* that contains the listing */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_directory_listing_continue Actual client directory */ -/* listing continue call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client directory listing continue function. */ - status = _nx_ftp_client_directory_listing_continue(ftp_client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_directory_listing_continue PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the next listing buffer. It is assumed that */ -/* a successful _nx_ftp_client_directory_listing_get immediately */ -/* preceded this call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* that contains the listing */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_server_socket_unlisten Unlisten on server port */ -/* nx_tcp_socket_receive Receive packet from server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; -NX_PACKET *response_ptr; -UCHAR *buffer_ptr; - - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Ensure the client is the proper state for directory listing request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Now read a listing packet from the data socket. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); - - /* Determine if the block mode is enabled. */ - if ((status == NX_SUCCESS) && - (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)) - { - - /* Retrieve the block header. */ - status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); - } - - /* Determine if an error occurred. */ - if (status) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Wait for response from the FTP server on the control socket. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &response_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Directory listing error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = response_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "NLST" was processed successfully. */ - if ((response_ptr -> nx_packet_length >= 3) && (buffer_ptr[0] == '2')) - { - - /* Release the packet. */ - nx_packet_release(response_ptr); - - /* Appropriate end of listing error. */ - return(NX_FTP_END_OF_LISTING); - } - else - { - - /* Release the packet. */ - nx_packet_release(response_ptr); - - /* Map all other unsuccessful status to error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - } - - /* Return success to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client disconnect. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_disconnect Actual client disconnect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client disconnect function. */ - status = _nx_ftp_client_disconnect(ftp_client_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disconnects a previously established FTP connection. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_client_socket_unbind Unbind a socket */ -/* nx_tcp_socket_disconnect Disconnect a socket */ -/* nx_tcp_socket_receive Receive response from server */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT status; - - - /* Determine if the client is in a not connected state. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - { - - /* Already connected, return an error. */ - return(NX_FTP_NOT_CONNECTED); - } - - /* Enter the not connected state. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_NOT_CONNECTED; - - /* Allocate a packet for sending the port and IP address. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Clean up connection socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) - { - - /* Clean up connection socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Build QUIT message to end the FTP connection. */ - buffer_ptr[0] = 'Q'; - buffer_ptr[1] = 'U'; - buffer_ptr[2] = 'I'; - buffer_ptr[3] = 'T'; - buffer_ptr[4] = 13; - buffer_ptr[5] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 6; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the QUIT message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Clean up connection socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Clean up connection socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the disconnect was processed properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Clean up connection socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Success. Disconnect and unbind the control socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_control_socket), wait_option); - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_control_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_close PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file close. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_close Actual client file close call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file close function. */ - status = _nx_ftp_client_file_close(ftp_client_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_close PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function closes a previously open client FTP file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ -/* nx_packet_release Release packet */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_server_socket_unlisten Unlisten on server socket */ -/* nx_tcp_socket_disconnect Disconnect a socket */ -/* nx_tcp_socket_receive Receive response from server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT status; - - - /* Ensure the client is in the proper state for closing the socket. */ - if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_NOT_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - else if ((ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_OPEN) && - (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN)) - return(NX_FTP_NOT_OPEN); - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Set the state to connected. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_CONNECTED; - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* Unable to connect socket to server FTP control port. */ - return(status); - } - - /* We have a packet, setup pointer to the packet payload area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the close was processed properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file delete. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_name File name to delete */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_delete Actual client file delete call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (file_name == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file delete function. */ - status = _nx_ftp_client_file_delete(ftp_client_ptr, file_name, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the specified file on the FTP */ -/* server. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_name File name to delete */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive packet from server */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - - /* Ensure the client is the proper state for file delete request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Allocate a packet for sending the file delete command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "DELE" message to indicate file delete. */ - buffer_ptr[0] = 'D'; - buffer_ptr[1] = 'E'; - buffer_ptr[2] = 'L'; - buffer_ptr[3] = 'E'; - buffer_ptr[4] = ' '; - - /* Copy the file name into the message. */ - for(i = 0; file_name[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the file name. */ - buffer_ptr[5+i] = (UCHAR)file_name[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+5] = 13; - buffer_ptr[i+6] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+7; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the DELE message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* DELE error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "DELE" was processed successfully. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* File delete error. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Yes, the file was deleted. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_passive_mode_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the request to passive mode. Once this is set */ -/* the Client will send a PASV command preceding any FTP Client command*/ -/* involving transferring data on the data socket. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* passive_mode_enabled True to enable */ -/* False to disable */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* status Completion status */ -/* */ -/* CALLS */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled) -{ - -UINT status; - - if (ftp_client_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - if ((passive_mode_enabled != NX_TRUE) && (passive_mode_enabled != NX_FALSE)) - { - return NX_INVALID_PARAMETERS; - } - - status = _nx_ftp_client_passive_mode_set(ftp_client_ptr, passive_mode_enabled); - - return status; - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_passive_mode_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the request to passive mode. Once this is set */ -/* the Client will send a PASV command preceding any FTP Client command*/ -/* for accessing a server data port. If passive mode is not set, */ -/* the FTP Client will send and receive data via active transfer mode. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* passive_mode_enabled True to enable passive mode */ -/* False to disable passive mode */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled) -{ - - /* Set the transfer status according to the passive mode enabled input. */ - ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled = passive_mode_enabled; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_transfer_mode_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP transfer mode set. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* transfer_mode Transfer mode */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_transfer_mode_set Actual transfer mode set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode) -{ - -UINT status; - - /* Check for valid pointer. */ - if (ftp_client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual transfer mode set function. */ - status = _nx_ftp_client_transfer_mode_set(ftp_client_ptr, transfer_mode); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_transfer_mode_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the transfer mode. */ -/* Note: just support stream mode and block mode yet. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* transfer_mode Transfer mode */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode) -{ - - /* Check for transfer mode. */ - if ((transfer_mode != NX_FTP_TRANSFER_MODE_STREAM) && - (transfer_mode != NX_FTP_TRANSFER_MODE_BLOCK)) - { - return(NX_INVALID_PARAMETERS); - } - - /* Set the transfer mode. */ - ftp_client_ptr -> nx_ftp_client_transfer_mode = transfer_mode; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file open. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_name Client file name */ -/* open_type Open for read or open for */ -/* write */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_open Actual client file open call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (file_name == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for illegal open option type. */ - if ((open_type != NX_FTP_OPEN_FOR_READ) && (open_type != NX_FTP_OPEN_FOR_WRITE)) - return(NX_OPTION_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file open function. */ - status = _nx_ftp_client_file_open(ftp_client_ptr, file_name, open_type, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens a client FTP file. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_name Client file name */ -/* open_type Open for read or open for */ -/* write */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_packet_allocate Allocate packet */ -/* _nx_ftp_client_active_transfer_setup Setup active transfer */ -/* _nx_ftp_client_passive_transfer_setup Setup passive transfer */ -/* _nx_ftp_client_block_mode_send Send block mode command */ -/* _nx_ftp_client_data_socket_cleanup Cleanup data socket */ -/* nx_packet_release Release packet */ -/* nx_tcp_server_socket_accept Connect data socket to server */ -/* nx_tcp_socket_receive Receive response from server */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - - /* Ensure the client is the proper state for an open request. */ - if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_NOT_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - else if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_OPEN) - return(NX_FTP_NOT_CLOSED); - else if (ftp_client_ptr -> nx_ftp_client_state == NX_FTP_STATE_WRITE_OPEN) - return(NX_FTP_NOT_CLOSED); - - /* Flush the control socket queue for any old messages before starting a new file open request. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, 1); - - /* Determine if a packet was received. */ - if (status == NX_SUCCESS) - { - - /* Just discard it. */ - nx_packet_release(packet_ptr); - } - - /* Allocate a packet for sending the TYPE command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status != NX_SUCCESS) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 8) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_INVALID_PACKET); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "TYPE I" message to indicate binary file transfer. */ - buffer_ptr[0] = 'T'; - buffer_ptr[1] = 'Y'; - buffer_ptr[2] = 'P'; - buffer_ptr[3] = 'E'; - buffer_ptr[4] = ' '; - buffer_ptr[5] = 'I'; - - /* Set the CR/LF. */ - buffer_ptr[6] = 13; - buffer_ptr[7] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 8; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the TYPE message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status != NX_SUCCESS) - { - - /* Unable to open file with FTP server. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "TYPE I" was received properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Divert to passive mode operation if passive mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled) - { - - /* Set up the passive transfer mode: - Send PASV request, - Get server IP and port to connect to, - Open data socket based on server info in PASV response. */ - status = _nx_ftp_client_passive_transfer_setup(ftp_client_ptr, wait_option); - } - else - { - - /* Open in active transfer mode. */ - status = _nx_ftp_client_active_transfer_setup(ftp_client_ptr, wait_option); - } - - /* Determine if set up successful. */ - if (status) - { - return(status); - } - - /* Check if enable block mode. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Send MODE B command to FTP server. */ - status = _nx_ftp_client_block_mode_send(ftp_client_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - return(status); - } - } - - /* Allocate a packet for sending the TYPE command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Return error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build the actual open request. */ - if (open_type == NX_FTP_OPEN_FOR_WRITE) - { - - /* File write request, STOR is the command for writing a file. */ - buffer_ptr[0] = 'S'; - buffer_ptr[1] = 'T'; - buffer_ptr[2] = 'O'; - buffer_ptr[3] = 'R'; - buffer_ptr[4] = ' '; - } - else - { - - /* File read request, RETR is the command for reading a file. */ - buffer_ptr[0] = 'R'; - buffer_ptr[1] = 'E'; - buffer_ptr[2] = 'T'; - buffer_ptr[3] = 'R'; - buffer_ptr[4] = ' '; - } - - /* Copy the file name into the buffer. */ - for(i = 0; file_name[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of file name. */ - buffer_ptr[5+i] = (UCHAR)file_name[i]; - } - - /* Insert the CR/LF. */ - buffer_ptr[5+i] = 13; - buffer_ptr[5+i+1] = 10; - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = i + 7; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the STOR/RETR message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Check if enable passive mode. */ - if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) - { - - /* Active mode. Now wait for the data connection to connect. */ - status = nx_tcp_server_socket_accept(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); - - /* Determine if the accept was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Return error. */ - return(status); - } - } - - /* Now wait for response from the FTP server control port. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status != NX_SUCCESS) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Unable to open file with FTP server. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 1xx message, signaling the data port was connected properly and ready for transfer. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '1')) - { - - /* Cleanup data socket. */ - _nx_ftp_client_data_socket_cleanup(ftp_client_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_1XX_CODE); - } - - /* Release the last packet. */ - nx_packet_release(packet_ptr); - - /* At this point, the client has successfully opened a FTP connection. */ - if (open_type == NX_FTP_OPEN_FOR_WRITE) - { - - /* Set the client state to open for write. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_WRITE_OPEN; - } - else - { - - /* Set the client state to open for read. */ - ftp_client_ptr -> nx_ftp_client_state = NX_FTP_STATE_OPEN; - } - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file read. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_read Actual client file read call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file read function. */ - status = _nx_ftp_client_file_read(ftp_client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reads a packet of the file from the data connection */ -/* with the FTP server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Destination of for the */ -/* received packet pointer */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive response from server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Determine if the file is open for writing. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_OPEN) - return(NX_FTP_NOT_OPEN); - - /* Default the packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Read the packet from the data connection. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); - - /* Determine if an error occurred. */ - if (status == NX_NOT_CONNECTED) - { - - /* Map not-connected status to end of file. */ - status = NX_FTP_END_OF_FILE; - } - - /* Determine if the block mode is enabled. */ - if ((status == NX_SUCCESS) && - (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK)) - { - - /* Retrieve the block header. */ - status = _nx_ftp_client_block_header_retrieve(ftp_client_ptr, (*packet_ptr)); - } - - /* Return status to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_rename PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file rename. */ -/* */ -/* Note: The string lengths of filename and new_filename are limited */ -/* by the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* filename Current file name */ -/* new_filename New file name */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_ftp_client_file_rename Actual client file rename call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || - (filename == NX_NULL) || (new_filename == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file rename function. */ - status = _nx_ftp_client_file_rename(ftp_client_ptr, filename, new_filename, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_rename PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function renames the specified file with the supplied */ -/* filename. */ -/* */ -/* Note: The string lengths of filename and new_filename are limited */ -/* by the packet payload size. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* filename Current file name */ -/* new_filename New file name */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive packet from server */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option) -{ - -UINT i; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; - - - /* Ensure the client is the proper state for a rename file request. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_CONNECTED) - return(NX_FTP_NOT_CONNECTED); - - /* Allocate a packet for sending the file rename command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build "RNFR" message to indicate file rename request. */ - buffer_ptr[0] = 'R'; - buffer_ptr[1] = 'N'; - buffer_ptr[2] = 'F'; - buffer_ptr[3] = 'R'; - buffer_ptr[4] = ' '; - - /* Copy the old file name into the message. */ - for(i = 0; filename[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the file name. */ - buffer_ptr[5+i] = (UCHAR)filename[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+5] = 13; - buffer_ptr[i+6] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+7; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the RNFR message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* RNFR file error. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 3xx message, signaling the "RNFR" was received properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '3')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to rename file with FTP server. */ - return(NX_FTP_EXPECTED_3XX_CODE); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 7) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Now build "RNTO" message to specify new file name. */ - buffer_ptr[0] = 'R'; - buffer_ptr[1] = 'N'; - buffer_ptr[2] = 'T'; - buffer_ptr[3] = 'O'; - buffer_ptr[4] = ' '; - - /* Copy the old file name into the message. */ - for(i = 0; new_filename[i]; i++) - { - - /* Check if out of boundary. */ - if ((i + 7) >= (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* Copy character of the new file name. */ - buffer_ptr[5+i] = (UCHAR)new_filename[i]; - } - - /* Set the CR/LF. */ - buffer_ptr[i+5] = 13; - buffer_ptr[i+6] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = i+7; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the RNTO message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status) - { - - /* RNTO file error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the "RNTO" was processed properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to rename with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Release packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_size_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file size set. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_size The total size of file */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_size_set Actual file size set call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file size set function. */ - status = _nx_ftp_client_file_size_set(ftp_client_ptr, file_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_size_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the file size for block mode before send packets */ -/* to the file on the data connection with the FTP server. */ -/* */ -/* Note:a. This API is only used for block mode, */ -/* b. Must call this API before call nx_ftp_client_file_write. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* file_size The total size of file */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size) -{ - -UINT status; - - - /* Check for invalid file size. */ - if (file_size == 0) - return(NX_FTP_CLIENT_INVALID_SIZE); - - /* Check if already set the file size. */ - if (ftp_client_ptr -> nx_ftp_client_block_total_size != 0) - return(NX_FTP_CLIENT_FILE_SIZE_ALREADY_SET); - - /* Determine if the block mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode != NX_FTP_TRANSFER_MODE_BLOCK) - return(NX_FTP_CLIENT_NOT_BLOCK_MODE); - - /* Determine if the file is open for writing. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN) - return(NX_FTP_NOT_OPEN); - - /* Send start block header for file size. */ - status = _nx_ftp_client_block_header_send(ftp_client_ptr, file_size); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Store the file size for writing. */ - ftp_client_ptr -> nx_ftp_client_block_total_size = file_size; - ftp_client_ptr -> nx_ftp_client_block_remaining_size = file_size; - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_client_file_write PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP client file write. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Pointer to packet to write */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_file_write Actual client file write call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NXD_FTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file write function. */ - status = _nx_ftp_client_file_write(ftp_client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_file_write PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function writes a packet to the file on the data connection */ -/* with the FTP server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Pointer to packet to write */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; -ULONG file_size = 0; - - - /* Determine if the file is open for writing. */ - if (ftp_client_ptr -> nx_ftp_client_state != NX_FTP_STATE_WRITE_OPEN) - return(NX_FTP_NOT_OPEN); - - /* Determine if the block mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Record the file size. */ - file_size = packet_ptr -> nx_packet_length; - - /* Check the file size. */ - if (ftp_client_ptr -> nx_ftp_client_block_remaining_size < packet_ptr -> nx_packet_length) - return(NX_FTP_CLIENT_INVALID_SIZE); - } - - /* Write packet payload to the file. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Determine if the block mode is enabled. */ - if (ftp_client_ptr -> nx_ftp_client_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Update the file size. */ - ftp_client_ptr -> nx_ftp_client_block_remaining_size -= file_size; - - /* Check if the file is already sent. */ - if (ftp_client_ptr -> nx_ftp_client_block_remaining_size == 0) - { - - /* Send end block header for file size. */ - status = _nx_ftp_client_block_header_send(ftp_client_ptr, 0); - } - } - - /* Return success to caller. */ - return(status); -} - - -#ifdef FEATURE_NX_IPV6 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_utility_convert_IPv6_to_ascii PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an IP address to ascii e.g. for insertion */ -/* into FTP EPRT or PORT command. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* buffer Pointer to ascii port number string*/ -/* buffer_length Size of buffer */ -/* size IPv6 address string size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful conversion */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_utility_convert_number_ascii */ -/* Converts a single number to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open FTP Client file open service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_ftp_utility_convert_IPv6_to_ascii(NX_TCP_SOCKET *socket_ptr, CHAR *buffer, UINT buffer_length, UINT *size) -{ - - -CHAR *temp; -CHAR number_buf[10]; /* 0x20010000 -> "2001:0000:" */ - - - /* Set a pointer to the start of the buffer. */ - temp = buffer; - - /* Clear the buffer. */ - memset(temp, 0, buffer_length); - - /* Clear the scratch buffer. */ - memset(number_buf, 0, 10); - - _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[0], number_buf); - - /* Append to string buffer. */ - memcpy(temp, number_buf, 10); - - /* Move the pointer past this number. */ - temp += 10; - - /* Clear the scratch buffer. */ - memset(number_buf, 0, 10); - - _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[1], number_buf); - - /* Append to string buffer. */ - memcpy(temp, number_buf, 10); - - /* Move the pointer past this number. */ - temp += 10; - - /* Clear the scratch buffer. */ - memset(number_buf, 0, 10); - - _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[2], number_buf); - - /* Append to string buffer. */ - memcpy(temp, number_buf, 10); - - /* Move the pointer past this number. */ - temp += 10; - - /* Clear the scratch buffer. */ - memset(number_buf, 0, 10); - - _nx_ftp_utility_convert_number_ascii(socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address[3], number_buf); - - /* Append to string buffer. */ - memcpy(temp, number_buf, 10); - - /* Move the pointer past this number. */ - temp += 10; - - /* Remove the trailing ':'. */ - *(temp - 1) = 0x0; - *size = 39; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_utility_convert_number_ascii PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number to ascii text for inserting IP */ -/* address and port numbers into FTP EPRT and PORT commands. It is up */ -/* to the caller to provide a buffer large enough to hold the ascii */ -/* conversion of the input number. */ -/* */ -/* INPUT */ -/* */ -/* number Number to convert to ASCII */ -/* numstring Pointer to ascii string */ -/* */ -/* OUTPUT */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* None */ -/* */ -/* CALLED BY */ -/* _nx_ftp_utility_convert_IPv6_to_ascii */ -/* Convert IPv6 address to ASCII */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_ftp_utility_convert_number_ascii(ULONG number, CHAR *numstring) -{ - -UINT j; -UCHAR c; - - /* Go through each bit of the ULONG to convert. */ - for (j = 0; j <=7 ; j++) - { - - /* Save the bit off the most significant end. */ - c = (UCHAR)((number & 0xF0000000) >> 28); - - /* Make it the most significant byte. */ - number = number << 4; - - /* Convert the digit to an ascii character. */ - if (c < 10) - { - *numstring = (CHAR)('0' + c); - } - else /* Handle HEX digits... */ - { - *numstring = (CHAR)('A' + (c - 10)); - } - - /* Move past the digit. */ - numstring++; - - /* Determine if we need to add a colon. */ - if (j == 3 || j == 7) - { - /* Yes, append the colon and move the pointer past it. */ - *numstring = ':'; - numstring++; - } - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_utility_convert_portnumber_ascii PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number to ascii text e.g. used by */ -/* _nx_nat_utility_convert_portnumber_ULONG_to_ascii for inserting */ -/* changed port numbers back into FTP PORT command . */ -/* */ -/* INPUT */ -/* */ -/* number Port number to convert to ASCII */ -/* numstring Pointer to ascii portnumber string */ -/* numstring_length Portnumber string length */ -/* */ -/* OUTPUT */ -/* */ -/* NX_FTP_ERROR Unable to convert e.g. overflow error*/ -/* NX_SUCCESS Successful conversion */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open Processes the FTP file open service */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_ftp_utility_convert_portnumber_ascii(UINT number, CHAR *numstring, UINT *numstring_length) -{ - -UINT j; -UINT digit; - - - /* Initialize counters. */ - (*numstring_length) = 0; - - /* Loop to convert the number to ASCII. */ - while ((*numstring_length) < 10) - { - - /* Shift the current digits over one. */ - for (j = (*numstring_length); j != 0; j--) - { - - /* Move each digit over one place. */ - numstring[j] = numstring[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - numstring[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - (*numstring_length)++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Make the string NULL terminated. */ - numstring[(*numstring_length)] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - (*numstring_length) = 0; - numstring[0] = '0'; - return NX_FTP_INVALID_NUMBER; - } - - /* Return size to caller. */ - return NX_SUCCESS; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines which IP TCP packet to allocate based on */ -/* the FTP connection address IP type and then allocates the packet. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Allocated packet to return */ -/* wait_option Packet allocate wait option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_NOT_ENABLED IPv6 not enabled */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_packet_allocate(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT packet_type; -UINT status; - - - /* Default to IPv4 TCP packet to allocate. */ - packet_type = NX_IPv4_TCP_PACKET; - - /* Determine IP version by FTP connection type. */ - if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - - return NX_NOT_ENABLED; -#else - - /* Allocate a TCP IPv6 packet. */ - packet_type = NX_IPv6_TCP_PACKET; -#endif - } - - - /* Allocate the actual packet. */ - status = nx_packet_allocate(ftp_client_ptr -> nx_ftp_client_packet_pool_ptr, packet_ptr, packet_type, wait_option); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_active_transfer_setup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the Client data socket for active transfer */ -/* where the Client data socket is the TCP client. */ -/* */ -/* Find free port and listen on it, sends the PORT/EPRT command to */ -/* server, then wait for a connection from server. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_packet_allocate Allocate packet */ -/* _nx_ftp_utility_convert_IPv6_to_ascii Convert IPv6 address to ASCII */ -/* _nx_ftp_utility_convert_portnumber_ascii Convert port to ASCII */ -/* nx_packet_release Release packet */ -/* nx_tcp_free_port_find Find a free port */ -/* nx_tcp_server_socket_listen Listen for TCP data socket */ -/* connection from server */ -/* nx_tcp_server_socket_unlisten Unlisten on server socket */ -/* nx_tcp_socket_receive Receive response from server */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open Open a file for read or write */ -/* _nx_ftp_client_directory_listing_get Get directory list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_active_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -UINT status; -UINT data_port; -#ifndef NX_DISABLE_IPV4 -ULONG ip_address; -#endif /* NX_DISABLE_IPV4 */ -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -#ifdef FEATURE_NX_IPV6 -UINT ipduo_size; -#endif - - - /* Pickup the next free port for the data socket. */ - status = nx_tcp_free_port_find(ftp_client_ptr -> nx_ftp_client_ip_ptr, - ftp_client_ptr -> nx_ftp_client_data_port + 1, &data_port); - - /* Determine if the port find was successful. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Save the data port to the client record. */ - ftp_client_ptr -> nx_ftp_client_data_port = data_port; - - /* Start listening on the data port. */ - status = nx_tcp_server_socket_listen(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port, &(ftp_client_ptr -> nx_ftp_client_data_socket), 5, NX_NULL); - - /* Determine if the listen is successful. */ - if (status != NX_SUCCESS) - { - - /* Return error. */ - return(status); - } - - /* Allocate a packet for sending the PORT/EPRT command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status != NX_SUCCESS) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Return error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build the IP and port number FTP message. */ - if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { -#ifndef FEATURE_NX_IPV6 - return NX_NOT_ENABLED; -#else - CHAR ipduo_buffer[NX_FTP_IPV6_ADDRESS_BUFSIZE]; - UINT index; - - /* EPRT command: EPRT |2|1080::8:800:200C:417A|5282| - RFC2428, Section2, Page3. */ - - /* Check if out of boundary. - Max EPRT command sring: 8 ("EPRT |2|") + 39 (IPv6 address string) + 1 ('|') + 5 (Max port string) + 1 ('|') + 2 ("\r\n") = 56. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 56) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_INVALID_PACKET); - } - - buffer_ptr[0] = 'E'; - buffer_ptr[1] = 'P'; - buffer_ptr[2] = 'R'; - buffer_ptr[3] = 'T'; - buffer_ptr[4] = ' '; - buffer_ptr[5] = '|'; - buffer_ptr[6] = '2'; - buffer_ptr[7] = '|'; - - /* Convert the PORT command ipv6 address and port number format to ascii text. */ - - /* Clear our scratch buffer. */ - memset(&ipduo_buffer[0], 0, NX_FTP_IPV6_ADDRESS_BUFSIZE); - - /* Convert the IPv6 address to text. */ - status = _nx_ftp_utility_convert_IPv6_to_ascii(&(ftp_client_ptr -> nx_ftp_client_control_socket), - &ipduo_buffer[0], NX_FTP_IPV6_ADDRESS_BUFSIZE, &ipduo_size); - - /* Append to the packet buffer . */ - memcpy(buffer_ptr + 8, ipduo_buffer, ipduo_size); - - /* Update the index past the IPv6 address. */ - index = 8 + ipduo_size; - - /* Add the required space character. */ - buffer_ptr[index++] = '|'; - - /* Clear the scratch buffer again. */ - memset(&ipduo_buffer[0], 0, NX_FTP_IPV6_ADDRESS_BUFSIZE); - - /* Convert the preferred port to ascii. */ - status = _nx_ftp_utility_convert_portnumber_ascii(data_port, &ipduo_buffer[0], &ipduo_size); - - /* Append to the packet buffer. */ - memcpy(buffer_ptr + index, ipduo_buffer, ipduo_size); - - /* Update the index past the port. */ - index += ipduo_size; - - /* Add the required space character. */ - buffer_ptr[index++] = '|'; - - /* Set the CR/LF. */ - buffer_ptr[index++] = 13; - buffer_ptr[index++] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = index; -#endif /* FEATURE_NX_IPV6 */ - } - else - { - /* IPv4 FTP connection */ -#ifdef NX_DISABLE_IPV4 - return NX_NOT_ENABLED; -#else - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 30) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_INVALID_PACKET); - } - - /* Pickup the IPv4 address of this IP instance. */ - ip_address = ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address ; - - /* Now build the IP and port number FTP message. */ - buffer_ptr[0] = 'P'; - buffer_ptr[1] = 'O'; - buffer_ptr[2] = 'R'; - buffer_ptr[3] = 'T'; - buffer_ptr[4] = ' '; - - buffer_ptr[5] = (UCHAR)('0' + (ip_address >> 24)/100); - buffer_ptr[6] = (UCHAR)('0' + ((ip_address >> 24)/10)%10); - buffer_ptr[7] = (UCHAR)('0' + (ip_address >> 24)%10); - buffer_ptr[8] = ','; - - buffer_ptr[9] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)/100); - buffer_ptr[10] = (UCHAR)('0' + (((ip_address >> 16) & 0xFF)/10)%10); - buffer_ptr[11] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)%10); - buffer_ptr[12] = ','; - - buffer_ptr[13] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)/100); - buffer_ptr[14] = (UCHAR)('0' + (((ip_address >> 8) & 0xFF)/10)%10); - buffer_ptr[15] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)%10); - buffer_ptr[16] = ','; - - buffer_ptr[17] = (UCHAR)('0' + (ip_address & 0xFF)/100); - buffer_ptr[18] = (UCHAR)('0' + ((ip_address & 0xFF)/10)%10); - buffer_ptr[19] = (UCHAR)('0' + (ip_address & 0xFF)%10); - buffer_ptr[20] = ','; - - buffer_ptr[21] = (UCHAR)('0' + (data_port >> 8)/100); - buffer_ptr[22] = (UCHAR)('0' + ((data_port >> 8)/10)%10); - buffer_ptr[23] = (UCHAR)('0' + ((data_port >> 8)%10)); - buffer_ptr[24] = ','; - - buffer_ptr[25] = (UCHAR)('0' + (data_port & 255)/100); - buffer_ptr[26] = (UCHAR)('0' + ((data_port & 255)/10)%10); - buffer_ptr[27] = (UCHAR)('0' + ((data_port & 255)%10)); - - /* Set the CR/LF. */ - buffer_ptr[28] = 13; - buffer_ptr[29] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 30; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the PORT/EPRT message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status != NX_SUCCESS) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Unable to open file with FTP server. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the IP/port was received properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2')) - { - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, data_port); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_passive_transfer_setup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the Client data socket for passive transfer */ -/* where the Client data socket is the TCP client. */ -/* */ -/* It sends the PASV command and if the server sends an OK status, it */ -/* extracts the server connection info from the server response and */ -/* opens a connection on the data socket. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_client_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_client_socket_bind Bind the data socket to a port*/ -/* nxd_tcp_client_socket_connect Connect to server data socket */ -/* nx_tcp_socket_receive Receive response from server */ -/* nx_tcp_socket_send Send request to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open Open a file for read or write */ -/* _nx_ftp_client_directory_listing_get Get directory list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_passive_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT status; -UINT i; -UINT data_port; -#ifndef NX_DISABLE_IPV4 -UINT commas = 0; -ULONG ip_address = 0; -ULONG temp = 0; -#endif /* NX_DISABLE_IPV4 */ - - - /* Send the PASV command to switch to passive mode. */ - - /* Allocate a packet for sending the TYPE command. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, wait_option); - - /* Determine if the packet allocation was successful. */ - if (status != NX_SUCCESS) - { - - /* Return error. */ - return(status); - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < 6) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Set the error status. */ - return(NX_FTP_FAILED); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { -#ifndef FEATURE_NX_IPV6 - return(NX_NOT_ENABLED); -#else - - /* Now build "EPSV" message. RFC2428. */ - buffer_ptr[0] = 'E'; - buffer_ptr[1] = 'P'; - buffer_ptr[2] = 'S'; - buffer_ptr[3] = 'V'; -#endif /* FEATURE_NX_IPV6 */ - } - else - { -#ifdef NX_DISABLE_IPV4 - return(NX_NOT_ENABLED); -#else - - /* Now build "PASV" message . */ - buffer_ptr[0] = 'P'; - buffer_ptr[1] = 'A'; - buffer_ptr[2] = 'S'; - buffer_ptr[3] = 'V'; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Set the CR/LF. */ - buffer_ptr[4] = 13; - buffer_ptr[5] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 6; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the PASV or EPSV message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Wait for response from the FTP server. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status != NX_SUCCESS) - { - - /* Unable to open file with FTP server. */ - return(status); - } - - /* Setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - if (ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { -#ifndef FEATURE_NX_IPV6 - return(NX_NOT_ENABLED); -#else - - /* EPSV command, RFC2428. */ - - /* Check for 2xx message, signaling the "EPSV" was received properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2') || (buffer_ptr[2] != '9')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* The text returned in response to the EPSV command MUST be: - \ - () */ - - /* The netowrk address used to establish the data connnection will be the same - network address used for the control connection. - An example response string follows: - Entering Extended Passive Mode (|||6446|) */ - - /* Check the length. command + + passive key word "(|||"*/ - if (packet_ptr -> nx_packet_length < 8) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_INVALID_COMMAND); - } - - /* Set the index. */ - i = 7; - - /* Skip the text to locate the key word "(|||". */ - while (i < packet_ptr -> nx_packet_length) - { - - /* Check if match the key word. */ - if ((buffer_ptr[i - 3] == '(') && - (buffer_ptr[i - 2] == '|') && - (buffer_ptr[i - 1] == '|') && - (buffer_ptr[i] == '|')) - { - break; - } - - /* Move to next character. */ - i++; - } - - /* Check for properly formated address command from server. */ - if (i >= packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_INVALID_COMMAND); - } - - /* Update the index to pickup the port number. */ - data_port = 0; - i++; - while ((i < packet_ptr -> nx_packet_length) && (buffer_ptr[i] != '|')) - { - - /* Is a numeric character present? */ - if ((buffer_ptr[i] < '0') || (buffer_ptr[i] > '9')) - { - - /* Invalid port number. */ - break; - } - - /* Yes, numeric character is present. Update the IP port. */ - data_port = (data_port * 10) + (UINT) (buffer_ptr[i] - '0'); - - /* Move to next character. */ - i++; - } - - /* At this point we are done with the packet. */ - nx_packet_release(packet_ptr); - - /* Determine if an error occurred. */ - if ((buffer_ptr[i] != '|') || (data_port == 0)) - { - - /* Set the error status. */ - return(NX_FTP_INVALID_COMMAND); - } - - /* Save the passive IP address and data port. */ - COPY_NXD_ADDRESS(&(ftp_client_ptr -> nx_ftp_client_control_socket.nx_tcp_socket_connect_ip), &(ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip)); - ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_port = data_port; -#endif /* FEATURE_NX_IPV6 */ - } - else - { -#ifdef NX_DISABLE_IPV4 - return(NX_NOT_ENABLED); -#else - - /* Check for 2xx message, signaling the "PASV" was received properly. */ - if ((packet_ptr -> nx_packet_length < 3) || (buffer_ptr[0] != '2') || (buffer_ptr[1] != '2') || (buffer_ptr[2] != '7')) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Now parse the address and port for the Client to connect to on the data socket. - IP address and port are comma delimited and port number is the last two numbers, - PASV port = (p1 * 256) + p2. */ - - /* Skip non numeric text and whitespace. */ - i = 3; - while (((buffer_ptr[i] > '9') || (buffer_ptr[i] < '0')) && (i < packet_ptr -> nx_packet_length)) - { - i++; - } - - /* Check for properly formated command from server. */ - if (i >= packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return NX_FTP_INVALID_COMMAND; - } - - /* First, pickup the IP address. */ - commas = 0; - ip_address = 0; - temp = 0; - status = NX_SUCCESS; - - while (i < packet_ptr -> nx_packet_length) - { - - /* Is a numeric character present? */ - if ((buffer_ptr[i] >= '0') && (buffer_ptr[i] <= '9')) - { - - /* Yes, numeric character is present. Update the IP address. */ - temp = (temp*10) + (ULONG) (buffer_ptr[i] - '0'); - } - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[i] == 0x0D) || (buffer_ptr[i] == 0x0A) || (buffer_ptr[i] == 0)) - { - status = NX_FTP_INVALID_COMMAND; - break; - } - - /* Determine if a comma is present. */ - if (buffer_ptr[i] == ',') - { - - /* Increment the comma count. */ - commas++; - - /* Setup next byte of IP address. */ - ip_address = (ip_address << 8) & 0xFFFFFFFF; - ip_address = ip_address | (temp & 0xFF); - temp = 0; - - /* Have we finished with the IP address? */ - if (commas == 4) - { - - /* Finished with IP address. */ - i++; - break; - } - } - - /* Move to next character. */ - i++; - } - - /* Now pickup the port number. */ - data_port = 0; - temp = 0; - while (i < packet_ptr -> nx_packet_length) - { - - /* Is a numeric character present? */ - if ((buffer_ptr[i] >= '0') && (buffer_ptr[i] <= '9')) - { - - /* Yes, numeric character is present. Update the IP port. */ - temp = (temp*10) + (UINT) (buffer_ptr[i] - '0'); - } - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[i] == 0x0D) || (buffer_ptr[i] == 0x0A) || (buffer_ptr[i] == 0)) - { - /* Good condition on the port number! */ - break; - } - - /* Determine if a comma is present. */ - if (buffer_ptr[i] == ',') - { - - /* Increment the comma count. */ - commas++; - - /* Move the data port number up. */ - data_port = (data_port << 8) & 0xFFFFFFFF; - data_port = data_port | (temp & 0xFF); - temp = 0; - - /* Have we finished with the port? */ - if (commas >= 6) - { - - /* Error, get out of the loop. */ - status = NX_FTP_INVALID_ADDRESS; - break; - } - } - - /* Move to next character. */ - i++; - } - - /* Move port number up. */ - data_port = (data_port << 8) & 0xFFFFFFFF; - data_port = data_port | (temp & 0xFF); - - /* At this point we are done with the packet. */ - nx_packet_release(packet_ptr); - - /* Determine if an error occurred. */ - if ((status != NX_SUCCESS) || (buffer_ptr[i] != 13) || (commas != 5) || (ip_address == 0) || (data_port == 0)) - { - - /* Set the error status. */ - return NX_FTP_INVALID_COMMAND; - } - - /* Save the passive IP address and data port. */ - ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4; - ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4 = ip_address; - ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_port = data_port; - -#endif /* NX_DISABLE_IPV4 */ - } - - /* Bind the client data socket to any port. */ - status = nx_tcp_client_socket_bind((&ftp_client_ptr -> nx_ftp_client_data_socket), NX_ANY_PORT, wait_option); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Unable to bind socket to port. */ - return(status); - } - - /* Now connect to the IP address and port the server asked us to. */ - status = nxd_tcp_client_socket_connect(&(ftp_client_ptr -> nx_ftp_client_data_socket), - &(ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_ip), - data_port, wait_option); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_data_socket)); - } - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_data_socket_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function cleans up the data socket. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_disconnect Disconnect a socket */ -/* nx_tcp_client_socket_unbind Release the data socket port */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_server_socket_unlisten Unlisten on server socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open Open a file for read or write */ -/* _nx_ftp_client_file_close Actual client file close call */ -/* _nx_ftp_client_directory_listing_get Get directory list */ -/* _nx_ftp_client_directory_listing_continue */ -/* Continue to get directory list*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_client_data_socket_cleanup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - - - /* Disconnect the data socket. */ - nx_tcp_socket_disconnect(&(ftp_client_ptr -> nx_ftp_client_data_socket), wait_option); - - /* Check if enable passive mode. */ - if (ftp_client_ptr -> nx_ftp_client_passive_transfer_enabled == NX_FALSE) - { - - /* Unaccept the data socket. */ - nx_tcp_server_socket_unaccept(&(ftp_client_ptr -> nx_ftp_client_data_socket)); - - /* Stop listening on the data port. */ - nx_tcp_server_socket_unlisten(ftp_client_ptr -> nx_ftp_client_ip_ptr, - ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_port); - } - else - { - - /* Release the socket port. */ - nx_tcp_client_socket_unbind(&(ftp_client_ptr -> nx_ftp_client_data_socket)); - } - - /* Clear the block size. */ - ftp_client_ptr -> nx_ftp_client_block_total_size = 0; - ftp_client_ptr -> nx_ftp_client_block_remaining_size = 0; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_block_mode_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends MODE B command to FTP server for block mode. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_open Open a file for read or write */ -/* _nx_ftp_client_directory_listing_get Get directory list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_block_mode_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option) -{ - -UINT status; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; - - - /* Send MODE B command. */ - - /* Allocate the packet. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, NX_NO_WAIT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build the actual MODE B request. */ - buffer_ptr[0] = 'M'; - buffer_ptr[1] = 'O'; - buffer_ptr[2] = 'D'; - buffer_ptr[3] = 'E'; - buffer_ptr[4] = ' '; - buffer_ptr[5] = 'B'; - - /* Insert the CR/LF. */ - buffer_ptr[6] = 13; - buffer_ptr[7] = 10; - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = 8; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the MODE B message. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_control_socket), packet_ptr, wait_option); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error. */ - return(status); - } - - /* Now wait for response from the FTP server control port. */ - status = nx_tcp_socket_receive(&(ftp_client_ptr -> nx_ftp_client_control_socket), &packet_ptr, wait_option); - - /* Determine if a packet was not received. */ - if (status != NX_SUCCESS) - { - - /* Unable to open file with FTP server. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for 2xx message, signaling the data port was connected properly and ready for transfer. */ - if (buffer_ptr[0] != '2') - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Unable to open file with FTP server. */ - return(NX_FTP_EXPECTED_2XX_CODE); - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_block_header_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the block header for block mode. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* block_size The size of block data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_size_set Set the file size for writing */ -/* _nx_ftp_client_file_write Send data packet to server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_block_header_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG block_size) -{ - -UINT status; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; - - - /* Use block mode to transfer data. RFC959, Section3.4.2, Page21-22. */ - - /* Allocate the packet. */ - status = _nx_ftp_client_packet_allocate(ftp_client_ptr, &packet_ptr, NX_NO_WAIT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Set the block header. */ - if (block_size) - { - - /* Descriptor. */ - buffer_ptr[0] = 0; - - /* Byte count. */ - buffer_ptr[1] = (UCHAR)(block_size >> 8); - buffer_ptr[2] = (UCHAR)(block_size); - } - else - { - - /* Descriptor. */ - buffer_ptr[0] = 64; - - /* Byte count. */ - buffer_ptr[1] = 0; - buffer_ptr[2] = 0; - } - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = 3; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Write packet payload to the file. */ - status = nx_tcp_socket_send(&(ftp_client_ptr -> nx_ftp_client_data_socket), packet_ptr, NX_NO_WAIT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Return success to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_client_block_header_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the block header for block mode. */ -/* */ -/* INPUT */ -/* */ -/* ftp_client_ptr Pointer to FTP client */ -/* packet_ptr Pointer to packet to write */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_client_file_read Read data from server */ -/* _nx_ftp_client_directory_listing_get Get directory list */ -/* _nx_ftp_client_directory_listing_continue */ -/* Continue to get directory list*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_client_block_header_retrieve(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr) -{ - -ULONG delta; -UCHAR *buffer_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN -NX_PACKET *before_last_packet; -NX_PACKET *last_packet; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - - /* Check if it is the first packet. */ - if (ftp_client_ptr -> nx_ftp_client_block_total_size == 0) - { - - /* Check the packet length. */ - if ((packet_ptr -> nx_packet_length < 3) || - (packet_ptr -> nx_packet_prepend_ptr + 3 > packet_ptr -> nx_packet_append_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_CLIENT_INVALID_SIZE); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Process block header. */ - ftp_client_ptr -> nx_ftp_client_block_total_size = (ULONG)((buffer_ptr[1] << 8) | buffer_ptr[2]); - ftp_client_ptr -> nx_ftp_client_block_remaining_size = ftp_client_ptr -> nx_ftp_client_block_total_size; - - /* Skip the block header. */ - packet_ptr -> nx_packet_prepend_ptr += 3; - packet_ptr -> nx_packet_length -= 3; - } - - /* Check if have remaining data. */ - if (ftp_client_ptr -> nx_ftp_client_block_remaining_size == 0) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_CLIENT_END_OF_BLOCK); - } - - /* Check the data of current packet. */ - if (ftp_client_ptr -> nx_ftp_client_block_remaining_size < packet_ptr -> nx_packet_length) - { - - /* Remove the extra data, such as: end block header. */ - - /* Calculate the difference in the length. */ - delta = packet_ptr -> nx_packet_length - ftp_client_ptr -> nx_ftp_client_block_remaining_size; - - /* Adjust the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta; - - /* Adjust the append pointer. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Loop to process adjustment that spans multiple packets. */ - while (delta) - { - - /* Determine if the packet is chained (or still chained after the adjustment). */ - if (packet_ptr -> nx_packet_last == NX_NULL) - { - - /* No, packet is not chained, simply adjust the append pointer in the packet. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; - - /* Break out of the loop, since the adjustment is complete. */ - break; - } - - /* Pickup the pointer to the last packet. */ - last_packet = packet_ptr -> nx_packet_last; - - /* Determine if the amount to adjust is less than the payload in the last packet. */ - /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ - if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta) - { - - /* Yes, simply adjust the append pointer of the last packet in the chain. */ - /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ - last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta; - - /* Get out of the loop, since the adjustment is complete. */ - break; - } - else - { - - /* Adjust the delta by the amount in the last packet. */ - delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)); - - /* Find the packet before the last packet. */ - before_last_packet = packet_ptr; - while (before_last_packet -> nx_packet_next != last_packet) - { - - /* Move to the next packet in the chain. */ - before_last_packet = before_last_packet -> nx_packet_next; - } - - /* At this point, we need to release the last packet and adjust the other packet - pointers. */ - - /* Ensure the next packet pointer is NULL in what is now the last packet. */ - before_last_packet -> nx_packet_next = NX_NULL; - - /* Determine if the packet is still chained. */ - if (packet_ptr != before_last_packet) - { - - /* Yes, the packet is still chained, setup the last packet pointer. */ - packet_ptr -> nx_packet_last = before_last_packet; - } - else - { - - /* The packet is no longer chained, set the last packet pointer to NULL. */ - packet_ptr -> nx_packet_last = NX_NULL; - } - - /* Release the last packet. */ - _nx_packet_release(last_packet); - } - } -#else - - /* Simply adjust the append pointer in the packet. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Update the file size. */ - ftp_client_ptr -> nx_ftp_client_block_remaining_size -= packet_ptr -> nx_packet_length; - - /* Return success to caller. */ - return(NX_SUCCESS); -} diff --git a/protocol_handlers/ftp/nxd_ftp_client.h b/protocol_handlers/ftp/nxd_ftp_client.h deleted file mode 100644 index c79b8e18..00000000 --- a/protocol_handlers/ftp/nxd_ftp_client.h +++ /dev/null @@ -1,373 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** File Transfer Protocol (FTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_ftp_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Duo File Transfer Protocol (FTP over */ -/* IPv6) component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_FTP_CLIENT_H -#define NXD_FTP_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -/* Define the FTP Client ID. */ - - -#define NXD_FTP_CLIENT_ID 0x46545200UL - - -/* Define the maximum number of clients the FTP Server can accommodate. */ - -#ifndef NX_FTP_MAX_CLIENTS -#define NX_FTP_MAX_CLIENTS 4 -#endif - - -/* Define FTP TCP socket create options. Normally any TCP port will do but this - gives the application a means to specify a source port. */ - -#ifndef NX_FTP_CLIENT_SOURCE_PORT -#define NX_FTP_CLIENT_SOURCE_PORT NX_ANY_PORT -#endif - -#ifndef NX_FTP_CONTROL_TOS -#define NX_FTP_CONTROL_TOS NX_IP_NORMAL -#endif - -#ifndef NX_FTP_DATA_TOS -#define NX_FTP_DATA_TOS NX_IP_NORMAL -#endif - -#ifndef NX_FTP_FRAGMENT_OPTION -#define NX_FTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_FTP_CONTROL_WINDOW_SIZE -#define NX_FTP_CONTROL_WINDOW_SIZE 400 -#endif - -#ifndef NX_FTP_DATA_WINDOW_SIZE -#define NX_FTP_DATA_WINDOW_SIZE 2048 -#endif - - -#ifndef NX_FTP_TIME_TO_LIVE -#define NX_FTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_FTP_USERNAME_SIZE -#define NX_FTP_USERNAME_SIZE 20 -#endif - -#ifndef NX_FTP_PASSWORD_SIZE -#define NX_FTP_PASSWORD_SIZE 20 -#endif - -#ifndef NX_FTP_TIMEOUT_PERIOD -#define NX_FTP_TIMEOUT_PERIOD 60 /* Number of seconds to check */ -#endif - - - -/* Define open types. */ - -#define NX_FTP_OPEN_FOR_READ 0x01 /* FTP file open for reading */ -#define NX_FTP_OPEN_FOR_WRITE 0x02 /* FTP file open for writing */ - - -/* Define transfer modes. Note: just support stream mode and block mode yet. */ - -#define NX_FTP_TRANSFER_MODE_STREAM 0 /* FTP stream transmission mode */ -#define NX_FTP_TRANSFER_MODE_BLOCK 1 /* FTP block transmission mode */ -#define NX_FTP_TRANSFER_MODE_COMPRESSED 2 /* FTP compressed transmission mode */ - - -/* Define return code constants. */ - -#define NX_FTP_ERROR 0xD0 /* Generic FTP internal error - deprecated */ -#define NX_FTP_TIMEOUT 0xD1 /* FTP timeout occurred */ -#define NX_FTP_FAILED 0xD2 /* FTP error */ -#define NX_FTP_NOT_CONNECTED 0xD3 /* FTP not connected error */ -#define NX_FTP_NOT_DISCONNECTED 0xD4 /* FTP not disconnected error */ -#define NX_FTP_NOT_OPEN 0xD5 /* FTP not opened error */ -#define NX_FTP_NOT_CLOSED 0xD6 /* FTP not closed error */ -#define NX_FTP_END_OF_FILE 0xD7 /* FTP end of file status */ -#define NX_FTP_END_OF_LISTING 0xD8 /* FTP end of directory listing status */ -#define NX_FTP_EXPECTED_1XX_CODE 0xD9 /* Expected a 1xx response from server */ -#define NX_FTP_EXPECTED_2XX_CODE 0xDA /* Expected a 2xx response from server */ -#define NX_FTP_EXPECTED_22X_CODE 0xDB /* Expected a 22x response from server */ -#define NX_FTP_EXPECTED_23X_CODE 0xDC /* Expected a 23x response from server */ -#define NX_FTP_EXPECTED_3XX_CODE 0xDD /* Expected a 3xx response from server */ -#define NX_FTP_EXPECTED_33X_CODE 0xDE /* Expected a 33x response from server */ -#define NX_FTP_INVALID_NUMBER 0xDF /* Extraced an invalid number from server response */ -#define NX_FTP_INVALID_ADDRESS 0x1D0 /* Invalid IP address parsed from FTP command */ -#define NX_FTP_INVALID_COMMAND 0x1D1 /* Invalid FTP command (bad syntax, unknown command) */ -#define NX_FTP_CLIENT_INVALID_SIZE 0x1D2 /* Invalid FTP file size */ -#define NX_FTP_CLIENT_FILE_SIZE_ALREADY_SET 0x1D3 /* The file size is already set */ -#define NX_FTP_CLIENT_NOT_BLOCK_MODE 0x1D4 /* Block mode is not enabled */ -#define NX_FTP_CLIENT_END_OF_BLOCK 0x1D5 /* FTP end of block */ - - -/* Define FTP connection states. */ - -#define NX_FTP_STATE_NOT_CONNECTED 1 /* FTP not connected */ -#define NX_FTP_STATE_CONNECTED 2 /* FTP connected */ -#define NX_FTP_STATE_OPEN 3 /* FTP file open for reading */ -#define NX_FTP_STATE_WRITE_OPEN 4 /* FTP file open for writing */ - - -/* Define the FTP Server TCP port numbers. */ - -#define NX_FTP_SERVER_CONTROL_PORT 21 /* Control Port for FTP server */ -#define NX_FTP_SERVER_DATA_PORT 20 /* Data Port for FTP server in active transfer mode */ - -/* Define the size for buffer to store an IPv6 address represented in ASCII. */ -#define NX_FTP_IPV6_ADDRESS_BUFSIZE 60 - -/* Define the FTP basic commands. The ASCII command will be parsed and converted to the numerical - representation shown below. */ - -#define NX_FTP_NOOP 0 -#define NX_FTP_USER 1 -#define NX_FTP_PASS 2 -#define NX_FTP_QUIT 3 -#define NX_FTP_RETR 4 -#define NX_FTP_STOR 5 -#define NX_FTP_RNFR 6 -#define NX_FTP_RNTO 7 -#define NX_FTP_DELE 8 -#define NX_FTP_RMD 9 -#define NX_FTP_MKD 10 -#define NX_FTP_NLST 11 -#define NX_FTP_PORT 12 -#define NX_FTP_CWD 13 -#define NX_FTP_PWD 14 -#define NX_FTP_TYPE 15 -#define NX_FTP_LIST 16 -#define NX_FTP_CDUP 17 -#define NX_FTP_INVALID 18 -#define NX_FTP_EPRT 19 -#define NX_FTP_PASV 20 -#define NX_FTP_EPSV 21 -#define NX_FTP_MODE 22 - - - -/* Define the basic FTP Client data structure. */ - -typedef struct NX_FTP_CLIENT_STRUCT -{ - ULONG nx_ftp_client_id; /* FTP Client ID */ - CHAR *nx_ftp_client_name; /* Name of this FTP client */ - NX_IP *nx_ftp_client_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_ftp_client_packet_pool_ptr; /* Pointer to FTP client packet pool */ - ULONG nx_ftp_client_server_ip; /* Server's IP address */ - UINT nx_ftp_client_state; /* State of FTP client */ - NX_TCP_SOCKET nx_ftp_client_control_socket; /* Client FTP control socket */ - NX_TCP_SOCKET nx_ftp_client_data_socket; /* Client FTP data transfer socket */ - UINT nx_ftp_client_data_port; /* Port the Client data socket binds */ - UINT nx_ftp_client_passive_transfer_enabled; /* Client enabled for passive transfer */ - UINT nx_ftp_client_transfer_mode; /* Client transfer mode */ - ULONG nx_ftp_client_block_total_size; /* Total size of data in block mode */ - ULONG nx_ftp_client_block_remaining_size; /* Remaining size of data in block mode*/ -} NX_FTP_CLIENT; - - -#ifndef NX_FTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_ftp_client_connect _nx_ftp_client_connect -#define nxd_ftp_client_connect _nxd_ftp_client_connect -#define nx_ftp_client_create _nx_ftp_client_create -#define nx_ftp_client_delete _nx_ftp_client_delete -#define nx_ftp_client_directory_create _nx_ftp_client_directory_create -#define nx_ftp_client_directory_default_set _nx_ftp_client_directory_default_set -#define nx_ftp_client_directory_delete _nx_ftp_client_directory_delete -#define nx_ftp_client_directory_listing_get _nx_ftp_client_directory_listing_get -#define nx_ftp_client_directory_listing_continue _nx_ftp_client_directory_listing_continue -#define nx_ftp_client_disconnect _nx_ftp_client_disconnect -#define nx_ftp_client_file_close _nx_ftp_client_file_close -#define nx_ftp_client_file_delete _nx_ftp_client_file_delete -#define nx_ftp_client_file_open _nx_ftp_client_file_open -#define nx_ftp_client_file_read _nx_ftp_client_file_read -#define nx_ftp_client_file_rename _nx_ftp_client_file_rename -#define nx_ftp_client_file_write _nx_ftp_client_file_write -#define nx_ftp_client_file_size_set _nx_ftp_client_file_size_set -#define nx_ftp_client_passive_mode_set _nx_ftp_client_passive_mode_set -#define nx_ftp_client_transfer_mode_set _nx_ftp_client_transfer_mode_set - -#else - -/* Services with error checking. */ - -#define nx_ftp_client_connect _nxe_ftp_client_connect -#define nxd_ftp_client_connect _nxde_ftp_client_connect -#define nx_ftp_client_create _nxe_ftp_client_create -#define nx_ftp_client_delete _nxe_ftp_client_delete -#define nx_ftp_client_directory_create _nxe_ftp_client_directory_create -#define nx_ftp_client_directory_default_set _nxe_ftp_client_directory_default_set -#define nx_ftp_client_directory_delete _nxe_ftp_client_directory_delete -#define nx_ftp_client_directory_listing_get _nxe_ftp_client_directory_listing_get -#define nx_ftp_client_directory_listing_continue _nxe_ftp_client_directory_listing_continue -#define nx_ftp_client_disconnect _nxe_ftp_client_disconnect -#define nx_ftp_client_file_close _nxe_ftp_client_file_close -#define nx_ftp_client_file_delete _nxe_ftp_client_file_delete -#define nx_ftp_client_file_open _nxe_ftp_client_file_open -#define nx_ftp_client_file_read _nxe_ftp_client_file_read -#define nx_ftp_client_file_rename _nxe_ftp_client_file_rename -#define nx_ftp_client_file_write _nxe_ftp_client_file_write -#define nx_ftp_client_file_size_set _nxe_ftp_client_file_size_set -#define nx_ftp_client_passive_mode_set _nxe_ftp_client_passive_mode_set -#define nx_ftp_client_transfer_mode_set _nxe_ftp_client_transfer_mode_set - -#endif - -/* Define the prototypes accessible to the application software. */ - -UINT nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); -UINT nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); -UINT nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); -UINT nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); -UINT nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); -UINT nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); -UINT nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); -UINT nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); -UINT nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); -UINT nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); -UINT nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); - -#else - -/* FTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxde_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxd_ftp_client_connect(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ipduo, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxe_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); -UINT _nx_ftp_client_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *ftp_client_name, NX_IP *ip_ptr, ULONG window_size, NX_PACKET_POOL *pool_ptr); -UINT _nxe_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); -UINT _nx_ftp_client_delete(NX_FTP_CLIENT *ftp_client_ptr); -UINT _nxe_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT _nx_ftp_client_directory_create(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT _nxe_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); -UINT _nx_ftp_client_directory_default_set(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, ULONG wait_option); -UINT _nxe_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT _nx_ftp_client_directory_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_name, ULONG wait_option); -UINT _nxe_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_ftp_client_directory_listing_get(NX_FTP_CLIENT *ftp_client_ptr, CHAR *directory_path, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_ftp_client_directory_listing_continue(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nx_ftp_client_disconnect(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nxe_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nx_ftp_client_file_close(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nxe_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); -UINT _nx_ftp_client_file_delete(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, ULONG wait_option); -UINT _nxe_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); -UINT _nx_ftp_client_file_open(NX_FTP_CLIENT *ftp_client_ptr, CHAR *file_name, UINT open_type, ULONG wait_option); -UINT _nxe_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_ftp_client_file_read(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_ftp_client_file_rename(NX_FTP_CLIENT *ftp_client_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); -UINT _nx_ftp_client_file_rename(NX_FTP_CLIENT *ftp_ptr, CHAR *filename, CHAR *new_filename, ULONG wait_option); -UINT _nxe_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_ftp_client_file_write(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nxe_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); -UINT _nx_ftp_client_file_size_set(NX_FTP_CLIENT *ftp_client_ptr, ULONG file_size); -UINT _nxe_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); -UINT _nx_ftp_client_passive_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT passive_mode_enabled); -UINT _nxe_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); -UINT _nx_ftp_client_transfer_mode_set(NX_FTP_CLIENT *ftp_client_ptr, UINT transfer_mode); - -#endif /* NX_FTP_SOURCE_CODE */ - -/* Internal functions. */ -VOID _nx_ftp_client_data_disconnect(NX_TCP_SOCKET *data_socket_ptr); -UINT _nx_ftp_client_packet_allocate(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_ftp_client_active_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nx_ftp_client_passive_transfer_setup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -VOID _nx_ftp_client_data_socket_cleanup(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nx_ftp_client_block_mode_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG wait_option); -UINT _nx_ftp_client_block_header_send(NX_FTP_CLIENT *ftp_client_ptr, ULONG block_size); -UINT _nx_ftp_client_block_header_retrieve(NX_FTP_CLIENT *ftp_client_ptr, NX_PACKET *packet_ptr); -UINT _nx_ftp_client_connect_internal(NX_FTP_CLIENT *ftp_client_ptr, NXD_ADDRESS *server_ip, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_ftp_utility_convert_IPv6_to_ascii(NX_TCP_SOCKET *tcp_socket_ptr, CHAR *buffer, UINT buffer_length, UINT *size); -UINT _nx_ftp_utility_convert_number_ascii(ULONG number, CHAR *numstring); -UINT _nx_ftp_utility_convert_portnumber_ascii(UINT number, CHAR *numstring, UINT *numstring_length); - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_FTP_CLIENT_H */ diff --git a/protocol_handlers/ftp/nxd_ftp_server.c b/protocol_handlers/ftp/nxd_ftp_server.c deleted file mode 100644 index 0eb1f635..00000000 --- a/protocol_handlers/ftp/nxd_ftp_server.c +++ /dev/null @@ -1,6684 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** File Transfer Protocol */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_FTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* If FileX is not used in this application, define this option and define the FileX services - declared in filex_stub.h elsewhere. -#define NX_FTP_NO_FILEX -*/ - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_ftp_server.h" -#include "stdio.h" -#include "string.h" - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/* Define FTP Error codes. */ - -#define NX_FTP_CODE_RESTART_MARKER "110" /* Restart marker reply. - In this case, the text is exact and not left to the - particular implementation; it must read: - MARK yyyy = mmmm - Where yyyy is User-process data stream marker, and mmmm - server's equivalent marker (note the spaces between markers - and "="). */ -#define NX_FTP_CODE_READY_NNN "120" /* Service ready in nnn minutes. */ -#define NX_FTP_CODE_START_XFER "125" /* Data connection already open; transfer starting. */ -#define NX_FTP_CODE_OPENING "150" /* File status okay; about to open data connection. */ -#define NX_FTP_CODE_CMD_OK "200" /* Command okay. */ -#define NX_FTP_CODE_CONNECTION_OK "220" /* Connection okay. */ -#define NX_FTP_CODE_CLOSE "221" /* Service closing control connection. */ -#define NX_FTP_CODE_LOGOFF "226" /* Closing data connection. */ -#define NX_FTP_CODE_LOGIN "230" /* User logged in, proceed. */ -#define NX_FTP_CODE_COMPLETED "250" /* Requested file action okay, completed. */ -#define NX_FTP_CODE_MADE_DIR "257" /* PATHNAME created. */ -#define NX_FTP_CODE_USER_OK "331" /* User name okay, need password. */ -#define NX_FTP_CODE_NEED_ACCT "332" /* Need account for login. */ -#define NX_FTP_CODE_FILE_PEND "350" /* Requested file action pending further information. */ -#define NX_FTP_CODE_CMD_FAIL "501" /* Syntax error in parameters or arguments. */ -#define NX_FTP_CODE_NOT_IMPLEMENTED "502" /* Command not implemented. */ -#define NX_FTP_CODE_UNAUTHORIZED "530" /* Not logged in. */ -#define NX_FTP_CODE_NO_ACCT "532" /* Need account for storing files. */ -#define NX_FTP_CODE_BAD_TYPE "504" /* Invalid TYPE. */ -#define NX_FTP_CODE_BAD_FILE "550" /* Requested action not taken. File unavailable (e.g., file not found, no access). */ -#define NX_FTP_CODE_BAD_PAGE_TYPE "551" /* Requested action aborted: page type unknown. */ -#define NX_FTP_CODE_NO_SPACE "552" /* Requested file action aborted, no space. */ -#define NX_FTP_CODE_BAD_NAME "553" /* Requested action not taken, File name not allowed. */ - -static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number); - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* ftp_server_name Name of FTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* ftp_login Pointer to user's login */ -/* function */ -/* ftp_logout Pointer to user's logout */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (ftp_server_ptr == NX_NULL) || (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) || - (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server create function. */ - status = _nx_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(ftp_server_ptr); - NX_PARAMETER_NOT_USED(ftp_server_name); - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(media_ptr); - NX_PARAMETER_NOT_USED(stack_ptr); - NX_PARAMETER_NOT_USED(stack_size); - NX_PARAMETER_NOT_USED(pool_ptr); - NX_PARAMETER_NOT_USED(ftp_login); - NX_PARAMETER_NOT_USED(ftp_logout); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an FTP server on the specified IP. */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* ftp_server_name Name of FTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* ftp_login Pointer to user's login */ -/* function */ -/* ftp_logout Pointer to user's logout */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_create_internal Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Call actual server create function but set the ftp login and logout arguments to NULL. */ - status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, NX_NULL, NX_NULL); - - /* Set the FTP server to accept login functions having IPv4 address arguments. */ - ftp_server_ptr -> nx_ftp_login_ipv4 = ftp_login_ipv4; - ftp_server_ptr -> nx_ftp_logout_ipv4 = ftp_logout_ipv4; - - /* Return status. */ - return status; -#else - NX_PARAMETER_NOT_USED(ftp_server_ptr); - NX_PARAMETER_NOT_USED(ftp_server_name); - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(media_ptr); - NX_PARAMETER_NOT_USED(stack_ptr); - NX_PARAMETER_NOT_USED(stack_size); - NX_PARAMETER_NOT_USED(pool_ptr); - NX_PARAMETER_NOT_USED(ftp_login_ipv4); - NX_PARAMETER_NOT_USED(ftp_logout_ipv4); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_ftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP duo (IPv4 and IPv6) */ -/* server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* ftp_server_name Name of FTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* ftp_login Pointer to user's login */ -/* function */ -/* ftp_logout Pointer to user's logout */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_ftp_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id == NXD_FTP_SERVER_ID) || - (ftp_logout == NX_NULL) || (ftp_login == NX_NULL) || - (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server create function. */ - status = _nxd_ftp_server_create(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_ftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a "duo" FTP server on the specified IP for */ -/* IPv4 or IPv6 networks. */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* ftp_server_name Name of FTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* ftp_login Pointer to user's login */ -/* function */ -/* ftp_logout Pointer to user's logout */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_create_internal Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) -{ - - -UINT status; - - - /* Call actual server create function. */ - status = _nx_ftp_server_create_internal(ftp_server_ptr, ftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, ftp_login, ftp_logout); - - /* Return status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_create_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a FTP server on the specified IP. */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* ftp_server_name Name of FTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* ftp_login Pointer to user's login */ -/* function */ -/* ftp_logout Pointer to user's logout */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_FTP_INSUFFICIENT_PACKET_PAYLOAD Packet payload too small */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create control sockets */ -/* nx_tcp_socket_delete Delete control sockets */ -/* nx_tcp_socket_receive_notify Register receive notify */ -/* callback */ -/* tx_event_flags_create Create event flags */ -/* tx_event_flags_delete Delete event flags */ -/* tx_thread_create Create FTP server thread */ -/* tx_thread_delete Delete FTP server thread */ -/* tx_timer_create Create FTP server timer */ -/* tx_timer_delete Delete FTP server timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_create_internal(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)) -{ - -UINT i; -UINT status; - - - /* Clear the FTP server structure. */ - memset((void *) ftp_server_ptr, 0, sizeof(NX_FTP_SERVER)); - - /* Check the supplied packet pool for minimum required payload length (NX_FTP_SERVER_MIN_PACKET_PAYLOAD). This configurable - option is explained in more detail in the header file. */ - if (pool_ptr -> nx_packet_pool_payload_size < NX_FTP_SERVER_MIN_PACKET_PAYLOAD) - { - - return NX_FTP_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Save the packet pool pointer. */ - ftp_server_ptr -> nx_ftp_server_packet_pool_ptr = pool_ptr; - - /* Create the FTP Server thread. */ - status = tx_thread_create(&(ftp_server_ptr -> nx_ftp_server_thread), "FTP Server Thread", _nx_ftp_server_thread_entry, - (ULONG) ftp_server_ptr, stack_ptr, stack_size, NX_FTP_SERVER_PRIORITY, NX_FTP_SERVER_PRIORITY, - NX_FTP_SERVER_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred creating the thread. */ - if (status) - { - - /* Error creating the server thread. */ - return(status); - } - - /* Create the ThreadX event flags. These will be used to driver the FTP server thread. */ - status = tx_event_flags_create(&(ftp_server_ptr -> nx_ftp_server_event_flags), - "FTP Server Thread Events"); - - /* Determine if an error occurred creating the event flags. */ - if (status) - { - - - /* Delete the server thread. */ - tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Error creating the server event flags. */ - return(status); - } - - /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if - a client connection has gone silent and needs to be terminated. */ - status = tx_timer_create(&(ftp_server_ptr -> nx_ftp_server_timer), "FTP Server Timer", _nx_ftp_server_timeout, - (ULONG) ftp_server_ptr, (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD), - (NX_IP_PERIODIC_RATE * NX_FTP_TIMEOUT_PERIOD), TX_NO_ACTIVATE); - - /* Determine if an error occurred creating the timer. */ - if (status) - { - - /* Delete the server thread. */ - tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Delete the server event flags. */ - tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); - - /* Error creating the server timer. */ - return(status); - } - - /* Loop to create all the FTP client control sockets. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Create an FTP client control socket. */ - status += nx_tcp_socket_create(ip_ptr, &(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket), - "FTP Server Control Socket", NX_FTP_CONTROL_TOS, NX_FTP_FRAGMENT_OPTION, - NX_FTP_TIME_TO_LIVE, NX_FTP_CONTROL_WINDOW_SIZE, NX_NULL, _nx_ftp_server_control_disconnect); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Register the receive function. */ - nx_tcp_socket_receive_notify(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket), - _nx_ftp_server_command_present); - } - - /* Make sure each socket points to the FTP server. */ - ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - } - - /* Determine if an error has occurred. */ - if (status) - { - - /* Loop to delete any created sockets. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Delete the FTP socket. */ - nx_tcp_socket_delete(&(ftp_server_ptr -> nx_ftp_server_client_list[i].nx_ftp_client_request_control_socket)); - } - - /* Delete the server thread. */ - tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); - - /* Delete the timer. */ - tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer)); - - /* Return an error. */ - return(status); - } - - /* Initialize the data port. */ - ftp_server_ptr -> nx_ftp_server_data_port = NX_SEARCH_PORT_START; - - /* Save the Server name. */ - ftp_server_ptr -> nx_ftp_server_name = ftp_server_name; - - /* Save the IP pointer address. */ - ftp_server_ptr -> nx_ftp_server_ip_ptr = ip_ptr; - - /* Set the FTP media pointer address. */ - ftp_server_ptr -> nx_ftp_server_media_ptr = media_ptr; - - /* Save the user-supplied login and logout functions. */ - ftp_server_ptr -> nx_ftp_login = ftp_login; - ftp_server_ptr -> nx_ftp_logout = ftp_logout; - - /* Set the server ID to indicate the FTP server thread is ready. */ - ftp_server_ptr -> nx_ftp_server_id = NXD_FTP_SERVER_ID; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP server delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_delete Actual server delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_ftp_server_delete(ftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created FTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_server_socket_unaccept Unaccept server socket */ -/* nx_tcp_server_socket_unlisten Unlisten on server */ -/* nx_tcp_socket_delete Delete socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* tx_event_flags_delete Delete event flags */ -/* tx_thread_delete Delete thread */ -/* tx_thread_suspend Suspend thread */ -/* tx_thread_terminate Terminate thread */ -/* tx_timer_deactivate Deactivate timer */ -/* tx_timer_delete Delete timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -NX_FTP_CLIENT_REQUEST *client_request_ptr; - - - /* Clear the server ID to indicate the FTP server is no longer ready. */ - ftp_server_ptr -> nx_ftp_server_id = 0; - - /* Suspend the FTP server thread. */ - tx_thread_suspend(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Terminate server thread. */ - tx_thread_terminate(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Delete server thread. */ - tx_thread_delete(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(ftp_server_ptr -> nx_ftp_server_event_flags)); - - /* Deactivate and delete timer. */ - tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer)); - tx_timer_delete(&(ftp_server_ptr -> nx_ftp_server_timer)); - - /* Walk through the server structure to close any remaining open files. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++) - { - - /* Set the client request. */ - client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* If created, cleanup the data socket. */ - if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) - { - - /* Disconnect data socket. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Unbind/unaccept the data socket. */ - if (client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - } - - /* Delete data socket. */ - nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - - /* Close file. */ - fx_file_close(&(client_request_ptr -> nx_ftp_client_request_file)); - } - - /* Clear the passive transfer enabled flag. */ - client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Reset the transfer mode as stream mode. */ - client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Reset the block bytes. */ - client_request_ptr -> nx_ftp_client_request_block_bytes = 0; - - /* Disconnect the control and data ports. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); - - /* Unaccept the control socket. */ - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket)); - - /* Delete both the control and data sockets. */ - nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_control_socket)); - } - - /* Unlisten on the FTP control port. */ - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP server start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_start Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Call actual server start function. */ - status = _nx_ftp_server_start(ftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts a previously created FTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_listen Listen of FTP clients */ -/* tx_thread_resume Resume the FTP server thread */ -/* tx_timer_activate Activate FTP server timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT status; -ULONG events; - - - /* Start listening on the FTP control socket. */ - status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, - &(ftp_server_ptr -> nx_ftp_server_client_list[0].nx_ftp_client_request_control_socket), - NX_FTP_MAX_CLIENTS, _nx_ftp_server_connection_present); - - /* Determine if an error is present. */ - if (status) - { - - /* Error, return to caller. */ - return(status); - } - - /* Activate FTP server timer. */ - tx_timer_activate(&(ftp_server_ptr -> nx_ftp_server_timer)); - - /* Clear stop event. */ - tx_event_flags_get(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR_CLEAR, &events, TX_NO_WAIT); - - /* Start the FTP server thread. */ - tx_thread_resume(&(ftp_server_ptr -> nx_ftp_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ftp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the FTP server stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_stop Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ftp_server_ptr == NX_NULL) || (ftp_server_ptr -> nx_ftp_server_id != NXD_FTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_ftp_server_stop(ftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops a previously started FTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend the FTP server thread */ -/* tx_timer_deactivate Deactivate FTP server timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -NX_FTP_CLIENT_REQUEST *client_request_ptr; - - /* Deactivate FTP server timer. */ - tx_timer_deactivate(&(ftp_server_ptr -> nx_ftp_server_timer)); - - /* Suspend the FTP server thread. */ - tx_event_flags_set(&(ftp_server_ptr -> nx_ftp_server_event_flags), NX_FTP_STOP_EVENT, TX_OR); - - /* Walk through the server structure to close any remaining open files. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i ++) - { - - /* Set the client request. */ - client_request_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* If created, cleanup the data socket. */ - if (client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) - { - - /* Disconnect data socket. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Unbind/unaccept the data socket. */ - if (client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_request_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - } - - /* Delete data socket. */ - nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_data_socket)); - - /* Close file. */ - fx_file_close(&(client_request_ptr -> nx_ftp_client_request_file)); - } - - /* Clear the passive transfer enabled flag. */ - client_request_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Reset the transfer mode as stream mode. */ - client_request_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Reset the block bytes. */ - client_request_ptr -> nx_ftp_client_request_block_bytes = 0; - - /* Disconnect the control and data ports. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); - - /* Unaccept the control socket. */ - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_ftp_client_request_control_socket)); - - /* Delete both the control and data sockets. */ - nx_tcp_socket_delete(&(client_request_ptr -> nx_ftp_client_request_control_socket)); - } - - /* Unlisten on the FTP control port. */ - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an FTP Server response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket FTP socket */ -/* packet_ptr Response packet pointer */ -/* reply_code Reply code string */ -/* message Optional message */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Packet release */ -/* nx_tcp_socket_send Send TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* NetX FTP Routines */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message) -{ - -UCHAR *buffer_ptr; -UINT status; - - - /* Set the packet prepend pointer. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; - packet_ptr -> nx_packet_length = 0; - - /* Now setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Copy reply code to the packet. */ - while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) - { - - /* copy the next character */ - *buffer_ptr++ = (UCHAR) *reply_code++; - - /* Update the packet length. */ - packet_ptr -> nx_packet_length++; - } - - /* Add a separating space */ - *buffer_ptr++ = (UCHAR) ' '; - packet_ptr -> nx_packet_length++; - - /* Copy message to the packet */ - while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) - { - - /* copy the next character */ - *buffer_ptr++ = (UCHAR) *message++; - - /* Update the packet length. */ - packet_ptr -> nx_packet_length++; - } - - /* Add a trailing space, CR, LF. */ - *buffer_ptr++ = ' '; - *buffer_ptr++ = 13; - *buffer_ptr = 10; - - /* Adjust the packet length. */ - packet_ptr -> nx_packet_length += 3; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the failed message back. */ - status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_directory_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an FTP Server directory response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket FTP socket */ -/* packet_ptr Response packet pointer */ -/* reply_code Reply code string */ -/* message Optional message */ -/* directory Directory path */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Packet release */ -/* nx_tcp_socket_send Send TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* NetX FTP Routines */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_directory_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message, CHAR *directory) -{ - -UCHAR *buffer_ptr; -UINT status; - - - /* Set the packet prepend pointer. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; - packet_ptr -> nx_packet_length = 0; - - /* Now setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Copy reply code to the packet. */ - while ((*reply_code) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) - { - - /* copy the next character. */ - *buffer_ptr++ = (UCHAR) *reply_code++; - - /* Update the packet length. */ - packet_ptr -> nx_packet_length++; - } - - /* Add a separating space and the leading ". */ - *buffer_ptr++ = (UCHAR) ' '; - packet_ptr -> nx_packet_length++; - - *buffer_ptr++ = (UCHAR) '"'; - packet_ptr -> nx_packet_length++; - - /* Is there a valid directory. */ - if ((directory != NULL) && (*directory)) - { - - /* If the directory doesn't start with a / then make sure it does. */ - if ((*directory != '/') && (*directory != '\\')) - { - - /* Add / to message. */ - *buffer_ptr++ = (UCHAR) '/'; - packet_ptr -> nx_packet_length++; - } - - /* Copy directory to the packet. */ - while ((*directory) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) - { - - /* Copy the next character , doubling any " characters. */ - if (*directory == '"') - { - - /* Double the character. */ - *buffer_ptr++ = (UCHAR) *directory; - packet_ptr -> nx_packet_length++; - } - - /* Copy the directory character, converting backslashes to slashes. */ - if (*directory == '\\') - { - - /* Convert to slash for consistency. */ - *buffer_ptr++ = (UCHAR) '/'; - directory++; - } - else - { - - /* Copy regular directory character. */ - *buffer_ptr++ = (UCHAR) *directory++; - } - - /* Update the packet length. */ - packet_ptr -> nx_packet_length++; - } - } - else - { - - /* No valid directory, simply assume root. */ - *buffer_ptr++ = (UCHAR) '/'; - packet_ptr -> nx_packet_length++; - } - - /* Add the trailing " and a separating space. */ - *buffer_ptr++ = (UCHAR) '"'; - packet_ptr -> nx_packet_length++; - - *buffer_ptr++ = (UCHAR) ' '; - packet_ptr -> nx_packet_length++; - - /* Copy message to the packet. */ - while ((*message) && (buffer_ptr < (packet_ptr -> nx_packet_data_end - NX_PHYSICAL_TRAILER))) - { - - /* Copy the next character. */ - *buffer_ptr++ = (UCHAR) *message++; - - /* Update the packet length. */ - packet_ptr -> nx_packet_length++; - } - - /* Add a trailing space, CR, LF. */ - *buffer_ptr++ = (UCHAR) ' '; - *buffer_ptr++ = (UCHAR) 13; - *buffer_ptr = (UCHAR) 10; - - /* Adjust the packet length. */ - packet_ptr -> nx_packet_length += 3; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the failed message back. */ - status = nx_tcp_socket_send(socket, packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry of the FTP server. All basic */ -/* processing is initiated by this function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_address Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_command_process Process client FTP command */ -/* _nx_ftp_server_connect_process Process connection requests */ -/* _nx_ftp_server_control_disconnect_processing */ -/* Process control disconnect */ -/* _nx_ftp_server_data_disconnect_process Process data disconnection */ -/* requests */ -/* _nx_ftp_server_data_process Process client write data */ -/* _nx_ftp_server_timeout_processing Process activity timeout */ -/* tx_event_flags_get Get FTP event(s) */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_thread_entry(ULONG ftp_server_address) -{ - -NX_FTP_SERVER *server_ptr; -UINT status; -ULONG events; - - - /* Setup the server pointer. */ - server_ptr = (NX_FTP_SERVER *) ftp_server_address; - - /* Loop to process FTP Server requests. */ - while(1) - { - - /* Wait for an FTP client activity. */ - status = tx_event_flags_get(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_ANY_EVENT, - TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Check the return status. */ - if (status) - { - - /* If an error occurs, simply continue the loop. */ - continue; - } - - /* Check whether service is started. */ - if (events & NX_FTP_STOP_EVENT) - { - - /* Suspend thread here. */ - tx_thread_suspend(&server_ptr -> nx_ftp_server_thread); - continue; - } - - /* Otherwise, an event is present. Process according to the event. */ - - /* Check for a client connection event. */ - if (events & NX_FTP_SERVER_CONNECT) - { - - /* Call the connect processing. */ - _nx_ftp_server_connect_process(server_ptr); - } - - /* Check for an FTP client write data event. */ - if (events & NX_FTP_SERVER_DATA) - { - - /* Call processing to handle client file write data. */ - _nx_ftp_server_data_process(server_ptr); - } - - /* Check for a FTP client command event. */ - if (events & NX_FTP_SERVER_COMMAND) - { - - /* Call the command processing. */ - _nx_ftp_server_command_process(server_ptr); - } - - /* Check for a client disconnect event. */ - if (events & NX_FTP_SERVER_DATA_DISCONNECT) - { - - /* Call the data disconnect processing. */ - _nx_ftp_server_data_disconnect_process(server_ptr); - } - - /* Check for a control disconnect event. */ - if (events & NX_FTP_SERVER_CONTROL_DISCONNECT) - { - - /* Call the control disconnect processing. */ - _nx_ftp_server_control_disconnect_processing(server_ptr); - } - - - /* Check for a client activity timeout event. */ - if (events & NX_FTP_SERVER_ACTIVITY_TIMEOUT) - { - - /* Call the activity timeout processing. */ - _nx_ftp_server_timeout_processing(server_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_command_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all FTP client commands received on all */ -/* client connections. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_parse_command Parse FTP client command */ -/* _nx_ftp_server_response Send FTP response */ -/* _nx_ftp_server_directory_response Send FTP response for dir */ -/* _nx_ftp_server_number_to_ascii Converts number to ascii text */ -/* fx_file_attributes_read Read file attributes */ -/* fx_file_close Close file */ -/* fx_file_delete Delete file */ -/* fx_file_open Open file */ -/* fx_file_read Read from file */ -/* fx_file_rename Rename file */ -/* fx_file_truncate Truncate file */ -/* fx_directory_attributes_read Read directory attributes */ -/* fx_directory_create Create directory */ -/* fx_directory_delete Delete directory */ -/* fx_directory_first_entry_find Find first directory entry */ -/* fx_directory_local_path_restore Restore directory path */ -/* fx_directory_local_path_set Set directory path */ -/* fx_directory_next_entry_find Find next directory entry */ -/* fx_media_flush Flush cached media sectors */ -/* nx_ftp_packet_allocate Allocate a packet */ -/* nx_packet_release Release a packet */ -/* nx_tcp_client_socket_bind Bind client socket */ -/* nx_tcp_client_socket_connect Connect client socket */ -/* nxd_tcp_client_socket_connect Connect client socket in IPv6 */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_server_socket_relisten Relisten on server socket */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_socket_create Create data socket */ -/* nx_tcp_socket_delete Delete data socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* nx_tcp_socket_receive Receive from command socket */ -/* nx_tcp_socket_send Send packet */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_socket_delete Delete socket */ -/* nx_tcp_socket_receive Receive packet */ -/* nx_tcp_socket_receive_notify Register notification routine */ -/* nx_tcp_socket_transmit_configure Configure data transer socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr) -{ - - -#ifdef FEATURE_NX_IPV6 -NXD_ADDRESS ipduo_address; -UINT port_size; -#endif -#ifndef NX_DISABLE_IPV4 -ULONG connect_ip4_address = 0; -UINT commas; -ULONG ip_address; -UINT temp; -#endif /* NX_DISABLE_IPV4 */ -UINT i, j; -INT k; -UINT port; -ULONG length; -ULONG remaining_length; -UINT status; -UINT ftp_command; -UINT single_file; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -FX_LOCAL_PATH temp_path; -NX_FTP_CLIENT_REQUEST *client_req_ptr; -UINT attributes; -ULONG size; -UINT year, month, day; -UINT hour, minute, second; -CHAR filename[FX_MAX_LONG_NAME_LEN]; -const char *months[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; -UINT no_more_ftp_entries = NX_FALSE; -ULONG block_size; - - year = 1900; - month = 1; - day = 1; - hour = 1; - minute = 1; - second = 1; - attributes = 1; - size = 1; - - /* Now look for a socket that has receive data. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - -#ifndef NX_DISABLE_IPV4 - if(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - connect_ip4_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4; - } -#endif /* NX_DISABLE_IPV4 */ - - /* Now see if this socket has data. */ - if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_receive_queue_count) - { - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; - - /* Attempt to read a packet from this socket. */ - status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_control_socket), &packet_ptr, NX_NO_WAIT); - - /* Check for not data present. */ - if (status != NX_SUCCESS) - { - - /* Just continue the loop and look at the next socket. */ - continue; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* And continue looking at other client requests. */ - continue; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Now, parse the command in the packet. Note that the parse command adjusts the packet pointer - such that it is positioned at the next token in the buffer. */ - ftp_command = _nx_ftp_server_parse_command(packet_ptr); - - /* Check to make sure the client request is authenticated. */ - if ((client_req_ptr -> nx_ftp_client_request_authenticated == NX_FALSE) && - (ftp_command != NX_FTP_USER) && (ftp_command != NX_FTP_PASS)) - { - - /* Unauthorized request. */ - - /* Increment the access error count. */ - ftp_server_ptr -> nx_ftp_server_authentication_errors++; - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_UNAUTHORIZED, "Not logged in"); - - /* And continue looking at other client requests. */ - continue; - } - - /* Check to make sure the client has write access if requesting a write. */ - else if ((client_req_ptr -> nx_ftp_client_request_read_only == NX_TRUE) && - ((ftp_command == NX_FTP_STOR) || (ftp_command == NX_FTP_RNFR) || (ftp_command == NX_FTP_RNTO) || - (ftp_command == NX_FTP_DELE) || (ftp_command == NX_FTP_RMD ) || (ftp_command == NX_FTP_MKD ))) - { - - /* Unauthorized request. */ - - /* Increment the access error count. */ - ftp_server_ptr -> nx_ftp_server_authentication_errors++; - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_NO_ACCT, "Need account for storing files"); - - /* And continue looking at other client requests. */ - continue; - } - - /* Switch on the command received. */ - switch(ftp_command) - { - - case NX_FTP_USER: - { - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First, save the username in the request structure. */ - for (j = 0; j < (NX_FTP_USERNAME_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++) - { - - /* Copy a character. */ - client_req_ptr -> nx_ftp_client_request_username[j] = (CHAR) buffer_ptr[j]; - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - } - - /* Ensure the username is NULL terminated. */ - client_req_ptr -> nx_ftp_client_request_username[j] = NX_NULL; - - /* Now send an intermediate response to the username. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_USER_OK, "Enter password"); - break; - } - - case NX_FTP_PASS: - { - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First, save the password in the request structure. */ - for (j = 0; j < (NX_FTP_PASSWORD_SIZE - 1) && (j < packet_ptr -> nx_packet_length); j++) - { - - /* Copy a character. */ - client_req_ptr -> nx_ftp_client_request_password[j] = (CHAR) buffer_ptr[j]; - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - } - - /* Ensure the password is NULL terminated. */ - client_req_ptr -> nx_ftp_client_request_password[j] = NX_NULL; - - /* Initially assume client will have read-write access. */ - client_req_ptr -> nx_ftp_client_request_read_only = NX_FALSE; - - /* Initialize the login status as unsuccessful. */ - status = NX_FTP_INVALID_LOGIN; - - /* Does this FTP server have an login handler? */ - if (ftp_server_ptr -> nx_ftp_login) - { - - /* Now call the user's login callback routine to see if the username,password is valid. */ - status = (ftp_server_ptr -> nx_ftp_login)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, - &client_req_ptr -> nx_ftp_client_request_read_only); - } -#ifndef NX_DISABLE_IPV4 - else - { - - /* No duo handler. Check if this is an IPv4 connection. */ - if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4) - { - - /* This is an IPv4 connection. */ - - /* Does this server have an IPv4 login function? */ - if (ftp_server_ptr -> nx_ftp_login_ipv4) - { - - /* Yes; Now call the user's login callback routine to see if the username,password is valid. */ - status = (ftp_server_ptr -> nx_ftp_login_ipv4) - (ftp_server_ptr, - (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4), - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, - &client_req_ptr -> nx_ftp_client_request_read_only); - } - } - } -#endif /* NX_DISABLE_IPV4 */ - - /* Set the login as TRUE. */ - client_req_ptr -> nx_ftp_client_request_login = NX_TRUE; - - if (status == NX_SUCCESS) - { - - /* Successful connection. */ - - /* Mark as authenticated. */ - client_req_ptr -> nx_ftp_client_request_authenticated = NX_TRUE; - - /* Default transfer type is ASCII image. */ - client_req_ptr -> nx_ftp_client_request_transfer_type = 'A'; - - /* Now build a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_LOGIN, "Logged in"); - } - else - { - - /* Unsuccessful login. */ - - /* Increment the number of login errors. */ - ftp_server_ptr -> nx_ftp_server_login_errors++; - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_UNAUTHORIZED, "Login Fail"); - } - - break; - } - - case NX_FTP_QUIT: - { - - /* Increment the number of disconnection requests. */ - ftp_server_ptr -> nx_ftp_server_disconnection_requests++; - - /* Check if this client login. */ - if (client_req_ptr -> nx_ftp_client_request_login) - { - - /* Call the logout function. */ - -#ifndef NX_DISABLE_IPV4 - /* Does this server have an IPv4 login function? */ - if (ftp_server_ptr -> nx_ftp_logout_ipv4) - { - - /* Call the logout which takes IPv4 address input. */ - (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr, - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4, - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, NX_NULL); - } -#endif /* NX_DISABLE_IPV4 */ - if (ftp_server_ptr -> nx_ftp_logout) - { - - /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */ - (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, NX_NULL); - } - - /* Set the login as FALSE. */ - client_req_ptr -> nx_ftp_client_request_login = NX_FALSE; - } - - /* Clear authentication. */ - client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CLOSE, "Logging Off"); - - /* Now disconnect the command socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); - - /* Unaccept the server socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); - - /* Relisten on this socket. This will probably fail, but it is needed just in case all available - clients were in use at the time of the last relisten. */ - nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, - &(client_req_ptr -> nx_ftp_client_request_control_socket)); - - /* Check to see if a packet is queued up. */ - if (client_req_ptr -> nx_ftp_client_request_packet) - { - - /* Yes, release it! */ - nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); - } - - /* Disable the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; - break; - } - - case NX_FTP_RETR: - { - - /* Check that the transfer type is a Binary Image. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I') - { - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed"); - - /* We are done processing. */ - break; - } - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Attempt to open the file. */ - status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, - &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, - FX_OPEN_FOR_READ); - - /* Determine if the file open was successful. */ - if (status == FX_SUCCESS) - { - - /* Check if passive transfer enabled. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - - /* Now wait for the data connection to connect. */ - status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - else - { - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, - &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, - NX_NULL, NX_NULL); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Bind the socket to the FTP server data port. */ - status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); - - /* Determine if the socket was bound. */ - if (status) - { - - /* FTP server data port is busy, use any data port. */ - nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); - } - - /* Now attempt to connect the data port to the client's data port. */ - status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), - &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - } - } - - /* Now check and see if the open for read has any errors. */ - if (status == NX_SUCCESS) - { - - /* The open for read command is successful! */ - - /* Set the open for read type in the client request structure. */ - client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_READ; - - /* Set the total bytes field to files size. */ - client_req_ptr -> nx_ftp_client_request_total_bytes = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_START_XFER, "File Opened"); - - /* Determine if the block mode is enabled. */ - if ((client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) && - (client_req_ptr -> nx_ftp_client_request_total_bytes)) - { - - /* Send start block header for file size. */ - status = _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, - client_req_ptr -> nx_ftp_client_request_total_bytes); - } - - /* Now read the file and send the contents to the client. */ - while (status == NX_SUCCESS) - { - - /* Allocate a new packet. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Calculate the maximum read size. */ - length = ((ULONG) (packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)) - NX_PHYSICAL_TRAILER; - - /* Determine if the length is greater than the connected MSS. */ - if (length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) - { - - /* Yes, reduce the length to match the MSS. */ - length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; - } - - /* Read a buffer's worth of the file. */ - status = fx_file_read(&(client_req_ptr -> nx_ftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr, length, &length); - - /* Determine if the file read was successful. */ - if (status == FX_SUCCESS) - { - - /* Now send the packet on the data socket. */ - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = length; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the file data to the client. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), - packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - else - { - - /* Update the remaining bytes in the file. */ - client_req_ptr -> nx_ftp_client_request_total_bytes = client_req_ptr -> nx_ftp_client_request_total_bytes - length; - - /* Increment the number of bytes sent. */ - ftp_server_ptr -> nx_ftp_server_total_bytes_sent += length; - } - } - else - { - - /* Release packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Send end block header for file size. */ - _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); - } - - /* Disconnect the data socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); - - /* Tear down the client data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - - /* Clear the open type in the client request structure. */ - client_req_ptr -> nx_ftp_client_request_open_type = 0; - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Allocate a new packet. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Now determine if the read was a success. */ - if ((status == FX_END_OF_FILE) && (client_req_ptr -> nx_ftp_client_request_total_bytes == 0)) - { - - /* The read command was successful! */ - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "File Sent"); - } - else - { - - /* Read command failed. */ - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Read Fail"); - } - } - else - { - - /* Unsuccessful open for read or read command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "File Open Fail"); - } - - break; - } - - case NX_FTP_STOR: - { - - /* Check that the transfer type is a Binary Image. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I') - { - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Only Image transfer allowed"); - - /* And we are done processing. */ - break; - } - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Attempt to open the file. */ - status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); - - - /* Determine if there was an error. */ - if (status != FX_SUCCESS) - { - - /* Create a new file. */ - status = fx_file_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); - - if (status == FX_SUCCESS) - { - - /* Open the new file. */ - status = fx_file_open(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); - } - } - - /* Truncate the file to a size of 0. */ - status += fx_file_truncate(&(client_req_ptr -> nx_ftp_client_request_file), 0); - - /* Determine if the file create/open was successful. */ - if (status == FX_SUCCESS) - { - - /* Check if passive transfer enabled. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - - /* Set the disconnect callback. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_disconnect_callback = _nx_ftp_server_data_disconnect; - - /* Register the receive function. */ - nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket), _nx_ftp_server_data_present); - - /* Now wait for the data connection to connect. */ - status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - else - { - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, _nx_ftp_server_data_disconnect); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Register the receive function. */ - nx_tcp_socket_receive_notify(&(client_req_ptr -> nx_ftp_client_request_data_socket), - _nx_ftp_server_data_present); - - /* Bind the socket to the FTP server data port. */ - status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); - - /* Determine if the socket was bound. */ - if (status) - { - - /* FTP server data port is busy, use any data port. */ - nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); - } - /* Now attempt to connect the data port to the client's data port. */ - status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), - &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); - - - /* Check for connect error. */ - if (status) - { - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - } - else - { - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - } - } - - /* Now check and see if the open for write has any errors. */ - if (status == NX_SUCCESS) - { - - /* The open for writing command is successful! */ - - /* Set the open for write type in the client request structure. */ - client_req_ptr -> nx_ftp_client_request_open_type = NX_FTP_OPEN_FOR_WRITE; - - /* Set the total bytes field to zero. */ - client_req_ptr -> nx_ftp_client_request_total_bytes = 0; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_START_XFER, "File Open for Write"); - } - else - { - /* Unsuccessful open for writing command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "File Open Failed"); - } - - break; - } - - case NX_FTP_RNFR: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Read the file attributes to see if it is actually there. */ - status = fx_file_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j); - - /* If not a file, read the directory attributes. */ - if (status == FX_NOT_A_FILE) - status = fx_directory_attributes_read(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, &j); - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - /* Successful start to the file rename. */ - - /* Save the packet in the client request structure. */ - client_req_ptr -> nx_ftp_client_request_packet = packet_ptr; - - /* Allocate a new packet. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_FILE_PEND, "Rename File From"); - } - else - { - - /* Unsuccessful first half of file rename. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Rename File not found"); - } - break; - } - - case NX_FTP_RNTO: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Rename the file. */ - status = fx_file_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr); - - /* If not a file, rename the directory. */ - if (status == FX_NOT_A_FILE) - status = fx_directory_rename(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) (client_req_ptr -> nx_ftp_client_request_packet) -> nx_packet_prepend_ptr, (CHAR *) buffer_ptr); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - - /* Release the packet in the client request structure. */ - nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); - client_req_ptr -> nx_ftp_client_request_packet = NX_NULL; - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - /* Successful file rename. */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "File Renamed"); - } - else - { - - /* Unsuccessful file rename. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Rename failed"); - } - break; - } - - case NX_FTP_DELE: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Remove the specified file. */ - status = fx_file_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - /* Successful delete file. */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "File Deleted"); - } - else - { - - /* Unsuccessful file delete. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Delete Failed"); - } - break; - } - - case NX_FTP_RMD: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Remove the specified directory. */ - status = fx_directory_delete(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - /* Successful delete directory. */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "Directory Deleted"); - } - else - { - - /* Unsuccessful directory delete. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Delete Directory Fail"); - } - break; - } - - case NX_FTP_MKD: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Create the specified directory. */ - status = fx_directory_create(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - FX_LOCAL_PATH temporary_path; - - - /* Successful create directory. */ - - /* Change the path to the new directory, using a temporary directory structure */ - status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temporary_path, (CHAR *) buffer_ptr); - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - CHAR *local_dir; - - - /* Successful change directory. */ - - /* Get the actual path */ - fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); - - /* Now send a successful response to the client. */ - _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Directory Created", local_dir); - } - else - { - /* Unsuccessful directory change. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Set New Directory Fail"); - } - - /* Restore the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - } - else - { - - /* Unsuccessful directory create. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Directory Create failed"); - } - break; - } - - case NX_FTP_NLST: - { - - /* Assume ASCII and relax restriction. */ - if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') && - (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')) - { - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed"); - - /* And we are done processing. */ - break; - } - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Determine if there is a directory path. */ - if (j) - { - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Set the path to the supplied directory. */ - status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr); - } - else - { - - /* Just set the buffer pointer to NULL since there isn't a string. */ - buffer_ptr = NX_NULL; - - /* Default status to success. */ - status = FX_SUCCESS; - } - - - /* Determine if the path setup was successful. */ - if (status == FX_SUCCESS) - { - - /* Check if passive transfer enabled. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - - /* Now wait for the data connection to connect. */ - status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - else - { - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Bind the socket to the FTP server data port. */ - status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); - - /* Determine if the socket was bound. */ - if (status) - { - - /* FTP server data port is busy, use any data port. */ - nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); - } - /* Now attempt to connect the data port to the client's data port. */ - status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), - &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); - - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - } - } - - /* Now check and see if the directory listing command has any errors. */ - if (status == NX_SUCCESS) - { - - /* The directory listing is successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_START_XFER, "Sending List"); - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Get the directory listing size. */ - _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size); - - /* Send start block header for file size. */ - if (block_size) - _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size); - } - - /* Allocate a new packet. */ - status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Calculate the remaining length. */ - remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); - - /* Determine if the advertised MSS is even less. */ - if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) - { - - /* Reduce the remaining length to the MSS value. */ - remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; - } - - /* Now generate the full directory listing and send the contents to the client. */ - j = 0; - while (status == NX_SUCCESS) - { - - /* Pickup the next directory entry. */ - if (j == 0) - { - - - /* First directory entry. */ - status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - - } - else - { - - /* Not the first entry - pickup the next! */ - status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - - } - - /* Increment the entry count. */ - j++; - - /* Determine if successful. */ - if (status == NX_SUCCESS) - { - - /* Setup pointer to buffer. */ - buffer_ptr = packet_ptr -> nx_packet_append_ptr; - - /* Calculate the size of the name. */ - length = 0; - do - { - if (filename[length]) - length++; - else - break; - } while (length < FX_MAX_LONG_NAME_LEN); - - /* Make sure there is enough space for the file name. */ - if ((length + 2) > remaining_length) - { - - /* Send the current buffer out. */ - - /* Send the directory data to the client. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), - packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Allocate a new packet. */ - status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if the packet allocate was successfull. */ - if (status) - { - - /* Get out of the loop! */ - break; - } - - /* Calculate the remaining length. */ - remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); - - /* Determine if the advertised MSS is even less. */ - if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) - { - - /* Reduce the remaining length to the MSS value. */ - remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; - } - - /* Setup pointer to buffer. */ - buffer_ptr = packet_ptr -> nx_packet_append_ptr; - } - - /* Put the file name and cr/lf in the buffer*/ - memcpy(buffer_ptr, filename, length); - buffer_ptr[length++] = '\r'; - buffer_ptr[length++] = '\n'; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length; - - /* Adjust the remaining length. */ - remaining_length = remaining_length - length; - } - } - - /* Now determine if the directory listing was a success. */ - if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length)) - { - - no_more_ftp_entries = NX_TRUE; - - /* Send the directory data to the client. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), - packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - } - else if (packet_ptr) - { - - /* Release packet just in case! */ - nx_packet_release(packet_ptr); - } - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Send end block header for file size. */ - _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); - } - - /* Disconnect the data socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); - - /* Tear down the client data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Allocate a new packet. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Now determine if the directory listing was a success (e..g runs until no more entries found). */ - if (no_more_ftp_entries) - { - - /* The directory listing was successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "List End"); - } - else - { - - /* Directory listing command failed. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "List fail"); - } - } - else - { - /* Unsuccessful directory listing command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "List bad Directory"); - } - break; - } - - case NX_FTP_LIST: - { - - /* Assume ASCII and relax restriction. */ - if ((client_req_ptr -> nx_ftp_client_request_transfer_type != 'A') && - (client_req_ptr -> nx_ftp_client_request_transfer_type != 'I')) - { - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Only ASCII Listing allowed"); - - /* And we are done processing. */ - break; - } - - /* Change to the default directory of this connection. */ - status = fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Find the end of the message. */ - j = 0; - k = -1; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a slash or backslash is present. */ - if ((buffer_ptr[j] == '/') || (buffer_ptr[j] == '\\')) - k = (INT)j; - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Default the single file specified flag to false. */ - single_file = NX_FALSE; - - /* Determine if there is a directory path. */ - if (j) - { - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - - /* Set the path to the supplied directory. */ - status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &temp_path, (CHAR *) buffer_ptr); - - /* Determine if the path setup was unsuccessful. */ - if (status) - { - - /* Pickup the information for the single file. */ - status = fx_directory_information_get(ftp_server_ptr -> nx_ftp_server_media_ptr, (CHAR *) buffer_ptr, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - - /* Determine if a file is specified as the LIST parameter. */ - if ((status == FX_SUCCESS) && ((attributes & FX_DIRECTORY) == 0)) - { - - /* Yes, a file name was supplied. Set the single file flag for the processing below. */ - single_file = NX_TRUE; - - /* Advance to first character of the filename. */ - k++; - - /* Copy the file name from the last slash into the filename buffer. */ - j = 0; - while ((buffer_ptr[(UINT)k + j]) && (j < FX_MAX_LONG_NAME_LEN-1)) - { - - /* Copy a character of the filename. */ - filename[j] = (CHAR)(buffer_ptr[(UINT)k + j]); - - /* Move to next character. */ - j++; - } - - /* Null terminate the string. */ - filename[j] = NX_NULL; - } - } - } - else - { - - /* Just set the buffer pointer to NULL since there isn't a string. */ - buffer_ptr = NX_NULL; - } - - /* Determine if the path setup was successful. */ - if (status == FX_SUCCESS) - { - - CHAR *local_dir; - - - /* Get the actual path */ - fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); - - /* Check if passive transfer enabled. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - - /* Now wait for the data connection to connect. */ - status = nx_tcp_socket_state_wait(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_TCP_ESTABLISHED, NX_FTP_SERVER_TIMEOUT); - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - else - { - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Bind the socket to the FTP server data port. */ - status = nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_DATA_PORT, NX_NO_WAIT); - - /* Determine if the socket was bound. */ - if (status) - { - - /* FTP server data port is busy, use any data port. */ - nx_tcp_client_socket_bind(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_ANY_PORT, NX_NO_WAIT); - } - - /* Now attempt to connect the data port to the client's data port. */ - status = nxd_tcp_client_socket_connect(&(client_req_ptr -> nx_ftp_client_request_data_socket), - &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_data_port, NX_FTP_SERVER_TIMEOUT); - - - /* Check for connect error. */ - if (status) - { - - /* Yes, a connect error is present. Tear everything down. */ - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - } - else - { - - /* Setup the data port with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(client_req_ptr -> nx_ftp_client_request_data_socket), - NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_FTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_FTP_SERVER_RETRY_MAX, - NX_FTP_SERVER_RETRY_SHIFT); - } - } - } - } - - /* Now check and see if the directory listing command has any errors. */ - if (status == NX_SUCCESS) - { - - /* The directory listing is successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_START_XFER, "Sending List"); - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Get the directory listing size. */ - _nx_ftp_server_block_size_get(ftp_server_ptr, ftp_command, filename, &block_size); - - /* Send start block header for file size. */ - if (block_size) - _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, block_size); - } - - /* Allocate a new packet. */ - status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Calculate the remaining length. */ - remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); - - /* Determine if the advertised MSS is even less. */ - if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) - { - - /* Reduce the remaining length to the MSS value. */ - remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; - } - - /* Now generate the full directory listing and send the contents to the client. */ - j = 0; - while (status == NX_SUCCESS) - { - - /* Determine if a single file was specified. */ - if (single_file == NX_FALSE) - { - - /* Typical case - not a single file. */ - - /* Pickup the next directory entry. */ - if (j == 0) - { - - /* First directory entry. */ - status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - - } - else - { - - /* Not the first entry - pickup the next! */ - status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - - } - } - else - { - - /* The parameter to the LIST command is a single file. Simply return the information - already gathered above for this one file instead of traversing the entire list. */ - - /* Is this the first pass through the loop? */ - if (j) - { - - /* End the loop, since the single file has already been sent. */ - status = FX_NO_MORE_ENTRIES; - } - } - - /* Increment the entry count. */ - j++; - - /* Determine if successful. */ - if (status == NX_SUCCESS) - { - - /* Check if the month is valid before convert it. */ - if ((month < 1) || (month > 12)) - continue; - - /* Setup pointer to buffer. */ - buffer_ptr = packet_ptr -> nx_packet_append_ptr; - - /* Calculate the size of the name. */ - length = 0; - do - { - if (filename[length]) - length++; - else - break; - } while (length < FX_MAX_LONG_NAME_LEN); - - /* Make sure there is enough space for the data plus the file info. - File Info is 10 chars for permissions, 15 chars for owner and group, - 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */ - if ((length + 52) > remaining_length) - { - - /* Send the current buffer out. */ - - /* Send the directory data to the client. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Allocate a new packet. */ - status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if the packet allocate was successfull. */ - if (status) - { - - /* Get out of the loop! */ - break; - } - - /* Calculate the remaining length. */ - remaining_length = (ULONG)((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr) - NX_PHYSICAL_TRAILER); - - /* Determine if the advertised MSS is even less. */ - if (remaining_length > client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss) - { - - /* Reduce the remaining length to the MSS value. */ - remaining_length = client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_connect_mss; - } - - /* Setup pointer to buffer. */ - buffer_ptr = packet_ptr -> nx_packet_append_ptr; - } - - /* Put the file information followed by the file name */ - buffer_ptr[0] = ((attributes & FX_DIRECTORY) ? 'd' : '-'); - if (attributes & FX_READ_ONLY) - { - memcpy(&buffer_ptr[1], "r--r--r--", 9); - } - else - { - memcpy(&buffer_ptr[1], "rw-rw-rw-", 9); - } - memcpy(&buffer_ptr[10], " 1 owner group ", 16); - _nx_ftp_server_number_to_ascii(&buffer_ptr[26], 10, size); - buffer_ptr[36] = ' '; - buffer_ptr[37] = (UCHAR)months[month - 1][0]; - buffer_ptr[38] = (UCHAR)months[month - 1][1]; - buffer_ptr[39] = (UCHAR)months[month - 1][2]; - buffer_ptr[40] = ' '; - _nx_ftp_server_number_to_ascii(&buffer_ptr[41], 2, day); - buffer_ptr[43] = ' '; - _nx_ftp_server_number_to_ascii(&buffer_ptr[44], 2, hour); - buffer_ptr[46] = ':'; - _nx_ftp_server_number_to_ascii(&buffer_ptr[47], 2, minute); - buffer_ptr[49] = ' '; - memcpy(&buffer_ptr[50], filename, length); - length += 50; - buffer_ptr[length++] = '\r'; - buffer_ptr[length++] = '\n'; - - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + length; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + length; - - /* Adjust the remaining length. */ - remaining_length = remaining_length - length; - } - } - - /* Now determine if the directory listing was a success. */ - if ((status == FX_NO_MORE_ENTRIES) && (packet_ptr) && (packet_ptr -> nx_packet_length)) - { - - /* Send the directory data to the client. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_data_socket), - packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - else - { - - /* Reset the status for the response processing below. */ - status = FX_NO_MORE_ENTRIES; - } - } - else if (packet_ptr) - { - - /* Release packet just in case! */ - nx_packet_release(packet_ptr); - } - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Send end block header for file size. */ - _nx_ftp_server_block_header_send(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, 0); - } - - /* Disconnect the data socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); - - /* Tear down the client data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Allocate a new packet. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Now determine if the directory listing was a success. */ - if (status == FX_NO_MORE_ENTRIES) - { - - /* The directory listing was successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "List End"); - } - else - { - - /* Directory listing command failed. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "List fail"); - } - } - else - { - /* Unsuccessful directory listing command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Bad Directory"); - } - break; - } - -#ifndef NX_DISABLE_IPV4 - case NX_FTP_PORT: - { - - - /* Check that only IPv4 packets can use the PORT command. */ - if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - /* Illegal PORT command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_NOT_IMPLEMENTED, "PORT illegal in IPv6"); - - /* Bail out! */ - break; - } - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First, pickup the IP address. */ - commas = 0; - ip_address = 0; - j = 0; - temp = 0; - status = NX_SUCCESS; - while (j < packet_ptr -> nx_packet_length) - { - - /* Is a numeric character present? */ - if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) - { - - /* Yes, numeric character is present. Update the IP address. */ - temp = (temp*10) + (ULONG) (buffer_ptr[j] - '0'); - } - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - { - status = NX_FTP_INVALID_COMMAND; - break; - } - - /* Determine if a comma is present. */ - if (buffer_ptr[j] == ',') - { - - /* Increment the comma count. */ - commas++; - - /* Setup next byte of IP address. */ - ip_address = (ip_address << 8) & 0xFFFFFFFF; - ip_address = ip_address | (temp & 0xFF); - temp = 0; - - /* Have we finished with the IP address? */ - if (commas == 4) - { - - /* Finished with IP address. */ - j++; - break; - } - - } - - /* Move to next character. */ - j++; - } - - /* Now pickup the port number. */ - port = 0; - temp = 0; - while (j < packet_ptr -> nx_packet_length) - { - - /* Is a numeric character present? */ - if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) - { - - /* Yes, numeric character is present. Update the IP port. */ - temp = (temp*10) + (UINT) (buffer_ptr[j] - '0'); - } - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - { - /* Good condition on the port number! */ - break; - } - - /* Determine if a comma is present. */ - if (buffer_ptr[j] == ',') - { - - /* Increment the comma count. */ - commas++; - - /* Move port number up. */ - port = (port << 8) & 0xFFFFFFFF; - port = port | (temp & 0xFF); - temp = 0; - - /* Have we finished with the IP address? */ - if (commas >= 6) - { - - /* Error, get out of the loop. */ - status = NX_FTP_INVALID_ADDRESS; - break; - } - } - - /* Move to next character. */ - j++; - } - - /* Move port number up. */ - port = (port << 8) & 0xFFFFFFFF; - port = port | (temp & 0xFF); - temp = 0; - - /* Determine if an error occurred. */ - if ((buffer_ptr[j] != 13) || (commas != 5) || (ip_address == 0) || (port == 0) || - (ip_address != connect_ip4_address)) - { - - /* Set the error status. */ - status = NX_FTP_INVALID_COMMAND; - } - - /* Save the data port. */ - client_req_ptr -> nx_ftp_client_request_data_port = port; - - /* Determine if the port command was successful. */ - if (status == NX_SUCCESS) - { - - /* Yes, the port command is successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Port set"); - } - else - { - - /* Unsuccessful port command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "Port Fail"); - } - - break; - } - - case NX_FTP_PASV: - { - - /* Try to find the data port. */ - status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr, - ftp_server_ptr -> nx_ftp_server_data_port++, &port); - - /* Determine if the PASV command was successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful port find. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "PASV Fail"); - - /* And we are done processing. */ - break; - } - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); - - /* Determine if the listen is successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful data socket create. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "PASV Fail"); - - /* And we are done processing. */ - break; - } - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Start listening on the data port. */ - status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0); - - /* Determine if the listen is successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful data socket listen. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "PASV Fail"); - - /* Delete data socket. */ - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* And we are done processing. */ - break; - } - - /* Wait for the data connection to connect. */ - nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Pickup the IPv4 address of this IP instance. */ - ip_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address; - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build PASV response. "227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)." */ - - /* Build the string. "227 Entering Passive Mode " */ - memcpy(buffer_ptr, "227 Entering Passive Mode ", 26); - - /* Build the IP address and port. */ - buffer_ptr[26] = '('; - - buffer_ptr[27] = (UCHAR)('0' + (ip_address >> 24)/100); - buffer_ptr[28] = (UCHAR)('0' + ((ip_address >> 24)/10)%10); - buffer_ptr[29] = (UCHAR)('0' + (ip_address >> 24)%10); - buffer_ptr[30] = ','; - - buffer_ptr[31] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)/100); - buffer_ptr[32] = (UCHAR)('0' + (((ip_address >> 16) & 0xFF)/10)%10); - buffer_ptr[33] = (UCHAR)('0' + ((ip_address >> 16) & 0xFF)%10); - buffer_ptr[34] = ','; - - buffer_ptr[35] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)/100); - buffer_ptr[36] = (UCHAR)('0' + (((ip_address >> 8) & 0xFF)/10)%10); - buffer_ptr[37] = (UCHAR)('0' + ((ip_address >> 8) & 0xFF)%10); - buffer_ptr[38] = ','; - - buffer_ptr[39] = (UCHAR)('0' + (ip_address & 0xFF)/100); - buffer_ptr[40] = (UCHAR)('0' + ((ip_address & 0xFF)/10)%10); - buffer_ptr[41] = (UCHAR)('0' + (ip_address & 0xFF)%10); - buffer_ptr[42] = ','; - - buffer_ptr[43] = (UCHAR)('0' + (port >> 8)/100); - buffer_ptr[44] = (UCHAR)('0' + ((port >> 8)/10)%10); - buffer_ptr[45] = (UCHAR)('0' + ((port >> 8)%10)); - buffer_ptr[46] = ','; - - buffer_ptr[47] = (UCHAR)('0' + (port & 255)/100); - buffer_ptr[48] = (UCHAR)('0' + ((port & 255)/10)%10); - buffer_ptr[49] = (UCHAR)('0' + ((port & 255)%10)); - - buffer_ptr[50] = ')'; - buffer_ptr[51] = '.'; - - /* Set the CR/LF. */ - buffer_ptr[52] = 13; - buffer_ptr[53] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 54; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the PASV response message. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Delete data socket. */ - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Yes, passive transfer enabled. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE; - - break; - } -#endif /* NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 - case NX_FTP_EPRT: - { - - - /* Check that only IPv6 packets can use the EPRT command. */ - if (client_req_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V4) - { - /* Illegal EPRT command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_NOT_IMPLEMENTED, "EPRT illegal in IPv4"); - - /* Bail out! */ - break; - } - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First, pickup the IPv6 address. */ - status = _nx_ftp_utility_parse_IPv6_address((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &ipduo_address); - - if (status != NX_SUCCESS) - { - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "Bad IPv6 address"); - - return; - } - - /* Now pickup the port number. */ - status = _nx_ftp_utility_parse_port_number((CHAR *)buffer_ptr, packet_ptr -> nx_packet_length, &port); - - /* Save the data port. */ - client_req_ptr -> nx_ftp_client_request_data_port = port; - - /* Determine if the EPRT command was successful. */ - if (status == NX_SUCCESS) - { - - /* Yes, the EPRT command is successful! */ - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "EPRT command set"); - } - else - { - - /* Unsuccessful EPRT command. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "EPRT command failed"); - } - - break; - - } - - case NX_FTP_EPSV: - { - - /* Try to find the data port. */ - status = nx_tcp_free_port_find(ftp_server_ptr -> nx_ftp_server_ip_ptr, - ftp_server_ptr -> nx_ftp_server_data_port++, &port); - - /* Determine if the EPSV command was successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful port find. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); - - /* And we are done processing. */ - break; - } - - /* Create an FTP client data socket. */ - status = nx_tcp_socket_create(ftp_server_ptr -> nx_ftp_server_ip_ptr, &(client_req_ptr -> nx_ftp_client_request_data_socket), "FTP Server Data Socket", - NX_FTP_DATA_TOS, NX_FTP_FRAGMENT_OPTION, NX_FTP_TIME_TO_LIVE, NX_FTP_DATA_WINDOW_SIZE, NX_NULL, NX_NULL); - - /* Determine if the listen is successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful data socket create. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); - - /* And we are done processing. */ - break; - } - - /* Make sure each socket points to the corresponding FTP server. */ - client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_reserved_ptr = ftp_server_ptr; - - /* Start listening on the data port. */ - status = nx_tcp_server_socket_listen(ftp_server_ptr -> nx_ftp_server_ip_ptr, port, &(client_req_ptr -> nx_ftp_client_request_data_socket), 5, 0); - - /* Determine if the listen is successful. */ - if (status != NX_SUCCESS) - { - - /* Unsuccessful data socket listen. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_FAIL, "EPSV Fail"); - - /* Delete data socket. */ - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* And we are done processing. */ - break; - } - - /* Wait for the data connection to connect. */ - nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now build EPSV response. "229 Entering Extended Passive Mode (|||6446|)." */ - - /* Build the string. "229 Entering Extended Passive Mode " */ - memcpy(buffer_ptr, "229 Entering Extended Passive Mode ", 35); - - /* Build the IPv6 address and port. */ - buffer_ptr[35] = '('; - buffer_ptr[36] = '|'; - buffer_ptr[37] = '|'; - buffer_ptr[38] = '|'; - - port_size = _nx_ftp_server_utility_fill_port_number((CHAR*)(&buffer_ptr[39]), port); - - buffer_ptr[39 + port_size] = '|'; - buffer_ptr[40 + port_size] = ')'; - - /* Set the CR/LF. */ - buffer_ptr[41 + port_size] = 13; - buffer_ptr[42 + port_size] = 10; - - /* Set the packet length. */ - packet_ptr -> nx_packet_length = 43 + port_size; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Send the EPSV response message. */ - status = nx_tcp_socket_send(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Delete data socket. */ - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, port); - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Yes, passive transfer enabled. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_TRUE; - - break; - } -#endif /* FEATURE_NX_IPV6 */ - - case NX_FTP_CDUP: - case NX_FTP_CWD: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, - &(client_req_ptr -> nx_ftp_client_local_path)); - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* If CDUP command, create the "up one directory" pathname string. */ - if (ftp_command == NX_FTP_CDUP) - { - buffer_ptr[0] = '.'; - buffer_ptr[1] = '.'; - buffer_ptr[2] = NX_NULL; - } - - /* Otherwise CWD command, parse the pathname string. */ - else - { - - /* Find the end of the message. */ - j = 0; - while (j < packet_ptr -> nx_packet_length - 1) - { - - /* Determine if a CR/LF is present. */ - if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - break; - - /* Move to next character. */ - j++; - } - - /* If specified path ends with slash or backslash, strip it. */ - if ((j > 1) && ((buffer_ptr[j - 1] == '/') || (buffer_ptr[j - 1] == '\\'))) - { - j--; - } - - /* Ensure the name is NULL terminated. */ - buffer_ptr[j] = NX_NULL; - } - - /* Set the local path to the path specified. */ - status = fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, - &(client_req_ptr -> nx_ftp_client_local_path), (CHAR *) buffer_ptr); - - /* Determine if it was successful. */ - if (status == NX_SUCCESS) - { - - CHAR *local_dir; - - - /* Successful change directory. */ - - /* Get the actual path */ - fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); - - /* Now send a successful response to the client. */ - _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "set successfully", local_dir); - } - else - { - - /* Unsuccessful directory change. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "Change Dir Fail"); - } - break; - } - - case NX_FTP_PWD: - { - - /* Change to the default directory of this connection. */ - fx_directory_local_path_restore(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path)); - - { - - CHAR *local_dir; - - /* Pickup the current directory. */ - fx_directory_local_path_get(ftp_server_ptr -> nx_ftp_server_media_ptr, &local_dir); - - /* Now send a successful response to the client. */ - _nx_ftp_server_directory_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_MADE_DIR, "is current Directory", local_dir); - } - - break; - } - - case NX_FTP_TYPE: - { - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if a binary transfer is specified. */ - if (buffer_ptr[0] == 'I') - { - - /* Yes, a binary image is specified and supported. */ - client_req_ptr -> nx_ftp_client_request_transfer_type = 'I'; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Type Binary"); - } - - /* Not Binary - check if ASCII type is specified */ - else if (buffer_ptr[0] == 'A') - { - - /* Yes, a ASCII image is specified and supported. */ - client_req_ptr -> nx_ftp_client_request_transfer_type = 'A'; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Type ASCII"); - } - else - { - - /* Otherwise, a non-binary type is requested. */ - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Type Non ASCII or Binary"); - } - break; - } - - case NX_FTP_MODE: - { - - /* Setup pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if stream mode is specified. */ - if (buffer_ptr[0] == 'S') - { - - /* Yes, stream mode is specified and supported. */ - client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Mode Stream"); - } - - /* Not stream - check if block mode is specified */ - else if (buffer_ptr[0] == 'B') - { - - /* Yes, stream mode is specified and supported. */ - client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_BLOCK; - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "Mode Block"); - } - else - { - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_TYPE, "Mode Non Stream or Block"); - } - break; - } - - case NX_FTP_NOOP: - - /* Now send a successful response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CMD_OK, "NOOP Success"); - break; - - default: - - /* Unimplemented Command. */ - - /* Increment the number of unknown commands. */ - ftp_server_ptr -> nx_ftp_server_unknown_commands++; - - /* Now send an error response to the client. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_NOT_IMPLEMENTED, "Not Implemented"); - break; - } - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_connect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all FTP client connections received. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ftp_server_response Build and send response */ -/* fx_directory_local_path_set Set local path */ -/* nx_tcp_server_socket_accept Accept connection on socket */ -/* nx_tcp_server_socket_relisten Relisten for connection */ -/* nx_tcp_server_socket_unaccept Unaccept connection */ -/* nx_ftp_packet_allocate Allocate a packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_connect_process(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -UINT status; -NX_PACKET *packet_ptr; -NX_FTP_CLIENT_REQUEST *client_req_ptr; - - - /* One of the control ports is in the process of connection. */ - - /* Search the connections to see which one. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Now see if this socket was the one that is in being connected. */ - if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_CLOSED) && - (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_ESTABLISHED) && - (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port)) - { - - /* Yes, we have found the socket being connected. */ - - /* Increment the number of connection requests. */ - ftp_server_ptr -> nx_ftp_server_connection_requests++; - - /* Attempt to accept on this socket. */ - status = nx_tcp_server_socket_accept(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); - - /* Determine if it is successful. */ - if (status) - { - - /* Not successful, simply unaccept on this socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); - } - else - { - - /* Set the request type. */ - if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - - client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V6; - } - else - { - client_req_ptr -> nx_ftp_client_request_ip_type = NX_IP_VERSION_V4; - } - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; - - /* Send a connection ACK back to the client, indicating a successful connection - has been established. */ - - /* Allocate a packet for sending the connection ACK. */ - status = _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the packet allocation was successful. */ - if (status == NX_SUCCESS) - { - - /* Now send "220" ACK message to indicate connection is ready. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_CONNECTION_OK, "Connection Ready"); - - /* Set the local path to the root directory. */ - fx_directory_local_path_set(ftp_server_ptr -> nx_ftp_server_media_ptr, &(client_req_ptr -> nx_ftp_client_local_path), "\\"); - } - else - { - - /* Increment allocation error count. */ - ftp_server_ptr -> nx_ftp_server_allocation_errors++; - } - } - } - } - - /* Now look for a socket that is closed to relisten on. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Now see if this socket is closed. */ - if (client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - /* Relisten on this socket. */ - status = nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, - &(client_req_ptr -> nx_ftp_client_request_control_socket)); - /* Check for bad status. */ - if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - - /* Increment the error count and keep trying. */ - ftp_server_ptr -> nx_ftp_server_relisten_errors++; - continue; - } - - /* Break out of loop. */ - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_command_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all FTP client commands received on */ -/* the control socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* control_socket_ptr Socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX receive packet callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_command_present(NX_TCP_SOCKET *control_socket_ptr) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the command event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_COMMAND, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_connection_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all FTP client connections received on */ -/* the control socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* control_socket_ptr Socket event occurred */ -/* port Port the connection occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_connection_present(NX_TCP_SOCKET *control_socket_ptr, UINT port) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the connect event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONNECT, TX_OR); - - NX_PARAMETER_NOT_USED(port); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_data_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all FTP client disconnections received on */ -/* the data socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* data_socket_ptr Socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_data_disconnect(NX_TCP_SOCKET *data_socket_ptr) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_FTP_SERVER *) data_socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the disconnect event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA_DISCONNECT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_data_disconnect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes all FTP client disconnections received on */ -/* the data socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file */ -/* nx_ftp_packet_allocate Allocate a packet */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_socket_delete Delete socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_data_disconnect_process(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -UINT status; -UINT block_status; -ULONG length; -NX_PACKET *packet_ptr; -NX_FTP_CLIENT_REQUEST *client_req_ptr; - - - /* Now look for a socket that has receive data. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Initialize block status as NX_TRUE. */ - block_status = NX_TRUE; - - /* Now see if this socket has entered a disconnect state. */ - while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) - { - - /* Yes, a disconnect is present, which signals an end of file of a client FTP write request. */ - - /* First, cleanup this data socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_FTP_SERVER_TIMEOUT); - - /* Unbind/unaccept the data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - - /* And finally delete the data socket. */ - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Check if receive all block bytes. */ - if (client_req_ptr -> nx_ftp_client_request_total_bytes != client_req_ptr -> nx_ftp_client_request_block_bytes) - block_status = NX_FALSE; - - /* Reset the transfer mode as stream mode. */ - client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Reset the block bytes. */ - client_req_ptr -> nx_ftp_client_request_block_bytes = 0; - } - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; - - /* Pickup the file length. */ - length = (ULONG)client_req_ptr -> nx_ftp_client_request_file.fx_file_current_file_size; - - /* Close the file. */ - status = fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - - /* Allocate a packet for sending the file write response. */ - _nx_ftp_packet_allocate(ftp_server_ptr -> nx_ftp_server_packet_pool_ptr, client_req_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Now determine if the operation was successful. */ - if ((status == FX_SUCCESS) && (length == client_req_ptr -> nx_ftp_client_request_total_bytes) && (block_status == NX_TRUE)) - { - - /* Successful client file write. */ - - /* Now send "250" message to indicate successful file write. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_COMPLETED, "File Written"); - } - else - { - - /* Unsuccessful client file write. */ - - /* Now send "550" message to indicate unsuccessful file write. */ - _nx_ftp_server_response(&(client_req_ptr -> nx_ftp_client_request_control_socket), packet_ptr, - NX_FTP_CODE_BAD_FILE, "File Write Failed"); - } - - /* Clear the open type. */ - client_req_ptr -> nx_ftp_client_request_open_type = 0; - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_data_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the FTP server thread of data received */ -/* from a client on a data socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* data_socket_ptr Socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_data_present(NX_TCP_SOCKET *data_socket_ptr) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_FTP_SERVER *)data_socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_DATA, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_data_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes all FTP client data packets received on */ -/* the data socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_write Write client data to file */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive from data socket */ -/* _nx_ftp_server_block_header_retrieve Retrieve the block header */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_data_process(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -UINT status; -ULONG length; -NX_PACKET *packet_ptr; -NX_PACKET *next_packet_ptr; -NX_FTP_CLIENT_REQUEST *client_req_ptr; - - - /* Now look for a socket that has receive data. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Now see if this socket has data. If so, process all of it now! */ - while (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_receive_queue_count) - { - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = NX_FTP_ACTIVITY_TIMEOUT; - - /* Attempt to read a packet from this socket. */ - status = nx_tcp_socket_receive(&(client_req_ptr -> nx_ftp_client_request_data_socket), &packet_ptr, NX_NO_WAIT); - - /* Check for not data present. */ - if (status != NX_SUCCESS) - { - - /* Just continue the loop and look at the next socket. */ - continue; - } - - /* Check for open type. */ - if (client_req_ptr -> nx_ftp_client_request_open_type != NX_FTP_OPEN_FOR_WRITE) - { - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - - /* Continue the loop. */ - continue; - } - - /* Determine if the block mode is enabled. */ - if (client_req_ptr -> nx_ftp_client_request_transfer_mode == NX_FTP_TRANSFER_MODE_BLOCK) - { - - /* Retrieve the block header. */ - status = _nx_ftp_server_block_header_retrieve(client_req_ptr, packet_ptr); - - /* Determine if an error occurred. */ - if (status) - { - - /* Continue the loop. */ - continue; - } - } - - /* Update the total bytes for this file. This will be checked on close to see if - any error occurred. */ - client_req_ptr -> nx_ftp_client_request_total_bytes += packet_ptr -> nx_packet_length; - - /* Write the packet to the file. */ - length = packet_ptr -> nx_packet_length; - next_packet_ptr = packet_ptr; - do - { - - /* Write to the already opened file. */ - status = fx_file_write(&(client_req_ptr -> nx_ftp_client_request_file), next_packet_ptr -> nx_packet_prepend_ptr, - (ULONG)((next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr))); - - /* If unsuccessful file write, ok to receive the rest of the socket - packets from the receive queue. */ - - if (status == FX_SUCCESS) - { - - /* Increment the number of bytes received. */ - ftp_server_ptr -> nx_ftp_server_total_bytes_received += - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - } - - /* If not successful, keep retrieving packets from the socket receive queue so we can free - up the packets. */ - - /* Update the remaining length to write. */ - length = length - (ULONG) (next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - next_packet_ptr = NX_NULL; -#else - /* Pickup next packet pointer. */ - next_packet_ptr = next_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while ((next_packet_ptr) && (length)); - - /* Release the packet and continue the loop. */ - nx_packet_release(packet_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_parse_command PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines which FTP request is present, returns */ -/* a code for it, and adjusts the packet pointer to the next token. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to FTP packet */ -/* */ -/* OUTPUT */ -/* */ -/* FTP command code */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process FTP command process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_parse_command(NX_PACKET *packet_ptr) -{ - -UINT i; -char *buffer_ptr; - - - /* Setup pointer to command buffer area. */ - buffer_ptr = (char *) packet_ptr -> nx_packet_prepend_ptr; - - /* Search the packet to find the end of the token, converting the token to Uppercase. */ - i = 0; - while ((buffer_ptr[i] != ' ') && (buffer_ptr[i] != (char) 13) && (i < packet_ptr -> nx_packet_length - 1)) - { - - /* Determine if the character is lowercase. */ - if ((buffer_ptr[i] >= 'a') && (buffer_ptr[i] <= 'z')) - { - - /* Convert to uppercase. */ - buffer_ptr[i] = (char) (((UCHAR) buffer_ptr[i]) - ((UCHAR) 0x20)); - } - - /* Move to next character. */ - i++; - } - - /* Set the NULL termination for the command. */ - buffer_ptr[i] = NX_NULL; - - /* Move the packet pointer to the next token. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + (i + 1); - - /* Decrease the length of the packet. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (i + 1); - - /* Is it the "USER" command? */ - if (strcmp(buffer_ptr, "USER") == 0) - { - return(NX_FTP_USER); - } - - /* Is the the "PASS" command? */ - if (strcmp(buffer_ptr, "PASS") == 0) - { - return(NX_FTP_PASS); - } - - /* Is it the "QUIT" command? */ - if (strcmp(buffer_ptr, "QUIT") == 0) - { - return(NX_FTP_QUIT); - } - - /* Is it the "RETR" command? */ - if (strcmp(buffer_ptr, "RETR") == 0) - { - return(NX_FTP_RETR); - } - - /* Is it the "STOR" command? */ - if (strcmp(buffer_ptr, "STOR") == 0) - { - return(NX_FTP_STOR); - } - - /* Is it the "RNFR" command? */ - if (strcmp(buffer_ptr, "RNFR") == 0) - { - return(NX_FTP_RNFR); - } - - /* Is it the "RNTO" command? */ - if (strcmp(buffer_ptr, "RNTO") == 0) - { - return(NX_FTP_RNTO); - } - - /* Is it the "DELE" command? */ - if (strcmp(buffer_ptr, "DELE") == 0) - { - return(NX_FTP_DELE); - } - - /* Is it the "RMD" or "XRMD" command? */ - if ((strcmp(buffer_ptr, "RMD") == 0) || (strcmp(buffer_ptr, "XRMD") == 0)) - { - return(NX_FTP_RMD); - } - - /* Is it the "MKD" or "XMKD" command? */ - if ((strcmp(buffer_ptr, "MKD") == 0) || (strcmp(buffer_ptr, "XMKD")== 0)) - { - return(NX_FTP_MKD); - } - - /* Is it the "CDUP" command? */ - if (strcmp(buffer_ptr, "CDUP") == 0) - { - return(NX_FTP_CDUP); - } - - /* Is it the "CWD" command? */ - if (strcmp(buffer_ptr, "CWD") == 0) - { - return(NX_FTP_CWD); - } - - /* Is it the "PWD" command? */ - if (strcmp(buffer_ptr, "PWD") == 0) - { - return(NX_FTP_PWD); - } - - /* Is it the "NLST" command? */ - if (strcmp(buffer_ptr, "NLST") == 0) - { - return(NX_FTP_NLST); - } - - /* Is it the "LIST" command? */ - if (strcmp(buffer_ptr, "LIST") == 0) - { - return(NX_FTP_LIST); - } - - /* Is it the "PORT" command? */ - if (strcmp(buffer_ptr, "PORT") == 0) - { - return(NX_FTP_PORT); - } - - /* Is it the "EPRT" command? */ - if (strcmp(buffer_ptr, "EPRT") == 0) - { - return(NX_FTP_EPRT); - } - - /* Is it the "TYPE" command? */ - if (strcmp(buffer_ptr, "TYPE") == 0) - { - return(NX_FTP_TYPE); - } - - /* Is it the "NOOP" command? */ - if (strcmp(buffer_ptr, "NOOP") == 0) - { - return(NX_FTP_NOOP); - } - - /* Is it the "PASV" command? */ - if (strcmp(buffer_ptr, "PASV") == 0) - { - return(NX_FTP_PASV); - } - - /* Is it the "EPSV" command? */ - if (strcmp(buffer_ptr, "EPSV") == 0) - { - return(NX_FTP_EPSV); - } - - /* Is it the "MODE" command? */ - if (strcmp(buffer_ptr, "MODE") == 0) - { - return(NX_FTP_MODE); - } - - /* Otherwise, just return INVALID. */ - return(NX_FTP_INVALID); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the periodic timer for this FTP server. Its duty */ -/* is to inform the FTP server that it is time to check for activity */ -/* timeouts. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_address FTP server's address */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX ThreadX timer callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_timeout(ULONG ftp_server_address) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. */ - server_ptr = (NX_FTP_SERVER *) ftp_server_address; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_ACTIVITY_TIMEOUT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_timeout_processing PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reviews all the active FTP client connections and */ -/* looks for an activity timeout. If a connection has not had any */ -/* activity within NX_FTP_ACTIVITY_TIMEOUT seconds, the connection is */ -/* deleted and its resources are made available to a new connection. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file */ -/* nx_packet_release Release saved packet */ -/* nx_tcp_server_socket_relisten Relisten for another connect */ -/* nx_tcp_client_socket_unbind Unbind data socket */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_socket_delete Delete data socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_timeout_processing(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -NX_FTP_CLIENT_REQUEST *client_req_ptr; - - - /* Examine all the client request structures. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Now see if this socket has an activity timeout active. */ - if (client_req_ptr -> nx_ftp_client_request_activity_timeout) - { - - /* Decrement the activity timeout for this client request. */ - if (client_req_ptr -> nx_ftp_client_request_activity_timeout > NX_FTP_TIMEOUT_PERIOD) - client_req_ptr -> nx_ftp_client_request_activity_timeout = client_req_ptr -> nx_ftp_client_request_activity_timeout - NX_FTP_TIMEOUT_PERIOD; - else - client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; - - /* Determine if this entry has exceeded the activity timeout. */ - if (client_req_ptr -> nx_ftp_client_request_activity_timeout == 0) - { - - /* Yes, activity timeout has been exceeded. Tear down and cleanup the - entire client request structure. */ - - /* Increment the activity timeout counter. */ - ftp_server_ptr -> nx_ftp_server_activity_timeouts++; - - /* If create, cleanup the data socket. */ - if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) - { - - /* Disconnect client socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Unbind/unaccept the data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - - /* Delete the data socket. */ - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* Ensure the file is closed. */ - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - } - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Reset the transfer mode as stream mode. */ - client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Reset the block bytes. */ - client_req_ptr -> nx_ftp_client_request_block_bytes = 0; - - /* Now disconnect the command socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_NO_WAIT); - - /* Unaccept the server socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); - - /* Check to see if a packet is queued up. */ - if (client_req_ptr -> nx_ftp_client_request_packet) - { - - /* Yes, release it! */ - nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); - } - - /* Relisten on this socket. This will probably fail, but it is needed just in case all available - clients were in use at the time of the last relisten. */ - nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, - &(client_req_ptr -> nx_ftp_client_request_control_socket)); - } - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_control_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the FTP server thread of client disconnects */ -/* of the control socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* control_socket_ptr Control socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_control_disconnect(NX_TCP_SOCKET *control_socket_ptr) -{ - -NX_FTP_SERVER *server_ptr; - - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_FTP_SERVER *)control_socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_ftp_server_event_flags), NX_FTP_SERVER_CONTROL_DISCONNECT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_control_disconnect_processing PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reviews all the active FTP client connections and */ -/* looks for a client initiated disconnect activity that was done */ -/* without a QUIT command. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ftp_server_ptr Pointer to FTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file */ -/* nx_packet_release Release saved packet */ -/* nx_tcp_server_socket_relisten Relisten for another connect */ -/* nx_tcp_client_socket_unbind Unbind data socket */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_socket_delete Delete data socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_thread_entry FTP server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER *ftp_server_ptr) -{ - -UINT i; -NX_FTP_CLIENT_REQUEST *client_req_ptr; - - - /* Examine all the client request structures. */ - for (i = 0; i < NX_FTP_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(ftp_server_ptr -> nx_ftp_server_client_list[i]); - - /* Determine if this socket is in a disconnect state. This should only happen - if the client issues a disconnect without issuing a QUIT command. */ - if ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) || - ((client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_state < NX_TCP_SYN_SENT) && - (client_req_ptr -> nx_ftp_client_request_activity_timeout > 0))) - { - - /* Yes, this socket needs to be torn down. */ - - /* Increment the number of disconnection requests. */ - ftp_server_ptr -> nx_ftp_server_disconnection_requests++; - - /* Clear authentication. */ - client_req_ptr -> nx_ftp_client_request_authenticated = NX_FALSE; - - /* Disable the client request activity timeout. */ - client_req_ptr -> nx_ftp_client_request_activity_timeout = 0; - - /* If create, cleanup the associated data socket. */ - if (client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_id) - { - - /* Disconnect client socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_data_socket), NX_NO_WAIT); - - /* Unbind/unaccept the data socket. */ - if (client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled == NX_TRUE) - { - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - nx_tcp_server_socket_unlisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, client_req_ptr -> nx_ftp_client_request_data_socket.nx_tcp_socket_port); - } - else - { - nx_tcp_client_socket_unbind(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - } - - /* Delete the data socket. */ - nx_tcp_socket_delete(&(client_req_ptr -> nx_ftp_client_request_data_socket)); - - /* Ensure the file is closed. */ - fx_file_close(&(client_req_ptr -> nx_ftp_client_request_file)); - -#ifdef NX_FTP_FAULT_TOLERANT - - /* Flush the media. */ - fx_media_flush(ftp_server_ptr -> nx_ftp_server_media_ptr); -#endif - } - - /* Clear the passive transfer enabled flag. */ - client_req_ptr -> nx_ftp_client_request_passive_transfer_enabled = NX_FALSE; - - /* Reset the transfer mode as stream mode. */ - client_req_ptr -> nx_ftp_client_request_transfer_mode = NX_FTP_TRANSFER_MODE_STREAM; - - /* Reset the block bytes. */ - client_req_ptr -> nx_ftp_client_request_block_bytes = 0; - - /* Check if this client login. */ - if (client_req_ptr -> nx_ftp_client_request_login) - { - - /* Call the logout function. */ - -#ifndef NX_DISABLE_IPV4 - /* Does this server have an IPv4 login function? */ - if (ftp_server_ptr -> nx_ftp_logout_ipv4) - { - - /* Call the logout which takes IPv4 address input. */ - (ftp_server_ptr -> nx_ftp_logout_ipv4)(ftp_server_ptr, - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4, - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, NX_NULL); - } -#endif /* NX_DISABLE_IPV4 */ - if (ftp_server_ptr -> nx_ftp_logout) - { - - /* Call the 'duo' logout function which takes IPv6 or IPv4 IP addresses. */ - (ftp_server_ptr -> nx_ftp_logout)(ftp_server_ptr, &(client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip), - client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_port, - client_req_ptr -> nx_ftp_client_request_username, - client_req_ptr -> nx_ftp_client_request_password, NX_NULL); - } - - /* Set the login as FALSE. */ - client_req_ptr -> nx_ftp_client_request_login = NX_FALSE; - } - - /* Now disconnect the command socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_ftp_client_request_control_socket), NX_FTP_SERVER_TIMEOUT); - - /* Unaccept the server socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_ftp_client_request_control_socket)); - - /* Check to see if a packet is queued up. */ - if (client_req_ptr -> nx_ftp_client_request_packet) - { - - /* Yes, release it! */ - nx_packet_release(client_req_ptr -> nx_ftp_client_request_packet); - } - - /* Relisten on this socket. This will probably fail, but it is needed just in case all available - clients were in use at the time of the last relisten. */ - nx_tcp_server_socket_relisten(ftp_server_ptr -> nx_ftp_server_ip_ptr, NX_FTP_SERVER_CONTROL_PORT, - &(client_req_ptr -> nx_ftp_client_request_control_socket)); - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses knowledge of the client request connection type */ -/* to allocate the proper TCP packet type. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* pool_ptr Pointer to packet pool */ -/* client_request_ptr Pointer to Client request */ -/* packet_ptr Pointer to allocated packet */ -/* packet_type Packet type, usually TCP */ -/* wait_option Wait option on packet alloc */ -/* */ -/* OUTPUT */ -/* */ -/* status Packet allocation status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate NetX packet allocate service */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Client command handler */ -/* _nx_ftp_server_control_disconnect_processing */ -/* Client disconnect handler */ -/* _nx_ftp_server_connect_process Client Connect request handler*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_ftp_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET **packet_ptr, UINT packet_type, UINT wait_option) -{ - -UINT status; - - - /* Determine type of packet to allocate based on client connection. */ - - if (client_request_ptr -> nx_ftp_client_request_ip_type == NX_IP_VERSION_V6) - { - - /* This is an IPV6 connection. */ - status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv6_TCP_PACKET, wait_option); - } - else - { - - /* This is an IPv4 connection. */ - status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv4_TCP_PACKET, wait_option); - } - - - NX_PARAMETER_NOT_USED(packet_type); - - /* Return completion status. */ - return status; -} - - -#ifdef FEATURE_NX_IPV6 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_utility_parse_IPv6_address PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses a string containing a properly formatted IPv6 */ -/* string and while it does not assume it is part of the EPRT command */ -/* it does not expect to find any non IPv6 characters in the string */ -/* after checking for a leading 'EPRT |2|' and before an entire IPv6 */ -/* address is parsed. If there is a leading 'EPRT ' in the string, it */ -/* does check that it has the required '|2|' preamble to the IPv6 */ -/* address. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to the string to parse*/ -/* buffer_length Size of the IPv6 string */ -/* ipduo_address Pointer to the IPv6 address */ -/* parsed from the buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Proper IPv6 address parsed */ -/* NX_FTP_ERROR IPv6 address is bad */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Parse a received FTP command */ -/* packet service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_utility_parse_IPv6_address(CHAR *buffer_ptr, UINT buffer_length, NXD_ADDRESS *ipduo_address) -{ - -UINT j, k, i, m, colons, digit; -UINT number_consecutive_zeros_to_add, remaining_colons, actual_colons_left; -ULONG temp; - - - /* Initialize variables. */ - temp = 0; - colons = 0; - remaining_colons = 0; - actual_colons_left = 0; - j = 0; - k = 0; - i = 0; - - number_consecutive_zeros_to_add = 0; - - /* Check if the buffer includes the leading EPRT command. */ - if ( (buffer_ptr[0] == 'E' || buffer_ptr[0] == 'e') && - (buffer_ptr[1] == 'P' || buffer_ptr[1] == 'p') && - (buffer_ptr[2] == 'R' || buffer_ptr[2] == 'p') && - (buffer_ptr[3] == 'T' || buffer_ptr[3] == 't') && - (buffer_ptr[4] == ' ')) - { - - /* If this is an EPRT command it must be followed by a single - space and the |2| preamble. */ - if ((buffer_ptr[5] != '|') || (buffer_ptr[6] != '2') || (buffer_ptr[7] != '|')) - { - - /* It does not. Return error status. */ - return NX_FTP_INVALID_COMMAND; - } - - /* Set the start of where to resume parsing. */ - j = 8; - } - else - { - /* If the EPRT command has been removed already, check for the |2| preamble. */ - if ((buffer_ptr[0] == '|') && (buffer_ptr[1] == '2') && (buffer_ptr[2] == '|')) - { - - /* Set the start of where to resume parsing. */ - j = 3; - } - } - - /* Parse the buffer till the end is reached (or a complete - IPv6 address is parsed. */ - while (j < buffer_length) - { - - /* Is a numeric or hex character present? */ - if (((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) || - ((buffer_ptr[j] >= 'A') && (buffer_ptr[j] <= 'F')) || - ((buffer_ptr[j] >= 'a') && (buffer_ptr[j] <= 'f'))) - { - - /* Yes, is a numeric character is present? Update the IP address. */ - if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9') - { - temp = (temp*16) + (ULONG) (buffer_ptr[j] - '0'); - } - else - { - /* Is a hex character present? */ - switch (buffer_ptr[j] ) - { - case 'A': - case 'a': - digit = 10; - break; - - case 'B': - case 'b': - digit = 11; - break; - - case 'C': - case 'c': - digit = 12; - break; - - case 'D': - case 'd': - digit = 13; - break; - - case 'E': - case 'e': - digit = 14; - break; - - case 'F': - case 'f': - digit = 15; - break; - - default: - digit = 0; - } - - /* Update the ULONG. */ - temp = (temp*16 + digit); - } - - /* Increase the size of the digit by one. */ - i++; - - /* Check if the size of this digit is out of range. */ - if (i > 4) - { - - /* Yes, return an error status. */ - return NX_FTP_INVALID_ADDRESS; - } - } - - /* Determine if a CR/LF is present. */ - else if ((buffer_ptr[j] == 13) || (buffer_ptr[j] == 10) || (buffer_ptr[j] == 0)) - { - - /* Whether this is a prematurely terminated IPv6 string, abort any further parsing. */ - break; - } - - /* Determine if a colon is present. */ - else if (buffer_ptr[j] == ':') - { - - /* Increment the colon count. */ - colons++; - - /* Are we in the middle of a ULONG? */ - if (colons % 2 == 1) - { - - /* Yes, add this temp to the lower half. */ - ipduo_address -> nxd_ip_address.v6[k] = temp; - } - else - { - - /* No, shift the existing 16 bits left first. */ - ipduo_address -> nxd_ip_address.v6[k] <<= 16; - - /* Mask out the lower 16 bits. */ - ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; - - /* Add the number we just parsed. */ - ipduo_address -> nxd_ip_address.v6[k] += temp; - - /* Move to the next ULONG in the nxd_ip_address array. */ - k++; - } - - /* Reset our counters and temporary ULONG. */ - i = 0; - temp = 0; - - /* Check if we have encountered a double colon. */ - if (buffer_ptr[j + 1] == ':') - { - - /* Yes; Check if we already encountered a double colon. */ - if (remaining_colons) - { - - /* Yes we have. This is an improperly formatted IPv6 address. */ - return NX_FTP_INVALID_ADDRESS; - } - - /* Move the index to the second colon. */ - j++; - - /* Compute how many more colons should there be. */ - remaining_colons = 7 - colons; - - /* Start looking for the rest of the colons after the double. */ - m = j + 1; - - /* Count colons in the rest of the string. */ - while (m < buffer_length) - { - - /* Do we have another colon? */ - if (buffer_ptr [m] == ':') - { - - /* Yes, update the count. */ - actual_colons_left++; - } - m++; - } - - /* Compute the number of zeros to insert into the NXD_ADDRESS IPv6 ULONG array. */ - number_consecutive_zeros_to_add = remaining_colons - actual_colons_left; - - /* Add the zeroes until its time to start parsing rest of the IPv6 address string. */ - while (number_consecutive_zeros_to_add) - { - - /* Determine where to add the 16 bits depending - on odd or even number colon we're on. */ - - /* Are we in the middle of the current v6 ULONG?*/ - if (colons % 2 == 1) - { - - /* Yes, shift the bits in v6[k] left, and insert a zero at the least significant end. */ - ipduo_address -> nxd_ip_address.v6[k] <<= 16; - ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; - k++; - } - else - { - - /* No, starting the next ULONG in v6 so just set to zero. */ - ipduo_address -> nxd_ip_address.v6[k] = 0; - } - - /* Keep track of how many colons would have been in the IPv6 string - without the double colon. */ - colons++; - - number_consecutive_zeros_to_add--; - } - } - - } - /* Have we hit the end of the IPv6 address? */ - else if (buffer_ptr[j] == '|' && k <= 3) - { - - /* Yes, shift the existing 16 bits left first. */ - ipduo_address -> nxd_ip_address.v6[k] <<= 16; - - /* Mask out the lower 16 bits. */ - ipduo_address -> nxd_ip_address.v6[k] = ipduo_address -> nxd_ip_address.v6[k] & 0xFFFF0000; - - /* Add the number we just parsed. */ - ipduo_address -> nxd_ip_address.v6[k] += temp; - - /* Clear the temporary ULONG so we know we applied it to our IPv6 address array. */ - temp = 0; - - /* This is the end of the IP address. Bail out...*/ - break; - } - else /* No hex, not a seperator or part of the EPRT command. */ - { - /* Unknown character in the IPv6 string. */ - return NX_FTP_INVALID_ADDRESS; - } - - j++; - } - - /* Did we parse the full IP address? */ - if (colons != 7 ) - { - - /* No, it is either too long or too short. */ - return NX_FTP_INVALID_ADDRESS; - } - - /* Is there a parsed number to apply to the last ULONG e.g. no terminating '|' - in the buffer? */ - if (temp) - { - /* Yes, shift the existing 16 bits left first. */ - ipduo_address -> nxd_ip_address.v6[3] <<= 16; - - /* Mask out the lower 16 bits. */ - ipduo_address -> nxd_ip_address.v6[3] = ipduo_address -> nxd_ip_address.v6[3] & 0xFFFF0000; - - /* Add the number we just parsed. */ - ipduo_address -> nxd_ip_address.v6[3] += temp; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_utility_parse_port_number PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses a port number from the input buffer. It assumes*/ -/* the buffer holds an EPRT command string and therefore looks for the */ -/* last '|' separator in the string. If it does not find one, it */ -/* returns an error. If it encounters anything after this separator, */ -/* other than a digit or CRLF before reaching the end of the buffer it */ -/* returns an error. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to the string to parse*/ -/* buffer_length Size of the string */ -/* portnumber Pointer to the port number */ -/* parsed from the buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Proper port number parsed */ -/* NX_FTP_ERROR Port number is bad */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Parse a received FTP command */ -/* packet service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_ftp_utility_parse_port_number(CHAR *buffer_ptr, UINT buffer_length, UINT *portnumber) -{ - -UINT j; -UINT digits = 0; - - - j = (buffer_length - 1); - *portnumber = 0; - - /* Find the terminating CRLF. */ - while (j >= 1) - { - if (buffer_ptr[j - 1] == 13 && buffer_ptr[j] == 10) - { - /* Subtract for the extra LF character. */ - j--; - - /* We're ready to move on to the port number extraction. */ - break; - } - j--; - } - - /* Find the port number. There may be separators between the port number - and the CRLF. */ - while (j >= 1) - { - /* Skip everything except for digits. */ - if (buffer_ptr[j] >= '0' && buffer_ptr[j] <= '9') - { - break; - } - - /* But we should not encounter a colon! */ - if (buffer_ptr[j] == ':') - { - - /* Return an error status. */ - return NX_FTP_INVALID_NUMBER; - } - - j--; - } - - while ((INT)j >= 0) - { - - /* Is this a space separator '|'? */ - if (buffer_ptr[j] == '|') - { - /* Yes, so the port number must be adjacent. */ - j++; - - /* Now go back up the buffer. */ - while(j < buffer_length - 2) - { - - /* Check if we have backed up into the IPv6 address? */ - if ((buffer_ptr[j] == ':')) - { - /* Yes, apparently this string is missing the separator and port number. */ - return NX_FTP_INVALID_NUMBER; - } - - /* Is a numeric character present? */ - if ((buffer_ptr[j] >= '0') && (buffer_ptr[j] <= '9')) - { - - /* Yes, numeric character is present. Update the port number. */ - *portnumber = (*portnumber * 10) + (ULONG) (buffer_ptr[j] - '0'); - digits++; - - /* Check for overflow. */ - if (digits > 5) - { - return NX_FTP_INVALID_NUMBER; - } - /* Determine if a CR/LF or | separator is present. This marks - the end of the port number. */ - if ((buffer_ptr[j+1] == '|') || (buffer_ptr[j+1] == 13) || (buffer_ptr[j+2] == 10)) - { - return NX_SUCCESS; - } - - - } - else - { - - /* This is a non numeric character, and not a CRLF either. */ - return NX_FTP_INVALID_NUMBER; - } - j++; - } - - /* If we got here we did not parse a properly formatted port number. */ - return NX_FTP_INVALID_NUMBER; - } - - j--; - } - - /* If we got here we did not parse a properly formatted port number. */ - return NX_FTP_INVALID_NUMBER; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_utility_fill_port_number PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number to ascii text e.g. and fill the */ -/* text port into the buffer. */ -/* */ -/* INPUT */ -/* */ -/* number Port number to convert to ASCII */ -/* numstring Pointer to ascii portnumber string */ -/* */ -/* OUTPUT */ -/* */ -/* size Size of port number */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Processes FTP commands */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_utility_fill_port_number(CHAR *buffer_ptr, UINT port_number) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < 10) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - buffer_ptr[j] = buffer_ptr[j-1]; - } - - /* Compute the next decimal digit. */ - digit = (port_number % 10); - - /* Update the input number. */ - port_number = (port_number / 10); - - /* Store the new digit in ASCII form. */ - buffer_ptr[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (port_number == 0) - break; - } - - /* Determine if there is an overflow error. */ - if (port_number) - { - - /* Error, return bad values to user. */ - return(0); - } - - /* Return size to caller. */ - return(size); -} -#endif /* FEATURE_NX_IPV6 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_block_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the block size for LIST and NLST in block mode. */ -/* */ -/* INPUT */ -/* */ -/* client_request_ptr Pointer to FTP client */ -/* block_size The size of block data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* fx_directory_first_full_entry_find Find first directory entry */ -/* fx_directory_next_full_entry_find Find next directory entry */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Process command */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_ftp_server_block_size_get(NX_FTP_SERVER *ftp_server_ptr, UINT ftp_command, CHAR *filename, ULONG *block_size) -{ - -UINT j = 0; -UINT attributes; -ULONG size; -UINT year, month, day; -UINT hour, minute, second; -UINT length; -UINT status; - - - /* Block size for LIST and NLST. */ - *block_size = 0; - - /* Now get the full directory listing. */ - do - { - if (j == 0) - { - - /* First directory entry. */ - status = fx_directory_first_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - j++; - } - else - { - - /* Not the first entry - pickup the next! */ - status = fx_directory_next_full_entry_find(ftp_server_ptr -> nx_ftp_server_media_ptr, filename, - &attributes, &size, &year, &month, &day, &hour, &minute, &second); - } - - /* Determine if successful. */ - if (status == NX_SUCCESS) - { - - /* Calculate the size of the name. */ - if (_nx_utility_string_length_check(filename, &length, FX_MAX_LONG_NAME_LEN - 1)) - { - return; - } - - /* Check the command. */ - if (ftp_command == NX_FTP_NLST) - { - - /* NLST. Add extra "cr/lf" (2 bytes). */ - (*block_size) += (length + 2); - } - else - { - - /* Check if the month is valid. */ - if ((month < 1) || (month > 12)) - continue; - - /* LIST. Add extra file info (52 bytes). - File Info is 10 chars for permissions, 15 chars for owner and group, - 11 chars for size (for file size up to 4gB), 14 for date, 2 chars for cr lf. */ - (*block_size) += (length + 52); - } - } - } while (status == NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_block_header_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the block header for block mode. */ -/* */ -/* INPUT */ -/* */ -/* client_request_ptr Pointer to FTP client */ -/* block_size The size of block data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send data packet to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process Process command */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_block_header_send(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, ULONG block_size) -{ - -UINT status; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; - - - /* Use block mode to transfer data. RFC959, Section3.4.2, Page21-22. */ - - /* Allocate the packet. */ - status = _nx_ftp_packet_allocate(pool_ptr, client_request_ptr, &packet_ptr, NX_TCP_PACKET, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Set the block header. */ - if (block_size) - { - - /* Descriptor. */ - buffer_ptr[0] = 0; - - /* Byte count. */ - buffer_ptr[1] = (UCHAR)(block_size >> 8); - buffer_ptr[2] = (UCHAR)(block_size); - } - else - { - - /* Descriptor. */ - buffer_ptr[0] = 64; - - /* Byte count. */ - buffer_ptr[1] = 0; - buffer_ptr[2] = 0; - } - - /* Setup the length of the packet. */ - packet_ptr -> nx_packet_length = 3; - - /* Setup the packet append pointer. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Write packet payload to the file. */ - status = nx_tcp_socket_send(&(client_request_ptr -> nx_ftp_client_request_data_socket), packet_ptr, NX_FTP_SERVER_TIMEOUT); - - /* Determine if the send was unsuccessful. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Return success to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_block_header_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the block header for block mode. */ -/* */ -/* INPUT */ -/* */ -/* client_request_ptr Pointer to FTP client */ -/* packet_ptr Pointer to packet to write */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_data_process Process client write data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST *ftp_client_ptr, NX_PACKET *packet_ptr) -{ - -ULONG remaining_bytes; -ULONG delta; -UCHAR *buffer_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN -NX_PACKET *before_last_packet; -NX_PACKET *last_packet; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - - /* Check if it is the first packet. */ - if (ftp_client_ptr -> nx_ftp_client_request_block_bytes == 0) - { - - /* Check the packet length. */ - if ((packet_ptr -> nx_packet_length < 3) || - (packet_ptr -> nx_packet_prepend_ptr + 3 > packet_ptr -> nx_packet_append_ptr)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_SERVER_INVALID_SIZE); - } - - /* We have a packet, setup pointer to the buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Process block header. */ - ftp_client_ptr -> nx_ftp_client_request_block_bytes = (ULONG)((buffer_ptr[1] << 8) | buffer_ptr[2]); - - /* Skip the block header. */ - packet_ptr -> nx_packet_prepend_ptr += 3; - packet_ptr -> nx_packet_length -= 3; - } - - /* Check if have remaining data. */ - remaining_bytes = ftp_client_ptr -> nx_ftp_client_request_block_bytes - ftp_client_ptr -> nx_ftp_client_request_total_bytes; - if (remaining_bytes == 0) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_FTP_SERVER_END_OF_BLOCK); - } - - /* Check the data of current packet. */ - if (remaining_bytes < packet_ptr -> nx_packet_length) - { - - /* Remove the extra data, such as: end block header. */ - - /* Calculate the difference in the length. */ - delta = packet_ptr -> nx_packet_length - remaining_bytes; - - /* Adjust the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta; - - /* Adjust the append pointer. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Loop to process adjustment that spans multiple packets. */ - while (delta) - { - - /* Determine if the packet is chained (or still chained after the adjustment). */ - if (packet_ptr -> nx_packet_last == NX_NULL) - { - - /* No, packet is not chained, simply adjust the append pointer in the packet. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; - - /* Break out of the loop, since the adjustment is complete. */ - break; - } - - /* Pickup the pointer to the last packet. */ - last_packet = packet_ptr -> nx_packet_last; - - /* Determine if the amount to adjust is less than the payload in the last packet. */ - /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ - if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta) - { - - /* Yes, simply adjust the append pointer of the last packet in the chain. */ - /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */ - last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta; - - /* Get out of the loop, since the adjustment is complete. */ - break; - } - else - { - - /* Adjust the delta by the amount in the last packet. */ - delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)); - - /* Find the packet before the last packet. */ - before_last_packet = packet_ptr; - while (before_last_packet -> nx_packet_next != last_packet) - { - - /* Move to the next packet in the chain. */ - before_last_packet = before_last_packet -> nx_packet_next; - } - - /* At this point, we need to release the last packet and adjust the other packet - pointers. */ - - /* Ensure the next packet pointer is NULL in what is now the last packet. */ - before_last_packet -> nx_packet_next = NX_NULL; - - /* Determine if the packet is still chained. */ - if (packet_ptr != before_last_packet) - { - - /* Yes, the packet is still chained, setup the last packet pointer. */ - packet_ptr -> nx_packet_last = before_last_packet; - } - else - { - - /* The packet is no longer chained, set the last packet pointer to NULL. */ - packet_ptr -> nx_packet_last = NX_NULL; - } - - /* Release the last packet. */ - _nx_packet_release(last_packet); - } - } -#else - - /* Simply adjust the append pointer in the packet. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta; -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ftp_server_number_to_ascii PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number to ascii text. Fill space at the */ -/* beginning if possible. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to output string buffer */ -/* buffer_size Size of output buffer */ -/* number Number to convert to ASCII */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ftp_server_command_process */ -/* Process command */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_ftp_server_number_to_ascii(UCHAR *buffer_ptr, UINT buffer_size, UINT number) -{ -UINT digit; -UINT size; - - /* Initialize counters. */ - size = 1; - - /* Initialize buffer with spaces. */ - memset(buffer_ptr, ' ', buffer_size); - - /* Loop to convert the number to ASCII. */ - while (size < buffer_size) - { - - /* Compute the next decimal digit. */ - digit = (number % 10); - - /* Update the input number. */ - number = (number / 10); - - /* Store the new digit in ASCII form. */ - buffer_ptr[buffer_size - size] = (UCHAR)(digit + '0'); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } -} diff --git a/protocol_handlers/ftp/nxd_ftp_server.h b/protocol_handlers/ftp/nxd_ftp_server.h deleted file mode 100644 index a6c5fbd6..00000000 --- a/protocol_handlers/ftp/nxd_ftp_server.h +++ /dev/null @@ -1,438 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** File Transfer Protocol (FTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_ftp_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Duo File Transfer Protocol (FTP over */ -/* IPv6) component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_FTP_SERVER_H -#define NXD_FTP_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -#ifndef NX_FTP_NO_FILEX -#include "fx_api.h" -#else -#include "filex_stub.h" -#endif - - -/* Define the FTP Server ID. */ - -#define NXD_FTP_SERVER_ID 0x46545201UL - - -/* Define the maximum number of clients the FTP Server can accommodate. */ - -#ifndef NX_FTP_MAX_CLIENTS -#define NX_FTP_MAX_CLIENTS 4 -#endif - - -/* Define FTP TCP socket create options. */ - - -#ifndef NX_FTP_CONTROL_TOS -#define NX_FTP_CONTROL_TOS NX_IP_NORMAL -#endif - -#ifndef NX_FTP_DATA_TOS -#define NX_FTP_DATA_TOS NX_IP_NORMAL -#endif - -#ifndef NX_FTP_FRAGMENT_OPTION -#define NX_FTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_FTP_CONTROL_WINDOW_SIZE -#define NX_FTP_CONTROL_WINDOW_SIZE 400 -#endif - -#ifndef NX_FTP_DATA_WINDOW_SIZE -#define NX_FTP_DATA_WINDOW_SIZE 2048 -#endif - - -#ifndef NX_FTP_TIME_TO_LIVE -#define NX_FTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_FTP_SERVER_TIMEOUT -#define NX_FTP_SERVER_TIMEOUT NX_IP_PERIODIC_RATE -#endif - -#ifndef NX_FTP_SERVER_PRIORITY -#define NX_FTP_SERVER_PRIORITY 16 -#endif - -#ifndef NX_FTP_SERVER_TIME_SLICE -#define NX_FTP_SERVER_TIME_SLICE 2 -#endif - -#ifndef NX_FTP_USERNAME_SIZE -#define NX_FTP_USERNAME_SIZE 20 -#endif - -#ifndef NX_FTP_PASSWORD_SIZE -#define NX_FTP_PASSWORD_SIZE 20 -#endif - -#ifndef NX_FTP_ACTIVITY_TIMEOUT -#define NX_FTP_ACTIVITY_TIMEOUT 240 /* Seconds allowed with no activity */ -#endif - -#ifndef NX_FTP_TIMEOUT_PERIOD -#define NX_FTP_TIMEOUT_PERIOD 60 /* Number of seconds to check */ -#endif - -#ifndef NX_PHYSICAL_TRAILER -#define NX_PHYSICAL_TRAILER 4 /* Number of bytes to reserve at the end of buffer */ -#endif - -/* Define the FTP data port retry parameters. */ - -#ifndef NX_FTP_SERVER_RETRY_SECONDS -#define NX_FTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ -#endif - -#ifndef NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH -#define NX_FTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ -#endif - -#ifndef NX_FTP_SERVER_RETRY_MAX -#define NX_FTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ -#endif - -#ifndef NX_FTP_SERVER_RETRY_SHIFT -#define NX_FTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ -#endif - -/* The minimum FTP Server packet size must accomodate the largest expected packet sent e.g. the LIST command: - The filename can be up to 256 bytes, plus file info (which has a fixed size of 52 bytes). - Note the 256 value is the assumed max size of a filename, defined by FX_MAX_LONG_NAME_LEN. - . - File download (data) packets can be split up over multiple packets, but commands should be in one packet. */ - -#ifndef NX_FTP_SERVER_MIN_PACKET_PAYLOAD -#define NX_FTP_SERVER_MIN_PACKET_PAYLOAD (256 + 52 + NX_TCP_PACKET + NX_PHYSICAL_TRAILER) -#endif - - -/* Define open types. */ - -#define NX_FTP_OPEN_FOR_READ 0x01 /* FTP file open for reading */ -#define NX_FTP_OPEN_FOR_WRITE 0x02 /* FTP file open for writing */ - - -/* Define transfer modes. Note: just support stream mode and block mode yet. */ - -#define NX_FTP_TRANSFER_MODE_STREAM 0 /* FTP stream transfer mode */ -#define NX_FTP_TRANSFER_MODE_BLOCK 1 /* FTP block transfer mode */ -#define NX_FTP_TRANSFER_MODE_COMPRESSED 2 /* FTP compressed transfer mode */ - - -/* Define Server thread events. */ - -#define NX_FTP_SERVER_CONNECT 0x01 /* FTP connection is present */ -#define NX_FTP_SERVER_DATA_DISCONNECT 0x02 /* FTP data disconnection is present */ -#define NX_FTP_SERVER_COMMAND 0x04 /* FTP client command is present */ -#define NX_FTP_SERVER_DATA 0x08 /* FTP client data is present */ -#define NX_FTP_SERVER_ACTIVITY_TIMEOUT 0x10 /* FTP activity timeout check */ -#define NX_FTP_SERVER_CONTROL_DISCONNECT 0x20 /* FTP client disconnect of control socket */ -#define NX_FTP_STOP_EVENT 0x40 /* FTP stop service */ -#define NX_FTP_ANY_EVENT 0xFF /* Any FTP event */ - - -/* Define return code constants. */ - -#define NX_FTP_ERROR 0xD0 /* Generic FTP internal error - deprecated */ -#define NX_FTP_TIMEOUT 0xD1 /* FTP timeout occurred */ -#define NX_FTP_FAILED 0xD2 /* FTP error */ -#define NX_FTP_NOT_CONNECTED 0xD3 /* FTP not connected error */ -#define NX_FTP_NOT_DISCONNECTED 0xD4 /* FTP not disconnected error */ -#define NX_FTP_NOT_OPEN 0xD5 /* FTP not opened error */ -#define NX_FTP_NOT_CLOSED 0xD6 /* FTP not closed error */ -#define NX_FTP_END_OF_FILE 0xD7 /* FTP end of file status */ -#define NX_FTP_END_OF_LISTING 0xD8 /* FTP end of directory listing status */ -#define NX_FTP_EXPECTED_1XX_CODE 0xD9 /* Expected a 1xx response from server */ -#define NX_FTP_EXPECTED_2XX_CODE 0xDA /* Expected a 2xx response from server */ -#define NX_FTP_EXPECTED_22X_CODE 0xDB /* Expected a 22x response from server */ -#define NX_FTP_EXPECTED_23X_CODE 0xDC /* Expected a 23x response from server */ -#define NX_FTP_EXPECTED_3XX_CODE 0xDD /* Expected a 3xx response from server */ -#define NX_FTP_EXPECTED_33X_CODE 0xDE /* Expected a 33x response from server */ -#define NX_FTP_INVALID_NUMBER 0xDF /* Extraced an invalid number from server response */ -#define NX_FTP_INVALID_ADDRESS 0x1D0 /* Invalid IP address parsed from FTP command */ -#define NX_FTP_INVALID_COMMAND 0x1D1 /* Invalid FTP command (bad syntax, unknown command) */ -#define NX_FTP_INVALID_LOGIN 0x1D2 /* Unable to perform successful user login */ -#define NX_FTP_INSUFFICIENT_PACKET_PAYLOAD 0x1D3 /* Packet payload less than the max length filename */ -#define NX_FTP_SERVER_INVALID_SIZE 0x1D4 /* Invalid FTP file size */ -#define NX_FTP_SERVER_END_OF_BLOCK 0x1D5 /* FTP end of block */ - -/* Define FTP connection states. */ - -#define NX_FTP_STATE_NOT_CONNECTED 1 /* FTP not connected */ -#define NX_FTP_STATE_CONNECTED 2 /* FTP connected */ -#define NX_FTP_STATE_OPEN 3 /* FTP file open for reading */ -#define NX_FTP_STATE_WRITE_OPEN 4 /* FTP file open for writing */ - - -/* Define the FTP Server TCP port numbers. */ - -#define NX_FTP_SERVER_CONTROL_PORT 21 /* Control Port for FTP server */ -#define NX_FTP_SERVER_DATA_PORT 20 /* Data Port for FTP server */ - -/* Define the size for buffer to store an IPv6 address represented in ASCII. */ -#define NX_FTP_IPV6_ADDRESS_BUFSIZE 60 - -/* Define the FTP basic commands. The ASCII command will be parsed and converted to the numerical - representation shown below. */ - -#define NX_FTP_NOOP 0 -#define NX_FTP_USER 1 -#define NX_FTP_PASS 2 -#define NX_FTP_QUIT 3 -#define NX_FTP_RETR 4 -#define NX_FTP_STOR 5 -#define NX_FTP_RNFR 6 -#define NX_FTP_RNTO 7 -#define NX_FTP_DELE 8 -#define NX_FTP_RMD 9 -#define NX_FTP_MKD 10 -#define NX_FTP_NLST 11 -#define NX_FTP_PORT 12 -#define NX_FTP_CWD 13 -#define NX_FTP_PWD 14 -#define NX_FTP_TYPE 15 -#define NX_FTP_LIST 16 -#define NX_FTP_CDUP 17 -#define NX_FTP_INVALID 18 -#define NX_FTP_EPRT 19 -#define NX_FTP_PASV 20 -#define NX_FTP_EPSV 21 -#define NX_FTP_MODE 22 - - - -/* Define the per client request structure for the FTP Server data structure. */ - -typedef struct NX_FTP_CLIENT_REQUEST_STRUCT -{ - UINT nx_ftp_client_request_data_port; /* Client's data port */ - UINT nx_ftp_client_request_ip_type; /* Client IP type (IPv4 or IPv6) */ - UINT nx_ftp_client_request_open_type; /* Open type of client request */ - UINT nx_ftp_client_request_authenticated; /* Authenticated flag */ - CHAR nx_ftp_client_request_read_only; /* Read-only flag */ - CHAR nx_ftp_client_request_transfer_type; /* FTP Data transfer type */ - CHAR nx_ftp_client_request_login; /* FTP Login flag */ - CHAR nx_ftp_client_request_passive_transfer_enabled; /* Client enabled for passive transfer */ - UINT nx_ftp_client_request_transfer_mode; /* Client transfer mode */ - ULONG nx_ftp_client_request_activity_timeout; /* Timeout for client activity */ - ULONG nx_ftp_client_request_total_bytes; /* Total bytes read or written */ - ULONG nx_ftp_client_request_block_bytes; /* Block bytes in block mode */ - CHAR nx_ftp_client_request_username[NX_FTP_USERNAME_SIZE]; - CHAR nx_ftp_client_request_password[NX_FTP_PASSWORD_SIZE]; - NX_PACKET *nx_ftp_client_request_packet; /* Previous request packet */ - FX_FILE nx_ftp_client_request_file; /* File control block */ - FX_LOCAL_PATH nx_ftp_client_local_path; /* Local path control block */ - NX_TCP_SOCKET nx_ftp_client_request_control_socket; /* Client control socket */ - NX_TCP_SOCKET nx_ftp_client_request_data_socket; /* Client data socket */ -} NX_FTP_CLIENT_REQUEST; - - -/* Define the FTP Server data structure. */ - -typedef struct NX_FTP_SERVER_STRUCT -{ - ULONG nx_ftp_server_id; /* FTP Server ID */ - CHAR *nx_ftp_server_name; /* Name of this FTP server */ - NX_IP *nx_ftp_server_ip_ptr; /* Pointer to associated IP structure */ - - NX_PACKET_POOL *nx_ftp_server_packet_pool_ptr; /* Pointer to FTP server packet pool */ - FX_MEDIA *nx_ftp_server_media_ptr; /* Pointer to media control block */ - ULONG nx_ftp_server_connection_requests; /* Number of connection requests */ - ULONG nx_ftp_server_disconnection_requests; /* Number of disconnection requests */ - ULONG nx_ftp_server_login_errors; /* Number of login errors */ - ULONG nx_ftp_server_authentication_errors; /* Number of access w/o authentication */ - ULONG nx_ftp_server_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_ftp_server_total_bytes_received; /* Number of total bytes received */ - ULONG nx_ftp_server_unknown_commands; /* Number of unknown commands received */ - ULONG nx_ftp_server_allocation_errors; /* Number of allocation errors */ - ULONG nx_ftp_server_relisten_errors; /* Number of relisten errors */ - ULONG nx_ftp_server_activity_timeouts; /* Number of activity timeouts */ - UINT nx_ftp_server_data_port; /* Port the data socket binds */ - NX_FTP_CLIENT_REQUEST /* FTP client request array */ - nx_ftp_server_client_list[NX_FTP_MAX_CLIENTS]; - TX_EVENT_FLAGS_GROUP - nx_ftp_server_event_flags; /* FTP server thread events */ - TX_TIMER nx_ftp_server_timer; /* FTP server activity timeout timer */ - TX_THREAD nx_ftp_server_thread; /* FTP server thread */ - UINT (*nx_ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); - UINT (*nx_ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); -#ifndef NX_DISABLE_IPV4 - UINT (*nx_ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); - UINT (*nx_ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); -#endif /* NX_DISABLE_IPV4 */ - - struct NX_FTP_SERVER_STRUCT - *nx_ftp_next_server_ptr, - *nx_ftp_previous_server_ptr; -} NX_FTP_SERVER; - - -#ifndef NX_FTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_ftp_server_create _nx_ftp_server_create -#define nxd_ftp_server_create _nxd_ftp_server_create -#define nx_ftp_server_delete _nx_ftp_server_delete -#define nx_ftp_server_start _nx_ftp_server_start -#define nx_ftp_server_stop _nx_ftp_server_stop - -#else - -/* Services with error checking. */ - -#define nx_ftp_server_create _nxe_ftp_server_create -#define nxd_ftp_server_create _nxde_ftp_server_create -#define nx_ftp_server_delete _nxe_ftp_server_delete -#define nx_ftp_server_start _nxe_ftp_server_start -#define nx_ftp_server_stop _nxe_ftp_server_stop - -#endif - -/* Define the prototypes accessible to the application software. */ -UINT nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); -UINT nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); -UINT nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); - -#else - -/* FTP source code is being compiled, do not perform any API mapping. */ -UINT _nxe_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT _nx_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout_ipv4)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT _nxde_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT _nxd_ftp_server_create(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_ipduo_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -UINT _nxe_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); -UINT _nx_ftp_server_delete(NX_FTP_SERVER *ftp_server_ptr); -UINT _nxe_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); -UINT _nx_ftp_server_start(NX_FTP_SERVER *ftp_server_ptr); -UINT _nxe_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); -UINT _nx_ftp_server_stop(NX_FTP_SERVER *ftp_server_ptr); - -/* Internal FTP functions. */ -UINT _nx_ftp_server_create_internal(NX_FTP_SERVER *ftp_server_ptr, CHAR *ftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*ftp_login)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), - UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, NXD_ADDRESS *client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info)); -VOID _nx_ftp_server_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message); -VOID _nx_ftp_server_directory_response(NX_TCP_SOCKET *socket, NX_PACKET *packet_ptr, CHAR *reply_code, CHAR *message, CHAR *directory); -VOID _nx_ftp_server_thread_entry(ULONG ftp_server_address); -VOID _nx_ftp_server_command_process(NX_FTP_SERVER *ftp_server_ptr); -VOID _nx_ftp_server_connect_process(NX_FTP_SERVER *ftp_server_ptr); -VOID _nx_ftp_server_command_present(NX_TCP_SOCKET *control_socket_ptr); -VOID _nx_ftp_server_connection_present(NX_TCP_SOCKET *control_socket_ptr, UINT port); -VOID _nx_ftp_server_data_disconnect(NX_TCP_SOCKET *data_socket_ptr); -VOID _nx_ftp_server_data_disconnect_process(NX_FTP_SERVER *ftp_server_ptr); -VOID _nx_ftp_server_data_present(NX_TCP_SOCKET *data_socket_ptr); -VOID _nx_ftp_server_data_process(NX_FTP_SERVER *ftp_server_ptr); -UINT _nx_ftp_server_parse_command(NX_PACKET *packet_ptr); -VOID _nx_ftp_server_timeout(ULONG ftp_server_address); -VOID _nx_ftp_server_timeout_processing(NX_FTP_SERVER *ftp_server_ptr); -VOID _nx_ftp_server_control_disconnect(NX_TCP_SOCKET *control_socket_ptr); -VOID _nx_ftp_server_control_disconnect_processing(NX_FTP_SERVER *ftp_server_ptr); - -#endif /* NX_FTP_SOURCE_CODE */ - -/* Internal functions. */ -#ifdef FEATURE_NX_IPV6 -UINT _nx_ftp_utility_parse_IPv6_address(CHAR *buffer_ptr, UINT buffer_length, NXD_ADDRESS *ipduo_address); -UINT _nx_ftp_utility_parse_port_number(CHAR *buffer_ptr, UINT buffer_length, UINT *portnumber); -UINT _nx_ftp_server_utility_fill_port_number(CHAR *buffer_ptr, UINT port_number); -#endif - -UINT _nx_ftp_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET **packet_ptr, UINT packet_type, UINT wait_option); -VOID _nx_ftp_server_block_size_get(NX_FTP_SERVER *ftp_server_ptr, UINT ftp_command, CHAR *filename, ULONG *block_size); -UINT _nx_ftp_server_block_header_send(NX_PACKET_POOL *pool_ptr, NX_FTP_CLIENT_REQUEST *client_request_ptr, ULONG block_size); -UINT _nx_ftp_server_block_header_retrieve(NX_FTP_CLIENT_REQUEST *client_request_ptr, NX_PACKET *packet_ptr); - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_FTP_SERVER_H */ diff --git a/protocol_handlers/http/nxd_http_client.c b/protocol_handlers/http/nxd_http_client.c deleted file mode 100644 index 9e938adc..00000000 --- a/protocol_handlers/http/nxd_http_client.c +++ /dev/null @@ -1,3418 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_HTTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - - -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_tcp.h" -#include "nxd_http_client.h" -#include "stdio.h" -#include "string.h" - - -/* Define global HTTP variables and strings. */ - - -/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing - into this array yields the base64 representation of the 6bit number. */ - -CHAR _nx_http_client_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* client_name Name of HTTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* window_size Size of HTTP client rx window */ -/* http_client_size Size of HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size) -{ - -NX_PACKET *packet_ptr; -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id == NXD_HTTP_CLIENT_ID) || - (pool_ptr == NX_NULL) || (http_client_size != sizeof(NX_HTTP_CLIENT))) - return(NX_PTR_ERROR); - - /* Pickup a packet from the supplied packet pool. */ - packet_ptr = pool_ptr -> nx_packet_pool_available_list; - - /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ - if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_HTTP_CLIENT_MIN_PACKET_SIZE) - return(NX_HTTP_POOL_ERROR); - - /* Call actual client create function. */ - status = _nx_http_client_create(client_ptr, client_name, ip_ptr, pool_ptr, window_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a HTTP client on the specified IP. In doing */ -/* so this function creates an TCP socket for subsequent HTTP */ -/* transfers. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* client_name Name of HTTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* window_size Size of HTTP client rx window */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create HTTP client socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size) -{ - -UINT status; - - - /* Clear the HTTP Client structure. */ - memset((void *) client_ptr, 0, sizeof(NX_HTTP_CLIENT)); - - /* Create the Client's TCP socket. */ - status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_http_client_socket), client_name, - NX_HTTP_TYPE_OF_SERVICE, NX_HTTP_FRAGMENT_OPTION, NX_HTTP_TIME_TO_LIVE, - window_size, NX_NULL, NX_NULL); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, return error code. */ - return(status); - } - - /* Save the Client name. */ - client_ptr -> nx_http_client_name = client_name; - - /* Save the IP pointer address. */ - client_ptr -> nx_http_client_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - client_ptr -> nx_http_client_packet_pool_ptr = pool_ptr; - - /* Set the client state to ready to indicate a get or put operation can be done. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Set the Client ID to indicate the HTTP client thread is ready. */ - client_ptr -> nx_http_client_id = NXD_HTTP_CLIENT_ID; - - /* Set the default port the client connects to the HTTP server on (80). */ - client_ptr -> nx_http_client_connect_port = NX_HTTP_SERVER_PORT; - - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_delete Actual client delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_delete(NX_HTTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nx_http_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created HTTP client on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_delete Delete the HTTP client socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_delete(NX_HTTP_CLIENT *client_ptr) -{ - - /* Clear the client ID to indicate the HTTP client is no longer ready. */ - client_ptr -> nx_http_client_id = 0; - - /* Determine if a GET or PUT state is present. */ - if ((client_ptr -> nx_http_client_state == NX_HTTP_CLIENT_STATE_PUT) || - (client_ptr -> nx_http_client_state == NX_HTTP_CLIENT_STATE_GET)) - { - - /* Check for a saved packet. */ - if (client_ptr -> nx_http_client_first_packet) - { - - /* Release the packet. */ - nx_packet_release(client_ptr -> nx_http_client_first_packet); - } - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), NX_HTTP_CLIENT_TIMEOUT); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - } - - /* Delete the TCP socket. */ - nx_tcp_socket_delete(&(client_ptr -> nx_http_client_socket)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_set_connect_port PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client set connect port */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* port Port to connect to server on */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_set_connect_port Actual set port call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid port. */ - if (((ULONG)port) > (ULONG)NX_MAX_PORT) - { - return(NX_INVALID_PORT); - } - else if (port == 0) - { - return(NX_INVALID_PORT); - } - - status = _nx_http_client_set_connect_port(client_ptr, port); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_set_connect_port PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the HTTP Client port to connect to the server on.*/ -/* This is useful if the HTTP Client needs to connect to a server on */ -/* another port than the default 80 port. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* port Port to connect to server on */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port) -{ - - client_ptr-> nx_http_client_connect_port = port; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client get start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_get_start Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, - UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || (resource == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_http_client_get_start(client_ptr, ip_address, resource, input_ptr, input_size, - username, password, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(input_ptr); - NX_PARAMETER_NOT_USED(input_size); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client get start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_get_start_extended Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, - CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || (resource == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_http_client_get_start_extended(client_ptr, ip_address, resource, resource_length, - input_ptr, input_size, username, username_length, - password, password_length, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(resource_length); - NX_PARAMETER_NOT_USED(input_ptr); - NX_PARAMETER_NOT_USED(input_size); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(username_length); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(password_length); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is a wrapper for the actual _nxd_http_client_get_start*/ -/* service that enables HTTP applications running on IPv4 to access */ -/* HTTP duo API without enabling IPv6. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_get_start Actual HTTP Client duo get */ -/* start service */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, - UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_ip_addr; - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; - server_ip_addr.nxd_ip_address.v4 = ip_address; - - /* Call the NetX HTTP 'duo' get start service. */ - status = _nxd_http_client_get_start(client_ptr, &server_ip_addr, resource, input_ptr, input_size, - username, password, wait_option); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(input_ptr); - NX_PARAMETER_NOT_USED(input_size); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is a wrapper for the actual _nxd_http_client_get_start*/ -/* service that enables HTTP applications running on IPv4 to access */ -/* HTTP duo API without enabling IPv6. */ -/* */ -/* Note: The strings of resource, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length to resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_get_start_extended Actual HTTP Client duo get */ -/* start service */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, - CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_ip_addr; - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; - server_ip_addr.nxd_ip_address.v4 = ip_address; - - /* Call the NetX HTTP 'duo' get start service. */ - status = _nxd_http_client_get_start_extended(client_ptr, &server_ip_addr, resource, resource_length, - input_ptr, input_size, username, username_length, - password, password_length, wait_option); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(resource_length); - NX_PARAMETER_NOT_USED(input_ptr); - NX_PARAMETER_NOT_USED(input_size); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(username_length); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(password_length); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo client get start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_get_start Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, - CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, - ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !ip_address) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nxd_http_client_get_start(client_ptr, ip_address, resource, input_ptr, input_size, - username, password, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo client get start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_get_start_extended Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, - CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !ip_address) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nxd_http_client_get_start_extended(client_ptr, ip_address, resource, resource_length, - input_ptr, input_size, username, username_length, - password, password_length, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. If input was specified, the request will actually be */ -/* sent as a POST instead of a GET. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_get_start_extended Actual client get start call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, CHAR *input_ptr, - UINT input_size, CHAR *username, CHAR *password, ULONG wait_option) -{ - -UINT resource_length = 0; -UINT username_length = 0; -UINT password_length = 0; -UINT status; - - /* Make sure there is enough room in the destination string. */ - if((username) && (password)) - { - if (_nx_utility_string_length_check(username, &username_length, NX_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &password_length, NX_HTTP_MAX_PASSWORD)) - { - - /* Error, return to caller. */ - return(NX_HTTP_PASSWORD_TOO_LONG); - } - } - - /* Check resource length. */ - if (_nx_utility_string_length_check(resource, &resource_length, NX_MAX_STRING_LENGTH)) - { - return(NX_HTTP_ERROR); - } - - status = _nxd_http_client_get_start_extended(client_ptr, server_ip, resource, resource_length, - input_ptr, input_size, username, username_length, - password, password_length, wait_option); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. If input was specified, the request will actually be */ -/* sent as a POST instead of a GET. */ -/* */ -/* Note: The strings of resource, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* input_ptr Additional input pointer */ -/* input_size Additional input size */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_base64_encode Encode username/password */ -/* _nx_http_client_calculate_content_offset Calculate content offset */ -/* _nx_http_client_content_length_get Get content length */ -/* _nx_http_client_number_convert Convert number to ASCII */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_append Append data to packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_client_socket_bind Bind client socket to port */ -/* nxd_tcp_client_socket_connect Connect to HTTP Server */ -/* nx_tcp_socket_disconnect Disconnect client socket */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_socket_receive Get response packet */ -/* nx_tcp_socket_send Send request to Server */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, UINT resource_length, - CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG wait_option) -{ - -UINT status; -NX_PACKET *packet_ptr; -UINT length = 0, offset = 0; -NX_PACKET *response_packet_ptr; -CHAR string1[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; -CHAR string2[NX_HTTP_MAX_STRING + 1]; -CHAR *buffer_ptr; -CHAR crlf[2] = {13,10}; -UINT string1_length; -UINT string2_length; -UINT temp_resource_length = 0; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - - /* Determine if the client is in a ready state. */ - if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_READY) - { - - /* Client not ready, return error. */ - return(NX_HTTP_NOT_READY); - } - - /* Make sure there is enough room in the destination string. */ - if((username) && (password)) - { - if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || - _nx_utility_string_length_check(password, &temp_password_length, password_length)) - { - - /* Error, return to caller. */ - return(NX_HTTP_PASSWORD_TOO_LONG); - } - - /* Validate string length. */ - if ((username_length != temp_username_length) || - (password_length != temp_password_length)) - { - return(NX_HTTP_ERROR); - } - } - - /* Check resource length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, resource_length)) - { - return(NX_HTTP_ERROR); - } - - /* Validate string length. */ - if (resource_length != temp_resource_length) - { - return(NX_HTTP_ERROR); - } - - /* Otherwise, attempt to bind the client socket. */ - status = nx_tcp_client_socket_bind(&(client_ptr -> nx_http_client_socket), NX_ANY_PORT, wait_option); - - /* Check status of the bind. */ - if (status != NX_SUCCESS) - { - - /* Error binding to a port, return to caller. */ - return(status); - } - - /* Invoke the connection call. */ - status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_http_client_socket), server_ip, - client_ptr -> nx_http_client_connect_port, wait_option); - - /* Check for connection status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - return(status); - } - - /* At this point we have a connection setup with an HTTP server! */ - - /* Allocate a packet for the GET (or POST) message. */ - if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, - NX_IPv4_TCP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, - NX_IPv6_TCP_PACKET, wait_option); - } - - /* Check allocation status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - return(status); - } - - /* Determine if a GET or POST is requested. */ - if ((input_ptr) && (input_size)) - { - - /* Additional information requested, build the POST request. */ - nx_packet_data_append(packet_ptr, "POST ", 5, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - } - else - { - - /* No additional information, build the GET request. */ - nx_packet_data_append(packet_ptr, "GET ", 4, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - } - - /* Determine if the resource needs a leading "/". */ - if (resource[0] != '/') - { - - /* Is this another website e.g. begins with http and has a colon? */ - if ( - ((resource[0] == 'h') || (resource[0] == 'H')) && - ((resource[1] == 't') || (resource[1] == 'T')) && - ((resource[2] == 't') || (resource[2] == 'T')) && - ((resource[3] == 'p') || (resource[3] == 'P')) && - (resource[4] == ':') - ) - { - - /* Yes, to send this string as is. */ - } - else - { - - /* Local file URI which needs a leading '/' character. */ - nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - /* Else URI string refers to root directory file, and has a leading '/' character already. */ - - /* Place the resource in the header. */ - nx_packet_data_append(packet_ptr, resource, resource_length, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - - /* Place the HTTP version in the header. */ - nx_packet_data_append(packet_ptr, " HTTP/1.0", 9, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - - /* Place the end of line character in the header. */ - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - - /* Determine if basic authentication is required. */ - if ((username) && (password)) - { - - /* Yes, attempt to build basic authentication. */ - nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, client_ptr -> nx_http_client_packet_pool_ptr, - NX_WAIT_FOREVER); - - /* Encode and append the "name:password" into next. */ - - /* Place the name and password in a single string. */ - - /* Copy the name into the merged string. */ - memcpy(string1, username, username_length); - - /* Insert the colon. */ - string1[username_length] = ':'; - - /* Copy the password into the merged string. */ - memcpy(&string1[username_length + 1], password, password_length); - - /* Make combined string NULL terminated. */ - string1[username_length + password_length + 1] = NX_NULL; - - /* Now encode the username:password string. */ - _nx_http_client_base64_encode(string1, username_length + password_length + 1, string2); - - /* Check string length. */ - _nx_utility_string_length_check(string2, &string2_length, NX_HTTP_MAX_STRING); - nx_packet_data_append(packet_ptr, string2, string2_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Check to see if a Content-Length field is needed. */ - if ((input_ptr) && (input_size)) - { - - /* Now build the content-length entry. */ - nx_packet_data_append(packet_ptr, "Content-Length: ", 16, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - string1_length = _nx_http_client_number_convert(input_size, string1); - nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Place an extra cr/lf to signal the end of the HTTP header. */ - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Check to see if we need to append the additional user data. */ - if ((input_ptr) && (input_size)) - { - - /* Now build the content-length entry. */ - nx_packet_data_append(packet_ptr, input_ptr, input_size, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Now send the packet to the HTTP server. */ - status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return an error. */ - return(status); - } - - /* Pickup the response from the Server. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, wait_option); - - /* Check for a response from the Server. */ - if (status == NX_SUCCESS) - { - - /* Setup pointer to server response. */ - buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; - - /* Check if packet contains the HTTP status. */ - if ((buffer_ptr + 11) >= (CHAR *)response_packet_ptr -> nx_packet_append_ptr) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr->nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr->nx_http_client_socket)); - - /* Return an error. */ - return(NX_HTTP_FAILED); - } - - /* Determine if the request was successful. */ - if (buffer_ptr[9] == '2') - { - - /* Determine if we need to copy the packet. */ - if ((response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_data_start) < NX_HTTP_CLIENT_MIN_PACKET_SIZE) - { - - /* Copy the packet to a packet in the packet pool. */ - nx_packet_copy(response_packet_ptr, &packet_ptr, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Release the original packet. */ - nx_packet_release(response_packet_ptr); - - /* Copy the packet pointer. */ - response_packet_ptr = packet_ptr; - } - - /* Pickup the content length. */ - length = _nx_http_client_content_length_get(response_packet_ptr); - - /* Pickup the content offset. */ - offset = _nx_http_client_calculate_content_offset(response_packet_ptr); - - /* Indicate a successful completion. */ - status = NX_SUCCESS; - } - /* Determine if it is an authentication error. */ - else if ((buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Inform caller of an authentication error. */ - status = NX_HTTP_AUTHENTICATION_ERROR; - } - else - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - } - } - - /* Check for error processing received packet. */ - if (status != NX_SUCCESS) - { - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - return status; - } - - /* Check for invalid packet parameters. */ - if ((length == 0) || (offset == 0)) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return an error. */ - return(NX_HTTP_FAILED); - } - - - /* Determine if the offset is in this request. */ - if (response_packet_ptr -> nx_packet_length > (offset + 3)) - { - - /* Adjust the pointers to skip over the response header. */ - response_packet_ptr -> nx_packet_prepend_ptr = response_packet_ptr -> nx_packet_prepend_ptr + offset; - - /* Reduce the length. */ - response_packet_ptr -> nx_packet_length = response_packet_ptr -> nx_packet_length - offset; - - /* Save the packet pointer for the get packet call. */ - client_ptr -> nx_http_client_first_packet = response_packet_ptr; - } - else - { - - /* Clear the saved packet pointer. */ - client_ptr -> nx_http_client_first_packet = NX_NULL; - - /* This packet only contains the header, just release it! */ - nx_packet_release(response_packet_ptr); - } - - /* Store the total number of bytes to receive. */ - client_ptr -> nx_http_client_total_transfer_bytes = length; - client_ptr -> nx_http_client_actual_bytes_transferred = 0; - - /* Enter the GET state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_GET; - - /* Return success to the caller. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_get_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client get packet call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Destination for packet pointer*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_get_packet Actual client get packet call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET packet routine. */ - status = _nx_http_client_get_packet(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_get_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets a data packet associated with the resource */ -/* specified by the previous GET start request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Destination for packet pointer*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_socket_disconnect Disconnect client socket */ -/* nx_tcp_socket_receive Receive a resource data packet*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -NX_PACKET *data_packet_ptr; -UINT status; - - - /* Default the return packet to NULL. */ - *packet_ptr = NX_NULL; - - /* Determine if the client is in a get state. */ - if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_GET) - { - - /* Client not ready, return error. */ - return(NX_HTTP_NOT_READY); - } - - /* Determine if the GET packet operation is complete. */ - if (client_ptr -> nx_http_client_total_transfer_bytes == client_ptr -> nx_http_client_actual_bytes_transferred) - { - - /* Yes, we are finished. */ - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Reenter the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return the GET done code. */ - return(NX_HTTP_GET_DONE); - } - - /* Determine if there is a queued packet. */ - if (client_ptr -> nx_http_client_first_packet) - { - - /* Yes, just use the saved packet. */ - data_packet_ptr = client_ptr -> nx_http_client_first_packet; - - /* Clear the saved packet pointer. */ - client_ptr -> nx_http_client_first_packet = NX_NULL; - } - else - { - - /* Receive a data packet from the TCP connection. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &data_packet_ptr, wait_option); - - /* Determine if a packet is available. */ - if (status != NX_SUCCESS) - { - - /* Ensure the packet pointer is NULL. */ - data_packet_ptr = NX_NULL; - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - return status; - } - } - - /* Check for an error condition. */ - if (data_packet_ptr -> nx_packet_length > (client_ptr -> nx_http_client_total_transfer_bytes - client_ptr -> nx_http_client_actual_bytes_transferred)) - { - - /* Release the invalid HTTP packet. */ - nx_packet_release(data_packet_ptr); - - /* Error, break down the connection and return to the caller. */ - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Reenter the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return an error. */ - return(NX_HTTP_BAD_PACKET_LENGTH); - } - - /* Adjust the actual transfer bytes. */ - client_ptr -> nx_http_client_actual_bytes_transferred = client_ptr -> nx_http_client_actual_bytes_transferred + - data_packet_ptr -> nx_packet_length; - - /* Move the packet pointer into the return pointer. */ - *packet_ptr = data_packet_ptr; - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP (IPv4) Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_put_start Actual IPv4 HTTP Client put */ -/* start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, - CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - resource == NX_NULL || !ip_address) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_http_client_put_start(client_ptr, ip_address, resource, username, password, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(total_bytes); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP (IPv4) Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_put_start_extended Actual IPv4 HTTP Client put */ -/* start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, - UINT resource_length, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - resource == NX_NULL || !ip_address) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_http_client_put_start_extended(client_ptr, ip_address, resource, resource_length, - username, username_length, password, password_length, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(resource_length); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(username_length); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(password_length); - NX_PARAMETER_NOT_USED(total_bytes); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is a wrapper for the actual _nxd_http_client_put_start*/ -/* service that enables HTTP applications running on IPv4 to access */ -/* HTTP duo API without enabling IPv6. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_put_start Actual put start service for */ -/* HTTP Duo Client */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, - CHAR *password, ULONG total_bytes, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_ip_addr; - - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; - server_ip_addr.nxd_ip_address.v4 = ip_address; - - status = _nxd_http_client_put_start(client_ptr, &server_ip_addr, resource, username, - password, total_bytes, wait_option); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(total_bytes); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is a wrapper for the actual _nxd_http_client_put_start*/ -/* service that enables HTTP applications running on IPv4 to access */ -/* HTTP duo API without enabling IPv6. */ -/* */ -/* Note: The strings of resource, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* ip_address IPv4 address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_put_start_extended Actual put start service for */ -/* HTTP Duo Client */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, - UINT resource_length, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_ip_addr; - - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ip_addr.nxd_ip_version = NX_IP_VERSION_V4; - server_ip_addr.nxd_ip_address.v4 = ip_address; - - status = _nxd_http_client_put_start_extended(client_ptr, &server_ip_addr, resource, resource_length, - username, username_length, password, password_length, - total_bytes, wait_option); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(resource); - NX_PARAMETER_NOT_USED(resource_length); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(username_length); - NX_PARAMETER_NOT_USED(password); - NX_PARAMETER_NOT_USED(password_length); - NX_PARAMETER_NOT_USED(total_bytes); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_put_start Actual client put start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, - CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - resource == NX_NULL || !server_ip) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nxd_http_client_put_start(client_ptr, server_ip, resource, username, password, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_put_start_extended Actual client put start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, - UINT resource_length, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - resource == NX_NULL || !server_ip) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nxd_http_client_put_start_extended(client_ptr, server_ip, resource, resource_length, - username, username_length, password, password_length, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processesthe application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_http_client_put_start_extended Actual client put start call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, - CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) - -{ - -UINT resource_length = 0; -UINT username_length = 0; -UINT password_length = 0; -UINT status; - - /* Make sure there is enough room in the destination string. */ - if((username) && (password)) - { - if (_nx_utility_string_length_check(username, &username_length, NX_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &password_length, NX_HTTP_MAX_PASSWORD)) - { - - /* Error, return to caller. */ - return(NX_HTTP_PASSWORD_TOO_LONG); - } - } - - /* Check resource length. */ - if (_nx_utility_string_length_check(resource, &resource_length, NX_MAX_STRING_LENGTH)) - { - return(NX_HTTP_ERROR); - } - - status = _nxd_http_client_put_start_extended(client_ptr, server_ip, resource, resource_length, - username, username_length, password, password_length, - total_bytes, wait_option); - - /* Return status to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processesthe application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* Note: The strings of resource, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length Length of resource (URL) */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_base64_encode Encode username/password */ -/* _nx_http_client_number_convert Convert number to ASCII */ -/* nx_http_client_type_get Get the HTTP file type */ -/* nx_packet_allocate Allocate a packet */ -/* nx_packet_data_append Append data to packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_client_socket_bind Bind client socket to port */ -/* nxd_tcp_client_socket_connect Connect to HTTP Server */ -/* nx_tcp_socket_disconnect Disconnect client socket */ -/* nx_tcp_client_socket_unbind Unbind client socket */ -/* nx_tcp_socket_send Send request to Server */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, CHAR *resource, - UINT resource_length, CHAR *username, UINT username_length, - CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option) - -{ - -NX_PACKET *packet_ptr; -CHAR string1[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; -CHAR string2[NX_HTTP_MAX_STRING + 1]; -CHAR crlf[2] = {13,10}; -UINT status; -UINT string1_length; -UINT string2_length; -UINT temp_resource_length = 0; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - - - /* Determine if the client is in a ready state. */ - if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_READY) - { - - /* Client not ready, return error. */ - return(NX_HTTP_NOT_READY); - } - - if ((username) && (password)) - { - - /* Make sure there is enough room in the destination string. */ - if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || - _nx_utility_string_length_check(password, &temp_password_length, password_length)) - { - - /* Error, return to caller. */ - return(NX_HTTP_USERNAME_TOO_LONG); - } - - /* Validate string length. */ - if ((username_length != temp_username_length) || - (password_length != temp_password_length)) - { - return(NX_HTTP_ERROR); - } - } - - /* Check resource length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, resource_length)) - { - return(NX_HTTP_ERROR); - } - - /* Validate string length. */ - if (resource_length != temp_resource_length) - { - return(NX_HTTP_ERROR); - } - - /* Otherwise, attempt to bind the client socket. */ - status = nx_tcp_client_socket_bind(&(client_ptr -> nx_http_client_socket), NX_ANY_PORT, wait_option); - - /* Check status of the bind. */ - if (status != NX_SUCCESS) - { - - /* Error binding to a port, return to caller. */ - return(status); - } - - /* Connect to the HTTP server. */ - - /* Invoke the 'Duo' (supports IPv6/IPv4) connection call. */ - status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_http_client_socket), server_ip, - client_ptr -> nx_http_client_connect_port, wait_option); - - /* Check for connection status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - return(status); - } - - /* At this point we have a connection setup with an HTTP server! */ - - /* Allocate a packet for the PUT message. */ - if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, - NX_IPv4_TCP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, - NX_IPv6_TCP_PACKET, wait_option); - } - - /* Check allocation status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - return(status); - } - - /* Build the PUT request. */ - nx_packet_data_append(packet_ptr, "PUT ", 4, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if this is a root directory based URI string. */ - if (resource[0] != '/') - { - - /* Then check if this another website e.g. begins with http and has a colon. */ - if ( - ((resource[0] == 'h') || (resource[0] == 'H')) && - ((resource[1] == 't') || (resource[1] == 'T')) && - ((resource[2] == 't') || (resource[2] == 'T')) && - ((resource[3] == 'p') || (resource[3] == 'P')) && - (resource[4] == ':') - ) - { - - /* Yes, ok to send this string as is. */ - } - else - { - - /* This URI is a root directory based file but it needs a leading / character. */ - nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - - /* (Else the URI begins with a '/' and is ok to send as is.) */ - - /* Place the resource in the header. */ - nx_packet_data_append(packet_ptr, resource, resource_length, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the HTTP version in the header. */ - nx_packet_data_append(packet_ptr, " HTTP/1.0", 9, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the end of line character in the header. */ - nx_packet_data_append(packet_ptr, crlf, 2, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if basic authentication is required. */ - if ((username) && (password)) - { - - /* Yes, attempt to build basic authentication. */ - nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Encode and append the "name:password" into next. */ - - /* Place the name and password in a single string. */ - - /* Copy the name into the merged string. */ - memcpy(string1, username, username_length); - - /* Insert the colon. */ - string1[username_length] = ':'; - - /* Copy the password into the merged string. */ - memcpy(&string1[username_length + 1], password, password_length); - - /* Make combined string NULL terminated. */ - string1[username_length + password_length + 1] = NX_NULL; - - /* Now encode the username:password string. */ - _nx_http_client_base64_encode(string1, username_length + password_length + 1, string2); - - /* Check string length. */ - _nx_utility_string_length_check(string2, &string2_length, NX_HTTP_MAX_STRING); - nx_packet_data_append(packet_ptr, string2, string2_length, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Now build the content-type entry. */ - nx_packet_data_append(packet_ptr, "Content-Type: ", 14, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - string1_length = _nx_http_client_type_get(resource, string1); - nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Now build the content-length entry. */ - nx_packet_data_append(packet_ptr, "Content-Length: ", 16, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - string1_length = _nx_http_client_number_convert(total_bytes, string1); - nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place an extra cr/lf to signal the end of the HTTP header. */ - nx_packet_data_append(packet_ptr, crlf, 2, - client_ptr -> nx_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Now send the packet to the HTTP server. */ - status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return an error. */ - return(status); - } - - /* Store the total number of bytes to send. */ - client_ptr -> nx_http_client_total_transfer_bytes = total_bytes; - client_ptr -> nx_http_client_actual_bytes_transferred = 0; - - /* Enter the PUT state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_PUT; - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_client_put_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client put packet call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Resource data packet pointer */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_client_put_packet Actual client put packet call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NXD_HTTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Ensure there is enough room for the TCP packet header. */ - if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_TCP_PACKET) - { - - /* Return an invalid packet error. */ - return(NX_INVALID_PACKET); - } - - /* Call actual PUT data routine. */ - status = _nx_http_client_put_packet(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_put_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a packet of resource data associated with */ -/* the previous PUT request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Resource data packet pointer */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release the packet */ -/* nx_tcp_client_socket_unbind Unbind the client socket */ -/* nx_tcp_socket_disconnect Disconnect form Server */ -/* nx_tcp_socket_receive Receive response from Server */ -/* nx_tcp_socket_send Send resource data packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -NX_PACKET *response_packet_ptr; -CHAR *buffer_ptr; -UINT length; -UINT status; - - - /* First, check and see if the client instance is still in the PUT state. */ - if (client_ptr -> nx_http_client_state != NX_HTTP_CLIENT_STATE_PUT) - { - - /* Client not ready, return error. */ - return(NX_HTTP_NOT_READY); - } - - /* Next, check and see if there is a response from the Server. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, NX_NO_WAIT); - - /* Check for an early response from the Server. */ - if (status == NX_SUCCESS) - { - - /* This is an error condition since the Server should not respond until the PUT is complete. */ - - /* Setup pointer to server response. */ - buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if it is an authentication error. */ - if (((buffer_ptr + 11) < (CHAR *)response_packet_ptr -> nx_packet_append_ptr) && - (buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) - { - - /* Inform caller of an authentication error. */ - status = NX_HTTP_AUTHENTICATION_ERROR; - } - else - { - - /* Inform caller of general Server failure. */ - status = NX_HTTP_INCOMPLETE_PUT_ERROR; - } - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return to the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return error to caller. */ - return(status); - } - - /* Otherwise, determine if the packet length fits in the available bytes to send. */ - if (packet_ptr -> nx_packet_length > - (client_ptr -> nx_http_client_total_transfer_bytes - client_ptr -> nx_http_client_actual_bytes_transferred)) - { - - /* Request doesn't fit into the remaining transfer window. */ - return(NX_HTTP_BAD_PACKET_LENGTH); - } - - /* Remember the packet length. */ - length = packet_ptr -> nx_packet_length; - - /* Now send the packet out. */ - status = nx_tcp_socket_send(&(client_ptr -> nx_http_client_socket), packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return to the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return an error. */ - return(status); - } - - /* Otherwise, update the actual bytes transferred. */ - client_ptr -> nx_http_client_actual_bytes_transferred = client_ptr -> nx_http_client_actual_bytes_transferred + length; - - /* Are we finished? */ - if (client_ptr -> nx_http_client_total_transfer_bytes > client_ptr -> nx_http_client_actual_bytes_transferred) - { - - /* No, we are not finished so just return success to the caller. */ - return(NX_SUCCESS); - } - - /* We are finished sending the PUT data. Now wait for a response from the Server. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_http_client_socket), &response_packet_ptr, wait_option); - - if (status != NX_SUCCESS) - { - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return to the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return status to caller. */ - return(status); - } - - - /* Setup pointer to server response. */ - buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if the request was successful. */ - if (((buffer_ptr + 9) >= (CHAR *) response_packet_ptr -> nx_packet_append_ptr) || - (buffer_ptr[9] != '2')) - { - - /* Inform caller of a successful completion. */ - status = NX_HTTP_REQUEST_UNSUCCESSFUL_CODE; - } - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_http_client_socket)); - - /* Return to the READY state. */ - client_ptr -> nx_http_client_state = NX_HTTP_CLIENT_STATE_READY; - - /* Return status to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_client_put_start_extended Start the PUT process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_type_get(CHAR *name, CHAR *http_type_string) -{ - -UINT i; - - - /* First find the end of the string. */ - i = 0; - while (name[i] != (CHAR) NX_NULL) - { - i++; - } - - /* Now look backwards to find the last period that signals the - file extension. */ - while ((i) && (name[i] != '.')) - { - i--; - } - - /* Position forward again, past the period. */ - i++; - - /* Now see what HTTP file type to return. */ - - /* Check for .txt file extension. */ - if (((name[i] == 't') || (name[i] == 'T')) && - ((name[i+1] == 'x') || (name[i+1] == 'X')) && - ((name[i+2] == 't') || (name[i+2] == 'T'))) - { - - /* Yes, we have a plain text file. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'p'; - http_type_string[6] = 'l'; - http_type_string[7] = 'a'; - http_type_string[8] = 'i'; - http_type_string[9] = 'n'; - - /* Return the size of the HTTP ASCII type string. */ - return(10); - } - - /* Check for .htm[l] file extension. */ - else if (((name[i] == 'h') || (name[i] == 'H')) && - ((name[i+1] == 't') || (name[i+1] == 'T')) && - ((name[i+2] == 'm') || (name[i+2] == 'M'))) - { - - /* Yes, we have an HTML text file. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'h'; - http_type_string[6] = 't'; - http_type_string[7] = 'm'; - http_type_string[8] = 'l'; - - /* Return the size of the HTTP ASCII type string. */ - return(9); - } - - /* Check for .gif file extension. */ - else if (((name[i] == 'g') || (name[i] == 'G')) && - ((name[i+1] == 'i') || (name[i+1] == 'I')) && - ((name[i+2] == 'f') || (name[i+2] == 'F'))) - { - - /* Yes, we have a GIF image file. */ - http_type_string[0] = 'i'; - http_type_string[1] = 'm'; - http_type_string[2] = 'a'; - http_type_string[3] = 'g'; - http_type_string[4] = 'e'; - http_type_string[5] = '/'; - http_type_string[6] = 'g'; - http_type_string[7] = 'i'; - http_type_string[8] = 'f'; - - /* Return the size of the HTTP ASCII type string. */ - return(9); - } - - /* Check for .xbm file extension. */ - else if (((name[i] == 'x') || (name[i] == 'X')) && - ((name[i+1] == 'b') || (name[i+1] == 'B')) && - ((name[i+2] == 'm') || (name[i+2] == 'M'))) - { - - /* Yes, we have a x-xbitmap image file. */ - http_type_string[0] = 'i'; - http_type_string[1] = 'm'; - http_type_string[2] = 'a'; - http_type_string[3] = 'g'; - http_type_string[4] = 'e'; - http_type_string[5] = '/'; - http_type_string[6] = 'x'; - http_type_string[7] = '-'; - http_type_string[8] = 'x'; - http_type_string[9] = 'b'; - http_type_string[10] = 'i'; - http_type_string[11] = 't'; - http_type_string[12] = 'm'; - http_type_string[13] = 'a'; - http_type_string[14] = 'p'; - - /* Return the size of the HTTP ASCII type string. */ - return(15); - } - - /* Default to plain text. */ - else - { - - /* Default to plain text. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'p'; - http_type_string[6] = 'l'; - http_type_string[7] = 'a'; - http_type_string[8] = 'i'; - http_type_string[9] = 'n'; - - /* Return the size of the HTTP ASCII type string. */ - return(10); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the content length of the supplied HTTP */ -/* response packet. If the packet is no content or the packet is */ -/* invalid, a zero is returned. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* length Length of content */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_client_get_start Start the GET operation */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_content_length_get(NX_PACKET *packet_ptr) -{ - -UINT length; -CHAR *buffer_ptr; -UINT found = NX_FALSE; - - - /* Default the content length to an invalid value. */ - length = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Content-length:" token first. */ - while ((buffer_ptr+14) < (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - - /* Check for the Content-length token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && - ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && - ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && - ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && - (*(buffer_ptr+7) == '-') && - ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && - ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && - ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && - ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && - ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && - ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && - (*(buffer_ptr+14) == ':')) - { - - /* Yes, found content-length token. */ - found = NX_TRUE; - - /* Move past the Content-Length: field. Exit the loop. */ - buffer_ptr += 15; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Check if found the content-length token. */ - if (found != NX_TRUE) - { - - /* No, return an invalid length indicating a bad HTTP packet. */ - return(length); - } - - /* Now skip over white space. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - buffer_ptr++; - } - - /* Now convert the length into a numeric value. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - { - - /* Update the content length. */ - length = length * 10; - length = length + (((UINT) (*buffer_ptr)) - 0x30); - - /* Move the buffer pointer forward. */ - buffer_ptr++; - } - - /* Determine if the content length was picked up properly. */ - if ((buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || - ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR)13))) - { - - /* Error, set the length to zero. */ - length = 0; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_calculate_content_offset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the byte offset to the start of the */ -/* HTTP request content area. This area immediately follows the HTTP */ -/* request header (which ends with a blank line). */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to request packet */ -/* */ -/* OUTPUT */ -/* */ -/* Byte Offset (0 implies no content) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_client_get_start Start GET processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_calculate_content_offset(NX_PACKET *packet_ptr) -{ - -UINT offset; -CHAR *buffer_ptr; - - - /* Default the content offset to zero. */ - offset = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "cr,lf,cr,lf" token. */ - while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the token. This signals a blank line, which also - specifies the start of the content. */ - if ((*buffer_ptr == (CHAR) 13) && - (*(buffer_ptr+1) == (CHAR) 10) && - (*(buffer_ptr+2) == (CHAR) 13) && - (*(buffer_ptr+3) == (CHAR) 10)) - { - - /* Adjust the offset. */ - offset = offset + 4; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - - /* Increment the offset. */ - offset++; - } - - /* Return the offset to the caller. */ - return(offset); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* string Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_client_get_start_extended Start GET processing */ -/* _nx_http_client_put_start_extended Start PUT processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_client_number_convert(UINT number, CHAR *string) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Default string to return '0'. */ - string[0] = '0'; - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while ((size < 10) && (number)) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string[j] = string[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - string[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - } - - /* Make the string NULL terminated. */ - string[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_client_base64_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the input string into a base64 */ -/* representation. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* length Length of name */ -/* base64name Encoded base64 name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_client_get_start_extended Start GET processing */ -/* _nx_http_client_put_start_extended Start PUT processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name) -{ - -UINT pad; -UINT i, j; -UINT step; - - - /* Adjust the length to represent the base64 name. */ - length = ((length * 8) / 6); - - /* Default padding to none. */ - pad = 0; - - /* Determine if an extra conversion is needed. */ - if ((length * 6) % 24) - { - - /* Some padding is needed. */ - - /* Calculate the number of pad characters. */ - pad = (length * 6) % 24; - pad = (24 - pad) / 6; - pad = pad - 1; - - /* Adjust the length to pickup the character fraction. */ - length++; - } - - /* Setup index into the base64name. */ - j = 0; - - /* Compute the base64name. */ - step = 0; - i = 0; - while (j < length) - { - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first 6 bits of name character for index. */ - base64name[j++] = _nx_http_client_base64_array[((UINT) name[i]) >> 2]; - step++; - } - else if (step == 1) - { - - /* Use last 2 bits of name character and first 4 bits of next name character for index. */ - base64name[j++] = _nx_http_client_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; - i++; - step++; - } - else if (step == 2) - { - - /* Use last 4 bits of name character and first 2 bits of next name character for index. */ - base64name[j++] = _nx_http_client_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; - i++; - step++; - } - else /* Step 3 */ - { - - /* Use last 6 bits of name character for index. */ - base64name[j++] = _nx_http_client_base64_array[(((UINT) name[i]) & 0x3F)]; - i++; - step = 0; - } - } - - /* Determine if the index needs to be advanced. */ - if (step != 3) - i++; - - /* Now add the PAD characters. */ - while ((pad--) && (j < NX_HTTP_MAX_STRING)) - { - - /* Pad base64name with '=' characters. */ - base64name[j++] = '='; - } - - /* Put a NULL character in. */ - base64name[j] = NX_NULL; -} - diff --git a/protocol_handlers/http/nxd_http_client.h b/protocol_handlers/http/nxd_http_client.h deleted file mode 100644 index 0756bcd6..00000000 --- a/protocol_handlers/http/nxd_http_client.h +++ /dev/null @@ -1,294 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_http_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_HTTP_CLIENT_H -#define NXD_HTTP_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_api.h" - -/* Define the HTTP ID. */ - -#define NXD_HTTP_CLIENT_ID 0x48545450UL - - -/* Define HTTP TCP socket create options. */ - -#ifndef NX_HTTP_TYPE_OF_SERVICE -#define NX_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_HTTP_FRAGMENT_OPTION -#define NX_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_HTTP_TIME_TO_LIVE -#define NX_HTTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_HTTP_MAX_RESOURCE -#define NX_HTTP_MAX_RESOURCE 40 -#endif - -#ifndef NX_HTTP_MAX_NAME -#define NX_HTTP_MAX_NAME 20 -#endif - -#ifndef NX_HTTP_MAX_PASSWORD -#define NX_HTTP_MAX_PASSWORD 20 -#endif - -#ifndef NX_HTTP_CLIENT_TIMEOUT -#define NX_HTTP_CLIENT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_PHYSICAL_TRAILER -#define NX_PHYSICAL_TRAILER 4 -#endif - -#ifndef NX_HTTP_CLIENT_MIN_PACKET_SIZE -#define NX_HTTP_CLIENT_MIN_PACKET_SIZE 600 -#endif - -/* NX_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ -#define NX_HTTP_MAX_STRING ((NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 1) * 4 / 3 + 1) -#define NX_HTTP_MAX_BINARY_MD5 16 -#define NX_HTTP_MAX_ASCII_MD5 32 - - -/* Define HTTP Client states. */ - -#define NX_HTTP_CLIENT_STATE_READY 1 -#define NX_HTTP_CLIENT_STATE_GET 2 -#define NX_HTTP_CLIENT_STATE_PUT 3 - - -/* Define return code constants. */ - -#define NX_HTTP_ERROR 0xE0 /* HTTP internal error */ -#define NX_HTTP_TIMEOUT 0xE1 /* HTTP timeout occurred */ -#define NX_HTTP_FAILED 0xE2 /* HTTP error */ -#define NX_HTTP_DONT_AUTHENTICATE 0xE3 /* HTTP authentication not needed */ -#define NX_HTTP_BASIC_AUTHENTICATE 0xE4 /* HTTP basic authentication requested */ -#define NX_HTTP_DIGEST_AUTHENTICATE 0xE5 /* HTTP digest authentication requested */ -#define NX_HTTP_NOT_FOUND 0xE6 /* HTTP request not found */ -#define NX_HTTP_DATA_END 0xE7 /* HTTP end of content area */ -#define NX_HTTP_CALLBACK_COMPLETED 0xE8 /* HTTP user callback completed the processing */ -#define NX_HTTP_POOL_ERROR 0xE9 /* HTTP supplied pool payload is too small */ -#define NX_HTTP_NOT_READY 0xEA /* HTTP client not ready for operation */ -#define NX_HTTP_AUTHENTICATION_ERROR 0xEB /* HTTP client authentication failed */ -#define NX_HTTP_GET_DONE 0xEC /* HTTP client get is complete */ -#define NX_HTTP_BAD_PACKET_LENGTH 0xED /* Invalid packet received - length incorrect */ -#define NX_HTTP_REQUEST_UNSUCCESSFUL_CODE 0xEE /* Received an error code instead of 2xx from server */ -#define NX_HTTP_INCOMPLETE_PUT_ERROR 0xEF /* Server responds before PUT is complete */ -#define NX_HTTP_PASSWORD_TOO_LONG 0xF0 /* Password exceeded expected length */ -#define NX_HTTP_USERNAME_TOO_LONG 0xF1 /* Username exceeded expected length */ -#define NX_HTTP_NO_QUERY_PARSED 0xF2 /* Server unable to find query in client request */ - -/* Define the default HTTP Server TCP port number. To change this at runtime - see nx_http_client_set_connect_port(). */ - -#define NX_HTTP_SERVER_PORT 80 - - -#ifdef NX_HTTP_DIGEST_ENABLE - -/* Include the MD5 digest header file. */ - -#include "nx_md5.h" - -#endif - - -/* Define the HTTP Client data structure. */ - -typedef struct NX_HTTP_CLIENT_STRUCT -{ - ULONG nx_http_client_id; /* HTTP Server ID */ - CHAR *nx_http_client_name; /* Name of this HTTP Client */ - UINT nx_http_client_state; /* Current state of HTTP Client */ - UINT nx_http_client_connect_port; /* Client port to connect to the server */ - NX_IP *nx_http_client_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_http_client_packet_pool_ptr; /* Pointer to HTTP Client packet pool */ - ULONG nx_http_client_total_transfer_bytes; /* Total number of bytes to transfer */ - ULONG nx_http_client_actual_bytes_transferred; /* Number of bytes actually transferred */ - NX_PACKET *nx_http_client_first_packet; /* Pointer to first packet with data */ - NX_TCP_SOCKET nx_http_client_socket; /* HTTP Client TCP socket */ -#ifdef NX_HTTP_DIGEST_ENABLE - NX_MD5 nx_http_client_md5data; /* HTTP Client MD5 work area */ -#endif -} NX_HTTP_CLIENT; - - - -#ifndef NX_HTTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_http_client_create _nx_http_client_create -#define nx_http_client_delete _nx_http_client_delete -#define nx_http_client_get_start _nx_http_client_get_start -#define nx_http_client_get_start_extended _nx_http_client_get_start_extended -#define nx_http_client_get_packet _nx_http_client_get_packet -#define nx_http_client_put_start _nx_http_client_put_start -#define nx_http_client_put_start_extended _nx_http_client_put_start_extended -#define nx_http_client_put_packet _nx_http_client_put_packet -#define nx_http_client_set_connect_port _nx_http_client_set_connect_port -#define nxd_http_client_get_start _nxd_http_client_get_start -#define nxd_http_client_get_start_extended _nxd_http_client_get_start_extended -#define nxd_http_client_put_start _nxd_http_client_put_start -#define nxd_http_client_put_start_extended _nxd_http_client_put_start_extended - -#else - -/* Services with error checking. */ - -#define nx_http_client_create(p,n,i,pp,w) _nxe_http_client_create(p,n,i,pp,w, sizeof(NX_HTTP_CLIENT)) -#define nx_http_client_delete _nxe_http_client_delete -#define nx_http_client_get_start _nxe_http_client_get_start -#define nx_http_client_get_start_extended _nxe_http_client_get_start_extended -#define nx_http_client_get_packet _nxe_http_client_get_packet -#define nx_http_client_put_start _nxe_http_client_put_start -#define nx_http_client_put_start_extended _nxe_http_client_put_start_extended -#define nx_http_client_put_packet _nxe_http_client_put_packet -#define nx_http_client_set_connect_port _nxe_http_client_set_connect_port -#define nxd_http_client_put_start _nxde_http_client_put_start -#define nxd_http_client_put_start_extended _nxde_http_client_put_start_extended -#define nxd_http_client_get_start _nxde_http_client_get_start -#define nxd_http_client_get_start_extended _nxde_http_client_get_start_extended - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -#ifdef NX_DISABLE_ERROR_CHECKING -UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); -#else -UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); -#endif /* NX_DISABLE_ERROR_CHECKING */ -UINT nx_http_client_delete(NX_HTTP_CLIENT *client_ptr); -UINT nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); -UINT nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); - -#else - -/* HTTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); -UINT _nx_http_client_create(NX_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); -UINT _nxe_http_client_delete(NX_HTTP_CLIENT *client_ptr); -UINT _nx_http_client_delete(NX_HTTP_CLIENT *client_ptr); -UINT _nxe_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxe_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT _nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT _nxe_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_http_client_get_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nx_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nxe_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT _nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT _nxe_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_http_client_put_packet(NX_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nxe_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); -UINT _nx_http_client_set_connect_port(NX_HTTP_CLIENT *client_ptr, UINT port); -UINT _nxde_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxd_http_client_get_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *input_ptr, UINT input_size, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxde_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT _nxd_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *input_ptr, UINT input_size, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT _nxde_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nxd_http_client_put_start(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nxde_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT _nxd_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, NXD_ADDRESS *ip_address, CHAR *resource, UINT resource_length, CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); - -/* Define internal HTTP functions. */ - -UINT _nx_http_client_type_get(CHAR *name, CHAR *http_type_string); -UINT _nx_http_client_content_length_get(NX_PACKET *packet_ptr); -UINT _nx_http_client_calculate_content_offset(NX_PACKET *packet_ptr); -UINT _nx_http_client_number_convert(UINT number, CHAR *string); -VOID _nx_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name); - - -#endif /* NX_HTTP_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_HTTP_CLIENT_H */ diff --git a/protocol_handlers/http/nxd_http_server.c b/protocol_handlers/http/nxd_http_server.c deleted file mode 100644 index fe66c208..00000000 --- a/protocol_handlers/http/nxd_http_server.c +++ /dev/null @@ -1,9253 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_HTTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_http_server.h" -#include "stdio.h" -#include "string.h" -#ifdef NX_HTTP_DIGEST_ENABLE -#include "nx_md5.h" -#endif - - -/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing - into this array yields the base64 representation of the 6bit number. */ - -CHAR _nx_http_server_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -#ifdef NX_HTTP_DIGEST_ENABLE -/* Define the default nonce, used only for MD5 authentication. For security reasons, this ASCII value should - change over time. */ - -CHAR _nx_http_server_nonce[] = "a4b8c8d7e0f6a7b2c3d2e4f5a4b7c5d2e7f"; -#endif - -/* Define date strings. */ -const CHAR *_nx_http_server_weekday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -const CHAR *_nx_http_server_month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -/* Define basic MIME maps. */ -static NX_HTTP_SERVER_MIME_MAP _nx_http_server_mime_maps[] = -{ - {"html", "text/html"}, - {"htm", "text/html"}, - {"txt", "text/plain"}, - {"gif", "image/gif"}, - {"jpg", "image/jpeg"}, - {"ico", "image/x-icon"}, -}; - - -/* Create two arrays to hold encoded and decoded username/password data. */ -static CHAR authorization_request[NX_HTTP_MAX_STRING + 1]; -static CHAR authorization_decoded[NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 2]; - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_content_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP content get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_content_get Actual server content get call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server content get function. */ - status = _nx_http_server_content_get(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_content_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the user's specified portion of the HTTP */ -/* content. Content is typically included in POST and PUT requests */ -/* from the client. This routine is designed to be called from the */ -/* application's request notify callback. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive another packet */ -/* _nx_http_server_content_length_get Pickup the content length */ -/* _nx_http_server_calculate_content_offset Pickup content offset */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -ULONG content_length; -ULONG get_offset; -ULONG offset; -#ifndef NX_DISABLE_PACKET_CHAIN -UINT status; -#endif /* NX_DISABLE_PACKET_CHAIN */ -UINT remaining_bytes; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; - - - /* Default the actual size to zero. */ - *actual_size = 0; - - /* Determine if there is content in this HTTP request. */ - content_length = (ULONG) _nx_http_server_content_length_get(packet_ptr); - - /* Make sure the content length is at least greater than the byte offset supplied. */ - if (content_length <= byte_offset) - { - - /* No more data in this buffer. */ - return(NX_HTTP_DATA_END); - } - - /* Determine if the destination size is greater than the content length. */ - if (destination_size > content_length) - { - - /* Yes, make the destination size equal to the content length. */ - destination_size = content_length; - } - - /* Calculate the offset to the requested content area. */ - get_offset = ((ULONG) _nx_http_server_calculate_content_offset(packet_ptr)) + byte_offset; - - /* Determine if we need to read one or more additional packets. */ - while (get_offset >= packet_ptr -> nx_packet_length) - { - -#ifdef NX_DISABLE_PACKET_CHAIN - NX_PARAMETER_NOT_USED(server_ptr); - - return NX_HTTP_ERROR; -#else - /* Read another packet because the offset reaches past the current packet - length. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* Otherwise, we have a new packet to append to the head packet. */ - - /* Determine if the current packet is already chained. */ - if (packet_ptr -> nx_packet_next) - { - - /* Yes, link the current last packet to the new packet. */ - (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; - } - else - { - - /* Otherwise, this is our first chained packet. Link to the head. */ - packet_ptr -> nx_packet_next = new_packet_ptr; - } - - /* Is the new packet chained? */ - if (new_packet_ptr -> nx_packet_next) - { - - /* Yes, there is a last packet pointer. Point to this from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; - } - else - { - - /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr; - } - - /* Update the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Default the buffer pointer to NULL. */ - buffer_ptr = NX_NULL; - - /* Now find the packet that contains the offset. */ - offset = 0; - new_packet_ptr = packet_ptr; - do - { - - /* Determine if the get request falls into this packet. */ - if (get_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) - { - - /* Yes, the get offset is in this packet. */ - - /* Setup the starting byte pointer. */ - buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (get_offset - offset); - break; - } - - /* Otherwise update the offset. */ - offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - new_packet_ptr = NX_NULL; -#else - /* Move to next packet in the chain. */ - new_packet_ptr = new_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while (new_packet_ptr); - - /* Determine if an error occurred in the search. */ - if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) - return(NX_HTTP_ERROR); - - /* Now determine if the maximum buffer size has to be adjusted. */ - if (destination_size > (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr)) - { - - /* Adjust the destination size downward. */ - destination_size = (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr); - } - - /* Initialize the remaining bytes. */ - remaining_bytes = destination_size; - - /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ - while (remaining_bytes--) - { - - /* Copy a byte to the destination. */ - *destination_ptr++ = *buffer_ptr++; - } - - /* Successful completion. */ - *actual_size = destination_size; - return(NX_SUCCESS); -} - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_packet_content_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP packet content find */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to pointer to the */ -/* packet that contains the */ -/* HTTP header */ -/* content_length Pointer to content length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_packet_content_find Actual server packet content */ -/* find call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) -{ - - - /* Check for invalid packet pointer. */ - if((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (*packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server content length get function. */ - return(_nx_http_server_packet_content_find(server_ptr, packet_ptr, content_length)); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_packet_content_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the content length specified in the HTTP */ -/* header, and move the nx_packet_prepend_ptr to the beginning of */ -/* the content. If the beginning of the content is not in the packet, */ -/* this function attempts to read the HTTP server socket for the */ -/* next packet. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to pointer to the */ -/* packet that contains the */ -/* HTTP header */ -/* content_length Pointer to content length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive another packet */ -/* _nx_http_server_calculate_content_offset Pickup content offset */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) -{ - -ULONG get_offset; -UINT status; - - /* Determine if there is content in this HTTP request. */ - if(content_length) - *content_length = (ULONG) _nx_http_server_content_length_get(*packet_ptr); - - - get_offset = (ULONG)_nx_http_server_calculate_content_offset(*packet_ptr); - - while((*packet_ptr) -> nx_packet_length <= get_offset) - { - /* Data is not present in this packet. So we have to read the next packet from the socket. */ - get_offset -= (*packet_ptr) -> nx_packet_length; - - /* Release this packet. */ - nx_packet_release(*packet_ptr); - - /* Make the receive call to obtain the next packet. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - if(status != NX_SUCCESS) - { - return(NX_HTTP_TIMEOUT); - } - - } - - (*packet_ptr) -> nx_packet_prepend_ptr += get_offset; - (*packet_ptr) -> nx_packet_length -= get_offset; - - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_packet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server packet get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to the packet to */ -/* be returned. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_packet_get Actual server packet get call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ - - - /* Check for invalid packet pointer. */ - if((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server content length get function. */ - return(_nx_http_server_packet_get(server_ptr, packet_ptr)); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_packet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function obtains the next packet from the HTTP server socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to the packet to */ -/* be returned. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive another packet */ -/* nx_packet_release Packet release */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ -NX_PACKET *new_packet_ptr; -UINT status; - - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - *packet_ptr = new_packet_ptr; - - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP content length get */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_content_length_get Actual server content length */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_content_length_get(NX_PACKET *packet_ptr) -{ - -UINT length; - - /* Check for invalid packet pointer. */ - if (packet_ptr == NX_NULL) - return(0); - - /* Call actual server content length get function. */ - length = _nx_http_server_content_length_get(packet_ptr); - - /* Return the length. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the content length of the supplied HTTP */ -/* request packet. If the packet is no content or the packet is */ -/* invalid, a zero is returned. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* length Length of content */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_content_length_get(NX_PACKET *packet_ptr) -{ - -UINT length; -CHAR *buffer_ptr; - - - /* Default the content length to zero. */ - length = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Content-length: " token first. */ - while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Content-length token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && - ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && - ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && - ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && - (*(buffer_ptr+7) == '-') && - ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && - ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && - ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && - ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && - ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && - ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && - (*(buffer_ptr+14) == ':') && - (*(buffer_ptr+15) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 16; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now convert the length into a numeric value. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - { - - /* Update the content length. */ - length = length * 10; - length = length + (((UINT) (*buffer_ptr)) - 0x30); - - /* Move the buffer pointer forward. */ - buffer_ptr++; - } - - /* Determine if the content length was picked up properly. */ - if ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13)) - { - - /* Error, set the length to zero. */ - length = 0; - } - - /* Return the length to the caller. */ - return(length); -} -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_content_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP extended get content */ -/* service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_content_get_extended Actual extended get content */ -/* get service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server content get function. */ - status = _nx_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_content_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the user's specified portion of the HTTP */ -/* content. Content is typically included in POST and PUT requests */ -/* from the client. This routine is designed to be called from the */ -/* application's request notify callback. */ -/* */ -/* This API is identical to _nx_http_server_content_get service except */ -/* for detecting a valid Content Length of length zero. In this case, */ -/* it sets the actual_size pointer to that value and returns a */ -/* successful outcome (empty POST requests are allowed in HTTP */ -/* 1.0/1.1). If this is called from a request notify callback the */ -/* caller is responsible for responding to the HTTP Client. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive another packet */ -/* _nx_http_server_content_length_get_extended */ -/* Get content length with error */ -/* status returned separately */ -/* content length value. */ -/* _nx_http_server_calculate_content_offset */ -/* Pickup content offset */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -ULONG content_length; -ULONG get_offset; -ULONG offset; -UINT status; -UINT remaining_bytes; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; - - - /* Default the actual size to zero. */ - *actual_size = 0; - - /* Determine if there is content in this HTTP request. */ - status = (ULONG) _nx_http_server_content_length_get_extended(packet_ptr, &content_length); - - if (status != NX_SUCCESS) - { - return status; - } - - /* Check for a empty POST request. */ - if (content_length == 0) - { - - /* Return the zero message body (content-length) size. */ - *actual_size = content_length; - - /* No more data in this buffer. */ - return(NX_SUCCESS); - } - - /* Make sure the content length is at least greater than the byte offset supplied. */ - if (content_length <= byte_offset) - { - - /* No more data in this buffer. */ - return(NX_HTTP_DATA_END); - } - - /* Determine if the destination size is greater than the content length. */ - if (destination_size > content_length) - { - - /* Yes, make the destination size equal to the content length. */ - destination_size = content_length; - } - - /* Calculate the offset to the requested content area. */ - get_offset = ((ULONG) _nx_http_server_calculate_content_offset(packet_ptr)) + byte_offset; - - /* Determine if we need to read one or more additional packets. */ - while (get_offset >= packet_ptr -> nx_packet_length) - { - -#ifdef NX_DISABLE_PACKET_CHAIN - NX_PARAMETER_NOT_USED(server_ptr); - - return NX_HTTP_ERROR; -#else - /* Read another packet because the offset reaches past the current packet - length. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* Otherwise, we have a new packet to append to the head packet. */ - - /* Determine if the current packet is already chained. */ - if (packet_ptr -> nx_packet_next) - { - - /* Yes, link the current last packet to the new packet. */ - (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; - } - else - { - - /* Otherwise, this is our first chained packet. Link to the head. */ - packet_ptr -> nx_packet_next = new_packet_ptr; - } - - /* Is the new packet chained? */ - if (new_packet_ptr -> nx_packet_next) - { - - /* Yes, there is a last packet pointer. Point to this from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; - } - else - { - - /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr; - } - - /* Update the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Default the buffer pointer to NULL. */ - buffer_ptr = NX_NULL; - - /* Now find the packet that contains the offset. */ - offset = 0; - new_packet_ptr = packet_ptr; - do - { - - /* Determine if the get request falls into this packet. */ - if (get_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) - { - - /* Yes, the get offset is in this packet. */ - - /* Setup the starting byte pointer. */ - buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (get_offset - offset); - break; - } - - /* Otherwise update the offset. */ - offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - new_packet_ptr = NX_NULL; -#else - /* Move to next packet in the chain. */ - new_packet_ptr = new_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while (new_packet_ptr); - - /* Determine if an error occurred in the search. */ - if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) - return(NX_HTTP_ERROR); - - /* Now determine if the maximum buffer size has to be adjusted. */ - if (destination_size > (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr)) - { - - /* Adjust the destination size downward. */ - destination_size = (UINT) (new_packet_ptr -> nx_packet_append_ptr - (UCHAR *) buffer_ptr); - } - - /* Initialize the remaining bytes. */ - remaining_bytes = destination_size; - - /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ - while (remaining_bytes--) - { - - /* Copy a byte to the destination. */ - *destination_ptr++ = *buffer_ptr++; - } - - /* Successful completion. */ - *actual_size = destination_size; - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_content_length_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the extended HTTP content length */ -/* service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP paclet */ -/* content_length Pointer for returning content */ -/* length value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_content_length_get_extended */ -/* Actual extended get content */ -/* length service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *content_length) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (content_length == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server content length get function. */ - status = _nx_http_server_content_length_get_extended(packet_ptr, content_length); - - /* Return completion status. */ - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_content_length_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function find a valid content length field and returns a */ -/* successful completion status (NX_SUCCESS) if so. Otherwise it */ -/* it returns an error status. A valid content length value is */ -/* zero or more and matches the size of the message body. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* content_length Pointer to a valid Content */ -/* Length value */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Content length extracted */ -/* status Invalid content length */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Threads */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length) -{ - -CHAR *buffer_ptr; - - - /* Default the content length to no data. */ - *length = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Content-length: " token first. */ - while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Content-length token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && - ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && - ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && - ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && - (*(buffer_ptr+7) == '-') && - ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && - ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && - ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && - ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && - ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && - ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && - (*(buffer_ptr+14) == ':') && - (*(buffer_ptr+15) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 16; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now convert the length into a numeric value. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - { - - /* Update the content length. */ - *length = *length * 10; - *length = *length + (((UINT) (*buffer_ptr)) - 0x30); - - /* Move the buffer pointer forward. */ - buffer_ptr++; - } - - /* Determine if the content length was picked up properly. */ - if ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13)) - { - - /* Error, set the length to zero. */ - return NX_HTTP_INCOMPLETE_PUT_ERROR; - } - - /* Return successful completion status to the caller. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* http_server_name Name of HTTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* authentication_check Pointer to application's */ -/* authentication checking */ -/* request_notify Pointer to application's */ -/* request notify service */ -/* http_server_size Size of HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), - UINT http_server_size) -{ - -NX_PACKET *packet_ptr; -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id == NXD_HTTP_SERVER_ID) || - (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL) || - (http_server_size != sizeof(NX_HTTP_SERVER))) - return(NX_PTR_ERROR); - - /* Pickup a packet from the supplied packet pool. */ - packet_ptr = pool_ptr -> nx_packet_pool_available_list; - - /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ - if (((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) - NX_PHYSICAL_TRAILER) - < NX_HTTP_SERVER_MIN_PACKET_SIZE) - return(NX_HTTP_POOL_ERROR); - - /* Call actual server create function. */ - status = _nx_http_server_create(http_server_ptr, http_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr, - authentication_check, request_notify); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a HTTP server on the specified IP. In doing */ -/* so this function creates an TCP socket for subsequent HTTP */ -/* transfers and a thread for the HTTP server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* http_server_name Name of HTTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* authentication_check Pointer to application's */ -/* authentication checking */ -/* request_notify Pointer to application's */ -/* request notify service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create HTTP server socket */ -/* nx_tcp_socket_delete Delete the HTTP server socket */ -/* tx_thread_create Create the HTTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)) -{ - -UINT status; - - - /* Clear the HTTP server structure. */ - memset((void *) http_server_ptr, 0, sizeof(NX_HTTP_SERVER)); - - /* Create the Server's TCP socket. */ - status = nx_tcp_socket_create(ip_ptr, &(http_server_ptr -> nx_http_server_socket), http_server_name, - NX_HTTP_TYPE_OF_SERVICE, NX_HTTP_FRAGMENT_OPTION, NX_HTTP_TIME_TO_LIVE, - NX_HTTP_SERVER_WINDOW_SIZE, NX_NULL, NX_NULL); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, return error code. */ - return(status); - } - - /* Now create the HTTP Server thread. */ - status = tx_thread_create(&(http_server_ptr -> nx_http_server_thread), "HTTP Server Thread", _nx_http_server_thread_entry, - (ULONG) http_server_ptr, stack_ptr, stack_size, NX_HTTP_SERVER_PRIORITY, NX_HTTP_SERVER_PRIORITY, - NX_HTTP_SERVER_THREAD_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred creating the thread. */ - if (status != NX_SUCCESS) - { - - /* Delete the TCP socket. */ - nx_tcp_socket_delete(&(http_server_ptr -> nx_http_server_socket)); - - /* Yes, return error code. */ - return(status); - } - - /* Save the Server name. */ - http_server_ptr -> nx_http_server_name = http_server_name; - - /* Save the IP pointer address. */ - http_server_ptr -> nx_http_server_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - http_server_ptr -> nx_http_server_packet_pool_ptr = pool_ptr; - - /* Save the media pointer address. */ - http_server_ptr -> nx_http_server_media_ptr = media_ptr; - - /* Save the user-supplied routines, if specified. */ - http_server_ptr -> nx_http_server_authentication_check = authentication_check; - http_server_ptr -> nx_http_server_request_notify = request_notify; - - - /* Remember this server structure in the TCP socket. */ - http_server_ptr -> nx_http_server_socket.nx_tcp_socket_reserved_ptr = (void *) http_server_ptr; - - /* Set the server ID to indicate the HTTP server thread is ready. */ - http_server_ptr -> nx_http_server_id = NXD_HTTP_SERVER_ID; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_delete Actual server delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_delete(NX_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_http_server_delete(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_delete Delete the HTTP server socket */ -/* nx_tcp_socket_disconnect Disconnect HTTP server socket */ -/* nx_tcp_socket_unaccept Unaccept HTTP server connect */ -/* nx_tcp_socket_unlisten Unlisten on the HTTP port */ -/* tx_thread_delete Delete the HTTP server thread */ -/* tx_thread_suspend Suspend the HTTP server thread*/ -/* tx_thread_terminate Terminate the HTTP server */ -/* thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr) -{ - - - /* Clear the server ID to indicate the HTTP server is no longer ready. */ - http_server_ptr -> nx_http_server_id = 0; - - /* Disconnect the TCP socket. */ - nx_tcp_socket_disconnect(&(http_server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); - - /* Unaccept any remaining connection on the TCP socket. */ - nx_tcp_server_socket_unaccept(&(http_server_ptr -> nx_http_server_socket)); - - /* Delete the TCP socket. */ - nx_tcp_socket_delete(&(http_server_ptr -> nx_http_server_socket)); - - /* Unlisten on the HTTP server port. */ - nx_tcp_server_socket_unlisten(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT); - - /* Suspend the HTTP server thread. */ - tx_thread_suspend(&(http_server_ptr -> nx_http_server_thread)); - - /* Terminate server thread. */ - tx_thread_terminate(&(http_server_ptr -> nx_http_server_thread)); - - /* Delete server thread. */ - tx_thread_delete(&(http_server_ptr -> nx_http_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_param_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP parameter get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* param_number Parameter number (start at 0) */ -/* param_ptr Pointer to destination */ -/* max_param_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_param_get Actual server parameter get */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (param_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server parameter get function. */ - status = _nx_http_server_param_get(packet_ptr, param_number, param_ptr, max_param_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_param_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the requested parameter specified in the URL */ -/* requested by the client. If the specified parameter is not present, */ -/* a not found error is returned to the caller. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* param_number Parameter number (start at 0) */ -/* param_ptr Pointer to destination */ -/* max_param_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size) -{ - -UINT i; -UINT current_param; -CHAR *buffer_ptr; - - - /* Set the destination string to NULL. */ - param_ptr[0] = (CHAR) NX_NULL; - - /* Set current parameter to 0. */ - current_param = 0; - - /* Setup a pointer to the HTTP buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Position to the start of the URL. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Move the buffer pointer. */ - buffer_ptr++; - } - - /* Not find URL. */ - if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) - { - return(NX_HTTP_NOT_FOUND); - } - - /* Loop through the buffer to search for the specified parameter. */ - do - { - - /* Determine if the character is a semicolon, indicating a parameter - is present. */ - if (*buffer_ptr == ';') - { - - /* Yes, a parameter is present. */ - - /* Move the buffer pointer forward. */ - buffer_ptr++; - - /* Is this the parameter requested? */ - if (current_param == param_number) - { - - - /* Yes, we have found the parameter. */ - for (i = 0; i < max_param_size; i++) - { - - /* Check if reach the end of the packet data. */ - if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - return(NX_HTTP_NOT_FOUND); - } - - /* Check for end of parameter. */ - if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || - (*buffer_ptr == '&') || (*buffer_ptr == ' ') || - (*buffer_ptr == (CHAR) 13)) - { - - /* Yes, we are finished and need to get out of the loop. */ - break; - } - - /* Otherwise, store the character in the destination. */ - param_ptr[i] = *buffer_ptr++; - } - - /* NULL terminate the parameter. */ - if (i < max_param_size) - param_ptr[i] = (CHAR) NX_NULL; - - /* Return to caller. */ - if (param_ptr[i] == (CHAR) NX_NULL) - return(NX_SUCCESS); - else - return(NX_HTTP_IMPROPERLY_TERMINATED_PARAM); - } - else - { - - /* Increment the current parameter. */ - current_param++; - } - } - else - { - - /* Check for any other character that signals the end of the param list. */ - if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == '&')) - break; - - /* Update the buffer pointer. */ - buffer_ptr++; - } - - } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); - - /* Return a not found error. */ - return(NX_HTTP_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_query_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP query get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* query_number Query number (start at 0) */ -/* query_ptr Pointer to destination */ -/* max_query_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_query_get Actual server query get */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (query_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server query get function. */ - status = _nx_http_server_query_get(packet_ptr, query_number, query_ptr, max_query_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_query_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the requested query specified in the URL */ -/* requested by the client. If the specified query is not present, */ -/* a not found error is returned to the caller. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* query_number Query number (start at 0) */ -/* query_ptr Pointer to destination */ -/* max_query_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size) -{ - -UINT i; -UINT current_query; -CHAR *buffer_ptr; - - - /* Set the destination string to NULL. */ - query_ptr[0] = (CHAR) NX_NULL; - - /* Set current query number to 0. */ - current_query = 0; - - /* Setup a pointer to the HTTP buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Position to the start of the URL. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Move the buffer pointer. */ - buffer_ptr++; - } - - /* Not find URL. */ - if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) - { - return(NX_HTTP_NOT_FOUND); - } - - /* Loop through the buffer to search for the specified query instance. */ - do - { - - /* Determine if the character is a '?' or a '&', indicating a query - is present. */ - if (((*buffer_ptr == '?') && (current_query == 0)) || - ((*buffer_ptr == '&') && (current_query != 0))) - { - - /* Yes, a query is present. */ - - /* Move the buffer pointer forward. */ - buffer_ptr++; - - /* Is this the query requested? */ - if (current_query == query_number) - { - - - /* Yes, we have found the query. */ - for (i = 0; i < max_query_size; i++) - { - - /* Check if reach the end of the packet data. */ - if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - return(NX_HTTP_NOT_FOUND); - } - - /* Check for end of query. */ - if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || - (*buffer_ptr == '&') || (*buffer_ptr == ' ') || - (*buffer_ptr == (CHAR) 13)) - { - - /* Yes, we are finished and need to get out of the loop. */ - break; - } - - /* Otherwise, store the character in the destination. */ - query_ptr[i] = *buffer_ptr++; - } - - /* NULL terminate the query. */ - query_ptr[i] = (CHAR) NX_NULL; - - /* Return to caller. */ - if (i) - return(NX_SUCCESS); - else - return(NX_HTTP_NO_QUERY_PARSED); - } - else - { - - /* Increment the current query. */ - current_query++; - } - } - else - { - - /* Check for any other character that signals the end of the query list. */ - if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == ';')) - break; - - /* Update the buffer pointer. */ - buffer_ptr++; - } - - } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); - - /* Return a not found error. */ - return(NX_HTTP_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_start Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_start(NX_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Call actual server start function. */ - status = _nx_http_server_start(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts a previously created HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_listen Start listening on HTTP port */ -/* tx_thread_resume Resume the HTTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_start(NX_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - - /* Start listening on the HTTP server port. */ - status = nx_tcp_server_socket_listen(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, - &(http_server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_MAX_PENDING, - _nx_http_server_connection_present); - - /* Determine if the listen was unsuccessful. */ - if (status != NX_SUCCESS) - { - - /* Just return an HTTP error. */ - return(status); - } - - /* Start the HTTP server thread. */ - tx_thread_resume(&(http_server_ptr -> nx_http_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_stop Actual server stop call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_stop(NX_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server stop function. */ - status = _nx_http_server_stop(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops a previously started HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend the HTTP server thread*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr) -{ - - /* Disconnect the TCP socket. */ - nx_tcp_socket_disconnect(&(http_server_ptr -> nx_http_server_socket), NX_NO_WAIT); - - /* Unaccept any remaining connection on the TCP socket. */ - nx_tcp_server_socket_unaccept(&(http_server_ptr -> nx_http_server_socket)); - - /* Unlisten on the HTTP server port. */ - nx_tcp_server_socket_unlisten(http_server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_data_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks errors for sending data. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* data_ptr Pointer to data to send */ -/* data_length Length of data to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_data_send Actual data send call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual data send function. */ - status = _nx_http_server_callback_data_send(server_ptr, data_ptr, data_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_data_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends data to the client from the application */ -/* callback function. This is typically done to satisfy a GET or */ -/* POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* data_ptr Pointer to data to send */ -/* data_length Length of data to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a NetX packet */ -/* nx_packet_data_append Append data to packet */ -/* nx_tcp_socket_send Send TCP data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) -{ - -NX_PACKET *new_packet_ptr; -UINT status; - - - /* Allocate a new packet for data. */ - status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &new_packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Error, return to caller. */ - return(NX_HTTP_ERROR); - } - - /* Now append the data to the packet. */ - status = nx_packet_data_append(new_packet_ptr, data_ptr, data_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Release the initial packet. */ - nx_packet_release(new_packet_ptr); - - /* Error, return to caller. */ - return(status); - } - - /* Send the data back to the client. */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Determine if this is successful. */ - if (status != NX_SUCCESS) - { - - /* Map the status to the generic HTTP error. */ - status = status; - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks errors for sending HTTP response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* header Pointer to HTTP header string */ -/* information Pointer to HTTP info string */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_response_send */ -/* Actual HTTP response send call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *header, CHAR *information, CHAR *additional_info) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (header == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual data send function. */ - status = _nx_http_server_callback_response_send(server_ptr, header, information, additional_info); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the completion response to the client from the */ -/* application callback function. This is typically done to satisfy a */ -/* GET or POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* header Pointer to HTTP header string */ -/* information Pointer to HTTP info string */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_response_send Send HTTP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *header, CHAR *information, CHAR *additional_info) -{ - -UINT header_length = 0; -UINT information_length = 0; -UINT additional_info_length = 0; -UINT status; - - /* Check length of header, information and additional information. */ - if (_nx_utility_string_length_check(header, &header_length, NX_MAX_STRING_LENGTH) || - (information && _nx_utility_string_length_check(information, &information_length, NX_MAX_STRING_LENGTH)) || - (additional_info && _nx_utility_string_length_check(additional_info, &additional_info_length, NX_MAX_STRING_LENGTH))) - { - return(NX_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - status = _nx_http_server_response_send(server_ptr, header, header_length, information, information_length, additional_info, additional_info_length); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_response_send_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks errors for sending HTTP response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* header Pointer to HTTP header string */ -/* header_length Length of HTTP header string */ -/* information Pointer to HTTP info string */ -/* information_length Length of HTTP info string */ -/* additional_info Pointer to additional HTTP */ -/* information */ -/* additional_info_length Length of additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_response_send_extended */ -/* Actual HTTP response send call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *header, UINT header_length, CHAR *information, - UINT information_length, CHAR *additional_info, UINT additional_info_length) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (header == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual data send function. */ - status = _nx_http_server_callback_response_send_extended(server_ptr, header, header_length, information, - information_length, additional_info, additional_info_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_response_send_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the completion response to the client from the */ -/* application callback function. This is typically done to satisfy a */ -/* GET or POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* Note: The strings of header, information and additional info must */ -/* be NULL-terminated and length of this string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* header Pointer to HTTP header string */ -/* header_length Length of HTTP header string */ -/* information Pointer to HTTP info string */ -/* information_length Length of HTTP info string */ -/* additional_info Pointer to additional HTTP */ -/* information */ -/* additional_info_length Length of additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_response_send Send HTTP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *header, UINT header_length, CHAR *information, - UINT information_length, CHAR *additional_info, UINT additional_info_length) -{ -UINT status; -UINT temp_header_length = 0; -UINT temp_information_length = 0; -UINT temp_additional_info_length = 0; - - /* Check length of header, information and additional information. */ - if (_nx_utility_string_length_check(header, &temp_header_length, NX_MAX_STRING_LENGTH) || - (information && _nx_utility_string_length_check(information, &temp_information_length, NX_MAX_STRING_LENGTH)) || - (additional_info && _nx_utility_string_length_check(additional_info, &temp_additional_info_length, NX_MAX_STRING_LENGTH))) - { - return(NX_HTTP_ERROR); - } - - /* Validate string length. */ - if ((temp_header_length != header_length) || - (information && (temp_information_length != information_length)) || - (additional_info && (temp_additional_info_length != additional_info_length))) - { - return(NX_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - status = _nx_http_server_response_send(server_ptr, header, header_length, information, information_length, additional_info, additional_info_length); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_connection_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the callback function executed whenever a client */ -/* connection appears on the HTTP Server port. It is responsible for */ -/* waking up the HTTP Server thread. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to HTTP Server socket */ -/* port HTTP Server port */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_resume Server thread resume */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port) -{ - -NX_HTTP_SERVER *server_ptr; - - NX_PARAMETER_NOT_USED(port); - - /* Pickup the server pointer. */ - server_ptr = (NX_HTTP_SERVER *) socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the connection pending flag. */ - server_ptr -> nx_http_connection_pending = NX_TRUE; - - /* Resume the HTTP Server thread. */ - tx_thread_resume(&(server_ptr -> nx_http_server_thread)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry of the HTTP server. All basic */ -/* processing is initiated by this function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_address Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_delete_process Process client DELETE request */ -/* _nx_http_server_get_client_request Get complete HTTP request */ -/* _nx_http_server_get_process Process client GET request */ -/* _nx_http_server_put_process Process client PUT request */ -/* _nx_http_server_response_send Send HTTP Server response */ -/* nx_packet_release Release request packet */ -/* nx_tcp_server_socket_accept Accept HTTP client connect */ -/* nx_tcp_socket_disconnect Disconnect from HTTP client */ -/* nx_tcp_server_socket_relisten Relisten for another HTTP */ -/* client connection */ -/* nx_tcp_server_socket_unaccept Unaccept HTTP client connect */ -/* tx_thread_preemption_change Disable/restore preemption */ -/* tx_thread_suspend Self suspend HTTP thread */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_thread_entry(ULONG http_server) -{ - -NX_HTTP_SERVER *server_ptr; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT original_threshold; -UINT status; -UINT loop_endlessly = NX_TRUE; - - - /* Set the HTTP server pointer. */ - server_ptr = (NX_HTTP_SERVER *) http_server; - - /* Loop to process HTTP Server requests. */ - while(loop_endlessly) - { - - /* Temporarily disable preemption. */ - tx_thread_preemption_change(&(server_ptr -> nx_http_server_thread), 0, &original_threshold); - - /* Is the connection pending flag not set? */ - if (server_ptr -> nx_http_connection_pending == NX_FALSE) - { - - /* If not, suspend the server thread. */ - tx_thread_suspend(&(server_ptr -> nx_http_server_thread)); - } - - /* Clear the connection pending flag. */ - server_ptr -> nx_http_connection_pending = NX_FALSE; - - /* Restore preemption. */ - tx_thread_preemption_change(&(server_ptr -> nx_http_server_thread), original_threshold, &original_threshold); - - /* Wait for connection on HTTP Server port. */ - status = nx_tcp_server_socket_accept(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_ACCEPT); - - /* Determine if we have an HTTP connection error. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of failed connections. */ - server_ptr -> nx_http_server_connection_failures++; - - /* Unaccept the connection. */ - nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); - - /* Relisten on the HTTP Server port. */ - nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, - &(server_ptr -> nx_http_server_socket)); - /* Restart the loop. */ - continue; - } - - /* Increment the number of successful connections. */ - server_ptr -> nx_http_server_connection_successes++; - - /* Get the complete HTTP client request. */ - status = _nx_http_server_get_client_request(server_ptr, &packet_ptr); - - /* Check if the HTTP request is valid. */ - if (status == NX_SUCCESS) - { - if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 7) - { - nx_packet_release(packet_ptr); - status = NX_HTTP_ERROR; - } - } - - /* Determine if it was successful. */ - if (status != NX_SUCCESS) - { - - if(status != NX_NO_PACKET) - { - - /* Increment the number of invalid HTTP requests. */ - server_ptr -> nx_http_server_invalid_http_headers++; - } - - /* Disconnect from the current connection. */ - nx_tcp_socket_disconnect(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); - - /* Unaccept the connection. */ - nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); - - /* Relisten on the HTTP Server port. */ - nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, - &(server_ptr -> nx_http_server_socket)); - /* Restart the loop. */ - continue; - } - - /* Otherwise, we have received an HTTP client request successfully. */ - - /* Setup a pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Determine what type of request is present. */ - - /* Check for a GET request. */ - if ((buffer_ptr[0] == 'G') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) - { - - /* We have a HTTP GET request to get a resource from this HTTP Server. */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_GET_REQUEST; - - /* Increment the number of GET requests. */ - server_ptr -> nx_http_server_get_requests++; - - /* Process the GET request. */ - _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_GET_REQUEST, packet_ptr); - } - - /* Check for a PUT request. */ - else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'U') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) - { - - /* We have a HTTP PUT request to store a resource on this HTTP Server. */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_PUT_REQUEST; - - /* Increment the number of PUT requests. */ - server_ptr -> nx_http_server_put_requests++; - - /* Process the PUT request. */ - _nx_http_server_put_process(server_ptr, packet_ptr); - } - - /* Check for a DELETE request. */ - else if ((buffer_ptr[0] == 'D') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'L') && (buffer_ptr[3] == 'E') && - (buffer_ptr[4] == 'T') && (buffer_ptr[5] == 'E') && (buffer_ptr[6] == ' ')) - { - - /* We have a HTTP DELETE request to delete a resource from this HTTP Server. */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_DELETE_REQUEST; - - /* Increment the number of DELETE requests. */ - server_ptr -> nx_http_server_delete_requests++; - - /* Process the Delete request. */ - _nx_http_server_delete_process(server_ptr, packet_ptr); - } - - /* Check for a POST request. */ - else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'O') && (buffer_ptr[2] == 'S') && - (buffer_ptr[3] == 'T') && (buffer_ptr[4] == ' ')) - { - - /* We have a HTTP POST request to send data to this HTTP Server for processing. Note that the POST - request is nearly identical to the GET request, except the parameter/query data is found in the - content rather than as part of the URL (resource). */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_POST_REQUEST; - - /* Increment the number of POST requests. */ - server_ptr -> nx_http_server_post_requests++; - -#ifdef NX_HTTP_MULTIPART_ENABLE - - /* Reset last received multipart packet. */ - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = NX_NULL; -#endif /* NX_HTTP_MULTIPART_ENABLE */ - - /* Process the POST request. */ - _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_POST_REQUEST, packet_ptr); - -#ifdef NX_HTTP_MULTIPART_ENABLE - /* Restore the packet to release. */ - if (server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet) - packet_ptr = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet; -#endif /* NX_HTTP_MULTIPART_ENABLE */ - } - - /* Check for a HEAD request. */ - else if ((buffer_ptr[0] == 'H') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'A') && - (buffer_ptr[3] == 'D') && (buffer_ptr[4] == ' ')) - { - - /* We have a HTTP HEAD request to get a resource header from this HTTP Server. Note that the HEAD - request is nearly identical to the GET request, except the requested content is not returned to - the client. */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_HEAD_REQUEST; - - /* Increment the number of HEAD requests. */ - server_ptr -> nx_http_server_head_requests++; - - /* Process the HEAD request. */ - _nx_http_server_get_process(server_ptr, NX_HTTP_SERVER_HEAD_REQUEST, packet_ptr); - } - - /* Unhandled request. */ - else - { - - /* We have an unhandled HTTP request. */ - server_ptr -> nx_http_server_request_type = NX_HTTP_SERVER_UNKNOWN_REQUEST; - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_IMPLEMENTED, sizeof(NX_HTTP_STATUS_NOT_IMPLEMENTED) - 1, - "NetX HTTP Request Not Implemented", sizeof("NetX HTTP Request Not Implemented") - 1, NX_NULL, 0); - - /* Increment the number of unhandled requests. */ - server_ptr -> nx_http_server_unknown_requests++; - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect from the current connection. */ - nx_tcp_socket_disconnect(&(server_ptr -> nx_http_server_socket), NX_HTTP_SERVER_TIMEOUT_DISCONNECT); - - /* Unaccept the connection. */ - nx_tcp_server_socket_unaccept(&(server_ptr -> nx_http_server_socket)); - - /* Relisten on the HTTP Server port. */ - nx_tcp_server_socket_relisten(server_ptr -> nx_http_server_ip_ptr, NX_HTTP_SERVER_PORT, - &(server_ptr -> nx_http_server_socket)); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_get_client_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds the complete HTTP client request in a single */ -/* NetX packet. Doing this makes the other parsing and searching */ -/* routines simple. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Destination for request */ -/* packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy Copy packet */ -/* nx_packet_data_append Move data into packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive an HTTP request packet*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_thread_entry HTTP Server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_get_client_request(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ - -NX_PACKET *head_packet_ptr; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; -UINT status; -NX_PACKET *work_ptr; -UINT crlf_found = 0; -NX_PACKET *tmp_ptr; - - - /* Default the return packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Wait for a request on the HTTP TCP well know port 80. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &head_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* At this point we have a connection setup with an HTTP server! */ - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Return an error condition. */ - return(status); - } - - /* Setup pointer to start of buffer. */ - buffer_ptr = (CHAR *) head_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if the packet is an HTTP request. */ - if ((buffer_ptr[0] != 'G') && (buffer_ptr[0] != 'g') && (buffer_ptr[0] != 'P') && (buffer_ptr[0] != 'p') && - (buffer_ptr[0] != 'D') && (buffer_ptr[0] != 'd') && (buffer_ptr[0] != 'H') && (buffer_ptr[0] != 'h') && - (buffer_ptr[0] != 'T') && (buffer_ptr[0] != 't')) - { - - /* Invalid first packet for HTTP request. */ - - /* Release the packet. */ - nx_packet_release(head_packet_ptr); - - /* Return an error. */ - return(NX_HTTP_ERROR); - } - - /* Determine if this packet is large enough. */ - if (((head_packet_ptr -> nx_packet_data_end - head_packet_ptr -> nx_packet_data_start) - - NX_PHYSICAL_TRAILER)< NX_HTTP_SERVER_MIN_PACKET_SIZE) - { - - /* Copy the packet into a packet allocated from the Server's packet pool (which must have packets - with a payload size >= NX_HTTP_SERVER_MIN_PACKET_SIZE. */ - status = nx_packet_copy(head_packet_ptr, &new_packet_ptr, server_ptr -> nx_http_server_packet_pool_ptr, NX_HTTP_SERVER_TIMEOUT); - - /* Determine if the packet copy was successful. */ - if (status != NX_SUCCESS) - { - - /* Error in packet copy. Release packet and return an error. */ - nx_packet_release(head_packet_ptr); - return(status); - } - - /* Copy is successful, release the original pointer and move the new pointer to the head pointer. */ - nx_packet_release(head_packet_ptr); - head_packet_ptr = new_packet_ptr; - } - - crlf_found = 0; - work_ptr = head_packet_ptr; - - /* Build a pointer to the buffer area. */ - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - - do - { - - /* See if there is a blank line present in the buffer. */ - /* Search the buffer for a cr/lf pair. */ - while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) - { - if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) - { - - /* Found CR. */ - crlf_found++; - } - else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) - { - - /* Found LF. */ - crlf_found++; - } - else - { - - /* Reset the CRLF marker. */ - crlf_found = 0; - } - - if (crlf_found == 4) - { - - /* Yes, we have found the end of the HTTP request header. */ - - /* Set the return packet pointer. */ - *packet_ptr = head_packet_ptr; - - /* Return a successful completion. */ - return(NX_SUCCESS); - } - - /* Move the buffer pointer up. */ - buffer_ptr++; - } - - /* Determine if the packet has already overflowed into another packet. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - - if (work_ptr -> nx_packet_next != NX_NULL) - { - /* Get the next packet in the chain. */ - work_ptr = work_ptr -> nx_packet_next; - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - } - else - -#endif - { - /* Receive another packet from the HTTP server port. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Release the current head packet. */ - nx_packet_release(head_packet_ptr); - - /* Return an error condition. */ - return(status); - } - - /* Successfully received another packet. Its contents now need to be placed in the head packet. */ - tmp_ptr = new_packet_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN - while (tmp_ptr) - { -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Copy the contents of the current packet into the head packet. */ - status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, - (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), - server_ptr -> nx_http_server_packet_pool_ptr, NX_HTTP_SERVER_TIMEOUT); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, an error is present. */ - - /* Release both packets. */ - nx_packet_release(head_packet_ptr); - nx_packet_release(new_packet_ptr); - - /* Return an error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - tmp_ptr = tmp_ptr -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Release the new packet. */ - nx_packet_release(new_packet_ptr); - } - - } while (status == NX_SUCCESS); - - /* Release the packet. */ - nx_packet_release(head_packet_ptr); - - return NX_HTTP_ERROR; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_get_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the GET, POST, and HEAD HTTP client */ -/* requests. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* request_type Type of request (GET, POST, */ -/* or HEAD) */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_basic_authenticate Process basic authentication */ -/* _nx_http_server_digest_authenticate Process digest authentication */ -/* _nx_http_server_calculate_content_offset Retrieve content offset */ -/* _nx_http_server_content_length_get Retrieve content length */ -/* _nx_http_server_response_send Send response back to client */ -/* _nx_http_server_retrieve_resource Retrieve resource from request*/ -/* _nx_http_server_type_get_extended Derive file type */ -/* fx_directory_information_get Get length of resource file */ -/* fx_file_close Close resource file */ -/* fx_file_open Open resource file */ -/* fx_file_read Read data from resource file */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_thread_entry HTTP Server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_get_process(NX_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr) -{ - -ULONG length = 0; -UINT status; -NX_PACKET *new_packet_ptr; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -ULONG temp; -CHAR temp_string[30]; -UINT auth_request_present = NX_FALSE; -UINT resource_length; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if a POST is present. */ - if (request_type == NX_HTTP_SERVER_POST_REQUEST) - { - - /* It is. Check for a valid content-length field. */ - status = _nx_http_server_content_length_get_extended(packet_ptr, &length); - - /* Check for errors. */ - if ( status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Length", sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Check for an invalid content offset . */ - if (_nx_http_server_calculate_content_offset(packet_ptr) == 0) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Offset", sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - -#ifdef NX_HTTP_MULTIPART_ENABLE - /* Cleanup the multipart field. */ - memset(&server_ptr -> nx_http_server_multipart, 0, sizeof(NX_HTTP_SERVER_MULTIPART)); -#endif /* NX_HTTP_MULTIPART_ENABLE */ - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_http_server_authentication_check || - server_ptr -> nx_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if (status == NX_HTTP_BASIC_AUTHENTICATE || - status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); - } -#ifdef NX_HTTP_DIGEST_ENABLE - else if (status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); - } -#endif - - /* Determine if the authentication failed. */ - if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes it did. Inform the HTTP server application about the failed authentication. */ - if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) - { - - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, request_type); - } - } - - return; - } - } - - /* Check whether a full response is necessary. */ - if((server_ptr -> nx_http_server_cache_info_get) && - (server_ptr -> nx_http_server_request_type == NX_HTTP_SERVER_GET_REQUEST)) - { - - /* Searching for "If-Modified-Since" header. */ - if(_nx_http_server_field_value_get(packet_ptr, (UCHAR *)"if-modified-since", 17, (UCHAR *)temp_string, sizeof(temp_string)) == NX_SUCCESS) - { - UINT max_age; - NX_HTTP_SERVER_DATE date; - CHAR date_string[30]; - - /* Get last modified date of this resource. */ - if(server_ptr -> nx_http_server_cache_info_get(server_ptr -> nx_http_server_request_resource, &max_age, &date) == NX_TRUE) - { - - /* Convert date to string, return length is always 29. */ - temp = _nx_http_server_date_to_string(&date, date_string); - date_string[temp] = 0; - - /* Check the last modified date with if-modified-since. */ - if(memcmp(temp_string, date_string, temp + 1) == 0) - { - - /* Send not modified. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_HTTP_STATUS_NOT_MODIFIED) - 1, NX_NULL, 0, NX_NULL, 0); - - /* Return to caller. */ - return; - } - } - } - } - - /* Setup the server socket with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(&(server_ptr -> nx_http_server_socket), - NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_HTTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_HTTP_SERVER_RETRY_MAX, - NX_HTTP_SERVER_RETRY_SHIFT); - - /* At this point, either there isn't any required authentication for this resource or the authentication is - complete. */ - - /* If the HTTP server receives an empty POST request (no message body, content length = 0, it is the - responsibility of the request notify callback to send a response (if any) to the HTTP Client. - The HTTP server will process the request no further. */ - - /* Determine if a user supplied get function has been specified. */ - if (server_ptr -> nx_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the get request. */ - status = (server_ptr -> nx_http_server_request_notify)(server_ptr, request_type, server_ptr -> nx_http_server_request_resource, packet_ptr); - -#ifdef NX_HTTP_MULTIPART_ENABLE - /* Release the packet that is not processed by callback function. */ - if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_next_packet) - nx_packet_release(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_next_packet); -#endif /* NX_HTTP_MULTIPART_ENABLE */ - - /* Determine if the user supplied routine is requesting the get should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_HTTP_CALLBACK_COMPLETED) - { - - /* User callback routine already sent success response back to HTTP Client. */ - return; - } - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Yes, error was detected. Abort the remainder of the get processing. */ - return; - } - } - - /* Was there a message body in the request? */ - if ((request_type == NX_HTTP_SERVER_POST_REQUEST) && (length == 0)) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - /* Get the length of request resource. */ - if (_nx_utility_string_length_check(server_ptr -> nx_http_server_request_resource, &resource_length, - sizeof(server_ptr -> nx_http_server_request_resource) - 1)) - { - return; - } - - /* Open the specified file for reading. */ - status = fx_file_open(server_ptr -> nx_http_server_media_ptr, &(server_ptr -> nx_http_server_file), server_ptr -> nx_http_server_request_resource, FX_OPEN_FOR_READ); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_NOT_FOUND, sizeof(NX_HTTP_STATUS_NOT_FOUND) - 1, - "NetX HTTP Server unable to find file: ", sizeof("NetX HTTP Server unable to find file: ") - 1, server_ptr -> nx_http_server_request_resource, resource_length); - - /* Error, return to caller. */ - return; - } - - /* Calculate the size of the file. */ - length = 0; - fx_directory_information_get(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource, FX_NULL, - &length, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL); - - /* Derive the file type. */ - temp = (ULONG) _nx_http_server_type_get_extended(server_ptr, server_ptr -> nx_http_server_request_resource, resource_length, temp_string, sizeof(temp_string)); - temp_string[temp] = 0; - - /* Now build a response header. */ - status = _nx_http_server_generate_response_header(server_ptr, &new_packet_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, length, temp_string, temp, NX_NULL, 0); - if(status) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Close the file. */ - fx_file_close(&(server_ptr -> nx_http_server_file)); - - /* Error, return to caller. */ - return; - } - - /* Check to see if only a response is required. */ - if ((!length) || (request_type == NX_HTTP_SERVER_HEAD_REQUEST)) - { - - /* Yes, only a response is required... send it! */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Determine if this is successful. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Force zero length. */ - length = 0; - } - } - - /* Get length of packet */ - temp = new_packet_ptr -> nx_packet_length; - - /* Now, loop to send the data contents. If the request type is "HEAD", skip this loop to output the - file contents. */ - while ((length) && (request_type != NX_HTTP_SERVER_HEAD_REQUEST)) - { - - /* Determine if we need to allocate a new packet for data. */ - if (!temp) - { - - /* Yes, allocate a new packet. */ - status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &new_packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Error, return to caller. */ - break; - } - } - - /* Calculate the maximum length. */ - temp = ((ULONG) (new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_append_ptr)) - NX_PHYSICAL_TRAILER; - - /* Determine if this exceeds the MSS of the peer. */ - if (temp > server_ptr -> nx_http_server_socket.nx_tcp_socket_connect_mss) - { - - /* Yes, reduce the maximum size to the mss size. */ - temp = server_ptr -> nx_http_server_socket.nx_tcp_socket_connect_mss; - } - - /* Read data from the file. */ - status = fx_file_read(&(server_ptr -> nx_http_server_file), new_packet_ptr -> nx_packet_append_ptr, - temp, &temp); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Error, return. */ - break; - } - - /* Update the packet information with the data read. */ - new_packet_ptr -> nx_packet_length = new_packet_ptr -> nx_packet_length + temp; - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_append_ptr + temp; - - /* Send the packet out. */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), new_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for success. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Return to caller. */ - break; - } - - /* Increment the bytes sent count. */ - server_ptr -> nx_http_server_total_bytes_sent = server_ptr -> nx_http_server_total_bytes_sent + temp; - - /* Adjust the file length based on what we have sent. */ - length = length - temp; - - /* Indicate new packet needed */ - temp = 0; - } - - /* Close the file. */ - fx_file_close(&(server_ptr -> nx_http_server_file)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_put_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the PUT HTTP client requests. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_basic_authenticate Process basic authentication */ -/* _nx_http_server_digest_authenticate Process digest authentication */ -/* _nx_http_server_calculate_content_offset Retrieve content offset */ -/* _nx_http_server_content_length_get Retrieve content length */ -/* _nx_http_server_response_send Send response back to client */ -/* _nx_http_server_retrieve_resource Retrieve resource from request*/ -/* fx_file_close Close resource file */ -/* fx_file_create Create resource file */ -/* fx_file_open Open resource file */ -/* fx_file_write Write data to resource file */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive HTTP data from client */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_content_get Content get processing */ -/* _nx_http_server_get_process GET request processing */ -/* _nx_http_server_put_process PUT request processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_put_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -ULONG length; -UINT offset; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -NX_PACKET *data_packet_ptr; -NX_PACKET *next_packet_ptr; -UINT auth_request_present = NX_FALSE; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Calculate the content length from the request. */ - status = _nx_http_server_content_length_get_extended(packet_ptr, &length); - - /* Determine if the content length is valid. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Length", sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Calculate the offset to the content (the two Cr LF tokens) in the request. */ - offset = _nx_http_server_calculate_content_offset(packet_ptr); - - /* Determine if the offset to the content is valid. */ - if (offset == 0) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Offset", sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_http_server_authentication_check || - server_ptr -> nx_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if (status == NX_HTTP_BASIC_AUTHENTICATE || - status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); - } -#ifdef NX_HTTP_DIGEST_ENABLE - else if (status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); - } -#endif - - /* Determine if the authentication is currently in progress. */ - if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ - if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) - { - - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, NX_HTTP_SERVER_PUT_REQUEST); - } - } - - return; - } - } - - /* At this point, either there isn't any required authentication for this resource or the authentication is - complete. */ - - /* If the request is empty (content-length = 0) the request notify callback is where a response is generated - to return to the Client. NetX HTTP Server will not process an empty request further. */ - - /* Determine if a user supplied get function has been specified. */ - if (server_ptr -> nx_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the put request. */ - status = (server_ptr -> nx_http_server_request_notify)(server_ptr, NX_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_http_server_request_resource, packet_ptr); - - /* Determine if the user supplied routine is requesting the put should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_HTTP_CALLBACK_COMPLETED) - { - - /* Send success response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); - return; - } - - /* No, an error was detected. Abort the remainder of the get processing. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - return; - } - } - - /* Was there a message body in the request? */ - if (length == 0) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - /* Otherwise, everything is okay... complete the request. */ - - /* Create the specified file. */ - status = fx_file_create(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource); - - - if (status != NX_SUCCESS) - { - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Create Failed", sizeof("NetX HTTP File Create Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Open the specified file for writing. */ - status = fx_file_open(server_ptr -> nx_http_server_media_ptr, &(server_ptr -> nx_http_server_file), server_ptr -> nx_http_server_request_resource, FX_OPEN_FOR_WRITE); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Open Failed", sizeof("NetX HTTP File Open Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - - /* Determine if there is any content in the first packet. */ - if ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) > offset) - { - - /* Write the content found in this packet. */ - status = fx_file_write(&(server_ptr -> nx_http_server_file), (packet_ptr -> nx_packet_prepend_ptr + offset), - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); - - /* Increment the bytes received count. */ - server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); - } - - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Loop to write chained packets out to the file. */ - next_packet_ptr = packet_ptr -> nx_packet_next; - while ((length) && (next_packet_ptr)) - { - - /* Write the content of the next packet. */ - status = fx_file_write(&(server_ptr -> nx_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Increment the bytes received count. */ - server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Move to the next pointer. */ - next_packet_ptr = next_packet_ptr -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* If necessary, receive more packets from the TCP socket to complete the write request. */ - while (length) - { - - /* Wait for a request on the HTTP TCP well know port 80. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &data_packet_ptr, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Receive Timeout", sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Loop to write the packet chain out to the file. */ - next_packet_ptr = data_packet_ptr; - do - { - - /* Write the content of this packet. */ - status = fx_file_write(&(server_ptr -> nx_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Release the previous data packet. */ - nx_packet_release(data_packet_ptr); - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - (UINT)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Increment the bytes received count. */ - server_ptr -> nx_http_server_total_bytes_received = server_ptr -> nx_http_server_total_bytes_received + - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - next_packet_ptr = NX_NULL; -#else - /* Move to the next pointer. */ - next_packet_ptr = next_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while ((length) && (next_packet_ptr)); - - /* Release the previous data packet. */ - nx_packet_release(data_packet_ptr); - } - - /* Success, at this point close the file and prepare a successful response for the client. */ - fx_file_close(&(server_ptr -> nx_http_server_file)); - - - /* Now build a response header. */ - status = _nx_http_server_generate_response_header(server_ptr, &data_packet_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); - if (status == NX_SUCCESS) - { - - /* Send the response back to the client. */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), data_packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(data_packet_ptr); - } - } - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_delete_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the DELETE HTTP client requests. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_basic_authenticate Process basic authentication */ -/* _nx_http_server_digest_authenticate Process digest authentication */ -/* _nx_http_server_response_send Send response back to client */ -/* _nx_http_server_retrieve_resource Retrieve resource from request*/ -/* fx_file_delete Delete resource file */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_thread_entry HTTP Server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_delete_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -NX_PACKET *response_ptr; -UINT auth_request_present = NX_FALSE; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_http_server_retrieve_resource(packet_ptr, server_ptr -> nx_http_server_request_resource, NX_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_BAD_REQUEST, sizeof(NX_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_http_server_authentication_check || - server_ptr -> nx_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_http_server_authentication_check_extended)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_http_server_authentication_check)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if (status == NX_HTTP_BASIC_AUTHENTICATE || - status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, temp_realm_length, &auth_request_present); - } -#ifdef NX_HTTP_DIGEST_ENABLE - else if (status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, temp_name_length, password_ptr, temp_password_length, realm_ptr, temp_realm_length, &auth_request_present); - } -#endif - - /* Determine if the authentication is currently in progress. */ - if ((status != NX_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ - if (server_ptr -> nx_http_server_invalid_username_password_callback && auth_request_present) - { - - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_http_server_invalid_username_password_callback)(server_ptr -> nx_http_server_request_resource, &client_nxd_address, NX_HTTP_SERVER_DELETE_REQUEST); - } - } - - return; - } - } - - /* Determine if a user supplied notify function has been specified. */ - if (server_ptr -> nx_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the delete request. */ - status = (server_ptr -> nx_http_server_request_notify)(server_ptr, NX_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_http_server_request_resource, packet_ptr); - - /* Determine if the user supplied routine is requesting the delete should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_HTTP_CALLBACK_COMPLETED) - { - - /* Send success response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); - return; - } - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Yes, error was detected. Abort the remainder of the delete processing. */ - return; - } - } - - /* Otherwise, everything is okay... complete the request. */ - - /* Delete the specified file. */ - status = fx_file_delete(server_ptr -> nx_http_server_media_ptr, server_ptr -> nx_http_server_request_resource); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_http_server_response_send(server_ptr, NX_HTTP_STATUS_INTERNAL_ERROR, sizeof(NX_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Delete Failed", sizeof("NetX HTTP File Delete Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Now build a response header. */ - status = _nx_http_server_generate_response_header(server_ptr, &response_ptr, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); - if (status == NX_SUCCESS) - { - - /* Send the response back to the client. */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), response_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(response_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_invalid_userpassword_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for service to set invalid */ -/* username password callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* invalid_username_password_callback Pointer to application's */ -/* invalid username password */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) -{ - -UINT status; - - - if ((http_server_ptr == NX_NULL) || (invalid_username_password_callback == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_http_server_invalid_userpassword_notify_set(http_server_ptr, invalid_username_password_callback); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_http_server_invalid_userpassword_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets invalid username password callback function. */ -/* */ -/* Note: The string length of resource in */ -/* invalid_username_password_callback is limited by */ -/* NX_HTTP_MAX_RESOURCE. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* invalid_username_password_callback Pointer to application's */ -/* invalid username password */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) -{ - - http_server_ptr -> nx_http_server_invalid_username_password_callback = invalid_username_password_callback; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the specified Server response to the requesting */ -/* HTTP client. */ -/* */ -/* Note: The strings of status code, information and additional info */ -/* must be NULL-terminated and length of this string matches the length*/ -/* specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* status_code Status-code and reason-phrase */ -/* information Pointer to HTTP info string */ -/* information_length Length of HTTP info string */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* additional_info_length Length of additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_thread_entry HTTP Server thread */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_put_process Process PUT request */ -/* _nx_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_information, UINT additional_info_length) -{ - -UINT status; -UINT length; -NX_PACKET *packet_ptr; - - - /* Determine if there is additional information. */ - if(information) - { - - /* Calculate the size of the information field. */ - length = information_length; - - /* Determine if there is additional information. */ - if (additional_information) - { - - /* Update the length with it as well. */ - length = length + additional_info_length; - } - } - else - length = 0; - - /* Generate response header. */ - status = _nx_http_server_generate_response_header(server_ptr, &packet_ptr, status_code, status_code_length, length, NX_NULL, 0, NX_NULL, 0); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Just return. */ - return(NX_HTTP_ERROR); - } - - /* Determine if there is additional information. */ - if (information) - { - - /* Place the first informational field. */ - status = nx_packet_data_append(packet_ptr, information, information_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* If there is additional information, place it in the buffer as well. */ - if (additional_information) - { - - /* Now, place the additional informational field. */ - status += nx_packet_data_append(packet_ptr, additional_information, additional_info_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet and return. */ - nx_packet_release(packet_ptr); - return(NX_HTTP_ERROR); - } - - /* Send the response back to the client. */ - status = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_basic_authenticate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for basic (name & password) authentication. */ -/* If found and correct, it returns a success. Otherwise, it returns */ -/* an authentication request to the requesting client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* name_ptr Pointer to name string */ -/* password_ptr Pointer to password string */ -/* realm_ptr Pointer to realm string */ -/* realm_length Length of realm string */ -/* auth_request_present Indicate if authentication */ -/* must be performed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_retrieve_basic_authorization Pickup authorization */ -/* _nx_http_base64_decode Decode authorization */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_put_process Process PUT request */ -/* _nx_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_basic_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present) -{ - -UINT i, j; -UINT status, status1; -CHAR quote[2] = {0x22, 0}; -CHAR crlf[2] = {13,10}; -UINT match; -UINT length; - - /* Default to no authentication request detected. */ - *auth_request_present = NX_FALSE; - - /* Default the status to authenticate. */ - status = NX_HTTP_BASIC_AUTHENTICATE; - - memset(&authorization_request[0], 0, sizeof(authorization_request)); - - memset(&authorization_decoded[0], 0, sizeof(authorization_decoded)); - - /* Is the authorization request present? */ - length = _nx_http_server_retrieve_basic_authorization(packet_ptr, authorization_request); - if (length) - { - - /* Yes, an authorization request is present. */ - *auth_request_present = NX_TRUE; - - /* Convert the request from Base64 representation to ASCII. */ - _nx_http_base64_decode(authorization_request, length, authorization_decoded); - - /* See if it is valid. */ - - /* Compare the name. */ - i = 0; - match = NX_TRUE; - while (name_ptr[i] && (i < sizeof(authorization_decoded))) - { - - /* Is there a mismatch? */ - if (name_ptr[i] != authorization_decoded[i]) - { - - /* Name mismatch. Continue to avoid timing attack. */ - match = NX_FALSE; - } - - /* Move to next character. */ - i++; - } - - /* Determine if everything matches. */ - if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == ':')) - { - - /* Move the authorization index past the semicolon. */ - i++; - - /* Now compare the passwords. */ - j = 0; - match = NX_TRUE; - while (password_ptr[j] && (i < sizeof(authorization_decoded))) - { - - /* Is there a mismatch? */ - if (password_ptr[j] != authorization_decoded[i]) - { - - /* Password mismatch. Continue to avoid timing attack. */ - match = NX_FALSE; - } - - /* Move to next character. */ - i++; - j++; - } - - /* Determine if we have a match. */ - if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == (CHAR) NX_NULL)) - { - - /* Yes, we have successful authorization!! */ - status = NX_SUCCESS; - } - } - } - - /* Determine if we need to send back an unauthorized request. */ - if (status == NX_HTTP_BASIC_AUTHENTICATE) - { - - /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ - - /* Allocate a packet for sending the response back. */ - status1 = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if (status1 != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Just return. */ - return(status1); - } - - /* Insert the response header. */ - nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, NX_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_HTTP_STATUS_UNAUTHORIZED) - 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the type of authentication requested. */ - nx_packet_data_append(packet_ptr, "WWW-Authenticate: Basic realm=", 30, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the realm string into the buffer. */ - nx_packet_data_append(packet_ptr, realm_ptr, realm_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place another into the buffer to signal end of FULL HTTP response. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Send the response back to the client. */ - status1 = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status1) - { - - /* Return the internal NetX error. */ - status = status1; - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Return the result of the authentication request. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_retrieve_basic_authorization PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves basic authentication information from the */ -/* HTTP request packet. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Request packet pointer */ -/* authorization_request_ptr Pointer to destination for */ -/* authorization string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_basic_authenticate Basic authenticate processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr) -{ - -UINT length; -UINT found; -CHAR *buffer_ptr; - - - /* Set the found flag to false. */ - found = NX_FALSE; - - /* Default the authorization request to zero. */ - length = 0; - - /* Set the authorization request string to NULL. */ - authorization_request_ptr[0] = NX_NULL; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - - /* Find the "Authorization: " token first. */ - while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Authorization: token. */ - if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && - ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && - ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && - ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && - ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && - ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && - ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && - ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && - ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && - ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && - ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && - ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && - (*(buffer_ptr+13) == ':') && - (*(buffer_ptr+14) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 15; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now check for the "Basic " token. */ - while (((buffer_ptr+6) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Basic token. */ - if (((*buffer_ptr == 'b') || (*buffer_ptr == 'B')) && - ((*(buffer_ptr+1) == 'a') || (*(buffer_ptr+1) == 'A')) && - ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+3) == 'i') || (*(buffer_ptr+3) == 'I')) && - ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+4) == 'C')) && - (*(buffer_ptr+5) == ' ')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 6; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the authorization string. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_STRING)) - { - - /* Copy a character of the authorization string into the destination. */ - authorization_request_ptr[length] = *buffer_ptr++; - length++; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_retrieve_resource PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource (URL) portion of the request */ -/* and places it in the destination. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* destination Destination for resource */ -/* max_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* Status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_put_process Process PUT request */ -/* _nx_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_retrieve_resource(NX_PACKET *packet_ptr, CHAR *destination, UINT max_size) -{ - -UINT i; -CHAR *buffer_ptr; - - - /* Set the destination to NULL. */ - destination[0] = (CHAR) 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the first space which is the start position of URI. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ')) - { - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Check for an error condition. */ - if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) - return(NX_HTTP_ERROR); - - buffer_ptr++; - - if ((buffer_ptr + 7 < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Check whether it is an absoluteURI*/ - if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && - ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && - ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 1) == 'T')) && - ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 1) == 'P')) && - (*(buffer_ptr + 4) == ':') && - (*(buffer_ptr + 5) == '/') && - (*(buffer_ptr + 6) == '/')) - { - - /* Yes it is. Find the absolute path. */ - buffer_ptr += 7; - - /* Find the first slash character. The first slash marks the beginning of the URL. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != '/')) - { - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - } - } - - /* Check for an error condition. */ - if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != '/')) - return(NX_HTTP_ERROR); - - /* Copy the rest of the resource to the destination. Space, semicolon, and question mark characters signal the - end of the resource. */ - i = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ') && (*buffer_ptr != ';') && (*buffer_ptr != '?') && (i < (max_size-1))) - { - - /* Check escape characters. */ - if(*buffer_ptr == '%') - { - - /* It is an escape character. */ - if((buffer_ptr + 2) < (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - - /* Convert the HEX number. */ - buffer_ptr++; - if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - destination[i] = (CHAR)(*buffer_ptr - '0'); - else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) - destination[i] = (CHAR)(*buffer_ptr - 'a' + 10); - else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) - destination[i] = (CHAR)(*buffer_ptr - 'A' + 10); - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_HTTP_ERROR); - } - destination[i] = (CHAR)(destination[i] << 4); - - /* Convert the HEX number. */ - buffer_ptr++; - if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - '0')); - else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'a' + 10)); - else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'A' + 10)); - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_HTTP_ERROR); - } - - /* Move to the next byte. */ - i++; - buffer_ptr++; - } - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_HTTP_ERROR); - } - } - else - { - - /* Copy the URL name into the destination. */ - destination[i++] = *buffer_ptr++; - } - } - - /* Determine if the resource was retrieved. */ - if ((destination[0] == (CHAR) 0) || (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || ((*buffer_ptr != ' ') && (*buffer_ptr != '?') && (*buffer_ptr != ';'))) - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_HTTP_ERROR); - } - - /* Everything is okay, place a NULL at the end of the resource. */ - destination[i] = (CHAR) 0; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_calculate_content_offset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the byte offset to the start of the */ -/* HTTP request content area. This area immediately follows the HTTP */ -/* request header (which ends with a blank line). */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to request packet */ -/* */ -/* OUTPUT */ -/* */ -/* Byte Offset (0 implies no content) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_content_get Application content get */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_put_process Process PUT request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_calculate_content_offset(NX_PACKET *packet_ptr) -{ - -UINT offset; -CHAR *buffer_ptr; - - - /* Default the content offset to zero. */ - offset = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "cr,lf,cr,lf" token. */ - while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the token. This signals a blank line, which also - specifies the start of the content. */ - if ((*buffer_ptr == (CHAR) 13) && - (*(buffer_ptr+1) == (CHAR) 10) && - (*(buffer_ptr+2) == (CHAR) 13) && - (*(buffer_ptr+3) == (CHAR) 10)) - { - - /* Adjust the offset. */ - offset = offset + 4; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - - /* Increment the offset. */ - offset++; - } - - /* Return the offset to the caller. */ - return(offset); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* string Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_response_send Send response to client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_number_convert(UINT number, CHAR *string) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < 10) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string[j] = string[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - string[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Make the string NULL terminated. */ - string[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for deriving the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_type_get */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (name == NX_NULL) || (http_type_string == NX_NULL)) - return(0); - - return _nx_http_server_type_get(server_ptr, name, http_type_string); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_type_get_extended */ -/* _nx_utility_string_length_check */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string) -{ -UINT name_length = 0; - - if (_nx_utility_string_length_check(name, &name_length, NX_MAX_STRING_LENGTH)) - { - return(0); - } - - return _nx_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, NX_MAX_STRING_LENGTH + 1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_type_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for deriving the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* name_length Length of name string */ -/* http_type_string Destination HTTP type string */ -/* http_type_string_max_size Size of the destination string*/ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string, or */ -/* 0 if http_type_string is too */ -/* small for the resource string*/ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_type_get_extended */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (name == NX_NULL) || (http_type_string == NX_NULL)) - return(0); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, http_type_string_max_size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_type_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* Note: The string of name must be NULL-terminated and length of each */ -/* string matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* name_length Length of name string */ -/* http_type_string Destination HTTP type string */ -/* http_type_string_max_size Size of the destination string*/ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string, or */ -/* 0 if http_type_string is too */ -/* small for the resource */ -/* string, or name exceeds */ -/* NX_HTTP_MAX_RESOURCE */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_memicmp */ -/* _nx_utility_string_length_check */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size) -{ - -UINT i; -CHAR *ch; -UINT ext_length; -UINT map_ext_length; -UINT map_type_length; -UINT temp_name_length; - - /* Check name length. */ - if (_nx_utility_string_length_check(name, &temp_name_length, name_length)) - { - return(NX_HTTP_ERROR); - } - - /* Validate string length. */ - if (name_length != temp_name_length) - { - return(NX_HTTP_ERROR); - } - - /* First find the end of the string. */ - ch = name + name_length; - - /* Now look backwards to find the last period that signals the - file extension. */ - ext_length = 0; - while ((ch >= name) && (*ch != '.') &&(*ch != '/')) - { - ch--; - ext_length++; - } - - if(*ch != '.') - { - - /* No extension is found. Return the default mime type. */ - if(http_type_string_max_size < (sizeof(NX_HTTP_SERVER_DEFAULT_MIME))) - { - /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into - the caller-supplied http_type_string. */ - return (0); - } - - /* return the default MIME type. */ - memcpy(http_type_string, NX_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_HTTP_SERVER_DEFAULT_MIME)); - return(sizeof(NX_HTTP_SERVER_DEFAULT_MIME) - 1); - } - - /* Position forward again, past the period. */ - ch++; - ext_length--; - - /* Now see what HTTP file type to return. */ - /* Search user defined MIME maps first. */ - if(server_ptr -> nx_http_server_mime_maps_additional && - (server_ptr -> nx_http_server_mime_maps_additional_num > 0)) - { - for(i = 0; i < server_ptr -> nx_http_server_mime_maps_additional_num; i++) - { - /* Check map extension and type length. */ - if (_nx_utility_string_length_check(server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_extension, - &map_ext_length, ext_length) || - _nx_utility_string_length_check(server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_type, - &map_type_length, http_type_string_max_size - 1)) - { - continue; - } - - if(_nx_http_server_memicmp((UCHAR *)ch, ext_length, - (UCHAR *)server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_extension, - map_ext_length) == NX_SUCCESS) - { - - /* Find the extension. Return the mapped MIME type. */ - memcpy(http_type_string, server_ptr -> nx_http_server_mime_maps_additional[i].nx_http_server_mime_map_type, map_type_length + 1); - return(map_type_length); - } - } - } - - /* Search default MIME maps. */ - for(i = 0; i < sizeof(_nx_http_server_mime_maps) / sizeof(NX_HTTP_SERVER_MIME_MAP); i++) - { - - /* Check map extension and type length. */ - if (_nx_utility_string_length_check(_nx_http_server_mime_maps[i].nx_http_server_mime_map_extension, - &map_ext_length, ext_length) || - _nx_utility_string_length_check(_nx_http_server_mime_maps[i].nx_http_server_mime_map_type, - &map_type_length, http_type_string_max_size - 1)) - { - continue; - } - - if(_nx_http_server_memicmp((UCHAR *)ch, ext_length, - (UCHAR *)_nx_http_server_mime_maps[i].nx_http_server_mime_map_extension, - map_ext_length) == NX_SUCCESS) - { - - /* Find the extension. Return the mapped MIME type. */ - memcpy(http_type_string, _nx_http_server_mime_maps[i].nx_http_server_mime_map_type, map_type_length + 1); - return(map_type_length); - } - } - - /* No extension matches. Return the default mime type. */ - if(http_type_string_max_size < (sizeof(NX_HTTP_SERVER_DEFAULT_MIME))) - { - /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into - the caller-supplied http_type_string. */ - return (0); - } - - /* return the default MIME type. */ - memcpy(http_type_string, NX_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_HTTP_SERVER_DEFAULT_MIME)); - return(sizeof(NX_HTTP_SERVER_DEFAULT_MIME) - 1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_base64_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the input string into a base64 */ -/* representation. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* length Length of name */ -/* base64name Encoded base64 name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* None */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_base64_encode(CHAR *name, UINT length, CHAR *base64name) -{ - -UINT pad; -UINT i, j; -UINT step; - - - /* Adjust the length to represent the base64 name. */ - length = ((length * 8) / 6); - - /* Default padding to none. */ - pad = 0; - - /* Determine if an extra conversion is needed. */ - if ((length * 6) % 24) - { - - /* Some padding is needed. */ - - /* Calculate the number of pad characters. */ - pad = (length * 6) % 24; - pad = (24 - pad) / 6; - pad = pad - 1; - - /* Adjust the length to pickup the character fraction. */ - length++; - } - - /* Setup index into the base64name. */ - j = 0; - - /* Compute the base64name. */ - step = 0; - i = 0; - while (j < length) - { - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first 6 bits of name character for index. */ - base64name[j++] = _nx_http_server_base64_array[((UINT) name[i]) >> 2]; - step++; - } - else if (step == 1) - { - - /* Use last 2 bits of name character and first 4 bits of next name character for index. */ - base64name[j++] = _nx_http_server_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; - i++; - step++; - } - else if (step == 2) - { - - /* Use last 4 bits of name character and first 2 bits of next name character for index. */ - base64name[j++] = _nx_http_server_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; - i++; - step++; - } - else /* Step 3 */ - { - - /* Use last 6 bits of name character for index. */ - base64name[j++] = _nx_http_server_base64_array[(((UINT) name[i]) & 0x3F)]; - i++; - step = 0; - } - } - - /* Determine if the index needs to be advanced. */ - if (step != 3) - i++; - - /* Now add the PAD characters. */ - while ((pad--) && (j < NX_HTTP_MAX_STRING)) - { - - /* Pad base64name with '=' characters. */ - base64name[j++] = '='; - } - - /* Put a NULL character in. */ - base64name[j] = NX_NULL; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_base64_decode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decodes the input base64 ASCII string and converts */ -/* it into a standard ASCII representation. */ -/* */ -/* INPUT */ -/* */ -/* base64name Encoded base64 name string */ -/* length Length of encoded base64 name */ -/* name Name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_basic_authenticate Basic authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_base64_decode(CHAR *base64name, UINT length, CHAR *name) -{ - -UINT i, j; -UINT value1, value2; -UINT step; - - - /* Adjust the length to represent the ASCII name. */ - length = ((length * 6) / 8); - - /* Setup index into the ASCII name. */ - j = 0; - - /* Compute the ASCII name. */ - step = 0; - i = 0; - while ((j < length) && (base64name[i]) && (base64name[i] != '=')) - { - - /* Derive values of the Base64 name. */ - if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) - value1 = (UINT) (base64name[i] - 'A'); - else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) - value1 = (UINT) (base64name[i] - 'a') + 26; - else if ((base64name[i] >= '0') && (base64name[i] <= '9')) - value1 = (UINT) (base64name[i] - '0') + 52; - else if (base64name[i] == '+') - value1 = 62; - else if (base64name[i] == '/') - value1 = 63; - else - value1 = 0; - - /* Derive value for the next character. */ - if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) - value2 = (UINT) (base64name[i+1] - 'A'); - else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) - value2 = (UINT) (base64name[i+1] - 'a') + 26; - else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) - value2 = (UINT) (base64name[i+1] - '0') + 52; - else if (base64name[i+1] == '+') - value2 = 62; - else if (base64name[i+1] == '/') - value2 = 63; - else - value2 = 0; - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first value and first 2 bits of second value. */ - name[j++] = (CHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); - i++; - step++; - } - else if (step == 1) - { - - /* Use last 4 bits of first value and first 4 bits of next value. */ - name[j++] = (CHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); - i++; - step++; - } - else if (step == 2) - { - - /* Use first 2 bits and following 6 bits of next value. */ - name[j++] = (CHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); - i++; - i++; - step = 0; - } - } - - /* Put a NULL character in. */ - name[j] = NX_NULL; -} - - -#ifdef NX_HTTP_DIGEST_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_digest_authenticate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for digest (MD5 only) authentication. */ -/* If the digest is correct, it returns a success. Otherwise, it */ -/* returns an authentication request to the requesting client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* name_ptr Pointer to name string */ -/* name_length Length of name string */ -/* password_ptr Pointer to password string */ -/* password_length Length of password string */ -/* realm_ptr Pointer to realm string */ -/* realm_length Length of realm string */ -/* auth_request_present Indicate if authentication */ -/* must be performed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_retrieve_digest_authorization Pickup authorization */ -/* _nx_http_server_digest_response_calculate Calculate the digest */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process Process GET request */ -/* _nx_http_server_put_process Process PUT request */ -/* _nx_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_digest_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, UINT name_length, CHAR *password_ptr, UINT password_length, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present) -{ - -CHAR authorization_response[NX_HTTP_MAX_ASCII_MD5 + 1]; -CHAR calculated_response[NX_HTTP_MAX_ASCII_MD5 + 1]; -CHAR authorization_uri[NX_HTTP_MAX_RESOURCE + 1]; -CHAR method[8]; -CHAR quote[2] = {0x22, 0}; -CHAR *buffer_ptr; -UINT i; -UINT status, status1, callback_status; -CHAR crlf[2] = {13,10}; -CHAR authorization_nc[NX_HTTP_MAX_RESOURCE + 1]; -CHAR authorization_cnonce[NX_HTTP_MAX_RESOURCE + 1]; - - /* Default to no authentication request detected. */ - *auth_request_present = NX_FALSE; - - /* Default the status to authenticate. */ - status = NX_HTTP_DIGEST_AUTHENTICATE; - - /* Is the authorization request present? */ - if (_nx_http_server_retrieve_digest_authorization(packet_ptr, authorization_response, authorization_uri, authorization_nc, authorization_cnonce)) - { - - /* Yes, an authorization request is present. */ - *auth_request_present = NX_TRUE; - - /* Pickup method from the packet. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - i = 0; - while (((buffer_ptr + i) < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (buffer_ptr[i] != ' ') && (i < (sizeof(method) - 1))) - { - - /* Copy bytes of method. */ - method[i] = buffer_ptr[i]; - i++; - } - - /* Null terminate method. */ - method[i] = (CHAR) NX_NULL; - - /* If the digest authenticate callback function is set, invoke the callback function. */ - if(server_ptr -> nx_http_server_digest_authenticate_callback) - { - callback_status = (server_ptr -> nx_http_server_digest_authenticate_callback)(server_ptr, name_ptr, realm_ptr, password_ptr, method, authorization_uri, authorization_nc, authorization_cnonce); - } - else - { - - /* If the digest authenticate callback is not set, assume it is success, for backward - compatibility reasons. */ - callback_status = NX_SUCCESS; - } - - - /* Calculate what the MD5 should be. */ - _nx_http_server_digest_response_calculate(server_ptr, name_ptr, name_length, realm_ptr, realm_length, password_ptr, password_length, _nx_http_server_nonce, method, authorization_uri, authorization_nc, authorization_cnonce, calculated_response); - - /* Determine if the calculated response is the same as the received response. */ - i = 0; - status = NX_SUCCESS; - while (i < NX_HTTP_MAX_ASCII_MD5 + 1) - { - /* Is there a mismatch? */ - if (calculated_response[i] != authorization_response[i]) - { - - /* Authorization mismatch. Continue to avoid timing attack. */ - status = NX_HTTP_DIGEST_AUTHENTICATE; - } - - /* Otherwise, look at next character. */ - i++; - } - /* If digest authenticate callback function returns non-success value, the request is - considered unauthenticated. */ - if(callback_status != NX_SUCCESS) - status = NX_HTTP_DIGEST_AUTHENTICATE; - } - - /* Determine if we need to send back an unauthorized request. */ - if (status == NX_HTTP_DIGEST_AUTHENTICATE) - { - - /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ - - /* Allocate a packet for sending the response back. */ - status1 = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if (status1 != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Return the internal NetX error. */ - return(status1); - } - - /* Insert the response header. */ - nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, NX_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_HTTP_STATUS_UNAUTHORIZED) - 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the type of authentication requested. */ - nx_packet_data_append(packet_ptr, "WWW-Authenticate: Digest realm=", 31, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the realm string into the buffer. */ - nx_packet_data_append(packet_ptr, realm_ptr, realm_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place a comma into the buffer. */ - nx_packet_data_append(packet_ptr, ",", 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the algorithm into the buffer. */ - nx_packet_data_append(packet_ptr, " algorithm=", 11, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the md5 tag into the buffer. */ - nx_packet_data_append(packet_ptr, "md5", 3, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place a comma into the buffer. */ - nx_packet_data_append(packet_ptr, ",", 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the nonce into the buffer. */ - nx_packet_data_append(packet_ptr, " nonce=", 7, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the nonce string into the buffer. */ - nx_packet_data_append(packet_ptr, _nx_http_server_nonce, sizeof(_nx_http_server_nonce) - 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the qop="auth" parameter string into the buffer. */ - nx_packet_data_append(packet_ptr, ", qop=\"auth\"", 12, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place another into the buffer to signal end of FULL HTTP response. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Send the response back to the client. */ - status1 = nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status1) - { - - /* Set the internal NetX error as the status return. */ - status = status1; - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Return the result of the authentication request. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_digest_response_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes the MD5 digest based on the supplied input */ -/* parameters. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* username Username string */ -/* realm Realm string */ -/* password Password string */ -/* nonce Authentication nonce string */ -/* method Request method string */ -/* uri Resource request string */ -/* nc Nonce count string */ -/* cnonce Client nonce string */ -/* result Computed digest string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_hex_ascii_convert Convert hex to ASCII */ -/* _nx_md5_initialize Initialize MD5 algorithm */ -/* _nx_md5_update Update MD5 digest */ -/* _nx_md5_digest_calculate Complete the MD5 algorithm */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_digest_authenticate Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_digest_response_calculate(NX_HTTP_SERVER *server_ptr, CHAR *username, UINT username_length, CHAR *realm, UINT realm_length, CHAR *password, UINT password_length, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result) -{ - -CHAR md5_binary[NX_HTTP_MAX_BINARY_MD5]; -CHAR ha1_string[NX_HTTP_MAX_ASCII_MD5 + 1]; -CHAR ha2_string[NX_HTTP_MAX_ASCII_MD5 + 1]; -UINT method_length; -UINT uri_length; -UINT nonce_length; -UINT nc_length; -UINT cnonce_length; - - /* Check string length. */ - if (_nx_utility_string_length_check(method, &method_length, 7) || - _nx_utility_string_length_check(uri, &uri_length, NX_HTTP_MAX_RESOURCE) || - _nx_utility_string_length_check(nonce, &nonce_length, sizeof(_nx_http_server_nonce) - 1) || - _nx_utility_string_length_check(nc, &nc_length, NX_HTTP_MAX_RESOURCE) || - _nx_utility_string_length_check(cnonce, &cnonce_length, NX_HTTP_MAX_RESOURCE)) - { - return; - } - - - /* Calculate the H(A1) portion of the digest. */ - _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) username, username_length); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) realm, realm_length); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) password, password_length); - _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); - - /* Convert this H(A1) portion to ASCII Hex representation. */ - _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, ha1_string); - - /* Make the H(A2) portion of the digest. */ - _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) method, method_length); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) uri, uri_length); - _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); - - /* Convert this H(A2) portion to ASCII Hex representation. */ - _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, ha2_string); - - /* Now make the final MD5 digest. */ - _nx_md5_initialize(&(server_ptr -> nx_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ha1_string, sizeof(ha1_string) - 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) nonce, nonce_length); - - /* Start of Internet Explorer bug work-around. */ - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) nc, nc_length); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) cnonce, cnonce_length); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":auth", 5); - /* End of Internet Explorer bug work-around. */ - - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_http_server_md5data), (unsigned char *) ha2_string, sizeof(ha2_string) - 1); - _nx_md5_digest_calculate(&(server_ptr -> nx_http_server_md5data), (unsigned char *) md5_binary); - - /* Finally, convert the response back to an ASCII string and place in - the destination. */ - _nx_http_server_hex_ascii_convert(md5_binary, NX_HTTP_MAX_BINARY_MD5, result); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_retrieve_digest_authorization PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the MD5 digest parameters from the */ -/* supplied request packet. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Request packet pointer */ -/* response Digest response pointer */ -/* uri URI from response pointer */ -/* nc Nonce count string */ -/* cnonce Client nonce string */ -/* */ -/* OUTPUT */ -/* */ -/* length Length of response (should be */ -/* 32). A value of 0 indicates */ -/* an error is present */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_digest_authenticate Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce) -{ - -UINT length; -UINT found; -CHAR *buffer_ptr; -CHAR *saved_buffer_ptr; - - - /* Set the found flag to false. */ - found = NX_FALSE; - - /* Default the authorization request to zero. */ - length = 0; - - /* Set the response and uri strings to NULL. */ - response[0] = NX_NULL; - uri[0] = NX_NULL; - - /* Internet Explorer bug work-around. */ - nc[0] = NX_NULL; - cnonce[0] = NX_NULL; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Authorization: " token first. */ - while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Authorization: token. */ - if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && - ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && - ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && - ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && - ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && - ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && - ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && - ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && - ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && - ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && - ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && - ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && - (*(buffer_ptr+13) == ':') && - (*(buffer_ptr+14) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 15; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Set the found flag back to false. */ - found = NX_FALSE; - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now check for the "Digest " token. */ - while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Digest token. */ - if (((*buffer_ptr == 'd') || (*buffer_ptr == 'D')) && - ((*(buffer_ptr+1) == 'i') || (*(buffer_ptr+1) == 'I')) && - ((*(buffer_ptr+2) == 'g') || (*(buffer_ptr+2) == 'G')) && - ((*(buffer_ptr+3) == 'e') || (*(buffer_ptr+3) == 'E')) && - ((*(buffer_ptr+4) == 's') || (*(buffer_ptr+4) == 'S')) && - ((*(buffer_ptr+5) == 't') || (*(buffer_ptr+5) == 'T')) && - (*(buffer_ptr+6) == ' ')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 7; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the second token was found. */ - if (!found) - { - - /* No, digest is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Start of Internet Explorer bug work-around (Parses nc and cnonce parameters). */ - - /* Save current buffer pointer, so each parameter search always starts from here. */ - saved_buffer_ptr = buffer_ptr; - - /* Now look for the nc in the digest response. */ - while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the nc token. */ - if (((*buffer_ptr == 'n') || (*buffer_ptr == 'N')) && - ((*(buffer_ptr+1) == 'c') || (*(buffer_ptr+1) == 'C')) && - (*(buffer_ptr+2) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 3; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes (should be no starting quote). */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the nc string (should be 8 hex characters; should not be quoted). */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote or comma is present (should be no ending quote). */ - if ((*buffer_ptr == (CHAR) 0x22) || (*buffer_ptr == ',')) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - nc[length++] = *buffer_ptr++; - } - - /* Null terminate the NC. */ - nc[length] = (CHAR) NX_NULL; - - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the cnonce in the digest response. */ - while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'n') || (*(buffer_ptr+1) == 'N')) && - ((*(buffer_ptr+2) == 'o') || (*(buffer_ptr+2) == 'O')) && - ((*(buffer_ptr+3) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+2) == 'C')) && - ((*(buffer_ptr+5) == 'e') || (*(buffer_ptr+2) == 'E')) && - (*(buffer_ptr+6) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 7; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the cnonce string. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - cnonce[length++] = *buffer_ptr++; - } - - /* Null terminate the CNONCE. */ - cnonce[length] = (CHAR) NX_NULL; - - /* End of Internet Explorer bug work-around. */ - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the uri in the digest response. */ - while (((buffer_ptr+4) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'u') || (*buffer_ptr == 'U')) && - ((*(buffer_ptr+1) == 'r') || (*(buffer_ptr+1) == 'R')) && - ((*(buffer_ptr+2) == 'i') || (*(buffer_ptr+2) == 'I')) && - (*(buffer_ptr+3) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 4; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the uri string. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - uri[length++] = *buffer_ptr++; - } - - /* Null terminate the URI. */ - uri[length] = (CHAR) NX_NULL; - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the digest response. */ - while (((buffer_ptr+9) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'r') || (*buffer_ptr == 'R')) && - ((*(buffer_ptr+1) == 'e') || (*(buffer_ptr+1) == 'E')) && - ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+3) == 'p') || (*(buffer_ptr+2) == 'P')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+2) == 'O')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+6) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+7) == 'e') || (*(buffer_ptr+2) == 'E')) && - (*(buffer_ptr+8) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 9; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and leading quote. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Finally, pickup the response. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (*buffer_ptr != (CHAR) 0x3A) && (length < NX_HTTP_MAX_ASCII_MD5)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the response string into the destination. */ - response[length++] = *buffer_ptr++; - } - - /* Null terminate response. */ - response[length] = (CHAR) NX_NULL; - - /* Check for an error. */ - if ((length != 32) || (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != (CHAR) 0x22)) - { - - /* Error, clear the length and the response string. */ - length = 0; - response[0] = (CHAR) NX_NULL; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_hex_ascii_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts hexadecimal characters into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* source Source hex string */ -/* source_length Length of source string */ -/* destination Pointer to destination string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_digest_response_calculate Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) -{ - -UINT i,j; -CHAR digit; - - - /* Setup destination index. */ - j = 0; - - /* Loop to process the entire source string. */ - for (i = 0; i < source_length; i++) - { - - /* Pickup the first nibble. */ - digit = (source[i] >> 4) & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - - /* Pickup the second nibble. */ - digit = source[i] & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - } - - /* Finally, place a NULL in the destination string. */ - destination[j] = (CHAR) NX_NULL; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_get_entity_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for getting the entity header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* entity_header_buffer Buffer to get entity header */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_get_entity_header */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) -{ - -#ifdef NX_HTTP_MULTIPART_ENABLE - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL)) - return NX_PTR_ERROR; - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_http_server_get_entity_header(server_ptr, packet_pptr, entity_header_buffer, buffer_size); -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(entity_header_buffer); - NX_PARAMETER_NOT_USED(buffer_size); - - return NX_HTTP_ERROR; -#endif /* NX_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_get_entity_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the entity header and skip header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* entity_header_buffer Buffer to get entity header */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_field_value_get */ -/* _nx_http_server_memicmp */ -/* _nx_http_server_boundary_find */ -/* nx_packet_release */ -/* nx_tcp_socket_receive */ -/* _nx_utility_string_length_check */ -/* memmove */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) -{ - -#ifdef NX_HTTP_MULTIPART_ENABLE -NX_HTTP_SERVER_MULTIPART *multipart_ptr; -UINT status; -UINT offset; -NX_PACKET *available_packet; -UINT crlf_match_count = 0; -UINT end_boundary_count = 2; -UINT skip_count = 2; -UCHAR *ch; -UINT index; - - /* Get multipart context. */ - multipart_ptr = &server_ptr -> nx_http_server_multipart; - - /* Is the multipart context initialized? */ - if(multipart_ptr -> nx_http_server_multipart_boundary[0] == 0) - { - ULONG field_length; - UINT quotation_index; - UINT i; - - /* No, it is not initialized. */ - - /* Get content type. */ - status = _nx_http_server_field_value_get(*packet_pptr, (UCHAR *)"content-type", 12, - multipart_ptr -> nx_http_server_multipart_boundary, NX_HTTP_MAX_HEADER_FIELD + 1); - if(status) - return status; - - /* Is the content type "multipart"? */ - /* Check the length. The length of "multipart/" is 10. */ - if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_http_server_multipart_boundary, (UINT *)&field_length, NX_HTTP_MAX_HEADER_FIELD)) - return NX_HTTP_ERROR; - if(field_length < 10) - return NX_HTTP_NOT_FOUND; - - /* Check the data. */ - if(_nx_http_server_memicmp(multipart_ptr -> nx_http_server_multipart_boundary, 10, - (UCHAR *)"multipart/", 10) != NX_SUCCESS) - return NX_HTTP_NOT_FOUND; - - /* Find the boundary. The length of "boundary=" is 9. */ - index = 0; - while((index + 9) < field_length) - { - if(_nx_http_server_memicmp(&multipart_ptr -> nx_http_server_multipart_boundary[index], 9, - (UCHAR *)"boundary=", 9) == NX_SUCCESS) - { - - break; - } - - /* Move the pointer up to the next character. */ - index++; - } - - /* Move the pointer up to the boundary value. */ - index += 9; - - /* Is boundary string found? */ - if((field_length - index) <= 1) - { - - /* Boundary not found or no boundary value. */ - return NX_HTTP_NOT_FOUND; - } - - /* Boundary is started with "CRLF--". */ - multipart_ptr -> nx_http_server_multipart_boundary[0] = 13; - multipart_ptr -> nx_http_server_multipart_boundary[1] = 10; - multipart_ptr -> nx_http_server_multipart_boundary[2] = '-'; - multipart_ptr -> nx_http_server_multipart_boundary[3] = '-'; - - /* Remove quotation. */ - if(multipart_ptr -> nx_http_server_multipart_boundary[index] == '"') - { - - /* Find the right quotation. */ - index++; - for(quotation_index = field_length; quotation_index > index; quotation_index--) - { - if(multipart_ptr -> nx_http_server_multipart_boundary[quotation_index] == '"') - break; - } - - /* Is the right quotation found? */ - if(quotation_index > index) - multipart_ptr -> nx_http_server_multipart_boundary[quotation_index] = 0; - else - { - - /* Boundary not valid. */ - return NX_HTTP_NOT_FOUND; - } - - /* Leave boundary string only. */ - memmove(&multipart_ptr -> nx_http_server_multipart_boundary[4], - &multipart_ptr -> nx_http_server_multipart_boundary[index], - quotation_index - index + 1); - } - else - { - - /* Directly copy boundary string to the head field. */ - i = 4; - index -= 4; - do - { - multipart_ptr -> nx_http_server_multipart_boundary[i] = multipart_ptr -> nx_http_server_multipart_boundary[index + i]; - i++; - }while((multipart_ptr -> nx_http_server_multipart_boundary[i - 1] != 0) && - (multipart_ptr -> nx_http_server_multipart_boundary[i - 1] != ' ')); - - /* Set the terminal character. */ - multipart_ptr -> nx_http_server_multipart_boundary[i - 1] = 0; - } - } - - /* Find the boundary. */ - while(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_FALSE) - { - if(_nx_http_server_boundary_find(server_ptr, packet_pptr) != NX_SUCCESS) - break; - } - - /* Whether the boundary is found? */ - if(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_FALSE) - return NX_HTTP_NOT_FOUND; - - /* Update the packet and offset. */ - _nx_http_server_boundary_find(server_ptr, packet_pptr); - - /* Get offset of available data in the packet. */ - offset = multipart_ptr -> nx_http_server_multipart_available_offset; - - /* Skip data that are not header. */ - available_packet = *packet_pptr; - - if(offset >= available_packet -> nx_packet_length) - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* All data has been processed. Get a new packet. */ - if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* FIXME: Check if the "offset" should be updated. */ - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; - } -#ifndef NX_DISABLE_PACKET_CHAIN - else - { - while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) - { - offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); - - /* Get next packet. */ - available_packet = available_packet -> nx_packet_next; - } - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Get entity header. */ - ch = available_packet -> nx_packet_prepend_ptr + offset; - index = 0; - while((entity_header_buffer == NX_NULL) || (index < buffer_size)) - { - - /* Calculate valid CRLF. */ - if((*ch == 13) && ((crlf_match_count & 1) == 0)) - crlf_match_count++; - else if((*ch == 10) && ((crlf_match_count & 1) == 1)) - crlf_match_count++; - else if(*ch == '-') - { - - /* Check whether the last boundary is found. */ - if(end_boundary_count < 3) - end_boundary_count--; - - if(end_boundary_count == 0) - break; - } - else - { - end_boundary_count = 0xFF; - crlf_match_count = 0; - } - - /* Copy data to buffer. */ - if(skip_count >0) - skip_count--; - else - { - if(entity_header_buffer) - entity_header_buffer[index] = *ch; - index++; - } - multipart_ptr -> nx_http_server_multipart_available_offset++; - - /* Check whether two CRLFs are found. */ - if(crlf_match_count == 4) - break; - - /* Get next character. */ - if((ch + 1) >= available_packet -> nx_packet_append_ptr) - { - - /* ch points to the end of this packet. */ -#ifndef NX_DISABLE_PACKET_CHAIN - if(available_packet -> nx_packet_next) - { - - /* Copy data from next packet. */ - available_packet = available_packet -> nx_packet_next; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* Get a new packet and copy data from it. */ - status = nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; - - /* Reset the offset. */ - multipart_ptr -> nx_http_server_multipart_available_offset = 0; - } - - ch = available_packet -> nx_packet_prepend_ptr; - } - else - ch++; - - } - - /* Check whether two CRLFs are found. */ - if(crlf_match_count == 4) - { - - /* Set terminal 0. */ - if(entity_header_buffer) - entity_header_buffer[index - 4] = 0; - return NX_SUCCESS; - } - else - return NX_HTTP_NOT_FOUND; -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(entity_header_buffer); - NX_PARAMETER_NOT_USED(buffer_size); - - return NX_HTTP_ERROR; -#endif /* NX_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_get_entity_content PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for getting the entity content. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* available_offset Return the offset */ -/* available_length Return the length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_get_entity_content */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) -{ - -#ifdef NX_HTTP_MULTIPART_ENABLE - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (available_offset == NX_NULL) || (available_length == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check whether boundary is found. */ - if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_boundary[0] == 0) - return(NX_HTTP_ERROR); - - return _nx_http_server_get_entity_content(server_ptr, packet_pptr, available_offset, available_length); -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(available_offset); - NX_PARAMETER_NOT_USED(available_length); - - return NX_HTTP_ERROR; -#endif /* NX_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_get_entity_content PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the entity content. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* available_offset Return the offset */ -/* available_length Return the length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_boundary_find */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) -{ - -#ifdef NX_HTTP_MULTIPART_ENABLE -UINT status; - - /* Whether the boundary is found? */ - if(server_ptr -> nx_http_server_multipart.nx_http_server_multipart_boundary_find == NX_TRUE) - return NX_HTTP_BOUNDARY_ALREADY_FOUND; - - status = _nx_http_server_boundary_find(server_ptr, packet_pptr); - if(status) - return status; - - /* Set the offset and length. */ - *available_offset = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_available_offset; - *available_length = server_ptr -> nx_http_server_multipart.nx_http_server_multipart_available_length; - - return NX_SUCCESS; -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(available_offset); - NX_PARAMETER_NOT_USED(available_length); - - return NX_HTTP_ERROR; -#endif /* NX_HTTP_MULTIPART_ENABLE */ -} - - -#ifdef NX_HTTP_MULTIPART_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_boundary_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds boundary in packet even if it is chained. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release */ -/* nx_tcp_socket_receive */ -/* _nx_http_server_match_string */ -/* _nx_utility_string_length_check */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_entity_header */ -/* _nx_http_server_get_entity_content */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_boundary_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr) -{ - -NX_HTTP_SERVER_MULTIPART *multipart_ptr; -NX_PACKET *available_packet; -UINT offset; -ULONG match_count = 0; -UCHAR *match_end_ptr; -UINT boundary_length; - - /* Get multipart context. */ - multipart_ptr = &server_ptr -> nx_http_server_multipart; - - /* Is boundary already found? */ - if(multipart_ptr -> nx_http_server_multipart_boundary_find == NX_TRUE) - { - - /* Yes. Update the packet and offset. */ - if(multipart_ptr -> nx_http_server_multipart_next_packet != NX_NULL) - { - nx_packet_release(*packet_pptr); - *packet_pptr = multipart_ptr -> nx_http_server_multipart_next_packet; - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = multipart_ptr -> nx_http_server_multipart_next_packet; - } - - multipart_ptr -> nx_http_server_multipart_available_offset = multipart_ptr -> nx_http_server_multipart_next_available_offset; - - /* Reset next packet and available offset. */ - multipart_ptr -> nx_http_server_multipart_next_packet = NX_NULL; - multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; - - /* Reset boundary find. */ - multipart_ptr -> nx_http_server_multipart_boundary_find = NX_FALSE; - - return NX_SUCCESS; - } - - /* Is the boundary in the next packet? */ - if(multipart_ptr -> nx_http_server_multipart_next_packet) - { - - /* Yes, we're done with this packet. */ - nx_packet_release(*packet_pptr); - - /* Update the packet and multipart offset. */ - *packet_pptr = multipart_ptr -> nx_http_server_multipart_next_packet; - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = multipart_ptr -> nx_http_server_multipart_next_packet; - multipart_ptr -> nx_http_server_multipart_available_offset = 0; - } - else if(multipart_ptr -> nx_http_server_multipart_next_available_offset) - { - - /* Find boundary in this packet. */ - /* Update the offset. */ - multipart_ptr -> nx_http_server_multipart_available_offset = multipart_ptr -> nx_http_server_multipart_next_available_offset; - } - else - { - - /* Find boundary from this packet. */ - /* Initialize the offset. */ - multipart_ptr -> nx_http_server_multipart_next_available_offset = multipart_ptr -> nx_http_server_multipart_available_offset; - } - - /* Reset next packet. */ - multipart_ptr -> nx_http_server_multipart_next_packet = NX_NULL; - - /* Reset boundary find. */ - multipart_ptr -> nx_http_server_multipart_boundary_find = NX_FALSE; - - - /* Get offset of available data in the packet. */ - offset = multipart_ptr -> nx_http_server_multipart_available_offset; - - /* Skip data that are not header. */ - available_packet = *packet_pptr; - - if(offset >= available_packet -> nx_packet_length) - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* All data has been processed. Get a new packet. */ - if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_http_server_multipart.nx_http_server_multipart_last_packet = available_packet; - - /* Reset the offset. */ - multipart_ptr -> nx_http_server_multipart_available_offset = 0; - multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; - offset = 0; - } - else - { -#ifndef NX_DISABLE_PACKET_CHAIN - while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) - { - offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); - - /* Get next packet. */ - available_packet = available_packet -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Check boundary length. */ - if (_nx_utility_string_length_check((CHAR *)multipart_ptr->nx_http_server_multipart_boundary, &boundary_length, NX_HTTP_MAX_HEADER_FIELD)) - { - return(NX_HTTP_ERROR); - } - - /* Look for the boundary string in the (next) packet. */ - while(_nx_http_server_match_string(available_packet -> nx_packet_prepend_ptr + offset, - available_packet -> nx_packet_append_ptr, - multipart_ptr -> nx_http_server_multipart_boundary, - boundary_length, - &match_count, &match_end_ptr) != NX_SUCCESS) - { - - /* Match string in the next packet. */ -#ifndef NX_DISABLE_PACKET_CHAIN - if(available_packet -> nx_packet_next) - { - multipart_ptr -> nx_http_server_multipart_next_available_offset += (UINT)((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) - offset); - available_packet = available_packet -> nx_packet_next; - offset = 0; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - break; - } - - /* Is boundary matched? */ - if(match_end_ptr) - { - - /* Yes. Found a match. */ - multipart_ptr -> nx_http_server_multipart_next_available_offset += (UINT)((UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) - offset); - multipart_ptr -> nx_http_server_multipart_available_length = multipart_ptr -> nx_http_server_multipart_next_available_offset - multipart_ptr -> nx_http_server_multipart_available_offset - match_count; - multipart_ptr -> nx_http_server_multipart_boundary_find = NX_TRUE; - - } - else if(match_count) - { - - /* Set the available length to all remaining data. */ - multipart_ptr -> nx_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_http_server_multipart_available_offset; - - /* Partial match. Get another packet. */ - if(nx_tcp_socket_receive(&(server_ptr -> nx_http_server_socket), &available_packet, NX_HTTP_SERVER_TIMEOUT_RECEIVE) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_HTTP_TIMEOUT); - } - - /* Match the boundary again. */ - if(_nx_http_server_match_string(available_packet -> nx_packet_prepend_ptr, - available_packet -> nx_packet_append_ptr, - multipart_ptr -> nx_http_server_multipart_boundary, - boundary_length, - &match_count, &match_end_ptr) == NX_SUCCESS) - { - - /* Yes. Find a match. */ - if((ULONG)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) < match_count) - { - - /* The boundary is between two packets. */ - multipart_ptr -> nx_http_server_multipart_next_available_offset = (UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr); - multipart_ptr -> nx_http_server_multipart_available_length -= boundary_length - multipart_ptr -> nx_http_server_multipart_next_available_offset; - multipart_ptr -> nx_http_server_multipart_boundary_find = NX_TRUE; - } - else - { - - /* The boundary is in the next packet. */ - multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; - } - } - else - { - - /* The boundary is not found. */ - multipart_ptr -> nx_http_server_multipart_next_available_offset = 0; - } - - /* Store the packet. */ - multipart_ptr -> nx_http_server_multipart_next_packet = available_packet; - - } - else - { - - /* Set the available length to all remaining data. */ - multipart_ptr -> nx_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_http_server_multipart_available_offset; - multipart_ptr -> nx_http_server_multipart_next_available_offset = (*packet_pptr) -> nx_packet_length; - } - - return NX_SUCCESS; -} -#endif /* NX_HTTP_MULTIPART_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_match_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares a target string in specified memory area. */ -/* */ -/* INPUT */ -/* */ -/* src_start Pointer to start of source */ -/* src_end Pointer to end of source */ -/* target Pointer to target */ -/* target_length Length of target */ -/* match_count Return the match count */ -/* match_end_ptr Return the end match position */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check */ -/* memcmp */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_boundary_find */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr) -{ - -UCHAR *ch; -ULONG pre_match = *match_count; -ULONG remain_match; - - /* Initialize. */ - *match_end_ptr = NX_NULL; - - /* Process part match. */ - while(pre_match) - { - - /* Compare pre-match. */ - if(memcmp(target, target + (*match_count - pre_match), pre_match) == 0) - { - - /* Calculate the remain match. */ - remain_match = target_length - pre_match; - - /* The pre-match is the same. */ - if((ULONG)(src_end - src_start) < remain_match) - remain_match = (ULONG)(src_end - src_start); - - if(memcmp(target + pre_match, src_start, remain_match) == 0) - { - - /* Remain part matches. */ - *match_count = pre_match + remain_match; - - if(*match_count < target_length) - { - - /* Part match. */ - return NX_HTTP_NOT_FOUND; - } - - /* Full match. */ - *match_end_ptr = src_start + remain_match; - return NX_SUCCESS; - } - } - - pre_match--; - } - - ch = src_start; - - /* Perform full match. */ - *match_count = target_length; - while(ch + *match_count <= src_end) - { - if(memcmp(ch, target, *match_count) == 0) - { - - /* Find a match. */ - *match_end_ptr = ch + *match_count; - return NX_SUCCESS; - } - - ch++; - } - - /* Perform part match. */ - for(*match_count = target_length - 1; *match_count > 0; *match_count = *match_count - 1) - { - if(ch + *match_count <= src_end) - { - if(memcmp(ch, target, *match_count) == 0) - { - - /* Find a match. */ - return NX_HTTP_NOT_FOUND; - } - - ch++; - } - } - - return NX_HTTP_NOT_FOUND; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_field_value_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets field value by field name from HTTP header. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet */ -/* field_name Name of filed in header */ -/* name_length Length of filed name */ -/* field_value Return fieald of value */ -/* field_value_size Size of fieald_value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check */ -/* _nx_http_server_memicmp */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process */ -/* _nx_http_server_get_entity_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size) -{ - -UCHAR *ch; -UINT index; - - - /* Initialize. */ - ch = packet_ptr -> nx_packet_prepend_ptr; - - /* Loop to find field name. */ - while(ch + name_length < packet_ptr -> nx_packet_append_ptr) - { - if(_nx_http_server_memicmp(ch, name_length, field_name, name_length) == NX_SUCCESS) - { - - /* Field name found. */ - break; - } - - /* Move the pointer up to the next character. */ - ch++; - } - - /* Skip field name and ':'. */ - ch += name_length + 1; - - /* Is field name found? */ - if(ch >= packet_ptr -> nx_packet_append_ptr) - return NX_HTTP_NOT_FOUND; - - /* Skip white spaces. */ - while(*ch == ' ') - { - if(ch >= packet_ptr -> nx_packet_append_ptr) - return NX_HTTP_NOT_FOUND; - - /* Get next character. */ - ch++; - } - - /* Copy field value. */ - index = 0; - while(index < field_value_size) - { - - /* Whether the end of line CRLF is not found? */ - if(ch + 2 > packet_ptr -> nx_packet_append_ptr) - return NX_HTTP_NOT_FOUND; - - /* Compare CRLF. */ - if((*ch == 13) && (*(ch + 1) == 10)) - break; - - /* Copy data. */ - field_value[index++] = *ch++; - } - - /* Buffer overflow? */ - if(index == field_value_size) - return NX_HTTP_NOT_FOUND; - - /* Trim white spaces. */ - while((index > 0) && (field_value[index - 1] == ' ')) - index--; - - /* Append terminal 0. */ - field_value[index] = 0; - - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_memicmp PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares two pieces of memory case insensitive. */ -/* */ -/* INPUT */ -/* */ -/* src Pointer to source */ -/* src_length Length of source */ -/* dest Pointer to destination */ -/* dest_length Length of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_entity_header */ -/* _nx_http_server_field_value_get */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) -{ -UCHAR ch; - - /* Compare the length. */ - if(src_length != dest_length) - return NX_HTTP_FAILED; - - while(src_length) - { - - /* Is src lowercase? */ - if((*src >= 'a') && (*src <= 'z')) - ch = (UCHAR)(*src - 'a' + 'A'); - - /* Is src uppercase? */ - else if((*src >= 'A') && (*src <= 'Z')) - ch = (UCHAR)(*src - 'A' + 'a'); - else - ch = *src; - - /* Compare case insensitive. */ - if((*src != *dest) && (ch != *dest)) - return NX_HTTP_FAILED; - - /* Pickup next character. */ - src_length--; - src++; - dest++; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_generate_response_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function generates HTTP response header. */ -/* */ -/* Note: The strings of status code, content type length and additional*/ -/* header length must be NULL-terminated and length of this string */ -/* matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate */ -/* nx_packet_data_append */ -/* memcmp */ -/* _nx_utility_string_length_check */ -/* _nx_http_server_number_convert */ -/* _nx_http_server_date_to_string */ -/* nx_packet_release */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process */ -/* _nx_http_server_put_process */ -/* _nx_http_server_delete_process */ -/* _nx_http_server_response_send */ -/* _nx_http_server_callback_generate_response_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length) -{ - -UINT status; -UINT temp; -CHAR temp_string[30]; -CHAR crlf[2] = {13,10}; -NX_PACKET *packet_ptr; -CHAR status_code_ok; -CHAR status_code_not_modified; - - /* Allocate a packet for sending the response back. */ - status = nx_packet_allocate(server_ptr -> nx_http_server_packet_pool_ptr, packet_pptr, NX_TCP_PACKET, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if(status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_http_server_allocation_errors++; - - /* Just return. */ - return status; - } - else - packet_ptr = *packet_pptr; - - /* Check status code. */ - if(memcmp(status_code, NX_HTTP_STATUS_OK, sizeof(NX_HTTP_STATUS_OK)) == 0) - status_code_ok = NX_TRUE; - else - status_code_ok = NX_FALSE; - - if(memcmp(status_code, NX_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_HTTP_STATUS_NOT_MODIFIED)) == 0) - status_code_not_modified = NX_TRUE; - else - status_code_not_modified = NX_FALSE; - - /* Insert the status line. */ - /* Place HTTP-Version. */ - status = nx_packet_data_append(packet_ptr, NX_HTTP_VERSION, sizeof(NX_HTTP_VERSION) - 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert space. */ - status += nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert Status-Code and Reason-Phrase. */ - status += nx_packet_data_append(packet_ptr, status_code, status_code_length, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if there is content_type. */ - if(content_type) - { - - /* Insert the content type. */ - status += nx_packet_data_append(packet_ptr, "Content-Type: ", 14, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - status += nx_packet_data_append(packet_ptr, content_type, content_type_length, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - -#ifndef NX_HTTP_SERVER_OMIT_CONTENT_LENGTH - /* Determine if there is content_length. */ - if(content_length || (status_code_not_modified == NX_TRUE)) - { - - /* Close. */ - status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if(content_length) - { - - /* Convert the content_length to ASCII representation. */ - temp = _nx_http_server_number_convert(content_length, temp_string); - - /* Place the "Content-Length" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Content-Length: ", 16, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - status += nx_packet_data_append(packet_ptr, temp_string, temp, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - } - else -#endif /* NX_HTTP_SERVER_OMIT_CONTENT_LENGTH */ - { - - /* Place the "Connection" field in the header. */ - - /* Force close the connection since there's no content-length. */ - status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Insert Date header if callback function is set. */ - if(server_ptr -> nx_http_server_gmt_get) - { - NX_HTTP_SERVER_DATE date; - - /* Get current date. */ - server_ptr -> nx_http_server_gmt_get(&date); - - /* Convert date to string. */ - temp = _nx_http_server_date_to_string(&date, temp_string); - - /* Place the "Date" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Date: ", 6, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert date. */ - status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Set Cache Control if callback function is set. */ - if((server_ptr -> nx_http_server_cache_info_get) && - ((status_code_ok == NX_TRUE) || (status_code_not_modified == NX_TRUE)) && - (server_ptr -> nx_http_server_request_type == NX_HTTP_SERVER_GET_REQUEST)) - { - UINT max_age; - - /* Get cache infomation. */ - if(server_ptr -> nx_http_server_cache_info_get(server_ptr -> nx_http_server_request_resource, &max_age, &date) == NX_TRUE) - { - - /* Place "Cache-control" header. */ - status += nx_packet_data_append(packet_ptr, "Cache-Control: max-age=", 23, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Convert the max-age to ASCII representation. */ - temp = _nx_http_server_number_convert(max_age, temp_string); - status += nx_packet_data_append(packet_ptr, temp_string, temp, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if(status_code_ok == NX_TRUE) - { - - /* Convert date to string. */ - temp = _nx_http_server_date_to_string(&date, temp_string); - - /* Place the "Last-Modified" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Last-Modified: ", 15, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert date. */ - status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - } - } - - /* Insert additional header. */ - if(additional_header) - { - - status += nx_packet_data_append(packet_ptr, additional_header, additional_header_length, - server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_generate_response_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for generating HTTP response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* content_length Length of content */ -/* content_type Type of content */ -/* additional_header Other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_generate_response_header */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (status_code == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_http_server_callback_generate_response_header(server_ptr, packet_pptr, status_code, content_length, content_type, additional_header); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_generate_response_header_extended */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for generating HTTP response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_generate_response_header_extended */ -/* Actual responder header */ -/* generation function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (status_code == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_http_server_callback_generate_response_header_extended(server_ptr, packet_pptr, status_code, status_code_length, content_length, - content_type, content_type_length, additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_generate_response_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to generate HTTP */ -/* response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* content_length Length of content */ -/* content_type Type of content */ -/* additional_header Other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_generate_response_header */ -/* Internal responder header */ -/* generation function */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header) -{ -UINT status_code_length = 0; -UINT content_type_length = 0; -UINT additional_header_length = 0; - - /* Check status code, content type and additional header length. */ - if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || - (content_type && _nx_utility_string_length_check(content_type, &content_type_length, NX_MAX_STRING_LENGTH)) || - (additional_header && _nx_utility_string_length_check(additional_header, &additional_header_length, NX_MAX_STRING_LENGTH))) - { - return(NX_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - return _nx_http_server_generate_response_header(server_ptr, packet_pptr, status_code, status_code_length, content_length, - content_type, content_type_length, additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_generate_response_header_extended */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to generate HTTP */ -/* response header. */ -/* */ -/* Note: The strings of status code, content type length and additional*/ -/* header length must be NULL-terminated and length of this string */ -/* matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_generate_response_header */ -/* Internal responder header */ -/* generation function */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length) -{ - -UINT temp_status_code_length = 0; -UINT temp_content_type_length = 0; -UINT temp_add_header_length = 0; - - /* Check status code, content type and additional header length. */ - if (_nx_utility_string_length_check(status_code, &temp_status_code_length, status_code_length) || - (content_type && _nx_utility_string_length_check(content_type, &temp_content_type_length, content_type_length)) || - (additional_header && _nx_utility_string_length_check(additional_header, &temp_add_header_length, additional_header_length))) - { - return(NX_HTTP_ERROR); - } - - /* Validate string length. */ - if ((status_code_length != temp_status_code_length) || - (content_type && content_type_length != temp_content_type_length) || - (additional_header && additional_header_length != temp_add_header_length)) - { - return(NX_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - return _nx_http_server_generate_response_header(server_ptr, packet_pptr, status_code, status_code_length, content_length, - content_type, content_type_length, additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_callback_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for sending a packet. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_callback_packet_send */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - return _nx_http_server_callback_packet_send(server_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_callback_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to send a packet. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_send */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - - /* Send internal. */ - return nx_tcp_socket_send(&(server_ptr -> nx_http_server_socket), packet_ptr, NX_HTTP_SERVER_TIMEOUT_SEND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_gmt_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting gmt callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* gmt_get Pointer to application's */ -/* GMT time function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_gmt_callback_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (gmt_get == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_http_server_gmt_callback_set(server_ptr, gmt_get); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_gmt_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets gmt callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* gmt_get Pointer to application's */ -/* GMT time function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the function pointer. */ - server_ptr -> nx_http_server_gmt_get = gmt_get; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_cache_info_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting cache info callback function.*/ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* cache_info_get Pointer to application's */ -/* cache information function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_cache_info_callback_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (cache_info_get == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_http_server_cache_info_callback_set(server_ptr, cache_info_get); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_cache_info_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets cache info callback function. */ -/* */ -/* Note: The string length of resource in cache_info_get is limited by */ -/* NX_HTTP_MAX_RESOURCE. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* cache_info_get Pointer to application's */ -/* cache information function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the function pointer. */ - server_ptr -> nx_http_server_cache_info_get = cache_info_get; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_date_to_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts from date to string. */ -/* */ -/* INPUT */ -/* */ -/* date Pointer to HTTP date */ -/* string Pointer to output buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_date_convert */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_get_process */ -/* _nx_http_server_generate_response_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_date_to_string(NX_HTTP_SERVER_DATE *date, CHAR *string) -{ - -UINT index = 0; - - /* RDC1122-date. */ - /* Append weekday. */ - string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday]); - string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday] + 1); - string[index++] = *(_nx_http_server_weekday[date -> nx_http_server_weekday] + 2); - string[index++] = ','; - string[index++] = ' '; - - /* Convert and append day. */ - _nx_http_server_date_convert(date -> nx_http_server_day, 2, &string[index]); - index += 2; - string[index++] = ' '; - - /* Append month. */ - string[index++] = *(_nx_http_server_month[date -> nx_http_server_month]); - string[index++] = *(_nx_http_server_month[date -> nx_http_server_month] + 1); - string[index++] = *(_nx_http_server_month[date -> nx_http_server_month] + 2); - string[index++] = ' '; - - /* Convert and append year. */ - _nx_http_server_date_convert(date -> nx_http_server_year, 4, &string[index]); - index += 4; - string[index++] = ' '; - - /* Convert and append hour. */ - _nx_http_server_date_convert(date -> nx_http_server_hour, 2, &string[index]); - index += 2; - string[index++] = ':'; - - /* Convert and append minute. */ - _nx_http_server_date_convert(date -> nx_http_server_minute, 2, &string[index]); - index += 2; - string[index++] = ':'; - - /* Convert and append second. */ - _nx_http_server_date_convert(date -> nx_http_server_second, 2, &string[index]); - index += 2; - string[index++] = ' '; - string[index++] = 'G'; - string[index++] = 'M'; - string[index++] = 'T'; - - return index; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_date_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a date from number to string. */ -/* */ -/* INPUT */ -/* */ -/* date The number to convert */ -/* count Digital count for string */ -/* string Pointer to output buffer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_http_server_date_to_string */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_http_server_date_convert(UINT date, UINT count, CHAR *string) -{ - -UINT digit; - - /* Initialize all 4 bytes to digit 0. */ - *((ULONG*)string) = 0x30303030; - string[count] = 0; - - /* Loop to convert the number to ASCII. */ - while(count > 0) - { - count--; - - /* Compute the next decimal digit. */ - digit = date % 10; - - /* Update the input date. */ - date = date / 10; - - /* Store the new digit in ASCII form. */ - string[count] = (CHAR) (digit + 0x30); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_mime_maps_additional_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting additional MIME maps. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* mime_maps Pointer MIME map array */ -/* mime_maps_num Number of MIME map array */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_mime_maps_additional_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_http_server_id != NXD_HTTP_SERVER_ID) || (mime_maps == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_http_server_mime_maps_additional_set(server_ptr, mime_maps, mime_maps_num); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_mime_maps_additional_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets additional MIME maps. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* mime_maps Pointer MIME map array */ -/* mime_maps_num Number of MIME map array */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the mime maps. */ - server_ptr -> nx_http_server_mime_maps_additional = mime_maps; - server_ptr -> nx_http_server_mime_maps_additional_num = mime_maps_num; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_digest_authenticate_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for service to set digest */ -/* authenticate callback function. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* digest_authenticate_callback Pointer to application's */ -/* digest authenticate callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_digest_authenticate_notify_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)) -{ - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (digest_authenticate_callback == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - return(_nx_http_server_digest_authenticate_notify_set(http_server_ptr, digest_authenticate_callback)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_digest_authenticate_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets digest authenticate callback function. */ -/* */ -/* Note: The string length of realm_ptr, name_ptr, and password_ptr in */ -/* digest_authenticate_callback is checked internally. The method, */ -/* authorization_uri, authorization_nc and authorization_cnonce in */ -/* digest_authenticate_callback are built internally. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* digest_authenticate_callback Pointer to application's */ -/* digest authenticate callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)) -{ - -#ifdef NX_HTTP_DIGEST_ENABLE - http_server_ptr -> nx_http_server_digest_authenticate_callback = digest_authenticate_callback; - - return(NX_SUCCESS); -#else - NX_PARAMETER_NOT_USED(http_server_ptr); - NX_PARAMETER_NOT_USED(digest_authenticate_callback); - - return(NX_NOT_SUPPORTED); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_http_server_authentication_check_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks errors for setting authentication checking */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* authentication_check_extended Pointer to application's */ -/* authentication checking */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_authentication_check_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (authentication_check_extended == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual authentication checking set function. */ - status= _nx_http_server_authentication_check_set(http_server_ptr, authentication_check_extended); - - /* Return staus. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_http_server_authentication_check_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the callback function of authentication checking.*/ -/* */ -/* Note: The strings of name, password and realm must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* authentication_check_extended Pointer to application's */ -/* authentication checking */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) -{ - - /* Set the extended authentication checking function. */ - http_server_ptr -> nx_http_server_authentication_check_extended = authentication_check_extended; - - /* Return success. */ - return(NX_SUCCESS); -} - diff --git a/protocol_handlers/http/nxd_http_server.h b/protocol_handlers/http/nxd_http_server.h deleted file mode 100644 index 8b3401ed..00000000 --- a/protocol_handlers/http/nxd_http_server.h +++ /dev/null @@ -1,652 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_http_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_HTTP_SERVER_H -#define NXD_HTTP_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_api.h" -/* If not using FileX, define this option and define the file writing services - declared in filex_stub.h. */ -/* #define NX_HTTP_NO_FILEX */ - -#ifndef NX_HTTP_NO_FILEX -#include "fx_api.h" -#else -#include "filex_stub.h" -#endif - -/* Define the HTTP Server ID. */ - -#define NXD_HTTP_SERVER_ID 0x48545451UL - - -/* Define the HTTP version. */ -#define NX_HTTP_VERSION "HTTP/1.0" - -/* Enable Digest authentication. -#define NX_HTTP_DIGEST_ENABLE -*/ - -/* Define HTTP TCP socket create options. */ - -#ifndef NX_HTTP_TYPE_OF_SERVICE -#define NX_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_HTTP_FRAGMENT_OPTION -#define NX_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_HTTP_TIME_TO_LIVE -#define NX_HTTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_HTTP_SERVER_PRIORITY -#define NX_HTTP_SERVER_PRIORITY 16 -#endif - -#ifndef NX_HTTP_SERVER_WINDOW_SIZE -#define NX_HTTP_SERVER_WINDOW_SIZE 2048 -#endif - -#ifndef NX_HTTP_SERVER_TIMEOUT_ACCEPT -#define NX_HTTP_SERVER_TIMEOUT_ACCEPT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_HTTP_SERVER_TIMEOUT_RECEIVE -#define NX_HTTP_SERVER_TIMEOUT_RECEIVE (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_HTTP_SERVER_TIMEOUT_SEND -#define NX_HTTP_SERVER_TIMEOUT_SEND (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_HTTP_SERVER_TIMEOUT_DISCONNECT -#define NX_HTTP_SERVER_TIMEOUT_DISCONNECT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_HTTP_SERVER_TIMEOUT -#define NX_HTTP_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_HTTP_SERVER_MAX_PENDING -#define NX_HTTP_SERVER_MAX_PENDING 5 -#endif - -#ifndef NX_HTTP_SERVER_THREAD_TIME_SLICE -#define NX_HTTP_SERVER_THREAD_TIME_SLICE 2 -#endif - -#ifndef NX_HTTP_MAX_RESOURCE -#define NX_HTTP_MAX_RESOURCE 40 -#endif - -#ifndef NX_HTTP_MAX_NAME -#define NX_HTTP_MAX_NAME 20 -#endif - -#ifndef NX_HTTP_MAX_PASSWORD -#define NX_HTTP_MAX_PASSWORD 20 -#endif - -#ifndef NX_PHYSICAL_TRAILER -#define NX_PHYSICAL_TRAILER 4 -#endif - -#ifndef NX_HTTP_SERVER_MIN_PACKET_SIZE -#define NX_HTTP_SERVER_MIN_PACKET_SIZE 600 -#endif - -/* Define the HTTP server retry parameters. */ - -#ifndef NX_HTTP_SERVER_RETRY_SECONDS -#define NX_HTTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ -#endif - -#ifndef NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH -#define NX_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ -#endif - -#ifndef NX_HTTP_SERVER_RETRY_MAX -#define NX_HTTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ -#endif - -#ifndef NX_HTTP_SERVER_RETRY_SHIFT -#define NX_HTTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ -#endif - -/* NX_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ -#define NX_HTTP_MAX_STRING ((NX_HTTP_MAX_NAME + NX_HTTP_MAX_PASSWORD + 1) * 4 / 3 + 1) - -#define NX_HTTP_MAX_BINARY_MD5 16 -#define NX_HTTP_MAX_ASCII_MD5 32 - - -/* Define HTTP Server request types. */ - -#define NX_HTTP_SERVER_UNKNOWN_REQUEST 0 -#define NX_HTTP_SERVER_GET_REQUEST 1 -#define NX_HTTP_SERVER_POST_REQUEST 2 -#define NX_HTTP_SERVER_HEAD_REQUEST 3 -#define NX_HTTP_SERVER_PUT_REQUEST 4 -#define NX_HTTP_SERVER_DELETE_REQUEST 5 - - -/* Define return code constants. */ - -#define NX_HTTP_ERROR 0xE0 /* HTTP internal error */ -#define NX_HTTP_TIMEOUT 0xE1 /* HTTP timeout occurred */ -#define NX_HTTP_FAILED 0xE2 /* HTTP error */ -#define NX_HTTP_DONT_AUTHENTICATE 0xE3 /* HTTP authentication not needed */ -#define NX_HTTP_BASIC_AUTHENTICATE 0xE4 /* HTTP basic authentication requested */ -#define NX_HTTP_DIGEST_AUTHENTICATE 0xE5 /* HTTP digest authentication requested */ -#define NX_HTTP_NOT_FOUND 0xE6 /* HTTP request not found */ -#define NX_HTTP_DATA_END 0xE7 /* HTTP end of content area */ -#define NX_HTTP_CALLBACK_COMPLETED 0xE8 /* HTTP user callback completed the processing */ -#define NX_HTTP_POOL_ERROR 0xE9 /* HTTP supplied pool payload is too small */ -#define NX_HTTP_NOT_READY 0xEA /* HTTP client not ready for operation */ -#define NX_HTTP_AUTHENTICATION_ERROR 0xEB /* HTTP client authentication failed */ -#define NX_HTTP_GET_DONE 0xEC /* HTTP client get is complete */ -#define NX_HTTP_BAD_PACKET_LENGTH 0xED /* Invalid packet received - length incorrect */ -#define NX_HTTP_REQUEST_UNSUCCESSFUL_CODE 0xEE /* Received an error code instead of 2xx from server */ -#define NX_HTTP_INCOMPLETE_PUT_ERROR 0xEF /* Server responds before PUT is complete */ -#define NX_HTTP_PASSWORD_TOO_LONG 0xF0 /* Password exceeded expected length */ -#define NX_HTTP_USERNAME_TOO_LONG 0xF1 /* Username exceeded expected length */ -#define NX_HTTP_NO_QUERY_PARSED 0xF2 /* Server unable to find query in client request */ -#define NX_HTTP_IMPROPERLY_TERMINATED_PARAM 0xF3 /* Client request parameter not properly terminated */ -#define NX_HTTP_BOUNDARY_ALREADY_FOUND 0xF4 /* Boundary is already found. */ - -/* Define the HTTP Server TCP port number */ - -#define NX_HTTP_SERVER_PORT 80 /* Port for HTTP server */ - -#ifdef NX_HTTP_DIGEST_ENABLE - -/* Include the MD5 digest header file. */ - -#include "nx_md5.h" - -#endif - -/* Define the status code. */ - -#define NX_HTTP_STATUS_CONTINUE "100 Continue" -#define NX_HTTP_STATUS_SWITCHING_PROTOCOLS "101 Switching Protocols" -#define NX_HTTP_STATUS_OK "200 OK" -#define NX_HTTP_STATUS_CREATED "201 Created" -#define NX_HTTP_STATUS_ACCEPTED "202 Accepted" -#define NX_HTTP_STATUS_NON_AUTH_INFO "203 Non-Authoritative Information" -#define NX_HTTP_STATUS_NO_CONTENT "204 No Content" -#define NX_HTTP_STATUS_RESET_CONTENT "205 Reset Content" -#define NX_HTTP_STATUS_PARTIAL_CONTENT "206 Partial Content" -#define NX_HTTP_STATUS_MULTIPLE_CHOICES "300 Multiple Choices" -#define NX_HTTP_STATUS_MOVED_PERMANETLY "301 Moved Permanently" -#define NX_HTTP_STATUS_FOUND "302 Found" -#define NX_HTTP_STATUS_SEE_OTHER "303 See Other" -#define NX_HTTP_STATUS_NOT_MODIFIED "304 Not Modified" -#define NX_HTTP_STATUS_USE_PROXY "305 Use Proxy" -#define NX_HTTP_STATUS_TEMPORARY_REDIRECT "307 Temporary Redirect" -#define NX_HTTP_STATUS_BAD_REQUEST "400 Bad Request" -#define NX_HTTP_STATUS_UNAUTHORIZED "401 Unauthorized" -#define NX_HTTP_STATUS_PAYMENT_REQUIRED "402 Payment Required" -#define NX_HTTP_STATUS_FORBIDDEN "403 Forbidden" -#define NX_HTTP_STATUS_NOT_FOUND "404 Not Found" -#define NX_HTTP_STATUS_METHOD_NOT_ALLOWED "405 Method Not Allowed" -#define NX_HTTP_STATUS_NOT_ACCEPTABLE "406 Not Acceptable" -#define NX_HTTP_STATUS_PROXY_AUTH_REQUIRED "407 Proxy Authentication Required" -#define NX_HTTP_STATUS_REQUEST_TIMEOUT "408 Request Time-out" -#define NX_HTTP_STATUS_CONFLICT "409 Conflict" -#define NX_HTTP_STATUS_GONE "410 Gone" -#define NX_HTTP_STATUS_LENGTH_REQUIRED "411 Length Required" -#define NX_HTTP_STATUS_PRECONDITION_FAILED "412 Precondition Failed" -#define NX_HTTP_STATUS_ENTITY_TOO_LARGE "413 Request Entity Too Large" -#define NX_HTTP_STATUS_URL_TOO_LARGE "414 Request-URL Too Large" -#define NX_HTTP_STATUS_UNSUPPORTED_MEDIA "415 Unsupported Media Type" -#define NX_HTTP_STATUS_RANGE_NOT_SATISFY "416 Requested range not satisfiable" -#define NX_HTTP_STATUS_EXPECTATION_FAILED "417 Expectation Failed" -#define NX_HTTP_STATUS_INTERNAL_ERROR "500 Internal Server Error" -#define NX_HTTP_STATUS_NOT_IMPLEMENTED "501 Not Implemented" -#define NX_HTTP_STATUS_BAD_GATEWAY "502 Bad Gateway" -#define NX_HTTP_STATUS_SERVICE_UNAVAILABLE "503 Service Unavailable" -#define NX_HTTP_STATUS_GATEWAY_TIMEOUT "504 Gateway Time-out" -#define NX_HTTP_STATUS_VERSION_ERROR "505 HTTP Version not supported" - - -/* Define the max length of header field. */ - -#ifndef NX_HTTP_MAX_HEADER_FIELD -#define NX_HTTP_MAX_HEADER_FIELD 256 -#endif - - -/* Define default MIME type. */ -/* Page 14, Section 5.2, RFC 2045 */ -#define NX_HTTP_SERVER_DEFAULT_MIME "text/plain" - - -/* Define the MIME map structure. */ - -typedef struct NX_HTTP_SERVER_MIME_MAP_STRUCT -{ - CHAR *nx_http_server_mime_map_extension; /* Extension of file */ - CHAR *nx_http_server_mime_map_type; /* MIME type of file */ -} NX_HTTP_SERVER_MIME_MAP; - - -/* Define the date structure. */ - -typedef struct NX_HTTP_SERVER_DATE_STRUCT -{ - USHORT nx_http_server_year; /* Year */ - UCHAR nx_http_server_month; /* Month */ - UCHAR nx_http_server_day; /* Day */ - UCHAR nx_http_server_hour; /* Hour */ - UCHAR nx_http_server_minute; /* Minute */ - UCHAR nx_http_server_second; /* Second */ - UCHAR nx_http_server_weekday; /* Weekday */ -} NX_HTTP_SERVER_DATE; - -/* Define the multipart context data structure. */ - -typedef struct NX_HTTP_SERVER_MULTIPART_STRUCT -{ - - /* Boundary string. */ - UCHAR nx_http_server_multipart_boundary[NX_HTTP_MAX_HEADER_FIELD + 1]; - - /* Offset of available data. */ - UINT nx_http_server_multipart_available_offset; - - /* Length of available data. */ - UINT nx_http_server_multipart_available_length; - - /* Boundary find status. */ - volatile UINT nx_http_server_multipart_boundary_find; - - /* The next packet to process. */ - NX_PACKET *nx_http_server_multipart_next_packet; - - /* Offset of next available data. */ - UINT nx_http_server_multipart_next_available_offset; - - /* The packet returned at last. */ - NX_PACKET *nx_http_server_multipart_last_packet; - -} NX_HTTP_SERVER_MULTIPART; - - -/* Define the HTTP Server data structure. */ - -typedef struct NX_HTTP_SERVER_STRUCT -{ - ULONG nx_http_server_id; /* HTTP Server ID */ - CHAR *nx_http_server_name; /* Name of this HTTP Server */ - NX_IP *nx_http_server_ip_ptr; /* Pointer to associated IP structure */ - CHAR nx_http_server_request_resource[NX_HTTP_MAX_RESOURCE + 1]; - /* Uniform Resource Locator (URL) */ - UINT nx_http_connection_pending; /* Connection pending flag */ - NX_PACKET_POOL *nx_http_server_packet_pool_ptr; /* Pointer to HTTP Server packet pool */ - FX_MEDIA *nx_http_server_media_ptr; /* Pointer to media control block */ - ULONG nx_http_server_get_requests; /* Number of get requests */ - ULONG nx_http_server_head_requests; /* Number of head requests */ - ULONG nx_http_server_put_requests; /* Number of put requests */ - ULONG nx_http_server_delete_requests; /* Number of delete requests */ - ULONG nx_http_server_post_requests; /* Number of post requests */ - ULONG nx_http_server_unknown_requests; /* Number of unknown requests */ - ULONG nx_http_server_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_http_server_total_bytes_received; /* Number of total bytes received */ - ULONG nx_http_server_allocation_errors; /* Number of allocation errors */ - ULONG nx_http_server_connection_failures; /* Number of failed connections */ - ULONG nx_http_server_connection_successes; /* Number of successful connections */ - ULONG nx_http_server_invalid_http_headers; /* Number of invalid http headers */ - FX_FILE nx_http_server_file; /* HTTP file control block */ - NX_TCP_SOCKET nx_http_server_socket; /* HTTP Server TCP socket */ - TX_THREAD nx_http_server_thread; /* HTTP server thread */ -#ifdef NX_HTTP_DIGEST_ENABLE - NX_MD5 nx_http_server_md5data; /* HTTP server MD5 work area */ -#endif /* NX_HTTP_DIGEST_ENABLE */ - -#ifdef NX_HTTP_MULTIPART_ENABLE - NX_HTTP_SERVER_MULTIPART - nx_http_server_multipart; /* HTTP multipart area */ -#endif /* NX_HTTP_MULTIPART_ENABLE */ - - UINT nx_http_server_request_type; /* HTTP request type */ - NX_HTTP_SERVER_MIME_MAP - *nx_http_server_mime_maps_additional; /* Additional HTTP MIME maps */ - UINT nx_http_server_mime_maps_additional_num; /* Number of additional HTTP MIME maps */ - /* Define the user supplied routines that are used to inform the application of particular server requests. */ - - UINT (*nx_http_server_authentication_check)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm); - UINT (*nx_http_server_authentication_check_extended)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length); - UINT (*nx_http_server_request_notify)(struct NX_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr); - UINT (*nx_http_server_invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type); - VOID (*nx_http_server_gmt_get)(NX_HTTP_SERVER_DATE *date); - UINT (*nx_http_server_cache_info_get)(CHAR *resource, UINT *max_age, NX_HTTP_SERVER_DATE *last_modified); -#ifdef NX_HTTP_DIGEST_ENABLE - UINT (*nx_http_server_digest_authenticate_callback)(struct NX_HTTP_SERVER_STRUCT *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce); -#endif -} NX_HTTP_SERVER; - - -#ifndef NX_HTTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_http_server_callback_data_send _nx_http_server_callback_data_send -#define nx_http_server_callback_response_send _nx_http_server_callback_response_send -#define nx_http_server_callback_response_send_extended _nx_http_server_callback_response_send_extended -#define nx_http_server_content_get _nx_http_server_content_get -#define nx_http_server_content_length_get _nx_http_server_content_length_get -#define nx_http_server_create _nx_http_server_create -#define nx_http_server_delete _nx_http_server_delete -#define nx_http_server_param_get _nx_http_server_param_get -#define nx_http_server_query_get _nx_http_server_query_get -#define nx_http_server_start _nx_http_server_start -#define nx_http_server_stop _nx_http_server_stop -#define nx_http_server_content_get_extended _nx_http_server_content_get_extended -#define nx_http_server_content_length_get_extended _nx_http_server_content_length_get_extended -#define nx_http_server_get_entity_header _nx_http_server_get_entity_header -#define nx_http_server_get_entity_content _nx_http_server_get_entity_content -#define nx_http_server_callback_generate_response_header _nx_http_server_callback_generate_response_header -#define nx_http_server_callback_generate_response_header_extended _nx_http_server_callback_generate_response_header_extended -#define nx_http_server_callback_packet_send _nx_http_server_callback_packet_send -#define nx_http_server_gmt_callback_set _nx_http_server_gmt_callback_set -#define nx_http_server_cache_info_callback_set _nx_http_server_cache_info_callback_set -#define nx_http_server_mime_maps_additional_set _nx_http_server_mime_maps_additional_set -#define nx_http_server_type_get _nx_http_server_type_get -#define nx_http_server_type_get_extended _nx_http_server_type_get_extended -#define nx_http_server_packet_content_find _nx_http_server_packet_content_find -#define nx_http_server_packet_get _nx_http_server_packet_get -#define nx_http_server_invalid_userpassword_notify_set _nx_http_server_invalid_userpassword_notify_set -#define nx_http_server_digest_authenticate_notify_set _nx_http_server_digest_authenticate_notify_set -#define nx_http_server_authentication_check_set _nx_http_server_authentication_check_set - -#else - -/* Services with error checking. */ - -#define nx_http_server_callback_data_send _nxe_http_server_callback_data_send -#define nx_http_server_callback_response_send _nxe_http_server_callback_response_send -#define nx_http_server_callback_response_send_extended _nxe_http_server_callback_response_send_extended -#define nx_http_server_content_get _nxe_http_server_content_get -#define nx_http_server_content_length_get _nxe_http_server_content_length_get -#define nx_http_server_create(p,n,i,m,sp,ss,pp,a,r) _nxe_http_server_create(p,n,i,m,sp,ss,pp,a,r,sizeof(NX_HTTP_SERVER)) -#define nx_http_server_delete _nxe_http_server_delete -#define nx_http_server_param_get _nxe_http_server_param_get -#define nx_http_server_query_get _nxe_http_server_query_get -#define nx_http_server_start _nxe_http_server_start -#define nx_http_server_stop _nxe_http_server_stop -#define nx_http_server_content_get_extended _nxe_http_server_content_get_extended -#define nx_http_server_content_length_get_extended _nxe_http_server_content_length_get_extended -#define nx_http_server_get_entity_header _nxe_http_server_get_entity_header -#define nx_http_server_get_entity_content _nxe_http_server_get_entity_content -#define nx_http_server_callback_generate_response_header _nxe_http_server_callback_generate_response_header -#define nx_http_server_callback_generate_response_header_extended _nxe_http_server_callback_generate_response_header_extended -#define nx_http_server_callback_packet_send _nxe_http_server_callback_packet_send -#define nx_http_server_gmt_callback_set _nxe_http_server_gmt_callback_set -#define nx_http_server_cache_info_callback_set _nxe_http_server_cache_info_callback_set -#define nx_http_server_mime_maps_additional_set _nxe_http_server_mime_maps_additional_set -#define nx_http_server_type_get _nxe_http_server_type_get -#define nx_http_server_type_get_extended _nxe_http_server_type_get_extended -#define nx_http_server_packet_content_find _nxe_http_server_packet_content_find -#define nx_http_server_packet_get _nxe_http_server_packet_get -#define nx_http_server_invalid_userpassword_notify_set _nxe_http_server_invalid_userpassword_notify_set -#define nx_http_server_digest_authenticate_notify_set _nxe_http_server_digest_authenticate_notify_set -#define nx_http_server_authentication_check_set _nxe_http_server_authentication_check_set - -#endif - -/* Define the prototypes accessible to the application software. */ - - -UINT nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT information_length, CHAR *additional_info, UINT additional_info_length); -UINT nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); -UINT nx_http_server_content_length_get(NX_PACKET *packet_ptr); -#ifdef NX_DISABLE_ERROR_CHECKING -UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); -#else -UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), - UINT http_server_size); -#endif /* NX_DISABLE_ERROR_CHECKING */ -UINT nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr); -UINT nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); -UINT nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); -UINT nx_http_server_start(NX_HTTP_SERVER *http_server_ptr); -UINT nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr); -UINT nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length); -UINT nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length); -UINT nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)); -UINT nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); -UINT nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); -UINT nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); -UINT nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); -UINT nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - -#else - -/* HTTP source code is being compiled, do not perform any API mapping. */ - -UINT _nx_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT _nx_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT _nx_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT infomation_length, CHAR *additional_info, UINT additional_info_length); -UINT _nx_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nx_http_server_content_length_get(NX_PACKET *packet_ptr); -UINT _nx_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); -UINT _nx_http_server_delete(NX_HTTP_SERVER *http_server_ptr); -UINT _nx_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); -UINT _nx_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); -UINT _nx_http_server_start(NX_HTTP_SERVER *http_server_ptr); -UINT _nx_http_server_stop(NX_HTTP_SERVER *http_server_ptr); -UINT _nx_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nx_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *length); -UINT _nx_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT _nx_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT _nx_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT _nx_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length); -UINT _nx_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nx_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_callback)(NX_HTTP_SERVER_DATE *)); -UINT _nx_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); -UINT _nx_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT _nx_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); -UINT _nx_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT _nx_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); -UINT _nx_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT _nx_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - - - -/* Define internal HTTP Server functions. */ - -VOID _nx_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); -VOID _nx_http_server_thread_entry(ULONG http_server_address); -UINT _nx_http_server_get_client_request(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -VOID _nx_http_server_get_process(NX_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr); -VOID _nx_http_server_put_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -VOID _nx_http_server_delete_process(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nx_http_server_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT information_length, CHAR *additional_info, UINT additional_info_length); -UINT _nx_http_server_basic_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present); -UINT _nx_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr); -UINT _nx_http_server_retrieve_resource(NX_PACKET *packet_ptr, CHAR *destination, UINT max_size); -UINT _nx_http_server_calculate_content_offset(NX_PACKET *packet_ptr); -UINT _nx_http_server_number_convert(UINT number, CHAR *string); -UINT _nx_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); -UINT _nx_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); -VOID _nx_http_base64_encode(CHAR *name, UINT length, CHAR *base64name); -VOID _nx_http_base64_decode(CHAR *base64name, UINT length, CHAR *name); - -#ifdef NX_HTTP_DIGEST_ENABLE -UINT _nx_http_server_digest_authenticate(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, UINT name_length, CHAR *password_ptr, UINT password_length, CHAR *realm_ptr, UINT realm_length, UINT *auth_request_present); -VOID _nx_http_server_digest_response_calculate(NX_HTTP_SERVER *server_ptr, CHAR *username, UINT username_length, CHAR *realm, UINT realm_length, CHAR *password, UINT password_length, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result); -UINT _nx_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce); -VOID _nx_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); -#endif - -#ifdef NX_HTTP_MULTIPART_ENABLE -UINT _nx_http_server_boundary_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr); -#endif /* NX_HTTP_MULTIPART_ENABLE */ - -UINT _nx_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr); -UINT _nx_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size); -UINT _nx_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); - -UINT _nx_http_server_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length); -UINT _nx_http_server_date_to_string(NX_HTTP_SERVER_DATE *date, CHAR *string); -VOID _nx_http_server_date_convert(UINT date, UINT count, CHAR *string); - -UINT _nxe_http_server_callback_data_send(NX_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT _nxe_http_server_callback_response_send(NX_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT _nxe_http_server_callback_response_send_extended(NX_HTTP_SERVER *server_ptr, CHAR *status_code, UINT status_code_length, CHAR *information, UINT infomation_length, CHAR *additional_info, UINT additional_info_length); -UINT _nxe_http_server_content_get(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nxe_http_server_packet_content_find(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); -UINT _nxe_http_server_packet_get(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT _nxe_http_server_content_length_get(NX_PACKET *packet_ptr); -UINT _nxe_http_server_content_get_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nxe_http_server_content_length_get_extended(NX_PACKET *packet_ptr, ULONG *content_length); -UINT _nxe_http_server_create(NX_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), - UINT http_server_size); -UINT _nxe_http_server_delete(NX_HTTP_SERVER *http_server_ptr); -UINT _nxe_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT max_param_size); -UINT _nxe_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT max_query_size); -UINT _nxe_http_server_start(NX_HTTP_SERVER *http_server_ptr); -UINT _nxe_http_server_stop(NX_HTTP_SERVER *http_server_ptr); -UINT _nxe_http_server_invalid_userpassword_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)); -UINT _nxe_http_server_type_get(NX_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string); -UINT _nxe_http_server_type_get_extended(NX_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, CHAR *http_type_string, UINT http_type_string_max_size); -UINT _nxe_http_server_get_entity_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT _nxe_http_server_get_entity_content(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT _nxe_http_server_callback_generate_response_header(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT _nxe_http_server_callback_generate_response_header_extended(NX_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, UINT additional_header_length); -UINT _nxe_http_server_callback_packet_send(NX_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nxe_http_server_gmt_callback_set(NX_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_HTTP_SERVER_DATE *)); -UINT _nxe_http_server_cache_info_callback_set(NX_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_HTTP_SERVER_DATE *)); -UINT _nxe_http_server_mime_maps_additional_set(NX_HTTP_SERVER *server_ptr, NX_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT _nxe_http_server_digest_authenticate_notify_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT _nxe_http_server_authentication_check_set(NX_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - -#endif /* NX_HTTP_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_HTTP_SERVER_H */ diff --git a/protocol_handlers/mdns/nxd_mdns.c b/protocol_handlers/mdns/nxd_mdns.c deleted file mode 100644 index 4a12357e..00000000 --- a/protocol_handlers/mdns/nxd_mdns.c +++ /dev/null @@ -1,13867 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Multicast Domain Name System (mDNS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -#define NX_MDNS_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif /* NX_DISABLE_ERROR_CHECKING */ - - -/* Include necessary system files. */ -#include "nxd_mdns.h" -#include "tx_thread.h" - -/* Define the application protocol. */ -static CHAR *nx_mdns_app_protocol[]= {"_tcp", "_udp", NX_NULL}; - -/* Define the service type. */ -#ifndef NX_MDNS_DISABLE_CLIENT -static CHAR *nx_mdns_service_types[] = -{ - "_device-info", - "_http", - "_https", - "_guid", - "_h323", - "_ntp", - "_objective", - "_rdp", - "_remote", - "_rtsp", - "_sip", - "_smb", - "_soap", - "_ssh", - "_telnet", - "_tftp", - "_xmpp-client", - NX_NULL -}; -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/* Define the mDNS internal Function. */ -static VOID _nx_mdns_udp_receive_notify(NX_UDP_SOCKET *socket_ptr); -static VOID _nx_mdns_timer_entry(ULONG mdns_value); -static VOID _nx_mdns_timer_set(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr, ULONG timer_count); -static VOID _nx_mdns_timer_event_process(NX_MDNS *mdns_ptr); -static VOID _nx_mdns_thread_entry(ULONG mdns_value); -static UINT _nx_mdns_packet_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index); -static UINT _nx_mdns_packet_create(NX_MDNS *mdns_ptr, NX_PACKET **packet_ptr, UCHAR type); -static VOID _nx_mdns_packet_send(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index); -static UINT _nx_mdns_packet_rr_add(NX_PACKET *packet_ptr, NX_MDNS_RR *rr, UINT op, UINT packet_type); -static UINT _nx_mdns_packet_rr_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op, UINT interface_index); -static UINT _nx_mdns_packet_rr_data_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op); -#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK -static UINT _nx_mdns_packet_address_check(NX_PACKET *packet_ptr); -#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ -static UINT _nx_mdns_service_name_assemble(UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *domain, UCHAR *record_buffer, UINT buffer_size, UINT *type_index); -static UINT _nx_mdns_service_name_resolve(UCHAR *srv_name, UCHAR **name, UCHAR **type, UCHAR **domain); -static UINT _nx_mdns_rr_delete(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr); -static UINT _nx_mdns_rr_size_get(UCHAR *resource); -static UINT _nx_mdns_name_match(UCHAR *src, UCHAR *dst, UINT length); -static UINT _nx_mdns_name_size_calculate(UCHAR *name); -static UINT _nx_mdns_name_string_encode(UCHAR *ptr, UCHAR *name); -static UINT _nx_mdns_name_string_decode(UCHAR *data, UINT start, UCHAR *buffer, UINT size); -static UINT _nx_mdns_txt_string_encode(UCHAR *ptr, UCHAR *name); -static UINT _nx_mdns_txt_string_decode(UCHAR *data, UINT data_length, UCHAR *buffer, UINT size); -static VOID _nx_mdns_short_to_network_convert(UCHAR *ptr, USHORT value); -static VOID _nx_mdns_long_to_network_convert(UCHAR *ptr, ULONG value); - -#ifndef NX_MDNS_DISABLE_SERVER -static VOID _nx_mdns_address_change_process(NX_MDNS *mdns_ptr); -static UINT _nx_mdns_host_name_register(NX_MDNS *mdns_ptr, UCHAR type, UINT interface_index); -static UINT _nx_mdns_service_interface_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT interface_index); -#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 -static UINT _nx_mdns_rr_a_aaaa_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG *address, UINT addr_length, UCHAR type, UINT interface_index); -#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ -static UINT _nx_mdns_rr_srv_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, USHORT priority, USHORT weights, USHORT port, UCHAR *target, NX_MDNS_RR **insert_rr, UINT interface_index); -static UINT _nx_mdns_rr_txt_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *txt, NX_MDNS_RR **insert_rr, UINT interface_index); -static UINT _nx_mdns_rr_ptr_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *ptr_name, UCHAR is_valid, NX_MDNS_RR **insert_rr, UINT interface_index); - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES -static UINT _nx_mdns_rr_nsec_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR add_a, UCHAR add_aaaa, UCHAR type, UINT interface_index); -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - -static UINT _nx_mdns_rr_parameter_set(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, ULONG ttl, UINT rdata_length, UCHAR set, UCHAR is_register, UCHAR is_valid, NX_MDNS_RR *rr_record, UINT interface_index); -static UINT _nx_mdns_conflict_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr); -static UINT _nx_mdns_additional_resource_record_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr); -static VOID _nx_mdns_additional_a_aaaa_find(NX_MDNS *mdns_ptr, UCHAR *name, UINT interface_index); -static VOID _nx_mdns_probing_send(NX_MDNS *mdns_ptr, UINT interface_index); -static VOID _nx_mdns_announcing_send(NX_MDNS *mdns_ptr, UINT interface_index); -static VOID _nx_mdns_response_send(NX_MDNS *mdns_ptr, UINT interface_index); -static VOID _nx_mdns_ip_address_change_notify(NX_IP *ip_ptr, VOID *additional_info); -#ifdef NX_MDNS_ENABLE_IPV6 -static VOID _nx_mdns_ipv6_address_change_notify(NX_IP *ip_ptr, UINT method, UINT interface_index, UINT index, ULONG *ipv6_address); -#endif /* NX_MDNS_ENABLE_IPV6 */ -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT -static VOID _nx_mdns_service_change_notify_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *new_rr, UCHAR is_present); -static UINT _nx_mdns_service_addition_info_get(NX_MDNS *mdns_ptr, UCHAR *srv_name, NX_MDNS_SERVICE *service, UINT interface_index); -static UINT _nx_mdns_service_mask_match(NX_MDNS *mdns_ptr, UCHAR *service_type, ULONG service_mask); -static UINT _nx_mdns_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, NX_MDNS_RR **out_rr, ULONG wait_option, UINT interface_index); -static UINT _nx_mdns_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT interface_index); -static VOID _nx_mdns_query_send(NX_MDNS *mdns_ptr, UINT interface_index); -static UINT _nx_mdns_query_check(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT one_shot, NX_MDNS_RR **search_rr, UINT interface_index); -static VOID _nx_mdns_query_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); -static VOID _nx_mdns_query_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), - NX_MDNS *mdns_ptr, NX_MDNS_RR **rr, ULONG wait_option); -static VOID _nx_mdns_query_thread_resume(TX_THREAD **suspension_list_head, NX_MDNS *mdns_ptr, NX_MDNS_RR *rr); -static UINT _nx_mdns_known_answer_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr); -static UINT _nx_mdns_packet_rr_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UINT interface_index); -#endif /* NX_MDNS_DISABLE_CLIENT */ - -UINT _nx_mdns_cache_initialize(NX_MDNS *mdns_ptr, VOID *local_cache_ptr, UINT local_cache_size, VOID *peer_cache_ptr, UINT peer_cache_size); -UINT _nx_mdns_cache_add_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, NX_MDNS_RR **insert_ptr, UCHAR *is_present); -UINT _nx_mdns_cache_delete_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr); -UINT _nx_mdns_cache_find_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, UINT match_type, NX_MDNS_RR **search_result); -UINT _nx_mdns_cache_add_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len, VOID **insert_ptr, UCHAR find_string, UCHAR add_name); -UINT _nx_mdns_cache_delete_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len); -VOID _nx_mdns_cache_delete_rr_string(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_rr); - - -/* Define the mDNS STRUCT. */ -static struct NX_MDNS_STRUCT *_nx_mdns_created_ptr; -static CHAR _nx_mdns_dns_sd[NX_MDNS_DNS_SD_MAX + 1] = "_services._dns-sd._udp.local"; -static UCHAR temp_string_buffer[NX_MDNS_NAME_MAX + 1]; -static UCHAR target_string_buffer[NX_MDNS_NAME_MAX + 1]; - -#ifdef NX_MDNS_ENABLE_IPV6 -static NXD_ADDRESS NX_MDNS_IPV6_MULTICAST_ADDRESS; -#endif /* NX_MDNS_ENABLE_IPV6 */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS create function call */ -/* */ -/* Note: the name string is generated by internal logic and it is */ -/* always NULL-terminated. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* ip_ptr Pointer to IP instance */ -/* priority The priority of mDNS Thread */ -/* stack_ptr Stack pointer for mDNS Thread */ -/* stack_size Stack size for mDNS Thread */ -/* host_name Pointer to host name */ -/* local_cache_ptr Pointer to local cache */ -/* local_cache_size The size of local cache */ -/* peer_cache_ptr Pointer to peer cache */ -/* peer_cache_size The size of peer cache */ -/* probing_notify mDNS probing notify */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_create Actual mDNS create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, - UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, - VOID *local_cache_ptr, UINT local_cache_size, - VOID *peer_cache_ptr, UINT peer_cache_size, - VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)) -{ - -UINT status; -UCHAR *ptr; - - - /* Check for invalid input pointers. */ - if ((!ip_ptr) || (!mdns_ptr) || (!stack_ptr) || (!packet_pool) || (!host_name)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if ((ip_ptr -> nx_ip_id != NX_IP_ID) || - (stack_size < TX_MINIMUM_STACK) || - (mdns_ptr -> nx_mdns_id == NX_MDNS_ID)) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check the host name format, RFC 1033,1034,1035 recomend that host names contain only letters, digits, and hyphens RFC6763, Appendix E, Page44. */ - ptr = host_name; - while (*ptr != '\0') - { - if (((*ptr >= 'a') && (*ptr <= 'z')) || - ((*ptr >= 'A') && (*ptr <= 'Z')) || - ((*ptr >= '0') && (*ptr <= '9')) || - ((*ptr == '-'))) - ptr++; - else - return(NX_MDNS_HOST_NAME_ERROR); - } - - /* Check the default domain name size. */ - if ((sizeof("local") - 1) > NX_MDNS_DOMAIN_NAME_MAX) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Check for invalid input pointers, cache header and tail (8 bytes). */ - if ((!local_cache_ptr) || (local_cache_size < 8)) - { - return(NX_PTR_ERROR); - } - - /* Make sure record_buffer is 4-byte aligned. */ - if ((((UINT)local_cache_ptr & 0x3) != 0) || - ((local_cache_size & 0x3) != 0)) - { - return(NX_MDNS_CACHE_ERROR); - } -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT - - /* Check for invalid input pointers, cache header and tail (8 bytes). */ - if ((!peer_cache_ptr) || (peer_cache_size < 8)) - { - return(NX_PTR_ERROR); - } - - /* Make sure peer cache is 4-byte aligned. */ - if ((((UINT)peer_cache_ptr & 0x3) != 0) || - ((peer_cache_size & 0x3) != 0)) - { - return(NX_MDNS_CACHE_ERROR); - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - - /* Call actual mDNS create service. */ - status = _nx_mdns_create(mdns_ptr, ip_ptr, packet_pool, priority, - stack_ptr, stack_size, host_name, - local_cache_ptr, local_cache_size, - peer_cache_ptr, peer_cache_size, - probing_notify); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the mDNS structure and associated IP */ -/* instance for mDNS operation. In doing so, it creates a UDP socket */ -/* for communication with the server and a mDNS processing thread */ -/* */ -/* Note: the name string is generated by internal logic and it is */ -/* always NULL-terminated. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* ip_ptr Pointer to IP instance */ -/* priority The priority of mDNS Thread */ -/* stack_ptr Stack pointer for mDNS Thread */ -/* stack_size Stack size for mDNS Thread */ -/* host_name Pointer to host name */ -/* local_cache_ptr Pointer to local cache */ -/* local_cache_size The size of local cache */ -/* peer_cache_ptr Pointer to peer cache */ -/* peer_cache_size The size of peer cache */ -/* probing_notify mDNS probing notify */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_create Create the mDNS UDP socket */ -/* nx_udp_socket_delete Delete the mDNS UDP socket */ -/* nx_udp_socket_bind Bind the mDNS UDP socket */ -/* nx_udp_socket_unbind Unbind the mDNS UDP socket */ -/* nx_udp_socket_receive_notify Register the mDNS function */ -/* nx_ip_address_change_notify Register IPv4 address function*/ -/* nxd_ipv6_address_change_notify Register IPv6 address function*/ -/* tx_mutex_create Create the mDNS mutex */ -/* tx_mutex_delete Delete the mDNS mutex */ -/* tx_thread_create Create the mDNS thread */ -/* tx_thread_delete Delete the mDNS thread */ -/* tx_event_flags_create Create the ThreadX flag event */ -/* _nx_mdns_cache_initialize Initialize the mDNS cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, - UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, - VOID *local_cache_ptr, UINT local_cache_size, - VOID *peer_cache_ptr, UINT peer_cache_size, - VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)) -{ - -UINT status; -UINT host_name_size; - - - /* Check the size of the host name string. The last four characters in the - host_name are reserved so DNS-SD is able to append " (2)" during the conflict - resolution process. */ -#if (NX_MDNS_HOST_NAME_MAX >= NX_MDNS_LABEL_MAX) - if (_nx_utility_string_length_check((CHAR *)host_name, &host_name_size, (NX_MDNS_LABEL_MAX - 4))) -#else - if (_nx_utility_string_length_check((CHAR *)host_name, &host_name_size, (NX_MDNS_HOST_NAME_MAX - 4))) -#endif - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Initialize the mDNS control block to zero. */ - memset((void *) mdns_ptr, 0, sizeof(NX_MDNS)); - -#ifdef NX_MDNS_ENABLE_IPV6 - - /* Initialize the IPv6 Multicast address. */ - memset(&NX_MDNS_IPV6_MULTICAST_ADDRESS, 0, sizeof(NXD_ADDRESS)); - NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_version = NX_IP_VERSION_V6; - NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0] = 0xFF020000; - NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1] = 0x00000000; - NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2] = 0x00000000; - NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3] = 0x000000FB; -#endif /* NX_MDNS_ENABLE_IPV6 */ - - /* Save the IP pointer. */ - mdns_ptr -> nx_mdns_ip_ptr = ip_ptr; - - /* Save the Packet pool. */ - mdns_ptr -> nx_mdns_packet_pool_ptr = packet_pool; - - /* Save the host name. */ - memcpy((char*)mdns_ptr -> nx_mdns_host_name, (const char*)host_name, (host_name_size + 1)); - - /* Set the domain name as "local" by default. */ - memcpy((char*)mdns_ptr -> nx_mdns_domain_name, "local", sizeof("local")); - - /* Assign the resource record change notify. */ - mdns_ptr -> nx_mdns_probing_notify = probing_notify; - - /* Set the mDNS announcing period. */ - mdns_ptr -> nx_mdns_announcing_period = (USHORT)NX_MDNS_ANNOUNCING_PERIOD; - - /* Set the mDNS announcing retransmission interval. */ - mdns_ptr -> nx_mdns_announcing_retrans_interval = (USHORT)NX_MDNS_ANNOUNCING_RETRANS_INTERVAL; - - /* Set the mDNS announcing period interval. */ - mdns_ptr -> nx_mdns_announcing_period_interval = (ULONG)NX_MDNS_ANNOUNCING_PERIOD_INTERVAL; - - /* Set the mDNS announcing count between one announcing period. */ - mdns_ptr -> nx_mdns_announcing_count = (UCHAR)NX_MDNS_ANNOUNCING_COUNT; - - /* Set the mDNS announcing factor. */ - mdns_ptr -> nx_mdns_announcing_factor = (UCHAR)NX_MDNS_ANNOUNCING_FACTOR; - - /* Set the mDNS announcing max time. */ - mdns_ptr -> nx_mdns_announcing_max_time = (UCHAR)NX_MDNS_ANNOUNCING_MAX_TIME; - - /* Set the pointer of global variable mDNS. */ - _nx_mdns_created_ptr = mdns_ptr; - -#ifndef NX_MDNS_DISABLE_SERVER - /* Register IP address change callback. */ - status = nx_ip_address_change_notify(mdns_ptr -> nx_mdns_ip_ptr, _nx_mdns_ip_address_change_notify, NX_NULL); - - /* Check for error */ - if (status) - { - return(status); - } - -#ifdef NX_MDNS_ENABLE_IPV6 - /* Register IPv6 address change callback. */ - status = nxd_ipv6_address_change_notify(mdns_ptr -> nx_mdns_ip_ptr, _nx_mdns_ipv6_address_change_notify); - - /* Check for error */ - if (status) - { - return(status); - } -#endif /* NX_MDNS_ENABLE_IPV6 */ -#endif /* NX_MDNS_DISABLE_SERVER */ - - /* Create the Socket and check the status */ - status = nx_udp_socket_create(mdns_ptr -> nx_mdns_ip_ptr, &(mdns_ptr -> nx_mdns_socket), "Multicast DNS", - NX_MDNS_UDP_TYPE_OF_SERVICE, NX_MDNS_UDP_FRAGMENT_OPTION, - NX_MDNS_UDP_TIME_TO_LIVE, NX_MDNS_UDP_QUEUE_DEPTH); - - /* Determine if it was successful. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Bind the UDP socket to the mDNS port. */ - status = nx_udp_socket_bind(&(mdns_ptr -> nx_mdns_socket), NX_MDNS_UDP_PORT, TX_NO_WAIT); - - /* Check for error */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - return(status); - } - - /* Register UDP receive callback. */ - status = nx_udp_socket_receive_notify(&(mdns_ptr -> nx_mdns_socket), _nx_mdns_udp_receive_notify); - - /* Check for error */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - return(status); - } - - /* Create the mDNS mutex. */ - status = tx_mutex_create(&(mdns_ptr -> nx_mdns_mutex), - "mDNS Mutex", TX_NO_INHERIT); - - /* Determine if the semaphore creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* No, return error status. */ - return(status); - } - - /* Create the internal mDNS event flag object. */ - status = tx_event_flags_create(&mdns_ptr -> nx_mdns_events, "mDNS Thread Events"); - - /* Determine if the event flags creation was successful. */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* Delete the mDNS mutex. */ - tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); - - /* No, return error status. */ - return(status); - } - - /* Create the mDNS processing thread. */ - status = tx_thread_create(&(mdns_ptr -> nx_mdns_thread), "mDNS Thread", - _nx_mdns_thread_entry, (ULONG) mdns_ptr, - stack_ptr, stack_size, priority, priority, - 1, TX_AUTO_START); - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* Delete the mDNS mutex. */ - tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); - - /* Delete the mDNS events. */ - tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); - - /* No, return error status. */ - return(status); - } - - /* Create the timer of Resource record lifetime. */ - status = tx_timer_create(&(mdns_ptr -> nx_mdns_timer), "mDNS Timer", - _nx_mdns_timer_entry, (ULONG) mdns_ptr, - 0xFFFFFFFF, 0, TX_NO_ACTIVATE); - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* Delete the mDNS mutex. */ - tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); - - /* Delete the mDNS events. */ - tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); - - /* Delete the mDNS thread. */ - tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); - - /* No, return error status. */ - return(status); - } - - /* Initialize the buffer. */ - status = _nx_mdns_cache_initialize(mdns_ptr, local_cache_ptr, local_cache_size, - peer_cache_ptr, peer_cache_size); - - /* Determine if the buffer initialize was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* Delete the mDNS timer. */ - tx_timer_delete(&(mdns_ptr -> nx_mdns_timer)); - - /* Delete the mDNS mutex. */ - tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); - - /* Delete the mDNS events. */ - tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); - - /* Delete the mDNS thread. */ - tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); - - /* No, return error status. */ - return(status); - } - - /* Update the mDNS structure ID. */ - mdns_ptr -> nx_mdns_id = NX_MDNS_ID; - - /* The random delay of first probing for RR. */ - mdns_ptr -> nx_mdns_first_probing_delay = (ULONG)(1 + (NX_RAND() % NX_MDNS_PROBING_TIMER_COUNT)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS delete function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_delete Actual mDNS delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_delete(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS delete service. */ - status = _nx_mdns_delete(mdns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS instance. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind the mDNS UDP socket */ -/* nx_udp_socket_delete Delete the mDNS UDP socket */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* tx_mutex_delete Delete the mDNS mutex */ -/* tx_thread_terminate Terminate the mDNS thread */ -/* tx_thread_delete Delete the mDNS thread */ -/* tx_event_flags_delete Delete the mDNS events flag */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_delete(NX_MDNS *mdns_ptr) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Clear the mDNS structure ID. */ - mdns_ptr -> nx_mdns_id = 0; - - /* Set the pointer of global variable mDNS. */ - _nx_mdns_created_ptr = NX_NULL; - - /* Unbind the port. */ - nx_udp_socket_unbind(&(mdns_ptr -> nx_mdns_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(mdns_ptr -> nx_mdns_socket)); - - /* Terminate the mDNS processing thread. */ - tx_thread_terminate(&(mdns_ptr -> nx_mdns_thread)); - - /* Delete the mDNS processing thread. */ - tx_thread_delete(&(mdns_ptr -> nx_mdns_thread)); - - /* Delete the event flags. */ - tx_event_flags_delete(&(mdns_ptr -> nx_mdns_events)); - - /* Delete the timer. */ - tx_timer_delete(&(mdns_ptr -> nx_mdns_timer)); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Delete the mDNS mutex. */ - tx_mutex_delete(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS cache full notify */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_notify_set Actual cache notify */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT, UINT)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS cache notify set function. */ - status = _nx_mdns_cache_notify_set(mdns_ptr, cache_full_notify_cb); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the cache full notify function. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT, UINT)) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the cache notify. */ - mdns_ptr -> nx_mdns_cache_full_notify = cache_full_notify_cb; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_cache_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS cache full notify */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_notify_clear Actual cache notify */ -/* clear function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_cache_notify_clear(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS cache notify clear function. */ - status = _nx_mdns_cache_notify_clear(mdns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the cache full notify function. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_notify_clear(NX_MDNS *mdns_ptr) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Clear the cache notify. */ - mdns_ptr -> nx_mdns_cache_full_notify = NX_NULL; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_ignore_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS service ignore mask */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* service_mask The service mask */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_ignore_set Actual ignore set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS service ignore mask set function. */ - status = _nx_mdns_service_ignore_set(mdns_ptr, service_mask); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_ignore_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the service mask to ignore the service. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* service_mask The service mask */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the MDNS mutex */ -/* tx_mutex_put Put the MDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the service ignore mask. */ - mdns_ptr -> nx_mdns_service_ignore_mask = service_mask; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS service notify function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* service_mask The service mask */ -/* service_change_notify Service change notify function*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_notify_set Actual mDNS service notify */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, - VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS service notify set function. */ - status = _nx_mdns_service_notify_set(mdns_ptr, service_mask, service_change_notify); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the service mask and notify callback function. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* service_mask The service mask */ -/* service_change_notify Service change notify function*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, - VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the service mask. */ - mdns_ptr -> nx_mdns_service_notify_mask = service_mask; - - /* Assign the service change notify. */ - mdns_ptr -> nx_mdns_service_change_notify = service_change_notify; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS service notify function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_notify_clear Actual service notify */ -/* clear function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_notify_clear(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS service notify clear function. */ - status = _nx_mdns_service_notify_clear(mdns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_notify_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the service mask and notify callback function. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_notify_clear(NX_MDNS *mdns_ptr) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Clear the service mask. */ - mdns_ptr -> nx_mdns_service_notify_mask = 0; - - /* Clear the service change notify. */ - mdns_ptr -> nx_mdns_service_change_notify = NX_NULL; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_announcement_timing_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS announcement timing */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* t Announcing period */ -/* p Announcing count */ -/* k Announcing factor */ -/* retrans_interval Announcing retransmission */ -/* interval */ -/* interval Announcing period interval */ -/* max_time Announcing max time */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_announcement_timing_set */ -/* Actual mDNS announcement */ -/* timing set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((!mdns_ptr) || (!t) || (!p) || (!k) || (!period_interval) || (!max_time)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS delete service. */ - status = _nx_mdns_service_announcement_timing_set(mdns_ptr, t, p, k, retrans_interval, period_interval, max_time); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_announcement_timing_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the service mask and notify callback function. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* t Announcing period */ -/* p Announcing count */ -/* k Announcing factor */ -/* retrans_interval Announcing retransmission */ -/* interval */ -/* interval Announcing period interval */ -/* max_time Announcing max time */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time) -{ - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the mDNS announcing period. */ - mdns_ptr -> nx_mdns_announcing_period = (USHORT)t; - - /* Set the mDNS announcing count between one announcing period. */ - mdns_ptr -> nx_mdns_announcing_count = (UCHAR)p; - - /* Set the mDNS announcing factor. */ - mdns_ptr -> nx_mdns_announcing_factor = (UCHAR)k; - - /* Set the mDNS announcing retransmission interval. */ - mdns_ptr -> nx_mdns_announcing_retrans_interval = (USHORT)retrans_interval; - - /* Set the mDNS announcing period interval. */ - mdns_ptr -> nx_mdns_announcing_period_interval = (ULONG)period_interval; - - /* Set the mDNS announcing max time. */ - mdns_ptr -> nx_mdns_announcing_max_time = (UCHAR)max_time; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS enable function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_enable Actual mDNS enable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input or invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS delete service. */ - status = _nx_mdns_enable(mdns_ptr, interface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables the mDNS of the physical host interface by */ -/* interface index. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* nx_ipv4_multicast_interface_join Join the IPv4 Multicast group */ -/* nxd_ipv6_multicast_interface_join Join the IPv6 Multicast group */ -/* _nx_mdns_host_name_register Register the host name */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; - -#ifndef NX_MDNS_DISABLE_SERVER -ULONG *head; -NX_MDNS_RR *p; -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifdef NX_MDNS_ENABLE_IPV6 -NX_INTERFACE *interface_ptr; -NXD_IPV6_ADDRESS *ipv6_address; -#endif /* NX_MDNS_ENABLE_IPV6 */ - - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check to see if mDNS is already enabled on this interface. */ - if (mdns_ptr -> nx_mdns_interface_enabled[interface_index] == NX_TRUE) - { - return(NX_MDNS_ALREADY_ENABLED); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Enable the mdns function. */ - mdns_ptr -> nx_mdns_interface_enabled[interface_index] = NX_TRUE; - -#ifdef NX_MDNS_ENABLE_IPV6 - /* Set the interface pointer. */ - interface_ptr = &(mdns_ptr -> nx_mdns_ip_ptr -> nx_ip_interface[interface_index]); - - /* Find the link-local address as source adress. Get first address from interface. */ - ipv6_address = interface_ptr -> nxd_interface_ipv6_address_list_head; - - /* Loop to check the address. */ - while (ipv6_address) - { - - /* Check for link-local address. */ - if (IPv6_Address_Type(ipv6_address -> nxd_ipv6_address) & IPV6_ADDRESS_LINKLOCAL) - { - break; - } - ipv6_address = ipv6_address -> nxd_ipv6_address_next; - } - - /* Check if found the link-local address. */ - if(ipv6_address) - { - - /* Set the IPv6 link-local address index. */ - mdns_ptr -> nx_mdns_ipv6_address_index[interface_index] = ipv6_address -> nxd_ipv6_address_index; - } - else - { - - /* No available address, set the address index as 0xFFFFFFFF. */ - mdns_ptr -> nx_mdns_ipv6_address_index[interface_index] = 0xFFFFFFFF; - } -#endif /* NX_MDNS_ENABLE_IPV6 */ - - /* Join the group. */ - status = nx_ipv4_multicast_interface_join(mdns_ptr -> nx_mdns_ip_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, interface_index); - - /* Check status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(status); - } - -#ifdef NX_MDNS_ENABLE_IPV6 - status = nxd_ipv6_multicast_interface_join(mdns_ptr -> nx_mdns_ip_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, interface_index); - - /* Check status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(status); - } -#endif /* NX_MDNS_ENABLE_IPV6 */ - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Register the host name. */ - status = _nx_mdns_host_name_register(mdns_ptr, NX_TRUE, interface_index); - - /* Check status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(status); - } - - /* Probing the all resource record wheneven a Multicast DNS responder starts up, waks up from sleep, receives an indication of a network interface "Link CHange" event.RFC6762, Section8, Page25. */ - - /* Get the header to the local buffer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - /* Set the pointer. */ - head = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the state and delete flag, GOODBYE state and DELETE FLAG means this resource record should be deleted. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) && - (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DELETE)) - { - - /* Delete the resource records. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); - continue; - } - - /* Check the resource reocrd type. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC)) - { - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; - continue; - } - - /* Check the unique flag. */ - if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) - { - /* For a unique type, we need to probe it on the network - to guarantee its uniqueness. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; - p -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; - p -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; - } - else - { - /* If the record is not marked as unique, start the announcement process. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; - p -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; - p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; - - /* Check the announcing max time. */ - if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) - p -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); - else - p -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; - - /* Set the retransmit count. */ - if (mdns_ptr -> nx_mdns_announcing_retrans_interval) - p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; - else - p -> nx_mdns_rr_retransmit_count = 1; - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } -#endif /* NX_MDNS_DISABLE_SERVER */ - - /* Set the mdns started flag. */ - mdns_ptr -> nx_mdns_started = NX_TRUE; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return. */ - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS disable function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_disable Actual mDNS disable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input or invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS delete service. */ - status = _nx_mdns_disable(mdns_ptr, interface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disables the mDNS of the physical host interface by */ -/* interface index. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* nx_ipv4_multicast_leave Leave the IPv4 Multicast group*/ -/* nxd_ipv6_multicast_interface_leave Leave the IPv6 Multicast group*/ -/* _nx_mdns_cache_initialize Initialize the mDNS peer cache*/ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT dns_sd_size; -UINT i; -ULONG *head; -NX_MDNS_RR *p; - - - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check to see if mDNS is not enabled on this interface. - Note: Only support one interface yet. */ - if (mdns_ptr -> nx_mdns_interface_enabled[interface_index] == NX_FALSE) - { - return(NX_MDNS_NOT_ENABLED); - } - - /* Check the DNS-SD string. */ - if (_nx_utility_string_length_check((CHAR *)_nx_mdns_dns_sd, &dns_sd_size, NX_MDNS_DNS_SD_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Disable the mdns function. */ - mdns_ptr -> nx_mdns_interface_enabled[interface_index] = NX_FALSE; - - /* Leave the group. */ - nx_ipv4_multicast_interface_leave(mdns_ptr -> nx_mdns_ip_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, interface_index); - -#ifdef NX_MDNS_ENABLE_IPV6 - nxd_ipv6_multicast_interface_leave(mdns_ptr -> nx_mdns_ip_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, interface_index); -#endif /* NX_MDNS_ENABLE_IPV6 */ - -#ifndef NX_MDNS_DISABLE_CLIENT - - /* Get the local buffer head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - - /* Set the pointer. */ - head = (ULONG*)(*head); - - /* Delete all services on this interface. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Delete the resource record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Get the local buffer head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - /* Set the pointer. */ - head = (ULONG*)(*head); - - /* Send the Goodbye message, RFC6762, Section10.1, Page33. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Skip the NSEC and DNS-SD PTR resource record. */ - if ((p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) || - ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, dns_sd_size)))) - { - - /* Suspend the resource record. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; - } - else - { - - /* Set the state to send Goodbye packet. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; - - /* Clear the retransmit count. */ - p -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; - - /* Set the timer count. 250ms. */ - p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } - } -#endif /* NX_MDNS_DISABLE_SERVER */ - - /* Check if all interfaces are disabled. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - if (mdns_ptr -> nx_mdns_interface_enabled[i]) - break; - } - - /* Set the mdns started flag. */ - if (i == NX_MAX_PHYSICAL_INTERFACES) - mdns_ptr -> nx_mdns_started = NX_FALSE; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_local_domain_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS domain sets */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* domain_name Domain name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_domain_name_set Actual domain set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((!mdns_ptr) || (!domain_name)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input or invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS domain name set service. */ - status = _nx_mdns_domain_name_set(mdns_ptr, domain_name); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_domain_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the mDNS domain name. By default is "local". */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* domain_name Domain name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name) -{ - -UINT index; -UINT domain_name_size; - - - /* Check the size. */ - if (_nx_utility_string_length_check((CHAR *)domain_name, &domain_name_size, NX_MDNS_DOMAIN_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Save the new domain name. */ - memcpy(&mdns_ptr -> nx_mdns_domain_name[0], domain_name, domain_name_size); - mdns_ptr -> nx_mdns_domain_name[domain_name_size] = NX_NULL; - - /* Initialize the struct. */ - memset(_nx_mdns_dns_sd, 0, NX_MDNS_DNS_SD_MAX); - - /* Update the services dns-sd. */ - memcpy(_nx_mdns_dns_sd, "_services._dns-sd._udp.", (sizeof("_services._dns-sd._udp.") - 1)); - index = (sizeof("_services._dns-sd._udp.") - 1); - memcpy(&_nx_mdns_dns_sd[index], domain_name, domain_name_size); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS service add */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name Service instance name */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* txt The txt string of the service */ -/* ttl The ttl of the service */ -/* priority The priority of target host */ -/* weights Service weight */ -/* port The port on this target host */ -/* is_unique The RR set of the service */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_add Actual service add function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, - USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if ((mdns_ptr -> nx_mdns_id != NX_MDNS_ID) || (!port)) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check the size of the service name string. The last four characters in the - service name are reserved so DNS-SD is able to append " (2)" during the conflict - resolution process. */ -#if (NX_MDNS_SERVICE_NAME_MAX >= NX_MDNS_LABEL_MAX) - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, (NX_MDNS_LABEL_MAX - 4))) -#else - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, (NX_MDNS_SERVICE_NAME_MAX - 4))) -#endif - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check the type. */ - if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check the txt string size. */ - if (txt) - { - if (_nx_utility_string_length_check((CHAR *)txt, NX_NULL, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Check the txt string size. */ - if (sub_type) - { - if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Check the interface index. */ - if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return(NX_INVALID_INTERFACE); - } - - /* Call actual mDNS service add service. */ - status = _nx_mdns_service_add(mdns_ptr, name, type, sub_type, txt, ttl, priority, - weights, port, is_unique, interface_index); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS services, and the PTR, SRV and TXT */ -/* records into the local buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name Service nstance name */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* txt The txt string of the service */ -/* ttl The ttl of the service */ -/* priority The priority of target host */ -/* weights Service weight */ -/* port The port on this target host */ -/* is_unique The RR set of the service */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_rr_srv_add Add the SRV resource record */ -/* _nx_mdns_rr_txt_add Add the TXT resource record */ -/* _nx_mdns_rr_ptr_add Add the PTR resource record */ -/* _nx_mdns_rr_delete Delete the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, - USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index) -{ - -UINT status; -UINT type_index; -NX_MDNS_RR *srv_rr; -NX_MDNS_RR *txt_rr; -NX_MDNS_RR *ptr_rr; -NX_MDNS_RR *dns_sd_rr; -ULONG *head; -NX_MDNS_RR *p; -ULONG srv_ttl; -ULONG txt_ttl; -ULONG ptr_ttl; -UINT string_length; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Check the ttl value. */ - if (ttl) - { - - /* Use user supplied TTL value if it is not zero. */ - srv_ttl = ttl; - txt_ttl = ttl; - ptr_ttl = ttl; - } - else - { - - /* Use the RFC recommended TTL values if user doesn't supply one. */ - srv_ttl = NX_MDNS_RR_TTL_HOST; - txt_ttl = NX_MDNS_RR_TTL_OTHER; - ptr_ttl = NX_MDNS_RR_TTL_OTHER; - } - - /* Construct the SRV name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(&temp_string_buffer[0]), &string_length, NX_MDNS_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check whether the same service name exist. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - { - - /* Compare the service name. */ - if (!_nx_mdns_name_match(&temp_string_buffer[0], p -> nx_mdns_rr_name, string_length)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(NX_MDNS_EXIST_SAME_SERVICE); - } - } - } - - /* Construct the SRV target name. */ - status = _nx_mdns_service_name_assemble(mdns_ptr -> nx_mdns_host_name, NX_NULL, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &target_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Add the SRV resource records message. */ - status = _nx_mdns_rr_srv_add(mdns_ptr, &temp_string_buffer[0], srv_ttl, is_unique, priority, weights, port, &target_string_buffer[0], &srv_rr, interface_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(status); - } - - /* Add the TXT resource records message. */ - status = _nx_mdns_rr_txt_add(mdns_ptr, &temp_string_buffer[0], txt_ttl, is_unique, txt, &txt_rr, interface_index); - - /* Check the status. */ - if (status) - { - - /* Delete the SRV records. */ - _nx_mdns_rr_delete(mdns_ptr, srv_rr); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add the dns-sd PTR resource records message. */ - status = _nx_mdns_rr_ptr_add(mdns_ptr, (UCHAR *)_nx_mdns_dns_sd, ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[type_index], NX_TRUE, &dns_sd_rr, interface_index); - - /* Check the status. */ - if (status) - { - - /* Delete the TXT records. */ - _nx_mdns_rr_delete(mdns_ptr, txt_rr); - - /* Delete the SRV records. */ - _nx_mdns_rr_delete(mdns_ptr, srv_rr); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add the PTR resource records message. */ - status = _nx_mdns_rr_ptr_add(mdns_ptr, &temp_string_buffer[type_index], ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[0], NX_TRUE, &ptr_rr, interface_index); - - /* Check the status. */ - if (status) - { - - /* Delete the TXT records. */ - _nx_mdns_rr_delete(mdns_ptr, txt_rr); - - /* Delete the SRV records. */ - _nx_mdns_rr_delete(mdns_ptr, srv_rr); - - /* Delete the DNS_SD PTR records. */ - _nx_mdns_rr_delete(mdns_ptr, dns_sd_rr); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add another PTR type for the subtype. */ - if (sub_type) - { - - /* Construct the PTR target name. */ - status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &target_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return (status); - } - - /* Add the Sub PTR resource records message. */ - status = _nx_mdns_rr_ptr_add(mdns_ptr, &target_string_buffer[type_index], ptr_ttl, NX_MDNS_RR_SET_SHARED, &temp_string_buffer[0], NX_TRUE, NX_NULL, interface_index); - - /* Check the status. */ - if (status) - { - - /* Delete the PTR records. */ - _nx_mdns_rr_delete(mdns_ptr, ptr_rr); - - /* Delete the DNS_SD PTR records. */ - _nx_mdns_rr_delete(mdns_ptr, dns_sd_rr); - - /* Delete the SRV records. */ - _nx_mdns_rr_delete(mdns_ptr, srv_rr); - - /* Delete the TXT records. */ - _nx_mdns_rr_delete(mdns_ptr, txt_rr); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - } - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - - /* Add the NSEC resource record for service. */ - _nx_mdns_rr_nsec_add(mdns_ptr, &temp_string_buffer[0], NX_FALSE, NX_FALSE, NX_MDNS_ADD_NSEC_FOR_SERVICE, interface_index); -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS service delete */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_delete Actual service delete function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((!mdns_ptr) || (!name) || (!type)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check the size. */ - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX) || - _nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Call actual mDNS service delete service. */ - status = _nx_mdns_service_delete(mdns_ptr, name, type, sub_type); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS services. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_delete_internal Actual service delete function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT i; -UINT status = NX_MDNS_NOT_ENABLED; -UINT service_delete_success = NX_FALSE; - - /* Delete service from all enabled interfaces. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i ++) - { - - /* Call actual mDNS service delete service. */ - status = _nx_mdns_service_interface_delete(mdns_ptr, name, type, sub_type, i); - - /* Check status. */ - if (status == NX_MDNS_SUCCESS) - { - service_delete_success = NX_TRUE; - } - } - - /* Check if delete service on all enabled interface. */ - if (service_delete_success) - return(NX_MDNS_SUCCESS); - else - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_interface_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS services, and remove SRV and TXT */ -/* records from local buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_name_match Match the name string */ -/* _nx_mdns_rr_delete Delete the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_interface_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT interface_index) -{ - -UINT status; -UINT found; -UINT delete_flag; -UINT type_index; -ULONG *head; -NX_MDNS_RR *p; -UINT rr_name_length; -UINT rr_ptr_name_length; - - NX_PARAMETER_NOT_USED(sub_type); - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Initialize the parameters. */ - type_index = 0; - delete_flag = NX_FALSE; - - /* Construct the SRV name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Get head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Clear the found value. */ - found = NX_FALSE; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - continue; - } - - /* Compare the RDATA. */ - switch (p -> nx_mdns_rr_type) - { - - case NX_MDNS_RR_TYPE_SRV: - case NX_MDNS_RR_TYPE_TXT: - { - if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length)) - { - found = NX_TRUE; - delete_flag = NX_TRUE; - } - break; - } - case NX_MDNS_RR_TYPE_PTR: - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), &rr_ptr_name_length, NX_MDNS_NAME_MAX)) - { - break; - } - - /* Find the PTR and Sub PTR resource record which pointer to the SRV resource record.*/ - if (!_nx_mdns_name_match(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &temp_string_buffer[0], rr_ptr_name_length)) - { - found = NX_TRUE; - } - - /* Find one DNS-SD PRT which pointer to the PTR resource record. */ - if ((!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length)) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &temp_string_buffer[type_index], rr_ptr_name_length))) - { - - /* Check the count. */ - if (p -> nx_mdns_rr_count) - { - p -> nx_mdns_rr_count --; - } - else - { - - /* Delete this resource record directly. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); - } - } - break; - } - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - case NX_MDNS_RR_TYPE_NSEC: - { - if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length)) - { - - /* Delete this resource record directly. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); - } - break; - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - } - - if (found) - { - - /* Delete the resource records. */ - status = _nx_mdns_rr_delete(mdns_ptr, p); - - /* Check the status. */ - if (status) - { - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - } - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - if (delete_flag == NX_TRUE) - return(NX_MDNS_SUCCESS); - else - return(NX_MDNS_ERROR); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_one_shot_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS resource record query */ -/* add function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service Pointer to response service */ -/* timeout The timeour for service query */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_one_shot_query Actual query service function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((!mdns_ptr) || (!type) || (!service)) - { - return(NX_PTR_ERROR); - } - - /* Check for mDNS started flag. */ - if (!mdns_ptr -> nx_mdns_started) - { - return(NX_MDNS_NOT_STARTED); - } - - /* Check for name. */ - if (name) - { - - /* Check the name size. */ - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Check the type size. */ - if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check the sub type. */ - if (sub_type) - { - - /* Check the name size. */ - if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_service_one_shot_query(mdns_ptr, name, type, sub_type, service, timeout); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_one_shot_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts service one-shot query on all enabled */ -/* interfaces. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service Pointer to response service */ -/* timeout The timeour for service query */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_service_name_resolve Resolve the service name */ -/* _nx_mdns_query Send the One Shot query */ -/* _nx_mdns_service_addition_info_get Get additional info of service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout) -{ - -UINT type_index; -UINT status; -NX_MDNS_RR *answer_rr; -UCHAR *query_name; -USHORT query_type; -UINT i; -UINT name_length; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); - - /* Initialize the struct. */ - memset(service, 0, sizeof(NX_MDNS_SERVICE)); - - /* Loop to start one-shot query on all enabled interfaces until get the answer or query timeout. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - - /* Check if this interface is enabled. */ - if (!mdns_ptr -> nx_mdns_interface_enabled[i]) - continue; - - /* Step1. Construct the query name and set the query type. */ - if (name) - { - - /* Construct the SRV name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(status); - } - - /* Set the query name and query type (NX_MDNS_RR_TYPE_ALL for SRV and TXT). */ - query_name = temp_string_buffer; - query_type = NX_MDNS_RR_TYPE_ALL; - } - else - { - - /* Construct the PTR name. */ - status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Set the query name and query type. */ - query_name = &temp_string_buffer[type_index]; - query_type = NX_MDNS_RR_TYPE_PTR; - } - - /* Step2. Start one shot query. */ - status = _nx_mdns_one_shot_query(mdns_ptr, query_name, query_type, &answer_rr, timeout, i); - - /* Check the status. */ - if ((status == NX_SUCCESS) || - (status == NX_MDNS_EXIST_UNIQUE_RR) || - (status == NX_MDNS_EXIST_SHARED_RR)) - { - - /* Check the query type. */ - if (name) - { - - /* Store the service name from SRV record. */ - if (_nx_utility_string_length_check((CHAR *)answer_rr -> nx_mdns_rr_name, &name_length, NX_MDNS_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - memcpy((char *)(service -> buffer), (char*)(answer_rr -> nx_mdns_rr_name), name_length); - } - else - { - - /* Store the service name from PTR record. */ - if (_nx_utility_string_length_check((CHAR *)answer_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &name_length, NX_MDNS_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - memcpy((CHAR *)(service -> buffer), (CHAR *)(answer_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), name_length); - } - - /* Get the additional information of service. */ - _nx_mdns_service_addition_info_get(mdns_ptr, service -> buffer, service, i); - - /* Reslove the service name. */ - status = _nx_mdns_service_name_resolve(service -> buffer, &(service -> service_name), &(service -> service_type), &(service -> service_domain)); - - /* Check status. */ - if (status) - continue; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return success. */ - return (NX_MDNS_SUCCESS); - } - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return error. */ - return (NX_MDNS_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_one_shot_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into remote buffer, */ -/* mDNS thread send the query message. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* type The resource record type */ -/* out_rr Pointer to response RR */ -/* one_shot One shot or continuous */ -/* wait_option Wait option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _tx_thread_system_suspend Suspend the thread */ -/* _nx_mdns_query_check Check the query RR */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, NX_MDNS_RR **out_rr, ULONG wait_option, UINT interface_index) -{ - -UINT status; -NX_MDNS_RR *rr; -NX_MDNS_RR *insert_rr; -NX_MDNS_RR temp_resource_record; -UINT name_length; - - - /* Clear the return record. */ - *out_rr = NX_NULL; - - /* Check the query RR. */ - status = _nx_mdns_query_check(mdns_ptr, name, type, NX_TRUE, &rr, interface_index); - - /* Check the state. */ - if (status) - { - - /* Whether exists unique resource record in cache. */ - if ((status == NX_MDNS_EXIST_UNIQUE_RR) || - (status == NX_MDNS_EXIST_SHARED_RR)) - { - *out_rr = rr; - return (NX_MDNS_SUCCESS); - } - else - { - return(status); - } - } - - if (wait_option != 0) - { - - /* Initialize the struct. */ - memset(&temp_resource_record, 0, sizeof(NX_MDNS_RR)); - - if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, name, name_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_name), NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - return(status); - } - - /* Add the parameters. */ - temp_resource_record.nx_mdns_rr_type = type; - temp_resource_record.nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; - - /* Set the resource record status. */ - temp_resource_record.nx_mdns_rr_state = NX_MDNS_RR_STATE_QUERY; - - /* Remote resource record, set the owner flag. */ - temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_PEER); - - /* Set the interface index. */ - temp_resource_record.nx_mdns_rr_interface_index = interface_index; - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, &insert_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_resource_record.nx_mdns_rr_name, 0); - return(status); - } - - /* A multicast DNS querier should also delay the first query of the series by - a randomly chosen amount in the range 20-120ms. */ - insert_rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); - insert_rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); - - /* Release the mDNS mutex to process response. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Suspend the thread on this mDNS query attempt. */ - _nx_mdns_query_thread_suspend(&(mdns_ptr -> nx_mdns_rr_receive_suspension_list), _nx_mdns_query_cleanup, mdns_ptr, out_rr, wait_option); - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); - - /* Determine if a packet was received successfully. */ - if (_tx_thread_current_ptr -> tx_thread_suspend_status != NX_MDNS_SUCCESS) - { - - /* Delete the query resource record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, insert_rr); - } - - /* Return the status. */ - return(_tx_thread_current_ptr -> tx_thread_suspend_status); - } - else - { - - /* Immediate return, return error completion. */ - return(NX_MDNS_NO_RR); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_continuous_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS resource record query */ -/* add function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_continuous_query Actual mDNS query RR function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Check for mDNS stareted flag. */ - if (!mdns_ptr -> nx_mdns_started) - { - return(NX_MDNS_NOT_STARTED); - } - - /* Check the type. If the type is null,indicate lookup the all service type, the name and sub type must be null. */ - if (!type) - { - if ((name) || (sub_type)) - { - return(NX_MDNS_PARAM_ERROR); - } - } - else - { - - /* Check the name, If the name is non-null, the sub type must be null. */ - if ((name) && (sub_type)) - { - return(NX_MDNS_PARAM_ERROR); - } - } - - /* Check the name. */ - if (name) - { - - /* Check the name size. */ - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_LABEL_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Check the type. */ - if (type) - { - - /* Check the type size. */ - if (_nx_utility_string_length_check((CHAR *)type, NX_NULL, NX_MDNS_TYPE_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Check the sub type. */ - if (sub_type) - { - - /* Check the sub type size. */ - if (_nx_utility_string_length_check((CHAR *)sub_type, NX_NULL, NX_MDNS_LABEL_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_service_continuous_query(mdns_ptr, name, type, sub_type); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_continuous_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts service continuous query on all enabled */ -/* interfaces. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_service_name_resolve Resolve the service name */ -/* _nx_mdns_query Send the One Shot query */ -/* _nx_mdns_service_addition_info_get Get additional info of service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT status = NX_MDNS_ERROR; -UINT type_index; -UCHAR *query_name; -USHORT query_type; -UINT query_success = NX_FALSE; -UINT i; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Step1. Construct the query name and set the query type. */ - /* Check the type. if the type is null, indicate search all service. */ - if (!type) - { - - /* Set the query name and query type. */ - query_name = (UCHAR *)_nx_mdns_dns_sd; - query_type = NX_MDNS_RR_TYPE_PTR; - } - else if (name) - { - - /* Construct the SRV name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Set the query name and query type (NX_MDNS_RR_TYPE_ALL for SRV and TXT). */ - query_name = temp_string_buffer; - query_type = NX_MDNS_RR_TYPE_ALL; - } - else - { - - /* Construct the PTR name. */ - status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Set the query name and query type. */ - query_name = &temp_string_buffer[type_index]; - query_type = NX_MDNS_RR_TYPE_PTR; - } - - /* Step2. Loop to start continuous query on all enabled interfaces. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - - /* Check if this interface is enabled. */ - if (!mdns_ptr -> nx_mdns_interface_enabled[i]) - continue; - - /* Start continuous query. */ - status = _nx_mdns_continuous_query(mdns_ptr, query_name, query_type, i); - - /* Check the status. */ - if ((status == NX_SUCCESS) || - (status == NX_MDNS_EXIST_SAME_QUERY) || - (status == NX_MDNS_EXIST_UNIQUE_RR) || - (status == NX_MDNS_EXIST_SHARED_RR)) - query_success = NX_TRUE; - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Check if start continuous query success. */ - if (query_success) - return (NX_MDNS_SUCCESS); - else - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_continuous_query PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts continuous query on specified interfaces. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* interface_index The interface index */ -/* name The resource record name */ -/* type The resource record type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_query_check Check the query RR */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT interface_index) -{ - -UINT status; -NX_MDNS_RR *insert_rr; -NX_MDNS_RR temp_resource_record; -UINT name_length; - - - /* Check the query RR. */ - status = _nx_mdns_query_check(mdns_ptr, name, type, NX_FALSE, NX_NULL, interface_index); - - /* Check the state. */ - if (status) - { - return(status); - } - - /* Initialize the struct. */ - memset(&temp_resource_record, 0, sizeof(NX_MDNS_RR)); - - if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, name, name_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_name), NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - return(status); - } - - /* Add the parameters. */ - temp_resource_record.nx_mdns_rr_type = type; - temp_resource_record.nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; - - /* Set the resource record status. */ - temp_resource_record.nx_mdns_rr_state = NX_MDNS_RR_STATE_QUERY; - - /* Remote resource record, set the owner flag. */ - temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_PEER); - - /* Continuous query, set the query type flag. */ - if ((type != NX_MDNS_RR_TYPE_A) && - (type != NX_MDNS_RR_TYPE_AAAA)) - { - temp_resource_record.nx_mdns_rr_word = (temp_resource_record.nx_mdns_rr_word | NX_MDNS_RR_FLAG_CONTINUOUS_QUERY); - } - - /* Set the interface index. */ - temp_resource_record.nx_mdns_rr_interface_index = interface_index; - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, &insert_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_resource_record.nx_mdns_rr_name, 0); - return(status); - } - - /* A multicast DNS querier should also delay the first query of the series by - a randomly chosen amount in the range 20-120ms. */ - insert_rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); - insert_rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); - - /* Return success. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_query_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS resource record query */ -/* add function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_query_stop Actual query RR function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - if (name) - { - - /* Check the size. */ - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_service_query_stop(mdns_ptr, name, type, sub_type); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_query_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into peer service cache,*/ -/* mDNS thread send the query message using continuous type. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_name_match Match the name string */ -/* _nx_mdns_rr_delete Delete the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type) -{ - -UINT status; -UINT type_index = 0; -UINT query_stop = NX_FALSE; -ULONG *head; -NX_MDNS_RR *p; -UINT rr_name_length; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - if (type) - { - if (name) - { - - /* Construct the SRV name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - } - else - { - - /* Construct the PTR name. */ - status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - } - } - - /* Get the remote buffer head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - - if (!head) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_MDNS_CACHE_ERROR); - } - - /* Set the pointer. */ - head = (ULONG*)(*head); - - /* Loop to delete query resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the resource record state. */ - if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) - continue; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - continue; - } - - if (!type) - { - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length))) - { - - /* Delete the resource records. */ - status = _nx_mdns_rr_delete(mdns_ptr, p); - - /* Check status. */ - if (status == NX_MDNS_SUCCESS) - query_stop = NX_TRUE; - } - } - else - { - if (name) - { - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_ALL) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], rr_name_length))) - { - - /* Delete the resource records. */ - status = _nx_mdns_rr_delete(mdns_ptr, p); - - /* Check status. */ - if (status == NX_MDNS_SUCCESS) - query_stop = NX_TRUE; - } - } - else - { - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR)&& - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[type_index], rr_name_length))) - { - - /* Delete the resource records. */ - status = _nx_mdns_rr_delete(mdns_ptr, p); - - /* Check status. */ - if (status == NX_MDNS_SUCCESS) - query_stop = NX_TRUE; - } - } - } - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Check if stop service continuous query. */ - if (query_stop == NX_TRUE) - return(NX_MDNS_SUCCESS); - else - return(NX_MDNS_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_service_lookup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS resource record query */ -/* add function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service_index The index of the service */ -/* service Pointer to Service instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_service_lookup Actual mDNS query RR function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - if (name) - { - - /* Check the size. */ - if (_nx_utility_string_length_check((CHAR *)name, NX_NULL, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_service_lookup(mdns_ptr, name, type, sub_type, service_index, service); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_lookup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into peer service cache,*/ -/* mDNS thread send the query message using continuous type. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service_index The index of the service */ -/* service Pointer to Service instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* tx_time_get Get the time */ -/* _nx_mdns_service_name_assemble Assemble the service name */ -/* _nx_mdns_service_name_resolve Resolve the service name */ -/* _nx_mdns_service_addition_info_get Get additional info of service*/ -/* _nx_mdns_name_match Match the name string */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service) -{ - -UINT status; -UINT type_index; -UINT dns_sd_flag; -UINT sub_type_flag; -UINT index; -UINT count; -UINT found; -UCHAR *srv_name = NX_NULL; -UCHAR *ptr; -UCHAR *tmp_sub_type; -UCHAR *tmp_type; -UCHAR *tmp_domain; -NX_MDNS_RR *p = NX_NULL; -NX_MDNS_RR *p1; -ULONG *head, *tail; -UCHAR i; -UINT interface_index = 0; -UINT temp_string_length; -UINT dns_sd_length; -UINT srv_name_length; -UINT target_string_length; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Zero out the content of service */ - memset(service, 0, sizeof(NX_MDNS_SERVICE)); - - /* Initialize the struct. */ - count = 0; - found = NX_FALSE; - - /* Check the type. */ - if (type) - { - if (name) - { - - /* Construct the Service name. */ - status = _nx_mdns_service_name_assemble(name, type, NX_NULL, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, NX_NULL); - - } - else - { - - /* Construct the Service name. */ - status = _nx_mdns_service_name_assemble(NX_NULL, type, sub_type, mdns_ptr -> nx_mdns_domain_name, &temp_string_buffer[0], NX_MDNS_NAME_MAX, &type_index); - } - /* Check the status. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - } - - /* Check the DNS-SD string. */ - if (_nx_utility_string_length_check((CHAR *)_nx_mdns_dns_sd, &dns_sd_length, NX_MDNS_DNS_SD_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (status); - } - - /* Loop to search local and peer cache. */ - for(i = 0; i < 2; i++) - { - - /* Set the pointer. */ - if(i == NX_MDNS_CACHE_TYPE_LOCAL) - { -#ifndef NX_MDNS_DISABLE_SERVER - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - } - - if(head == NX_NULL) - continue; - - /* Set the pointer. */ - tail = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p < tail; p++) - { - - /* Check whether the resource record is valid. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) - continue; - - if((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) || (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV)) - { - - if(type) - { - if (_nx_mdns_name_match(p -> nx_mdns_rr_name, &temp_string_buffer[0], temp_string_length)) - continue; - } - else if(p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - continue; - - if(name && (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV)) - { - - /* Store the service name. */ - srv_name = p -> nx_mdns_rr_name; - interface_index = p -> nx_mdns_rr_interface_index; - } - else - { - - /* Set the service name pointer. */ - srv_name = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name; - interface_index = p -> nx_mdns_rr_interface_index; - } - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)srv_name, &srv_name_length, NX_MDNS_NAME_MAX)) - continue; - - /* Store the service name. */ - memcpy((CHAR *)(service -> buffer), (CHAR *)srv_name, srv_name_length + 1); - - /* Reslove the service name and check the PTR rdata name. Ignore the PTR when the PTR rdata does not pointer the service. */ - status = _nx_mdns_service_name_resolve(service -> buffer, &(service -> service_name), &(service -> service_type), &(service -> service_domain)); - - if (status) - continue; - - if(type == NX_NULL) - { - - /* Set the parameters. */ - sub_type_flag = NX_FALSE; - dns_sd_flag = NX_FALSE; - index = 0; - - /* Check the PTR resource record with sub type. */ - ptr = p -> nx_mdns_rr_name; - while (*ptr != '\0') - { - if (*ptr == '.') - { - if (!_nx_mdns_name_match(ptr - index, (UCHAR *)"_sub", 4)) - { - sub_type_flag = NX_TRUE; - break; - } - index = 0; - } - else - index ++; - ptr ++; - } - if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, dns_sd_length)) - { - dns_sd_flag = NX_TRUE; - } - - /* Check the DNS-SD PTR reousrce record. */ - if ((dns_sd_flag == NX_TRUE) || - (sub_type_flag == NX_TRUE)) - { - - /* Find the PTR resource record which pointer to the service. */ - for(p1 = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p1 < tail; p1++) - { - - /* Check whether the resource record is valid. */ - if ((p1 == p) || - (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || - (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) - continue; - - /* Check the interface index. */ - if (p1 -> nx_mdns_rr_interface_index != p -> nx_mdns_rr_interface_index) - continue; - - if (p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) - { - if ((dns_sd_flag == NX_TRUE)) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p1 -> nx_mdns_rr_name), &target_string_length, NX_MDNS_NAME_MAX)) - { - continue; - } - - /* Set the pointer. */ - memcpy((CHAR *)&target_string_buffer[0], (CHAR *)(p1 -> nx_mdns_rr_name), target_string_length + 1); - - /* Reslove the type. */ - status = _nx_mdns_service_name_resolve(&target_string_buffer[0], &tmp_sub_type, &tmp_type, &tmp_domain); - - if (status) - continue; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)tmp_type, &target_string_length, NX_MDNS_TYPE_MAX)) - { - continue; - } - - /* Construct the type and doamin, _http._tcp.local. */ - *(tmp_type + target_string_length) = '.'; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)tmp_type, &target_string_length, NX_MDNS_TYPE_MAX)) - { - continue; - } - - /* Compare the DNS_SD rdata. */ - if (!_nx_mdns_name_match(tmp_type, p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, target_string_length)) - { - - /* Exist resource record including more info. */ - count --; - break; - } - } - else - { - - /* Exist the PTR RR which pointer to the same service. */ - if (p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) - { - count --; - break; - } - } - } - } - } - } - - /* Check the count state. */ - if (count == service_index) - { - /* Yes, find. */ - found = NX_TRUE; - break; - } - count ++; - } - } - - /* Check if find the service. */ - if (found == NX_TRUE) - { - break; - } - } - - if (found) - { - - /* Update the elasped time. */ - p -> nx_mdns_rr_elapsed_time = tx_time_get(); - - /* Get the additional information. */ - _nx_mdns_service_addition_info_get(mdns_ptr, srv_name, service, interface_index); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(NX_MDNS_SUCCESS); - } - else - { - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return(NX_MDNS_NO_MORE_ENTRIES); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_peer_cache_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS peer service cache */ -/* clear function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_peer_cache_clear Actual peer cache clear */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_peer_cache_clear(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_peer_cache_clear(mdns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_peer_cache_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the mDNS peer service cache. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_cache_initialize Initialize the cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_peer_cache_clear(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - status = _nx_mdns_cache_initialize(mdns_ptr, NX_NULL, NX_NULL, mdns_ptr -> nx_mdns_peer_service_cache, mdns_ptr -> nx_mdns_peer_service_cache_size); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a error status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_mdns_host_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the mDNS host address get */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service Pointer to response service */ -/* timeout The timeour for service query */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_host_address_get Actual mDNS host address */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((!mdns_ptr) || (!host_name)) - { - return(NX_PTR_ERROR); - } - - /* Check for mDNS started flag. */ - if (!mdns_ptr -> nx_mdns_started) - { - return(NX_MDNS_NOT_STARTED); - } - - /* Check the size. */ - if (_nx_utility_string_length_check((CHAR *)host_name, NX_NULL, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Call actual mDNS create service. */ - status = _nx_mdns_host_address_get(mdns_ptr, host_name, ipv4_address, ipv6_address, timeout); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_host_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS query record into peer buffer, */ -/* mDNS thread send the query message using one-shot type. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The name of the service */ -/* type The type of the service */ -/* subtype The subtype of the service */ -/* service Pointer to response service */ -/* timeout The timeour for service query */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* tx_time_get Get the mDNS time */ -/* _nx_mdns_host_check Check the host info */ -/* _nx_mdns_answer_wait Wait the answer */ -/* _nx_mdns_cache_add_query Add the query into cache */ -/* _nx_mdns_cache_delete_query Delete the query from cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout) -{ - -UINT status; -ULONG start_time; -ULONG current_time; -ULONG elapsed_time; -ULONG wait_time = timeout; -NX_MDNS_RR *a_rr; -NX_MDNS_RR *aaaa_rr; -UCHAR host_name_query[NX_MDNS_NAME_MAX + 1]; -UINT i = 0; -UCHAR domain_flag = NX_FALSE; -UINT answer = NX_FALSE; -UINT domain_name_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)host_name, NX_NULL, NX_MDNS_HOST_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), NX_WAIT_FOREVER); - - /* Clear the buffer. */ - memset(host_name_query, 0, NX_MDNS_NAME_MAX + 1); - - /* Copy the host name into host name query buffer. */ - while(host_name[i] != NX_NULL) - { - host_name_query[i] = host_name[i]; - if (host_name[i] == '.') - { - - /* Update the flag. */ - domain_flag = NX_TRUE; - } - i++; - } - - /* Check if include the domain. */ - if (domain_flag == NX_FALSE) - { - host_name_query[i++] = '.'; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_domain_name, &domain_name_length, NX_MDNS_DOMAIN_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr->nx_mdns_mutex)); - return (NX_MDNS_DATA_SIZE_ERROR); - } - - memcpy((char*)(&host_name_query[i]), (const char*)mdns_ptr -> nx_mdns_domain_name, domain_name_length + 1); - } - - /* Initialize the value. */ - if (ipv4_address) - *ipv4_address = NX_NULL; - if (ipv6_address) - memset(ipv6_address, 0, 16); - - /* Start host address query on all enabled interfaces until get the answer or query timeout. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - - /* Check if this interface is enabled. */ - if (!mdns_ptr -> nx_mdns_interface_enabled[i]) - continue; - - /* Get the query start time. */ - wait_time = timeout; - start_time = tx_time_get(); - - /* Get the host IPv4 address. */ - if (ipv4_address) - { - - /* One shot query for host name. */ - status = _nx_mdns_one_shot_query(mdns_ptr, host_name_query, NX_MDNS_RR_TYPE_A, &a_rr, wait_time, i); - - /* Check the status. */ - if (status == NX_MDNS_SUCCESS) - { - - /* Set the IPv4 address. */ - *ipv4_address = a_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address; - answer = NX_TRUE; - } - } - - /* Get the host IPv6 address. */ - if (ipv6_address) - { - - /* How much time has elapsed? */ - current_time = tx_time_get(); - - /* Has the time wrapped? */ - if (current_time >= start_time) - { - /* No, simply subtract to get the elapsed time. */ - elapsed_time = current_time - start_time; - } - else - { - - /* Yes it has. Time has rolled over the 32-bit boundary. */ - elapsed_time = (((ULONG) 0xFFFFFFFF) - start_time) + current_time; - } - - /* Update the timeout. */ - if (wait_time > elapsed_time) - wait_time -= elapsed_time; - else - wait_time = 0; - - /* Lookup the service. */ - status = _nx_mdns_one_shot_query(mdns_ptr, host_name_query, NX_MDNS_RR_TYPE_AAAA, &aaaa_rr, wait_time, i); - - /* Check the status. */ - if (status == NX_MDNS_SUCCESS) - { - - /* Set the IPv6 address. */ - *ipv6_address = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[0]; - *(ipv6_address + 1) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[1]; - *(ipv6_address + 2) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[2]; - *(ipv6_address + 3) = aaaa_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa .nx_mdns_rr_aaaa_address[3]; - answer = NX_TRUE; - } - } - - /* Check if get IPv4 address or IPv6 address. */ - if (answer == NX_TRUE) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (NX_MDNS_SUCCESS); - } - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (NX_MDNS_ERROR); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -#ifndef NX_MDNS_DISABLE_SERVER -#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_a_aaaa_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS A/AAAA resource record into local cache.*/ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* set The resource record set */ -/* address The resource record address */ -/* insert_rr Pointer to insert resource */ -/* record */ -/* name Host name */ -/* ttl The resource record ttl */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_host_name_register Register the host name */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_a_aaaa_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG *address, UINT addr_length, UCHAR type, UINT interface_index) -{ -UINT status; -NX_MDNS_RR *insert_rr; -USHORT rr_type; -NX_MDNS_RR temp_resource_record; - - - /* Set the resource record type. */ - if(addr_length == 4) - rr_type = NX_MDNS_RR_TYPE_A; - else - rr_type = NX_MDNS_RR_TYPE_AAAA; - - /* Set the resource record parameters. */ - status = _nx_mdns_rr_parameter_set(mdns_ptr, name, rr_type, NX_MDNS_RR_TTL_HOST, addr_length, NX_MDNS_RR_SET_UNIQUE, type, NX_FALSE, &temp_resource_record, interface_index); - - /* Check for error. */ - if (status) - { - return(status); - } - - /* Add the parameters. */ - if(rr_type == NX_MDNS_RR_TYPE_A) - { - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address = *address; - } - else - { - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0] = *address; - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1] = *(address +1); - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2] = *(address + 2); - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3] = *(address + 3); - } - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &insert_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - - /* Delete the name strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - return(status); - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, insert_rr, insert_rr -> nx_mdns_rr_timer_count); - - /* Return a successful status. */ - return(NX_SUCCESS); -} -#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_ptr_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS PTR resource record into local buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* ttl The resource record ttl */ -/* set The resource record set */ -/* ptr_name The domain name */ -/* insert_rr Pointer to insert resource */ -/* record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_ptr_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *ptr_name, UCHAR is_valid, NX_MDNS_RR **insert_rr, UINT interface_index) -{ - -UINT status; -NX_MDNS_RR *ptr_rr; -NX_MDNS_RR temp_resource_record; -UINT ptr_name_length; - - - if (_nx_utility_string_length_check((CHAR *)ptr_name, &ptr_name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the resource record parameters. Rdata length: PTR name, string should include the first'.' and last '\0'. */ - status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_PTR, ttl, (ptr_name_length + 2), set, NX_TRUE, is_valid, &temp_resource_record, interface_index); - - /* Check for error. */ - if (status) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add the ptr name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, ptr_name, ptr_name_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name), - NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - - /* Delete the strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &ptr_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, 0); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, ptr_rr, ptr_rr -> nx_mdns_rr_timer_count); - - if (insert_rr) - *insert_rr = ptr_rr; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_srv_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS SRV resource record into local buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name Service nstance name */ -/* ttl The ttl of the service */ -/* set The resource record set */ -/* priority The priority of target host */ -/* weights Service weight */ -/* port The port on this target host */ -/* target The target host */ -/* insert_rr Pointer to insert record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_srv_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, USHORT priority, - USHORT weights, USHORT port, UCHAR *target, NX_MDNS_RR **insert_rr, UINT interface_index) -{ - -UINT status; -NX_MDNS_RR *srv_rr; -NX_MDNS_RR temp_resource_record; -UINT target_length; - - if (_nx_utility_string_length_check((CHAR *)target, &target_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the resource record parameters. Rdata length: PRIORITY, WEIGHTS, PORT, TARGET, name string should include the first'.' and last '\0'. */ - status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_SRV, ttl, target_length + 8, set, NX_TRUE, NX_FALSE, &temp_resource_record, interface_index); - - /* Check for error. */ - if (status) - { - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Add the name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, target, target_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), - NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Set the SRV parameters. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority = priority; - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights = weights; - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port = port; - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &srv_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, 0); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, srv_rr, srv_rr -> nx_mdns_rr_timer_count); - - if (insert_rr) - *insert_rr = srv_rr; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_txt_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS TXT resource record into local buffer. */ -/* the TXT records are formatted in a "key=value" notation with ";" */ -/* acting as separator when more then one key is available. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* ttl The resource record ttl */ -/* set The resource record set */ -/* txt The txt string */ -/* insert_rr Pointer to insert record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into the cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_txt_add(NX_MDNS *mdns_ptr, UCHAR *name, ULONG ttl, UCHAR set, UCHAR *txt, NX_MDNS_RR **insert_rr, UINT interface_index) -{ - -UINT status; -NX_MDNS_RR *txt_rr; -NX_MDNS_RR temp_resource_record; -UINT txt_length; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Set the resource record parameters. */ - status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_TXT, ttl, 0, set, NX_TRUE, NX_FALSE, &temp_resource_record, interface_index); - - /* Check for error. */ - if (status) - { - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - if (txt) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)txt, &txt_length, NX_MDNS_NAME_MAX)) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Calculate the text string.inlcude the one byte label. */ - temp_resource_record.nx_mdns_rr_rdata_length = (USHORT)(txt_length + 1); - - /* Add the name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, txt, txt_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), - NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - } - else - { - temp_resource_record.nx_mdns_rr_rdata_length = 1; - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data = NX_NULL; - } - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &txt_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr,NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - if (txt) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data, 0); - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - return(status); - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, txt_rr, txt_rr -> nx_mdns_rr_timer_count); - - if (insert_rr) - *insert_rr = txt_rr; - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_nsec_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS A resource record into local cache. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* add_a Flag for adding A record */ -/* add_aaaa Flag for adding AAAA record */ -/* type Type for host or service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_add_string Add the string into cache */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into cache */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_host_name_register Register the host name */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_nsec_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR add_a, UCHAR add_aaaa, UCHAR type, UINT interface_index) -{ -UINT status; -NX_MDNS_RR *insert_rr; -UCHAR bitmap_length = 0; -ULONG rdata_length = 0; -NX_MDNS_RR temp_resource_record; -UINT name_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the next domain name, include the first'.' and last '\0'. */ - rdata_length = name_length + 2; - - /* Add the window block and bitmap length. */ - rdata_length += 2; - - /* Add the NSEC with A/AAAA Bitmap. */ - if (type == NX_MDNS_ADD_NSEC_FOR_HOST) - { - /* Set the Bitmaps length. */ - if (add_aaaa == NX_TRUE) - bitmap_length = 4; - else - bitmap_length = 1; - } - else - { - - /* Add the NSEC with SRV/TXT Bitmap. */ - bitmap_length = 5; - } - - /* Add the Bitmaps. */ - rdata_length += bitmap_length; - - /* Set the resource record parameters. */ - status = _nx_mdns_rr_parameter_set(mdns_ptr, name, NX_MDNS_RR_TYPE_NSEC, NX_MDNS_RR_TTL_HOST, rdata_length, - NX_MDNS_RR_SET_UNIQUE, NX_FALSE, NX_TRUE, &temp_resource_record, interface_index); - - /* Check for error. */ - if (status) - { - return(status); - } - - /* Add the next domain name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, name, name_length, - (VOID **)(&temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain), - NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - { - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - return(status); - } - - /* Set the window block and bitmap length. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block = 0; - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length = bitmap_length; - - /* Add the Bitmap for host. */ - if (type == NX_MDNS_ADD_NSEC_FOR_HOST) - { - - /* Encode the Bitmap. */ - if ((add_a == NX_TRUE) && (add_aaaa == NX_TRUE)) - { - - /* Add the A Bitmap. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0] = 64; - - /* Add the AAAA Bitmap. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[3] = 8; - } - else if ((add_a == NX_TRUE)) - { - - /* Add the A Bit map. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0] = 64; - } - else - { - - /* Add the AAAA Bitmap. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[3] = 8; - } - } - else - { - /* Add the TXT Bitmap for service. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[2] = 128; - - /* Add the SRV Bitmap for service. */ - temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[4] = 64; - - } - - /* Add the resource record. */ - status = _nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, &insert_rr, NX_NULL); - - /* Check for error. */ - if (status) - { - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_name, 0); - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, temp_resource_record.nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain, 0); - - return(status); - } - - /* Return a successful status. */ - return(NX_SUCCESS); -} -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_parameter_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the parameters of resource record. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* type The resource record type */ -/* ttl The resource record ttl */ -/* rdata_lenth The resource record length */ -/* set The resource record set */ -/* is_register Register flag */ -/* is_valid Valid flag */ -/* rr_record Pointer to resource record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_parameter_set(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, ULONG ttl, UINT rdata_length, - UCHAR set, UCHAR is_register, UCHAR is_valid, NX_MDNS_RR *rr_record, UINT interface_index) -{ - -UINT status; -UINT name_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Initialize the struct. */ - memset(rr_record, 0, sizeof(NX_MDNS_RR)); - - /* Add the name. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, name, name_length, - (VOID **)(&rr_record -> nx_mdns_rr_name), NX_FALSE, NX_TRUE); - - /* Check for error. */ - if (status) - return(status); - - /* Set the parameters. */ - rr_record -> nx_mdns_rr_interface_index = interface_index; - rr_record -> nx_mdns_rr_type = type; - rr_record -> nx_mdns_rr_class = NX_MDNS_RR_CLASS_IN; - rr_record -> nx_mdns_rr_ttl = ttl; - rr_record -> nx_mdns_rr_rdata_length = (USHORT)rdata_length; - - /* Set the resource record as uniqure. */ - if (set == NX_MDNS_RR_SET_UNIQUE) - rr_record -> nx_mdns_rr_word = (rr_record -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_UNIQUE); - - /* Check for mDNS started flag. */ - if (mdns_ptr -> nx_mdns_started) - { - - /* Check the valid flag for PTR resource record. */ - if (is_valid == NX_TRUE) - { - /* Set the resource record state. */ - rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; - } - else - { - - /* The is_register value be used for A/AAAA type, the value being NX_TRUE indicates the operation is to register the host name(probing and announcing the A/AAAA). The value being NX_FALSE indicates the operation is an address change, (announcing the A/AAAA). */ - if ((set == NX_MDNS_RR_SET_UNIQUE) && (is_register == NX_TRUE)) - { - - /* Set the resource record status. */ - rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; - rr_record -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; - rr_record -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; - } - else - { - - /* Set the resource record state. */ - rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; - rr_record -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; - rr_record -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; - - /* Check the announcing max time. */ - if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) - rr_record -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); - else - rr_record -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; - - /* Set the retransmit count. */ - if (mdns_ptr -> nx_mdns_announcing_retrans_interval) - rr_record -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; - else - rr_record -> nx_mdns_rr_retransmit_count = 1; - } - } - } - else - { - - /* Set the resource record status. */ - rr_record -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; - } - - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS resource record from the */ -/* local bufferor remote buffer according to the resource record set. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_rr The resource record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_delete(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr) -{ - -UINT status = NX_MDNS_SUCCESS; - -#ifndef NX_MDNS_DISABLE_CLIENT -ULONG *head; -NX_MDNS_RR *p; -#endif /* NX_MDNS_DISABLE_CLIENT */ - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - - /* Check for mDNS started flag. */ - if (mdns_ptr -> nx_mdns_started) - { - - /* Check the RR owner. */ - if (!(record_rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) - { - -#ifndef NX_MDNS_DISABLE_SERVER - if ((record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) - { - - /* Set the state to send Goodbye packet. */ - record_rr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; - - /* Set the retransmit count. */ - record_rr -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; - - /* Set the timer count. */ - record_rr -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; - - /* Set the delete flag. */ - record_rr -> nx_mdns_rr_word = (record_rr -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DELETE); - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, record_rr, record_rr -> nx_mdns_rr_timer_count); - } - else - { - - /* Delete the resource records. */ - status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, record_rr); - } - -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { - -#ifndef NX_MDNS_DISABLE_CLIENT - if (record_rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) - { - - /* Set the pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - - if(head) - { - head = (ULONG*)(*head); - - /* Check the remote resource record, stop the updating resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - if (p == record_rr) - continue; - - if ((p -> nx_mdns_rr_name == record_rr -> nx_mdns_rr_name) && - (p -> nx_mdns_rr_type == record_rr -> nx_mdns_rr_type) && - (p -> nx_mdns_rr_class == record_rr -> nx_mdns_rr_class)) - { - - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) - { - - /* Clear the Updating flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_UPDATING)); - } - - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING) - { - if (p -> nx_mdns_rr_retransmit_count) - { - - /* mDNS querier need not update the RR, The original updating ttl is at 80%, 85%, 90%, 95%. Update the timer.*/ - /* timer_count: P, timer_count: C, rr_ttl: T. - P = P + C * T * 5%. */ - p -> nx_mdns_rr_timer_count = (p -> nx_mdns_rr_timer_count + p -> nx_mdns_rr_retransmit_count * p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 5 /100); - - /* Clear the retransmit count. */ - p -> nx_mdns_rr_retransmit_count = 0; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } - } - } - } - } - } - - /* Delete the resource record. */ - status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, record_rr); - -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - } - else - { - /* Check the RR owner. */ - if (!(record_rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) - { - -#ifndef NX_MDNS_DISABLE_SERVER - status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, record_rr); -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { - -#ifndef NX_MDNS_DISABLE_CLIENT - status = _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, record_rr); -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return status. */ - return (status); -} - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_local_cache_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS instance. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_local_cache_clear Actual local cache clear */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_mdns_local_cache_clear(NX_MDNS *mdns_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!mdns_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid server attributes. */ - if (mdns_ptr -> nx_mdns_id != NX_MDNS_ID) - { - return(NX_MDNS_PARAM_ERROR); - } - - /* Call actual mDNS local cache clear service. */ - status = _nx_mdns_local_cache_clear(mdns_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_local_cache_clear PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function clears the mDNS local cache. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from cache */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_local_cache_clear(NX_MDNS *mdns_ptr) -{ - -UINT status = NX_MDNS_SUCCESS; -ULONG *head; -NX_MDNS_RR *p; - - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Delete the resource records. */ - status = _nx_mdns_rr_delete(mdns_ptr, p); - - /* Check the status. */ - if (status) - break; - } - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Return a successful status. */ - return(status); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_name_resolve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resloves the service name, type, domain. */ -/* */ -/* INPUT */ -/* */ -/* srv_name Pointer to SRV name */ -/* name The name of the service */ -/* type The type of to the service */ -/* domain The domain */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* mDNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_service_name_resolve(UCHAR *srv_name, UCHAR **name, UCHAR **type, UCHAR **domain) -{ - -UINT i; -UINT count; -UINT prepend_index; -UINT append_index; -UINT type_index; -UINT domain_index; -UCHAR *pointer; -UINT protocol_length; - - - /* Initialize the parameters. */ - count = 0; - prepend_index = 0; - append_index = 0; - type_index = 0; - domain_index = 0; - - /* Set the service name pointer. */ - pointer = srv_name; - - /* Service Instance name, */ - /* .._tcp. : - name: - type: ._tcp - domain: . */ - while (*srv_name != '\0') - { - - /* Update the index. */ - append_index ++; - - if (*srv_name == '.') - { - - /* Set the value. */ - i = 0; - - while (nx_mdns_app_protocol[i]) - { - - /* Check string length. */ - if (_nx_utility_string_length_check(nx_mdns_app_protocol[i], &protocol_length, NX_MDNS_TYPE_MAX)) - { - continue; - } - - /* Find the key string. "_tcp" , "_udp" etc. */ - if (!_nx_mdns_name_match(pointer + prepend_index, (UCHAR *)(nx_mdns_app_protocol[i]), protocol_length)) - { - - /* Get the pointer. */ - /* EL-PC.Test._http._tcp.local - type index pointer to the _http._tcp, - domain_index pointer to the local. */ - domain_index = append_index; - - /* Set the name pointer. */ - if (type_index) - { - *name = pointer; - - /* Set the trailing null of name. */ - *(pointer + type_index -1) = '\0'; - } - else - { - *name = NX_NULL; - } - - /* Set the type pointer. */ - *type = pointer + type_index; - - /* Set the trailing null of type. */ - *(pointer + domain_index -1) = '\0'; - - /* Set the type pointer. */ - *domain = pointer + domain_index; - - return(NX_MDNS_SUCCESS); - } - i ++; - } - - /* Update the '.' count. */ - count ++; - - /* The type index is pointer to the . */ - if (count != 1) - { - - /* Update the type index. */ - type_index = prepend_index; - } - - prepend_index = append_index; - } - - srv_name ++; - } - - return(NX_MDNS_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_name_assemble PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resloves the service name, type, domain. */ -/* */ -/* INPUT */ -/* */ -/* srv_name Pointer to SRV name */ -/* name The name of the service */ -/* type The type of to the service */ -/* domain The domain */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* mDNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_service_name_assemble(UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *domain, UCHAR *record_buffer, UINT buffer_size, UINT *type_index) -{ - -UINT index; -UINT length; - - /* Initialize the struct. */ - index = 0; - memset(record_buffer, 0, buffer_size); - if (type_index) - { - *type_index = 0; - } - - /* Construct the service name. */ - - /* Add the name. */ - if (name) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)name, &length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - memcpy((CHAR *)(record_buffer + index), (const char*)name, length); - index += length; - - *(record_buffer + index) = '.'; - index ++; - } - - /* Add the sub type. */ - if (sub_type) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)sub_type, &length, NX_MDNS_LABEL_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - if (type_index) - { - *type_index = index; - } - memcpy((CHAR *)(record_buffer + index), (const char*)sub_type, length); - index += length; - *(record_buffer + index) = '.'; - index ++; - - /* Add the key word "_sub". */ - memcpy((CHAR *)(record_buffer + index), (const char*)"_sub", 5); - index += 4; - *(record_buffer + index) = '.'; - index ++; - } - - /* Add the type. */ - if (type) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)type, &length, NX_MDNS_TYPE_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Set the type index. */ - if ((type_index) && - (!sub_type)) - { - *type_index = index; - } - - memcpy((CHAR *)record_buffer + index, (const char*)type, length); - index += length; - *(record_buffer + index) = '.'; - index ++; - } - - /* Add the domain. */ - if (domain) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)domain, &length, NX_MDNS_DOMAIN_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - memcpy((CHAR *)(record_buffer + index), (const char*)domain, length); - index += length; - } - - /* Check the size. Compliant Multicast DNS implementations MUST support names up to 255 bytes plus a terminating zero, RFC6762, Page64. */ - if ((index > buffer_size) || - (index > NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - return(NX_MDNS_SUCCESS); -} - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_mdns_host_name_register PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resloves the service name, type, domain. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* type The type of operation */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_rr_a_aaaa_add Add the A/AAAA resource record*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_enable Enable mDNS */ -/* _nx_mdns_address_change_process Process address change */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_host_name_register(NX_MDNS *mdns_ptr, UCHAR type, UINT interface_index) -{ - -#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 -UINT status; -#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ -NX_IP *ip_ptr; -UINT index = 0; -UCHAR add_a = NX_FALSE; -UCHAR add_aaaa = NX_FALSE; -UINT host_name_length; - -#ifdef NX_MDNS_ENABLE_IPV6 -NXD_IPV6_ADDRESS *ipv6_address_ptr; -#endif /* NX_MDNS_ENABLE_IPV6 */ - - -#if defined NX_DISABLE_IPV4 && !defined NX_MDNS_ENABLE_IPV6 - NX_PARAMETER_NOT_USED(type); -#endif /* NX_DISABLE_IPV4 && ! NX_MDNS_ENABLE_IPV6 */ - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_host_name, &host_name_length, NX_MDNS_HOST_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Construct the A/AAAA name. */ - memcpy((CHAR *)(&temp_string_buffer[index]), (const char*)mdns_ptr -> nx_mdns_host_name, host_name_length); - index += host_name_length; - - temp_string_buffer[index] = '.'; - index ++; - memcpy((CHAR *)(&temp_string_buffer[index]), (CHAR *)"local", sizeof("local")); - - /* Set the ip pointer. */ - ip_ptr = mdns_ptr -> nx_mdns_ip_ptr; - - /* Get the IP mutex. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - -#ifndef NX_DISABLE_IPV4 - /* Add the A resource records message. */ - if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address) - { - - /* Add the A resource records message. */ - status = _nx_mdns_rr_a_aaaa_add(mdns_ptr, &temp_string_buffer[0], &(ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address), - NX_MDNS_IPV4_ADDRESS_LENGTH, type, interface_index); - - /* Check the status. */ - if (status) - { - - /* Release the IP mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - return(status); - } - - /* Set the flag. */ - add_a = NX_TRUE; - } -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - /* Get the IPv6 address pointer.*/ - ipv6_address_ptr = ip_ptr -> nx_ip_interface[interface_index].nxd_interface_ipv6_address_list_head; - - while(ipv6_address_ptr) - { - - if (ipv6_address_ptr -> nxd_ipv6_address_state == NX_IPV6_ADDR_STATE_VALID) - { - - /* Add the AAAA resource records message. */ - status = _nx_mdns_rr_a_aaaa_add(mdns_ptr, &temp_string_buffer[0], (ULONG *)(&ipv6_address_ptr -> nxd_ipv6_address[0]), - NX_MDNS_IPV6_ADDRESS_LENGTH, type, interface_index); - - /* Check the status. */ - if (status) - { - - /* Release the IP mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - return(status); - } - - /* Set the flag. */ - add_aaaa = NX_TRUE; - } - - /* Update the pointer. */ - ipv6_address_ptr = ipv6_address_ptr -> nxd_ipv6_address_next; - } -#endif /* NX_MDNS_ENABLE_IPV6 */ - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - - /* Add the NSEC resource record. */ - if ((add_a == NX_TRUE) || (add_aaaa == NX_TRUE)) - _nx_mdns_rr_nsec_add(mdns_ptr, &temp_string_buffer[0], add_a, add_aaaa, NX_MDNS_ADD_NSEC_FOR_HOST, interface_index); -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* Release the IP mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Return a successful status. */ - return(NX_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles waking up the mDNS helper thread to process */ -/* the timer event on a periodic basis. */ -/* */ -/* INPUT */ -/* */ -/* mdns_value mDNS instance for a ulong */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX system timer thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_timer_entry(ULONG mdns_value) -{ - -NX_MDNS *mdns_ptr; - - - /* Setup mDNS pointer from the input value. */ - mdns_ptr = (NX_MDNS *) mdns_value; - - /* Set the timer event. */ - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_TIMER_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_timer_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process all resource records according to the state, */ -/* Set the flags to send the probing, announcing, query, response and */ -/* goodbye mDNS message. Delete the resource record when the resource */ -/* record is invalid. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_timer_info_get Get the timer info */ -/* tx_timer_deactivate Deactivate the timer */ -/* tx_timer_change Change the timer */ -/* tx_timer_activate Activate the timer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_enable Enable the mDNS */ -/* _nx_mdns_rr_a_aaaa_add Add the A/AAAA resource record*/ -/* _nx_mdns_rr_ptr_add Add the ptr resource record */ -/* _nx_mdns_rr_srv_add Add the srv resource record */ -/* _nx_mdns_rr_txt_add Add the txt resource record */ -/* _nx_mdns_rr_delete Delete the resource record */ -/* _nx_mdns_local_cache_clear Clear the local cache */ -/* _nx_mdns_query Send the continuous query */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* _nx_mdns_conflict_process Process the conflict */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_timer_set(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr, ULONG timer_count) -{ - - -TX_INTERRUPT_SAVE_AREA -ULONG remaining_ticks; -ULONG schedule_count; -UINT active; - - if (timer_count) - { - - /* Disable interrupt */ - TX_DISABLE - - /* Get the remaining_ticks of mDNS timer;*/ - tx_timer_info_get(&mdns_ptr -> nx_mdns_timer, TX_NULL, &active, &remaining_ticks, TX_NULL, TX_NULL); - - /* If the timer is not active, the remaining ticks and schedule count are set to 0. */ - if(active == NX_FALSE) - { - remaining_ticks = 0; - schedule_count = 0; - } - else - { - - /* Get the reschedule timer count of last timer. */ - schedule_count = mdns_ptr -> nx_mdns_timer_min_count; - } - - /* Check the timer. if exceed the timer count range, update the timer. */ - if((timer_count < remaining_ticks) || active == NX_FALSE) - { - - /* Set the minimum timer count. - The minimum timer count indicate the intervals between last timer event and next timer event. */ - mdns_ptr -> nx_mdns_timer_min_count = (schedule_count - remaining_ticks) + timer_count; - - /* Change the timer ticks with minimum timer count.*/ - tx_timer_deactivate(&(mdns_ptr -> nx_mdns_timer)); - tx_timer_change(&(mdns_ptr -> nx_mdns_timer), timer_count, timer_count ); - tx_timer_activate(&(mdns_ptr -> nx_mdns_timer)); - } - - /* Update the Resource record life timer count*/ - record_rr -> nx_mdns_rr_timer_count = (schedule_count - remaining_ticks) + timer_count; - - /* Restore interrupts. */ - TX_RESTORE - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_timer_event_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process all resource records according to the state, */ -/* Set the flags to send the probing, announcing, query, response and */ -/* goodbye mDNS message. Delete the resource record when the resource */ -/* record is invalid. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags to wake mDNS */ -/* tx_timer_deactivate Deactivate the timer */ -/* tx_timer_change Change the timer */ -/* tx_timer_activate Activate the timer */ -/* _nx_mdns_service_name_resolve Resolve the service name */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from the cache */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_thread_entry Processing thread for mDNS */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_timer_event_process(NX_MDNS *mdns_ptr) -{ - -ULONG event_flags = 0; -ULONG timer_min_count = 0xFFFFFFFF; -ULONG *head, *tail; -NX_MDNS_RR *p; -UCHAR i; - -#ifndef NX_MDNS_DISABLE_CLIENT -ULONG remaining_ticks; -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#ifndef NX_MDNS_DISABLE_SERVER -UINT status; -NX_MDNS_RR *p1; -UCHAR *service_name; -UCHAR *service_type; -UCHAR *service_domain; -UINT rr_name_length; -#endif /* NX_MDNS_DISABLE_SERVER */ - - - for(i = 0; i < 2; i++) - { - - /* Set the pointer. */ - if(i == NX_MDNS_CACHE_TYPE_LOCAL) - { -#ifndef NX_MDNS_DISABLE_SERVER - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { -#ifndef NX_MDNS_DISABLE_CLIENT - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - - if(head == NX_NULL) - continue; - - tail = (ULONG*)(*head); - - /* Check the remote resource record lifetime. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG*)p < tail; p++) - { - - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Update the remaining ticks of peer resource record. */ - if (((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING))) - { - if (p -> nx_mdns_rr_remaining_ticks > mdns_ptr -> nx_mdns_timer_min_count) - { - p -> nx_mdns_rr_remaining_ticks -= mdns_ptr -> nx_mdns_timer_min_count; - } - else - { - p -> nx_mdns_rr_remaining_ticks = 0; - } - } - - /* Calculate the time interval for two responses.*/ - if (p -> nx_mdns_rr_response_interval > (UCHAR)mdns_ptr -> nx_mdns_timer_min_count) - { - p -> nx_mdns_rr_response_interval = (UCHAR)(p -> nx_mdns_rr_response_interval - mdns_ptr -> nx_mdns_timer_min_count); - - /* Compare the timer count.and set the minimum timer count. */ - if ((p -> nx_mdns_rr_response_interval != 0) && - (p -> nx_mdns_rr_response_interval < timer_min_count)) - { - timer_min_count = p -> nx_mdns_rr_response_interval; - } - } - else - { - p -> nx_mdns_rr_response_interval = 0; - } - - /* If the timer count is zero, means do not do anything */ - if (p -> nx_mdns_rr_timer_count == 0) - continue; - - if (p -> nx_mdns_rr_timer_count > mdns_ptr -> nx_mdns_timer_min_count) - { - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_timer_count - mdns_ptr -> nx_mdns_timer_min_count; - - /* Check the timer count range. */ - if (p -> nx_mdns_rr_timer_count <= NX_MDNS_TIMER_COUNT_RANGE) - { - p -> nx_mdns_rr_timer_count = 0; - } - else - { - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - } - else - { - p -> nx_mdns_rr_timer_count = 0; - } - - /* If the timer count is zero, means the timeout. */ - if (p -> nx_mdns_rr_timer_count != 0) - continue; - - /* Check the state. */ - switch (p -> nx_mdns_rr_state) - { - -#ifndef NX_MDNS_DISABLE_SERVER - case NX_MDNS_RR_STATE_PROBING: - { - - /* mDNS Server probing the RRs at 0ms, 250ms, 500ms. RFC6762, Section8.1, Page26. */ - if (p -> nx_mdns_rr_retransmit_count) - { - - /* Set the send flag.*/ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the probing flag. */ - event_flags = event_flags | NX_MDNS_PROBING_SEND_EVENT; - - /* Set the timer count. 250ms. */ - p -> nx_mdns_rr_timer_count = NX_MDNS_PROBING_TIMER_COUNT; - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - else - { - - /* Probing complete, and move to the next step, Announcing. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_ANNOUNCING; - - /* Set the first announcing timer interval. */ - p -> nx_mdns_rr_timer_count = NX_MDNS_ANNOUNCING_TIMER_COUNT; - - /* Set the retransmit count. */ - if (mdns_ptr -> nx_mdns_announcing_retrans_interval) - p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; - else - p -> nx_mdns_rr_retransmit_count = 1; - - /* Set the next timer count. */ - p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period; - - /* Check the announcing max time. */ - if (mdns_ptr -> nx_mdns_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) - p -> nx_mdns_rr_announcing_max_time = (UCHAR)(mdns_ptr -> nx_mdns_announcing_max_time - 1); - else - p -> nx_mdns_rr_announcing_max_time = NX_MDNS_ANNOUNCING_FOREVER; - - /* Yes, probing complete, add the related PTR resource records. */ - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)p -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) - { - break; - } - - /* Store the service name. */ - memcpy((CHAR *)(&temp_string_buffer[0]), (const char*)p -> nx_mdns_rr_name, rr_name_length + 1); - - /* Reslove the service name. */ - status = _nx_mdns_service_name_resolve(&temp_string_buffer[0], &service_name, &service_type, &service_domain); - - /* Check the status. */ - if (status) - { - break; - } - - /* Service name registered success, invoke the notify function. */ - if (mdns_ptr -> nx_mdns_probing_notify) - { - (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, service_name, NX_MDNS_LOCAL_SERVICE_REGISTERED_SUCCESS); - } - } - - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) - { - - /* Service name registered success, invoke the notify function. */ - if (mdns_ptr -> nx_mdns_probing_notify) - { - (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, mdns_ptr -> nx_mdns_host_name, NX_MDNS_LOCAL_HOST_REGISTERED_SUCCESS); - } - } - - /* Probing complete, Has been wating for 250ms, Directly announcing the resource record. */ - p --; - } - break; - } - - case NX_MDNS_RR_STATE_ANNOUNCING: - { - - /* mDNS Server Announcing the Resource records. */ - if (p -> nx_mdns_rr_retransmit_count) - { - - /* Set the send flag to send the probing. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the announcing flag. */ - event_flags = event_flags | NX_MDNS_ANNOUNCING_SEND_EVENT; - - /* Yes, probing complete, add the related PTR resource records and NSEC resource records. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) - { - - for (p1 = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p1 < tail; p1++) - { - - /* Check the state. */ - if (p1 -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface. */ - if (p1 -> nx_mdns_rr_interface_index != p -> nx_mdns_rr_interface_index) - continue; - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - if ((p1 ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) && - (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_name)) - { - - /* Set the send flag to send the probing. */ - p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - } -#endif /*NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && - (p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && - (p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == p -> nx_mdns_rr_name)) - { - - /* Set the send flag to send the probing. */ - p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - } - } - } - - /* Check last the retransmit in this period announcing. */ - if (p -> nx_mdns_rr_retransmit_count - 1) - { - - if (mdns_ptr -> nx_mdns_announcing_retrans_interval) - { - - /* Set the timer count. */ - p -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_announcing_retrans_interval; - - /* Compare the timer count and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - } - else - { - if (p -> nx_mdns_rr_announcing_max_time) - { - - /* Update the timer count. */ - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_retransmit_lifetime; - - /* Calculate the next timer count. */ - p -> nx_mdns_rr_retransmit_lifetime = (ULONG)(p -> nx_mdns_rr_retransmit_lifetime * (ULONG)(2 << (mdns_ptr -> nx_mdns_announcing_factor - 1))); - - /* Check the announcing period time interval. */ - if (p -> nx_mdns_rr_retransmit_lifetime > mdns_ptr -> nx_mdns_announcing_period_interval) - p -> nx_mdns_rr_retransmit_lifetime = mdns_ptr -> nx_mdns_announcing_period_interval; - - /* Set the retransmit count. */ - if (mdns_ptr -> nx_mdns_announcing_retrans_interval) - p -> nx_mdns_rr_retransmit_count = mdns_ptr -> nx_mdns_announcing_count; - else - p -> nx_mdns_rr_retransmit_count = 1; - - /* Set the retransmit count. */ - p -> nx_mdns_rr_retransmit_count++; - - /* Check the announcing time. */ - if (p -> nx_mdns_rr_announcing_max_time != NX_MDNS_ANNOUNCING_FOREVER) - p -> nx_mdns_rr_announcing_max_time--; - - /* Compare the timer count and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - else - { - - /* Announcing complete, Update the resource record state valid, . */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; - - /* Clear the timer count. */ - p -> nx_mdns_rr_timer_count = 0; - } - } - } - break; - } - - case NX_MDNS_RR_STATE_GOODBYE: - { - - /* mDNS Server send Goodbye packet. */ - if (p -> nx_mdns_rr_retransmit_count) - { - - /* Set the send flag to send the probing. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the announcing flag. */ - event_flags = event_flags | NX_MDNS_ANNOUNCING_SEND_EVENT; - - /* Set the timer count. */ - p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - else - { - - /* Check for RR delete flag. */ - if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DELETE) - { - - /* Delete the resource records. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); - } - else - { - - /* Suspend the resource record. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_SUSPEND; - p -> nx_mdns_rr_timer_count = 0; - } - } - break; - } -#endif /* NX_MDNS_DISABLE_SERVER */ - - - case NX_MDNS_RR_STATE_VALID: - { - - if(i == NX_MDNS_CACHE_TYPE_PEER) - { - /* Set the resource record status. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_UPDATING; - - /* Check the updating flag. */ - if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UPDATING) - { - - /* Set the retransmit count. */ - p -> nx_mdns_rr_retransmit_count = NX_MDNS_RR_UPDATE_COUNT; - - /* 50% of the record lifetime has elapsed,the querier should plan to issure a query at 80%-82% of the record lifetime */ - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(30 + (NX_RAND() % 3)) / 100; - } - else - { - /* Set the retransmit count. */ - p -> nx_mdns_rr_retransmit_count = 0; - - /* 50% of the record lifetime has elapsed, Delete the resource record at 100% of the record lifetime */ - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 50 / 100; - } - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - - /* Check the send flag. */ - else - { - if (p -> nx_mdns_rr_send_flag) - { - - /* Set the send flag to send the response. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - /* Clear the NSEC additional send. */ - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) - p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_FALSE; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* mDNS Responder MUST NOT multicast a record until at least one second has elapsed since the last time that record was multicast. RFC6762, Section6, Page16. */ - /* Set the next response time interval. */ - p -> nx_mdns_rr_response_interval = (UCHAR)(NX_MDNS_RESPONSE_INTERVAL + NX_MDNS_TIMER_COUNT_RANGE); - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_response_interval < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_response_interval; - } - - /* Set the announcing flag. */ - event_flags = event_flags | NX_MDNS_RESPONSE_SEND_EVENT; - } - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - else - { - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) - { - if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send) - { - p -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_ADDITIONAL; - p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_FALSE; - - /* Set the announcing flag. */ - event_flags = event_flags | NX_MDNS_RESPONSE_SEND_EVENT; - } - } - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - } - break; - } - - -#ifndef NX_MDNS_DISABLE_CLIENT - case NX_MDNS_RR_STATE_QUERY: - { - - /* mDNS Client did not receive the response, send the query again. */ - if (!p -> nx_mdns_rr_timer_count) - { - - /* Check the Duplicate Question. If the flag set, Host should not send the query until the next timeout. */ - if (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_DUPLICATE_QUERY)) - { - - /* Set the send flag to send the query. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the query flag. */ - event_flags = event_flags | NX_MDNS_QUERY_SEND_EVENT; - } - - /* Clear the duplicate flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & ~NX_MDNS_RR_FLAG_DUPLICATE_QUERY); - - /* Double the next timer count. */ - p -> nx_mdns_rr_retransmit_lifetime = p -> nx_mdns_rr_retransmit_lifetime << 1; - - /* The interval between the first two queries MUST be at least one second. RFC6762, Section5.2, Page9. */ - if (p -> nx_mdns_rr_retransmit_lifetime < NX_MDNS_QUERY_MIN_TIMER_COUNT) - { - p -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_QUERY_MIN_TIMER_COUNT; - } - - /* When the interval between queries reaches or exceeds 60 minutes, a querier MAY cap the interval to a maximum of 60 minutes. RFC6762, Section5.2, Page10. */ - if (p -> nx_mdns_rr_retransmit_lifetime > NX_MDNS_QUERY_MAX_TIMER_COUNT) - { - p -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_QUERY_MAX_TIMER_COUNT; - } - - /* Update the timer count. */ - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_retransmit_lifetime; - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - break; - } - - case NX_MDNS_RR_STATE_UPDATING: - { - - /* The querier should plan to issure a query at 80%-82% of the record lifetime, and then if no answer is received, - at 85%-87%, 90%-92% and 95%-97%. the record is deleted when it reaches 100% of its lifetime. RFC6762, Section5.2, Page10. */ - if (p -> nx_mdns_rr_retransmit_count) - { - - /* Set the send flag to retransmit its query. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the query flag. */ - event_flags = event_flags | NX_MDNS_QUERY_SEND_EVENT; - - /* Update the timer count. Client should send the updating message every 5% of ttl. */ - if (p -> nx_mdns_rr_retransmit_count == 1) - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_remaining_ticks; - else - { - remaining_ticks = p -> nx_mdns_rr_remaining_ticks; - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 5 / 100; - - /* Get the remaining ticks in 5% of TTL. */ - while(remaining_ticks > p -> nx_mdns_rr_timer_count) - remaining_ticks -= p -> nx_mdns_rr_timer_count; - - p -> nx_mdns_rr_timer_count = remaining_ticks + (p -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(NX_RAND() % 3) / 100); - } - - /* Compare the timer count.and set the minimum timer count. */ - if (p -> nx_mdns_rr_timer_count < timer_min_count) - { - timer_min_count = p -> nx_mdns_rr_timer_count; - } - } - else - { - - /* Delete the resource record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); - } - break; - } - - case NX_MDNS_RR_STATE_DELETE: - case NX_MDNS_RR_STATE_POOF_DELETE: - { - - /* Delete the resource record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); - break; - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - - default: - { - break; - } - } - } - } - - /* If the specified timer rate is different with the new timer min count,then update it.*/ - if (mdns_ptr -> nx_mdns_timer_min_count != timer_min_count) - { - - /* Set the minimum timer count.*/ - mdns_ptr -> nx_mdns_timer_min_count = timer_min_count; - - /* Deactivate the timer. */ - tx_timer_deactivate(&(mdns_ptr -> nx_mdns_timer)); - - if (timer_min_count != 0xFFFFFFFF) - { - - /* Change the timer ticks with minimum timer count.*/ - tx_timer_change(&(mdns_ptr -> nx_mdns_timer), - mdns_ptr -> nx_mdns_timer_min_count, - mdns_ptr -> nx_mdns_timer_min_count); - tx_timer_activate(&(mdns_ptr -> nx_mdns_timer)); - } - } - - /* Set the event to send mDNS query. */ - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), event_flags, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_udp_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the mDNS UDP receive notify callback. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to udp socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* UDP receive callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_udp_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - - - NX_PARAMETER_NOT_USED(socket_ptr); - - /* Check the mDNS. */ - if(_nx_mdns_created_ptr) - { - - /* Set the receive UDP packet notify. */ - tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_PKT_RX_EVENT, TX_OR); - } - - return; -} - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_ip_address_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the mDNS UDP receive notify callback. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to udp socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* UDP receive callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_ip_address_change_notify(NX_IP *ip_ptr, VOID *additional_info) -{ - - - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(additional_info); - - /* Check the mDNS. */ - if(_nx_mdns_created_ptr) - { - - /* Set the address change event event. */ - tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_ADDRESS_CHANGE_EVENT, TX_OR); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_ipv6_address_change_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the mDNS UDP receive notify callback. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to udp socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flags */ -/* */ -/* CALLED BY */ -/* */ -/* UDP receive callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifdef NX_MDNS_ENABLE_IPV6 -static VOID _nx_mdns_ipv6_address_change_notify(NX_IP *ip_ptr, UINT method, UINT interface_index, UINT index, ULONG *ipv6_address) -{ - - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(method); - NX_PARAMETER_NOT_USED(interface_index); - NX_PARAMETER_NOT_USED(index); - NX_PARAMETER_NOT_USED(ipv6_address); - - /* Check the mDNS. */ - if(_nx_mdns_created_ptr) - { - - /* Set the address change event. */ - tx_event_flags_set(&(_nx_mdns_created_ptr -> nx_mdns_events), NX_MDNS_ADDRESS_CHANGE_EVENT, TX_OR); - } - return; -} -#endif /* NX_MDNS_ENABLE_IPV6 */ -#endif /* NX_MDNS_DISABLE_SERVER */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry point for the mDNS helper thread. */ -/* mDNS helper thread is responsible for processing mDNS events. */ -/* Receive and send the mDNS packet. */ -/* */ -/* INPUT */ -/* */ -/* mdns_value Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* tx_event_flags_get Get the mDNS events */ -/* nx_udp_socket_receive Receive the mDNS packet */ -/* nx_packet_release Release the mDNS packet */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* _nx_mdns_announcing_send Send announcing message */ -/* _nx_mdns_probing_send Send probing message */ -/* _nx_mdns_query_send Send query message */ -/* _nx_mdns_response_send Send response message */ -/* _nx_mdns_timer_event_process Process the mDNS timer event */ -/* _nx_mdns_address_change_process Process the address change */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX Scheduler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_thread_entry(ULONG mdns_value) -{ - -NX_MDNS *mdns_ptr; -NX_PACKET *packet_ptr; -ULONG mdns_events; -UINT status; -UINT interface_index; - - - /* Setup mDNS pointer from the input value. */ - mdns_ptr = (NX_MDNS *) mdns_value; - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Loop to process events for this mDNS instance. */ - while(1) - { - - /* Release the mDNS mutex. */ - tx_mutex_put(&(mdns_ptr -> nx_mdns_mutex)); - - /* Pickup mDNS event flags. */ - tx_event_flags_get(&mdns_ptr -> nx_mdns_events, - NX_MDNS_ALL_EVENTS, TX_OR_CLEAR, - &mdns_events, TX_WAIT_FOREVER); - - /* Get the mDNS mutex. */ - tx_mutex_get(&(mdns_ptr -> nx_mdns_mutex), TX_WAIT_FOREVER); - - /* Check for an UDP packet receive event. */ - if (mdns_events & NX_MDNS_PKT_RX_EVENT) - { - while (1) - { - - /* Receive a UDP packet. */ - status = _nx_udp_socket_receive(&mdns_ptr -> nx_mdns_socket, - &packet_ptr, TX_NO_WAIT); - - /* Check status. */ - if (status != NX_SUCCESS) - break; - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Discard the chained packets. */ - if (packet_ptr -> nx_packet_next) - { - nx_packet_release(packet_ptr); - continue; - } -#endif - - /* Get the interface. */ - if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) - { - interface_index = packet_ptr -> nx_packet_ip_interface -> nx_interface_index; - } - else - { - interface_index = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached -> nx_interface_index; - } - - /* Check the interface. */ - if (!mdns_ptr -> nx_mdns_interface_enabled[interface_index]) - { - /* Release the packet since mDNS is not enabled on this interface. */ - nx_packet_release(packet_ptr); - continue; - } - - /* Yes, Get the mDNS packet, process it. */ - _nx_mdns_packet_process(mdns_ptr, packet_ptr, interface_index); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Loop to send mDNS message for each interface. */ - for (interface_index = 0; interface_index < NX_MAX_PHYSICAL_INTERFACES; interface_index++) - { - - /* Check if this interface is enabled. - Exception: Goodbye message can be sent out after disable. */ - if ((!mdns_ptr -> nx_mdns_interface_enabled[interface_index]) && - (!(mdns_events & NX_MDNS_ANNOUNCING_SEND_EVENT))) - continue; - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Check for an mDNS probing send event. */ - if (mdns_events & NX_MDNS_PROBING_SEND_EVENT) - { - - /* Send probing. */ - _nx_mdns_probing_send(mdns_ptr, interface_index); - } - - /* Check for an mDNS announcing send event. */ - if (mdns_events & NX_MDNS_ANNOUNCING_SEND_EVENT) - { - - /* Send announcing. */ - _nx_mdns_announcing_send(mdns_ptr, interface_index); - } - - /* Check for an mDNS response send event. */ - if (mdns_events & NX_MDNS_RESPONSE_SEND_EVENT) - { - - /* Send response. */ - _nx_mdns_response_send(mdns_ptr, interface_index); - } -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Check for an mDNS query send event. */ - if (mdns_events & NX_MDNS_QUERY_SEND_EVENT) - { - - /* Send query. */ - _nx_mdns_query_send(mdns_ptr, interface_index); - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Check for an mDNS address change event. */ - if (mdns_events & NX_MDNS_ADDRESS_CHANGE_EVENT) - { - - /* Process the address change event. */ - _nx_mdns_address_change_process(mdns_ptr); - } -#endif /* NX_MDNS_DISABLE_SERVER */ - - /* Check for an mDNS timer process event. */ - if (mdns_events & NX_MDNS_TIMER_EVENT) - { - - /* Process the timer event. */ - _nx_mdns_timer_event_process(mdns_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks the interface and the IP address of received */ -/* packet, then preocesses the packet. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* packet_ptr Pointer to mDNS packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release the mDNS packet */ -/* _tx_thread_system_resume Resume thread service */ -/* _nx_mdns_timer_set Set the mDNS timer */ -/* _nx_mdns_name_string_decode Decode the name size */ -/* _nx_mdns_name_size_calculate Calculate the name size */ -/* _nx_mdns_rr_size_get Get the resource record size */ -/* _nx_mdns_conflict_process Process the mDNS conflict */ -/* _nx_mdns_cache_find_resource_record Find the mDNS resource record */ -/* _nx_mdns_packet_address_check Check the address and port */ -/* _nx_mdns_packet_rr_process Process resource record */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* from cache */ -/* nxd_udp_packet_info_extract Extract the packet info */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_thread_entry Processing thread for mDNS */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index) -{ - -USHORT mdns_flags; -UCHAR *data_ptr; -USHORT question_count; -USHORT authority_count; -USHORT answer_count; -UINT index; -NX_MDNS_RR *rr_search; -NX_MDNS_RR temp_resource_record; - -#ifndef NX_MDNS_DISABLE_SERVER -ULONG *head; -NX_MDNS_RR *p; -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES -ULONG match_count; -NX_MDNS_RR *nsec_rr; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ -#endif /* NX_MDNS_DISABLE_SERVER */ - - -#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK - /* Check the address and port. */ - if (_nx_mdns_packet_address_check(packet_ptr)) - { - return(NX_MDNS_ERROR); - } -#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ - - /* Check the packet length. */ - if (packet_ptr -> nx_packet_length < NX_MDNS_QDSECT_OFFSET) - { - return(NX_MDNS_ERROR); - } - - /* Extract the message type which should be the first byte. */ - mdns_flags = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET); - - /* Get the question count. */ - question_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET); - - /* Determine if we have any 'answers' to our DNS query. */ - answer_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET); - - /* Also check if there are any 'hints' from the Authoritative nameserver. */ - authority_count = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET); - - /* Update the answer count. Ignore the authority count and additional count for query message. */ - if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) - { - answer_count = (USHORT)(answer_count + authority_count); - - /* Include Additional section as well */ - answer_count = (USHORT)(answer_count + NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET)); - } - - /* Skip the Header. Point at the start of the question. */ - data_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDSECT_OFFSET; - - /* Process all the Question Section. */ - for (index = 0; index < question_count; index++) - { - - /* Check for data_ptr. */ - if (data_ptr >= packet_ptr -> nx_packet_append_ptr) - break; - - if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) - { - - /* Multicast DNS responses MUST NOT contain any question in the Question Section, - Any questions in the Question Section of a received Multicast DNS response MUST be silently ignored. RFC6762, Section6, Page14. */ - data_ptr += (_nx_mdns_name_size_calculate(data_ptr) + 4); - } - else - { - -#ifndef NX_MDNS_DISABLE_CLIENT - - /* Step1, mDNS Client process the Duplicate Question Suppression, RFC6762, Section7.3, Page24. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_PEER_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) - { - - /* Check the class top bit "QM". */ - if ((temp_resource_record.nx_mdns_rr_class & NX_MDNS_RR_CLASS_TOP_BIT) != NX_MDNS_RR_CLASS_TOP_BIT) - { - - /* Find the same resource record in remote buffer. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) - { - - /* Duplicate Question Suppression. */ - if (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) - { - - if (_nx_mdns_known_answer_find(mdns_ptr, rr_search) == NX_MDNS_NO_KNOWN_ANSWER) - { - - /* Yes, set the duplicate flag. process this flag in timer event process function. */ - rr_search -> nx_mdns_rr_word = rr_search -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DUPLICATE_QUERY; - } - } - -#ifdef NX_MDNS_ENABLE_CLIENT_POOF - /* Passive Observation Of Failures, RFC6762, Section10.5, Page38. */ - if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE)) - { - rr_search -> nx_mdns_rr_poof_count ++; - - /* After seeing two or more of these queries, and seeing no multicast response containing the expected anser within ten seconds, the record should be flushed from the cache. */ - if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) && - (rr_search -> nx_mdns_rr_poof_count >= NX_MDNS_POOF_MIN_COUNT)) - { - rr_search -> nx_mdns_rr_state = NX_MDNS_RR_STATE_POOF_DELETE; - rr_search -> nx_mdns_rr_timer_count = NX_MDNS_POOF_TIMER_COUNT; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, rr_search, rr_search -> nx_mdns_rr_timer_count); - } - } -#endif /* NX_MDNS_ENABLE_CLIENT_POOF */ - } - } - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Step2, mDNS Server process the normal query. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) - { - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - /* Set the match count. */ - match_count = 0; - nsec_rr = NX_NULL; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* Get head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - /* Find the same record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check whether the same record it is. RFC6762, Section6, Page13. */ - /* The rules: rrname must match the question name. - rrtype must match the question qtype unless the qtype is "ANY" or the rrtype is "CNAME". - rrclass must match the question qclass unless the qclass is "ANY". */ - if (p -> nx_mdns_rr_name != temp_resource_record.nx_mdns_rr_name) - continue; - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - - /* Check the NSEC type. */ - if (p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) - nsec_rr = p; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - if ((p -> nx_mdns_rr_type != temp_resource_record.nx_mdns_rr_type) && - (temp_resource_record.nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL) && - (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_CNAME)) - continue; - - /* Check the RR class, Ignore the top bit. */ - if ((p -> nx_mdns_rr_class != (temp_resource_record.nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)) && - ((temp_resource_record.nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)!= NX_MDNS_RR_CLASS_ALL)) - continue; - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - - /* Update the match count. */ - match_count ++; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* Check the state. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) - { - - /* Check the send flag, Flag is set indicate this resource record shoud be sent. */ - if (p -> nx_mdns_rr_send_flag) - { - - /* Set the flag to send this Resource records via multicast. - Store the old flag into the top bits. - Store the new flag into the low bits. - Format: 0001 0001 */ - p -> nx_mdns_rr_send_flag = ((NX_MDNS_RR_SEND_MULTICAST << 4) | NX_MDNS_RR_SEND_MULTICAST); - } - else - { - - /* Set the flag to send this Resource records via multicast.*/ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - } - - /* In the case where the query has the TC (truncated) bit set, indicating that subsequent Known-Answer packets will follow, - Responders SHOULD delay their responses by a random amount of time selected with uniform random distribution in the range 400-500ms. RFC6762, Section6, Page 15. */ - if (mdns_flags & NX_MDNS_TC_FLAG) - { - p -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_TC_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_TC_DELAY_RANGE)); - } - else - { - - /* A mDNS responder is only required to delay its transmission as necessary to ensure an interval of at least 250ms - since the last time the record was multicast on that interface. RFC6762, Section6, Page16 */ - if (authority_count) - { - if (p -> nx_mdns_rr_response_interval > (NX_MDNS_RESPONSE_INTERVAL - NX_MDNS_RESPONSE_PROBING_TIMER_COUNT)) - p -> nx_mdns_rr_response_interval = (UCHAR)(p -> nx_mdns_rr_response_interval - (NX_MDNS_RESPONSE_INTERVAL - NX_MDNS_RESPONSE_PROBING_TIMER_COUNT)); - else - p -> nx_mdns_rr_response_interval = 0; - } - - /* Check the response interval. */ - if (p -> nx_mdns_rr_response_interval <= NX_MDNS_TIMER_COUNT_RANGE) - { - - /* Set the timer count according to the resource record set.RFC6762, Section6, Page14. */ - if ((p ->nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) == NX_MDNS_RR_FLAG_UNIQUE) - { - p -> nx_mdns_rr_timer_count = NX_MDNS_RESPONSE_UNIQUE_DELAY; - } - else - { - /* Set the timer count, delay 20-120ms. */ - p -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_SHARED_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_SHARED_DELAY_RANGE)); - } - } - else - { - p -> nx_mdns_rr_timer_count = p -> nx_mdns_rr_response_interval; - } - } - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } - } - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - /* Send this NSEC response as additional answer. */ - if ((match_count == 0) && (nsec_rr)) - { - nsec_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_additional_send = NX_TRUE; - nsec_rr -> nx_mdns_rr_timer_count = NX_MDNS_RESPONSE_UNIQUE_DELAY; - _nx_mdns_timer_set(mdns_ptr, nsec_rr, nsec_rr -> nx_mdns_rr_timer_count); - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - } -#endif /* NX_MDNS_DISABLE_SERVER */ - - /* Update the data_ptr. */ - data_ptr += (_nx_mdns_name_size_calculate(data_ptr) + 4); - } - } - - /* Process all the Known-Answer records. */ - for (index = 0; index < answer_count; index++) - { - - /* Check for data_ptr. */ - if (data_ptr >= packet_ptr -> nx_packet_append_ptr) - break; - - if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) - { - -#ifndef NX_MDNS_DISABLE_SERVER - /* Step1, Cooperating Multicast DNS Responders, RFC6762, Section6.6, Page21. */ - /* Does the same rname and rdata name of resource record exist in the local buffer. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_ANSWER, interface_index) == NX_MDNS_SUCCESS) - { - - /* Find the same rname, rrtype, rrclass of resource record in local buffer. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) - { - - /* Probing state, conflict Resolution. */ - if ((rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) && - (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_PROBING)) - { - _nx_mdns_conflict_process(mdns_ptr, rr_search); - - /* Update the data_ptr. */ - data_ptr += _nx_mdns_rr_size_get(data_ptr); - - continue; - } - } - - /* Find the same rname, rrtype, rrclass and identical rdata of resource record in local buffer. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_ALL, &rr_search) == NX_MDNS_SUCCESS) - { - - /* If the TTL in this record(B) is less than half the true TTL in local record(A), A MUST announce local record via multicast. RFC6762, Section6.6,Page21. */ - if ((temp_resource_record.nx_mdns_rr_ttl << 1) < rr_search -> nx_mdns_rr_ttl) - { - - /* Set the flag. */ - rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_MULTICAST; - - /* Set the timer count, delay 20-120ms. */ - rr_search -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_RESPONSE_SHARED_DELAY_MIN + (NX_RAND() % NX_MDNS_RESPONSE_SHARED_DELAY_RANGE)); - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, rr_search, rr_search -> nx_mdns_rr_timer_count); - } - - /* Duplicate Answer Suppression, RFC6762, Section7.4,Page24. - The TTL in that record is not less than the TTL this host would have given. Host should not send this response again. */ - if (temp_resource_record.nx_mdns_rr_ttl >= rr_search -> nx_mdns_rr_ttl) - { - - if (rr_search -> nx_mdns_rr_send_flag) - { - - /* Clear the flag. */ - rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - - /* Check the resource records set. */ - if (rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) - { - - /* Update the data_ptr. */ - data_ptr += _nx_mdns_rr_size_get(data_ptr); - - continue; - } - } - } - - /* Did the same name of resource record have existed in local buffer. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) - { - - /* Find the same name, rrtype, rrclass and different rdata of resource record in local buffer. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) - { - - /* Check the resource records set. RFC6762, Section6.6, Page21. */ - if (rr_search -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) - { - _nx_mdns_conflict_process(mdns_ptr, rr_search); - - /* Update the data_ptr. */ - data_ptr += _nx_mdns_rr_size_get(data_ptr); - - continue; - } - } - } -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Step2. Add the response resource records in remote buffer. */ - _nx_mdns_packet_rr_process(mdns_ptr, packet_ptr, data_ptr, interface_index); -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - else - { -#ifndef NX_MDNS_DISABLE_CLIENT - /* Clear the record. */ - - /* Step1, mDNS Client process the Known-Answer about Duplicate Question Suppression. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_PEER_SET_QUESTION, interface_index) == NX_MDNS_SUCCESS) - { - - /* Find the same resource record in remote buffer. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &temp_resource_record, NX_MDNS_RR_MATCH_EXCEPT_RDATA, &rr_search) == NX_MDNS_SUCCESS) - { - - /* Duplicate Question Suppression. */ - if (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) - { - - /* Yes, the query includes the Known-Answer Section, clear the duplicate flag. */ - rr_search -> nx_mdns_rr_word = (USHORT)(rr_search -> nx_mdns_rr_word & ~NX_MDNS_RR_FLAG_DUPLICATE_QUERY); - } - -#ifdef NX_MDNS_ENABLE_CLIENT_POOF - /* Passive Observation Of Failures, RFC6762, Section10.5, Page38. */ - if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE)) - { - rr_search -> nx_mdns_rr_poof_count --; - - /* Check the count. */ - if ((rr_search -> nx_mdns_rr_state == NX_MDNS_RR_STATE_POOF_DELETE) && - (rr_search -> nx_mdns_rr_poof_count < NX_MDNS_POOF_MIN_COUNT)) - { - rr_search -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; - rr_search -> nx_mdns_rr_timer_count = 0; - } - } -#endif /* NX_MDNS_ENABLE_CLIENT_POOF */ - } - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#ifndef NX_MDNS_DISABLE_SERVER - - /* Step2. mDNS Server process the Known-Answer of normal query. */ - if (_nx_mdns_packet_rr_set(mdns_ptr, packet_ptr, data_ptr, &temp_resource_record, NX_MDNS_RR_OP_LOCAL_SET_ANSWER, interface_index) == NX_MDNS_SUCCESS) - { - - /* Find the same resource record. */ - if(_nx_mdns_cache_find_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_resource_record, NX_MDNS_RR_MATCH_ALL, &rr_search) == NX_MDNS_SUCCESS) - { - - /* mDNS responder Must Not answer a mDNS query if the answer included the Answer Section with an RR TTL at least half the correct value. RFC6762, Section7.1, Page23. */ - if ((!(rr_search -> nx_mdns_rr_send_flag & NX_MDNS_RR_SEND_FLAG_MASK)) && - ((temp_resource_record.nx_mdns_rr_ttl << 1) >= rr_search -> nx_mdns_rr_ttl)) - { - - /* Top four bit is zero and this resource reocrd is Known answer. - Clear the send flag. */ - rr_search -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - } -#endif /* NX_MDNS_DISABLE_SERVER */ - } - - /* Update the data_ptr. */ - data_ptr += _nx_mdns_rr_size_get(data_ptr); - } - - return(NX_MDNS_SUCCESS); -} - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_probing_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends mDNS probing message. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* none */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_probing_send(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; -NX_PACKET *packet_ptr; -ULONG *head; -NX_MDNS_RR *p; -USHORT question_count = 0; -USHORT answer_count = 0; -USHORT authority_count = 0; -USHORT additional_count = 0; -UCHAR resend_flag = NX_FALSE; -USHORT total_size; -USHORT rr_size; -UINT name_size; -NX_MDNS_RR *p1; -UINT rr_name_length; - - - /* Create the mdns packet and add the mDNS header. */ - status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_TRUE); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - return; - } - - /* Set the total size. */ - total_size = (USHORT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr); - - /* Set the head pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - /* Add the answer resource record. */ - for (p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check the send flag. */ - if (p -> nx_mdns_rr_send_flag == 0) - continue; - - /* Check the state. */ - if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) - continue; - - /* Add the resource record into packet. */ - - /* Calculate the question and answer size before sending the probing message, make sure the question and authority in one packet. */ - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)p -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) - { - continue; - } - - /* Calculate the name size. The name should plus the '.' and '\0'. */ - name_size = rr_name_length + 2; - - /* Calculate the resource record size for question. QNAME, QTYPE, QCLASS. */ - rr_size = (USHORT)(name_size + 4); - - /* Calcuate the resource record size for authority. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ - rr_size = (USHORT)(rr_size + (name_size + 10 + p -> nx_mdns_rr_rdata_length)); - - /* Check if need add other authority answers for this same question. */ - for(p1 = (NX_MDNS_RR*)(head + 1); (ULONG)p1 < *head; p1++) - { - - /* Check the interface index. */ - if (p1 -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check the state. */ - if (p1 -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) - continue; - - /* Check the name and flag. */ - if ((p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_name) && - (p1 -> nx_mdns_rr_send_flag) && - (p1 != p)) - { - - /* Calculate the resource record size for other authority. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ - rr_size = (USHORT)(rr_size + (name_size + 10 + p1 -> nx_mdns_rr_rdata_length)); - - /* Check the packet size. */ - if (rr_size <= total_size) - { - - /* Set the authority answer flag. */ - p1 -> nx_mdns_rr_word = p1 -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_AUTHORIY_ANSWER; - - /* Clear the send flag. */ - p1 -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - else - { - resend_flag = NX_TRUE; - break; - } - } - } - - /* Check the packet size. */ - if (rr_size > total_size) - { - resend_flag = NX_TRUE; - continue; - } - else - total_size = (USHORT)(total_size - rr_size); - - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_QUESTION, NX_MDNS_PACKET_PROBING); - - if (status) - { - resend_flag = NX_TRUE; - } - else - { - - /* Set the authority answer flag. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_AUTHORIY_ANSWER; - - /* Update the question count. */ - question_count ++; - - /* Clear the flag. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - - /* Add the authority answer resource record. */ - for (p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether set the resource record send flag. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_PROBING) && - (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_AUTHORIY_ANSWER)) - { - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_PROBING); - if (status) - resend_flag = NX_TRUE; - else - { - - /* Update the retransmit count. */ - p -> nx_mdns_rr_retransmit_count --; - - /* Update the authority count. */ - authority_count ++; - - /* Clear the additional flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_AUTHORIY_ANSWER)); - } - } - - /* Clear the answer flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); - } - - if (!question_count && - !answer_count && - !authority_count && - !additional_count) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Update the question count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); - - /* Update the answer count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); - - /* Send the mDNS packet. */ - _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); - - /* Resend the packet. */ - if (resend_flag) - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_PROBING_SEND_EVENT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_announcing_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends mDNS announcing message. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_announcing_send(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; -NX_PACKET *packet_ptr; -NX_PACKET *new_packet_ptr; -ULONG *head; -NX_MDNS_RR *p; -USHORT question_count = 0; -USHORT answer_count = 0; -USHORT authority_count = 0; -USHORT additional_count = 0; -UINT i; -UCHAR resend_flag = NX_FALSE; - - - /* Create the mdns packet and add the mDNS header. */ - status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_FALSE); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - return; - } - - /* Set the head pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - /* Add the answer resource record. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - if(p -> nx_mdns_rr_send_flag == 0) - continue; - - /* Check valid state. */ - if(!(((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID)))) - continue; - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); - - if (status) - { - resend_flag = NX_TRUE; - } - else - { - - /* Update the retransmit count. */ - p -> nx_mdns_rr_retransmit_count --; - - /* Update the count. */ - answer_count++; - - /* Clear the flag. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - - if (!question_count && - !answer_count && - !authority_count && - !additional_count) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Update the question count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); - - /* Update the answer count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); - - /* If the interval time is 0, repeat advertise. */ - if (!mdns_ptr -> nx_mdns_announcing_retrans_interval) - { - for (i = 1; i < mdns_ptr -> nx_mdns_announcing_count; i ++) - { - - /* Allocate new packet. */ - status = nx_packet_copy(packet_ptr, &new_packet_ptr, mdns_ptr -> nx_mdns_packet_pool_ptr, NX_NO_WAIT); - - /* Check for errors. */ - if (status) - { - break; - } - - /* Send the mDNS packet. */ - _nx_mdns_packet_send(mdns_ptr, new_packet_ptr, interface_index); - } - } - - /* Send the mDNS packet. */ - _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); - - /* Resend the packet. */ - if (resend_flag) - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_ANNOUNCING_SEND_EVENT, TX_OR); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends mDNS response. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* none */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_response_send(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; -NX_PACKET *packet_ptr; -ULONG *head; -NX_MDNS_RR *p; -USHORT question_count = 0; -USHORT answer_count = 0; -USHORT authority_count = 0; -USHORT additional_count = 0; -UCHAR resend_flag = NX_FALSE; - - - /* Create the mdns packet and add the mDNS header. */ - status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_FALSE); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - return; - } - - /* Set the head pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - /* Add the answer resource record. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - if(p -> nx_mdns_rr_send_flag == 0) - continue; - - /* Check valid state. */ - if ((p -> nx_mdns_rr_timer_count != 0) || - !((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID))) - continue; - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); - - if (status) - { - resend_flag = NX_TRUE; - } - else - { - - /* Set the answer flag to skip the resource record which has been added in answer section when find the additional records. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ANSWER; - - /* When including a DNS-SD Service Instance Enumeration or Selective Instance Enumeration PTR record in a response packet, - the server/responder SHOULD include the folowing additional records, SRV,TXT, A and AAAA.RFC3763, Section12.1, Page30. */ - _nx_mdns_additional_resource_record_find(mdns_ptr, p); - - /* Update the count. */ - answer_count++; - - /* Clear the flag. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - - /* Add the additional answer resource record. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether set the resource record send flag. */ - if ((p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ADDITIONAL) && - ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING))) - { - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_RESPONSE); - if (status) - { - resend_flag = NX_TRUE; - } - else - { - - /* Update the additional count. */ - additional_count++; - - /* Clear the additional flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ADDITIONAL)); - } - } - - /* Clear the answer flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); - } - - if (!question_count && - !answer_count && - !authority_count && - !additional_count) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Update the question count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); - - /* Update the answer count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); - - /* Send the mDNS packet. */ - _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); - - /* Resend the packet. */ - if (resend_flag) - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_RESPONSE_SEND_EVENT, TX_OR); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_query_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends mDNS query message. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* none */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_query_send(NX_MDNS *mdns_ptr, UINT interface_index) -{ - -UINT status; -NX_PACKET *packet_ptr; -ULONG *head; -NX_MDNS_RR *p; -USHORT question_count = 0; -USHORT answer_count = 0; -USHORT authority_count = 0; -USHORT additional_count = 0; -UCHAR resend_flag = NX_FALSE; -USHORT tc_bit; -UCHAR more_known_answer = NX_FALSE; -UINT i; - - - /* Create the mdns packet and add the mDNS header. */ - status = _nx_mdns_packet_create(mdns_ptr, &packet_ptr, NX_TRUE); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - return; - } - - /* Set the head pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - - /* Add the query resource record. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - if(p -> nx_mdns_rr_send_flag == 0) - continue; - - /* Check valid state. */ - if(!(((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING)))) - continue; - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_QUESTION, NX_MDNS_PACKET_QUERY); - - if (status) - { - resend_flag = NX_TRUE; - } - else - { - - /* Update the retransmit count for UPDATING state. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_UPDATING) - p -> nx_mdns_rr_retransmit_count --; - - /* Update the count. */ - question_count++; - - /* Find the known answer resource records. */ - _nx_mdns_known_answer_find(mdns_ptr, p); - - /* Clear the flag. */ - p -> nx_mdns_rr_send_flag = NX_MDNS_RR_SEND_FLAG_CLEAR; - } - } - - /* Add the known answer resource record. */ - for (i = 0; i < 2; i++) - { - if (i == 0) - { -#ifndef NX_MDNS_DISABLE_SERVER - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - } - - /* Add the peer resource code as known answer for query. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check whether set the resource record send flag. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) && - (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_KNOWN_ANSWER)) - { - - /* Add the resource record into packet. */ - status = _nx_mdns_packet_rr_add(packet_ptr, p, NX_MDNS_PACKET_ADD_RR_ANSWER, NX_MDNS_PACKET_QUERY); - if (status) - { - more_known_answer = NX_TRUE; - resend_flag = NX_TRUE; - } - else - { - /* Update the count. */ - answer_count ++; - - /* Clear the additional flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_KNOWN_ANSWER)); - } - } - - /* Clear the answer flag. */ - p -> nx_mdns_rr_word = (USHORT)(p -> nx_mdns_rr_word & (~NX_MDNS_RR_FLAG_ANSWER)); - } - } - - if (!question_count && - !answer_count && - !authority_count && - !additional_count) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Set the TC bit. */ - if (more_known_answer) - { - tc_bit = NX_MDNS_TC_FLAG; - *(USHORT *)(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET) |= NX_CHANGE_USHORT_ENDIAN(tc_bit); - } - - /* Update the question count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET, question_count); - - /* Update the answer count in header. */ - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ANCOUNT_OFFSET, answer_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET, authority_count); - _nx_mdns_short_to_network_convert(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_ARCOUNT_OFFSET, additional_count); - - /* Send the mDNS packet. */ - _nx_mdns_packet_send(mdns_ptr, packet_ptr, interface_index); - - /* Resend the packet. */ - if (resend_flag) - tx_event_flags_set(&(mdns_ptr -> nx_mdns_events), NX_MDNS_QUERY_SEND_EVENT, TX_OR); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the mDNS packet and add the mDNS header data. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* packet_ptr Pointer to mDNS packet */ -/* is_query Query flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate the mDNS packet */ -/* nx_packet_release Release the mDNS packet */ -/* _nx_mdns_short_to_network_convert Add the data into the packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_announcing_send Send announcing message */ -/* _nx_mdns_probing_send Send probing message */ -/* _nx_mdns_query_send Send query message */ -/* _nx_mdns_response_send Send response message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_create(NX_MDNS *mdns_ptr, NX_PACKET **packet_ptr, UCHAR is_query) -{ - -UINT status; -USHORT flags; - - - /* Allocate the mDNS packet. */ -#ifdef NX_MDNS_ENABLE_IPV6 - status = nx_packet_allocate(mdns_ptr -> nx_mdns_packet_pool_ptr, packet_ptr, NX_IPv6_UDP_PACKET, NX_NO_WAIT); -#else - status = nx_packet_allocate(mdns_ptr -> nx_mdns_packet_pool_ptr, packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); -#endif /* NX_MDNS_ENABLE_IPV6 */ - - /* Check for errors. */ - if (status) - { - - /* Return error. */ - return(status); - } - - /* Check if there is enough room to fill with mDNS header. */ - if ((UINT)((*packet_ptr) -> nx_packet_data_end - (*packet_ptr) -> nx_packet_append_ptr) < NX_MDNS_QDSECT_OFFSET) - { - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - return(NX_MDNS_PACKET_ERROR); - } - - /* Add the mDNS header. */ - - /* Set the transaction ID. */ - *(USHORT *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_ID_OFFSET) = 0; - - /* Set the flags and Command. */ - if (is_query == NX_TRUE) - { - flags = NX_MDNS_QUERY_FLAG; - } - else - { - flags = (NX_MDNS_RESPONSE_FLAG | NX_MDNS_AA_FLAG); - } - - /* Adjust for endianness. */ - NX_CHANGE_USHORT_ENDIAN(flags); - - /* Set the flags and Command. */ - *(USHORT *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET) = flags; - - /* Initialize counts to 0. */ - *(ULONG *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_QDCOUNT_OFFSET) = 0; - *(ULONG *)((*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_NSCOUNT_OFFSET) = 0; - - /* Set the pointer. */ - (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + NX_MDNS_QDSECT_OFFSET; - (*packet_ptr) -> nx_packet_length = NX_MDNS_QDSECT_OFFSET; - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the mDNS packet. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* packet_ptr Pointer to mDNS packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy Copy the mDNS packet */ -/* nx_packet_release Release the mDNS packet */ -/* nx_udp_socket_send Send the udp packet */ -/* nxd_udp_socket_send Send the udp packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_announcing_send Send announcing message */ -/* _nx_mdns_probing_send Send probing message */ -/* _nx_mdns_query_send Send query message */ -/* _nx_mdns_response_send Send response message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_packet_send(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UINT interface_index) -{ - -#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 -UINT status; -#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ -#ifdef NX_MDNS_ENABLE_IPV6 -UINT ipv6_packet = NX_FALSE; -NX_PACKET *new_packet_ptr; -UINT address_index = mdns_ptr -> nx_mdns_ipv6_address_index[interface_index]; -#endif /* NX_MDNS_ENABLE_IPV6 */ - - -#if defined NX_DISABLE_IPV4 && !defined NX_MDNS_ENABLE_IPV6 - NX_PARAMETER_NOT_USED(mdns_ptr); - NX_PARAMETER_NOT_USED(interface_index); -#endif /* NX_DISABLE_IPV4 && ! NX_MDNS_ENABLE_IPV6 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - if (address_index != 0xFFFFFFFF) - { - - /* Allocate new IPv6 packet. */ - status = nx_packet_copy(packet_ptr, &new_packet_ptr, mdns_ptr -> nx_mdns_packet_pool_ptr, NX_NO_WAIT); - - /* Check for errors. */ - if (!status) - { - ipv6_packet = NX_TRUE; - } - } -#endif /* NX_MDNS_ENABLE_IPV6 */ - -#ifndef NX_DISABLE_IPV4 - /* Send the IPv4 mDNS message. */ - status = nx_udp_socket_source_send(&mdns_ptr -> nx_mdns_socket, packet_ptr, NX_MDNS_IPV4_MULTICAST_ADDRESS, NX_MDNS_UDP_PORT, interface_index); - - /* If an error is detected, the packet was not sent and we have to release the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } -#else - - /* Release the packet. */ - nx_packet_release(packet_ptr); -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - - /* Check if send IPv6 packet. */ - if (ipv6_packet == NX_TRUE) - { - - /* Send the IPv6 mDNS message. */ - status = nxd_udp_socket_source_send(&mdns_ptr -> nx_mdns_socket, new_packet_ptr, &NX_MDNS_IPV6_MULTICAST_ADDRESS, NX_MDNS_UDP_PORT, address_index); - - /* If an error is detected, the packet was not sent and we have to release the packet. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - } - } -#endif /* NX_MDNS_ENABLE_IPV6 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_rr_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into the packet. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* packet_ptr Pointer to mDNS packet */ -/* rr Pointer to mDNS record */ -/* op RR adding Operation */ -/* packet_type Packet type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_name_string_encode Encode the name string */ -/* _nx_mdns_short_to_network_convert Convert and add the data */ -/* _nx_mdns_txt_string_encode Encode the txt string */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_announcing_send Send announcing message */ -/* _nx_mdns_probing_send Send probing message */ -/* _nx_mdns_query_send Send query message */ -/* _nx_mdns_response_send Send response message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_rr_add(NX_PACKET *packet_ptr, NX_MDNS_RR *rr, UINT op, UINT packet_type) -{ - -USHORT size = 0; -USHORT index = 0; -USHORT rr_size = 0; -USHORT rdata_length_index = 0; -UCHAR *data_ptr = packet_ptr -> nx_packet_append_ptr; -UINT rr_name_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)rr -> nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) - { - return (NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check whether set the resource record send flag. */ - if(op == NX_MDNS_PACKET_ADD_RR_QUESTION) - { - - /* The name size is should add the '.' and '\0', Calcuate the resource record size. QNAME, QTYPE, QCLASS. */ - rr_size = (USHORT)(rr_name_length + 2 + 4); - - if ((data_ptr + rr_size) > packet_ptr -> nx_packet_data_end) - { - return(NX_MDNS_PACKET_ERROR); - } - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr, rr -> nx_mdns_rr_name); - - /* Updat the index. */ - index = (USHORT)(index + size); - - /* Add the type. */ - if(packet_type == NX_MDNS_PACKET_PROBING) - { - _nx_mdns_short_to_network_convert(data_ptr + index, NX_MDNS_RR_TYPE_ALL); - } - else - { - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_type); - } - index = (USHORT)(index + 2); - - /* Add the class. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_class); - index = (USHORT)(index + 2); - } - - /* Check whether set the resource record send flag. */ - else - { - - /* Calcuate the resource record size. NAME, TYPE, CLASS, TTL, RDLENGTH, RDATA. */ - rr_size = (USHORT)(rr_name_length + 2 + 10 + rr -> nx_mdns_rr_rdata_length); - - if ((data_ptr + rr_size) > packet_ptr -> nx_packet_data_end) - { - return(NX_MDNS_PACKET_ERROR); - } - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_name); - - /* Updat the index. */ - index = (USHORT)(index + size); - - /* Add the type and class. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_type); - index = (USHORT)(index + 2); - - /* Add the class. */ - if ((!(rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER)) && - (rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE)) - { - _nx_mdns_short_to_network_convert(data_ptr + index, ((rr -> nx_mdns_rr_class) | NX_MDNS_RR_CLASS_TOP_BIT)); - } - else - { - - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_class); - } - index = (USHORT)(index + 2); - - /* Add the ttl. */ - /* Check the resource record owner. */ - if (rr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_PEER) - { - /* Add the remaining ttl of peer resource reocrd. */ - _nx_mdns_long_to_network_convert(data_ptr + index, (rr -> nx_mdns_rr_remaining_ticks / NX_IP_PERIODIC_RATE)); - } - else - { - if (rr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_GOODBYE) - { - _nx_mdns_long_to_network_convert(data_ptr + index, 0); - } - else - { - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_ttl); - } - } - index = (USHORT)(index + 4); - - /* Compare the RDATA. */ - switch (rr -> nx_mdns_rr_type) - { - - case NX_MDNS_RR_TYPE_A: - { - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + index, 4); - index = (USHORT)(index + 2); - - /* Add the rdata. */ - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address); - index = (USHORT)(index + 4); - - break; - } - case NX_MDNS_RR_TYPE_AAAA: - { - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + index, 16); - index = (USHORT)(index + 2); - - /* Add the rdata. */ - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0]); - index = (USHORT)(index + 4); - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1]); - index = (USHORT)(index + 4); - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2]); - index = (USHORT)(index + 4); - _nx_mdns_long_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3]); - index = (USHORT)(index + 4); - - break; - } - case NX_MDNS_RR_TYPE_PTR: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name); - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); - - break; - } - case NX_MDNS_RR_TYPE_SRV: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Add the prority. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority); - index = (USHORT)(index + 2); - - /* Add the weights. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights); - index = (USHORT)(index + 2); - - /* Add the port. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port); - index = (USHORT)(index + 2); - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target); - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 6)); - - break; - } - case NX_MDNS_RR_TYPE_TXT: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - if (rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data) - { - - /* Encode and add the text. */ - size = (USHORT)_nx_mdns_txt_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data); - } - else - { - - /* Encode the null. */ - *(data_ptr + index) = 0; - size = 1; - } - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); - - break; - } - -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - case NX_MDNS_RR_TYPE_CNAME: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_cname.nx_mdns_rr_cname_name); - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); - - break; - } - case NX_MDNS_RR_TYPE_NS: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ns.nx_mdns_rr_ns_name); - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, size); - - break; - } - case NX_MDNS_RR_TYPE_MX: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Add the preference. */ - _nx_mdns_short_to_network_convert(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference); - index = (USHORT)(index + 2); - - /* Encode and add the name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name); - index = (USHORT)(index + size); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 2)); - - break; - } -#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - case NX_MDNS_RR_TYPE_NSEC: - { - - /* Record the rdata length index then skip the rdata length. */ - rdata_length_index = index; - index = (USHORT)(index + 2); - - /* Encode and add the next domain name. */ - size = (USHORT)_nx_mdns_name_string_encode(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain); - index = (USHORT)(index + size); - - /* Add the window block. */ - *(data_ptr + index) = rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block; - index++; - - /* Add the bitmap length. */ - *(data_ptr + index) = rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length; - index++; - - /* Add the type bit maps. */ - memcpy(data_ptr + index, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap, rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length); - index = (USHORT)(index + rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length); - - /* Add the rdata length. */ - _nx_mdns_short_to_network_convert(data_ptr + rdata_length_index, (USHORT)(size + 2 + rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length)); - - break; - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - } - } - - /* Update the append pointer and packet length. */ - packet_ptr -> nx_packet_append_ptr += index; - packet_ptr -> nx_packet_length += index; - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_rr_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the resource record info from packet. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance. */ -/* packet_ptr Pointer to the packet. */ -/* data_ptr Pointer to the data. */ -/* rr_ptr Pointer to the record */ -/* op Operation: */ -/* set question or set answer. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_name_string_decode Decode the name string */ -/* _nx_mdns_cache_add_string Add the name string */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_rr_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op, UINT interface_index) -{ - -UCHAR *cache_ptr; -UINT cache_size; -UINT cache_type; -USHORT record_class; -UINT status; -UINT temp_string_length; - - - /* Initialize. */ - memset(rr_ptr, 0, sizeof(NX_MDNS_RR)); - - /* Get cache type and size. */ - if ((op == NX_MDNS_RR_OP_LOCAL_SET_QUESTION) || - (op == NX_MDNS_RR_OP_LOCAL_SET_ANSWER)) - { - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; - cache_type = NX_MDNS_CACHE_TYPE_LOCAL; - } - else - { - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; - cache_type = NX_MDNS_CACHE_TYPE_PEER; - } - - /* Check cache pointer and cache size. */ - if ((cache_ptr == NX_NULL) || (cache_size == 0)) - { - return(NX_MDNS_ERROR); - } - - /* Set the interface. */ - rr_ptr -> nx_mdns_rr_interface_index = interface_index; - - /* Process the name string. */ - if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, - (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), - temp_string_buffer, NX_MDNS_NAME_MAX)) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the string . */ - if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, - (VOID **)(&rr_ptr -> nx_mdns_rr_name), NX_TRUE, NX_TRUE) != NX_MDNS_SUCCESS) - { - return(NX_MDNS_ERROR); - } - } - else - { - return(NX_MDNS_ERROR); - } - - /* Set the resource record type. */ - rr_ptr -> nx_mdns_rr_type = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr)); - - /* Get the resource record class.*/ - record_class = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 2); - - /* Remote RR, set the RR owner flag.*/ - if (cache_type == NX_MDNS_CACHE_TYPE_PEER) - rr_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_PEER; - - /* Unique RR, Set the RR set flag. */ - if (record_class & (~NX_MDNS_TOP_BIT_MASK)) - { - rr_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UNIQUE; - } - - /* Check the operation and update the record class. */ - if((op == NX_MDNS_RR_OP_LOCAL_SET_QUESTION) || (op == NX_MDNS_RR_OP_PEER_SET_QUESTION)) - { - rr_ptr -> nx_mdns_rr_class = record_class; - return(NX_MDNS_SUCCESS); - } - else - { - rr_ptr -> nx_mdns_rr_class = record_class & NX_MDNS_TOP_BIT_MASK; - } - - /* Set the rdata information for answer record. */ - status = _nx_mdns_packet_rr_data_set(mdns_ptr, packet_ptr, data_ptr, rr_ptr, op); - - /* Return success. */ - return (status); -} - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_rr_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the resource record of packet, and add the */ -/* record into peer cache. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance. */ -/* packet_ptr Pointer to the packet. */ -/* data_ptr Pointer to the data. */ -/* insert_ptr Pointer to the insert record */ -/* op Operation: add answer, set */ -/* question or set answer. */ -/* cache_ptr The record buffer. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_name_string_decode Decode the name string */ -/* _nx_mdns_cache_add_string Add the name string */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_rr_process(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, UINT interface_index) -{ - -UINT status; -USHORT record_class; -UCHAR is_present; -NX_MDNS_RR rr_ptr; -NX_MDNS_RR *insert_ptr; -NX_MDNS_RR *p; -ULONG *head; -UCHAR *service_name,*service_type,*service_domain; -UINT temp_string_length; -UINT rr_name_length; - - - /* Check the peer cache. */ - if ((mdns_ptr -> nx_mdns_peer_service_cache == NX_NULL) || - (mdns_ptr -> nx_mdns_peer_service_cache_size == 0)) - { - return(NX_MDNS_ERROR); - } - - /* Initialize. */ - memset(&rr_ptr, 0, sizeof(NX_MDNS_RR)); - - /* Process the name string. */ - if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, - (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), - temp_string_buffer, NX_MDNS_NAME_MAX)) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the string . */ - if(_nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, temp_string_buffer, temp_string_length, - (VOID **)(&rr_ptr.nx_mdns_rr_name), NX_FALSE, NX_TRUE)) - { - return(NX_MDNS_ERROR); - } - } - else - { - return(NX_MDNS_ERROR); - } - - /* Set the resource record type. */ - rr_ptr.nx_mdns_rr_type = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr)); - - /* Get the resource record class.*/ - record_class = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 2); - - /* Set the resource record class. */ - rr_ptr.nx_mdns_rr_class = record_class & NX_MDNS_TOP_BIT_MASK; - - /* Remote RR, set the RR owner flag.*/ - rr_ptr.nx_mdns_rr_word |= NX_MDNS_RR_FLAG_PEER; - - /* Unique RR, Set the RR set flag. */ - if (record_class & (~NX_MDNS_TOP_BIT_MASK)) - { - rr_ptr.nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UNIQUE; - } - - /* Set the interface index. */ - rr_ptr.nx_mdns_rr_interface_index = interface_index; - - /* Set the rdata information for answer record. */ - status = _nx_mdns_packet_rr_data_set(mdns_ptr, packet_ptr, data_ptr, &rr_ptr, NX_MDNS_RR_OP_PEER_ADD_ANSWER); - - /* Check status. */ - if(status) - { - - /* Delete the name strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, rr_ptr.nx_mdns_rr_name, 0); - return (NX_MDNS_ERROR); - } - - /* Check if need to ignore this source reocrd. */ - if ((mdns_ptr -> nx_mdns_service_ignore_mask) && - ((rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || - (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || - (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR))) - { - - /* Get the service. */ - if (rr_ptr.nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)rr_ptr.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, &rr_name_length, NX_MDNS_NAME_MAX)) - { - _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); - return(NX_MDNS_DATA_SIZE_ERROR); - } - memcpy((CHAR *)temp_string_buffer, (const char *)rr_ptr.nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name, rr_name_length + 1); - } - else - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)rr_ptr.nx_mdns_rr_name, &rr_name_length, NX_MDNS_NAME_MAX)) - { - _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); - return(NX_MDNS_DATA_SIZE_ERROR); - } - memcpy((CHAR *)temp_string_buffer, (const char *)rr_ptr.nx_mdns_rr_name, rr_name_length + 1); - } - - /* Resolve the service type. */ - if (_nx_mdns_service_name_resolve(temp_string_buffer, &service_name, &service_type, &service_domain)) - { - _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); - return (status); - } - - /* Check if this service type should be ignored. */ - if (_nx_mdns_service_mask_match(mdns_ptr, service_type, mdns_ptr -> nx_mdns_service_ignore_mask) == NX_MDNS_SUCCESS) - { - _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); - return (NX_MDNS_ERROR); - } - } - - /* Add the resource record into remote buffer. */ - if (_nx_mdns_cache_add_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr, &insert_ptr, &is_present)) - { - - /* Delete the name strings. */ - _nx_mdns_cache_delete_rr_string(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, &rr_ptr); - return (NX_MDNS_ERROR); - } - - /* Check the ttl. */ - if (insert_ptr -> nx_mdns_rr_ttl) - { - - /* Step1. Process answer record. */ - /* Update the state. */ - insert_ptr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_VALID; - - /* Update the timer count. The querier should not include records in the Known-Answer list whose remaining TTL is less than half of their original TTL. */ - insert_ptr -> nx_mdns_rr_timer_count = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * 50 / 100; - - /* Record the remaining ticks of resource record. */ - if (insert_ptr -> nx_mdns_rr_ttl >= NX_MDNS_RR_MAX_TTL) - { - /* If the ttl of resource resource record is outside the range, set as 0xFFFFFFFF. */ - insert_ptr -> nx_mdns_rr_remaining_ticks = 0xFFFFFFFF; - } - else - { - /* Convert units(seconds to ticks). */ - insert_ptr -> nx_mdns_rr_remaining_ticks = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE; - } - - /* Step2. Process query record. */ - /* Set the pointer. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - head = (ULONG*)(*head); - - /* Check the remote resource record state. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the state. */ - if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != insert_ptr -> nx_mdns_rr_interface_index) - continue; - - /* Check the name. */ - if (p -> nx_mdns_rr_name != insert_ptr -> nx_mdns_rr_name) - continue; - - /* Check the type. */ - if ((p -> nx_mdns_rr_type != insert_ptr -> nx_mdns_rr_type) && - (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL)) - continue; - - /* Check the class. */ - if (p -> nx_mdns_rr_class != insert_ptr -> nx_mdns_rr_class) - continue; - - /* Check the query type. */ - if (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_CONTINUOUS_QUERY)) - { - - /* Determine if we need to wake a thread suspended. */ - if (mdns_ptr -> nx_mdns_rr_receive_suspension_list) - { - - /* Resume suspended thread. */ - _nx_mdns_query_thread_resume(&(mdns_ptr -> nx_mdns_rr_receive_suspension_list), mdns_ptr, insert_ptr); - } - - /* Get the answer, we need not send the question again. Delete the resource record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_PEER, p); - - } - else - { - - /* There is no need for the querier to continue issuing a stream of queries when a mDNS response - is received containing a unique answer. mDNS querier should send the next query at 80%-82% of the - record's TTL. RFC6762, Section5.2,Page11. */ - if ((insert_ptr -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) && (insert_ptr -> nx_mdns_rr_ttl)) - { - - /* Set the timer count. */ - p -> nx_mdns_rr_timer_count = insert_ptr -> nx_mdns_rr_ttl * NX_IP_PERIODIC_RATE * (ULONG)(80 + (NX_RAND() % 3)) / 100; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } - - /* Set the updating flag to update the resource record at 80% of the record's TTL. */ - insert_ptr -> nx_mdns_rr_word |= NX_MDNS_RR_FLAG_UPDATING; - } - } - } - else - { - - /* Update the state to delete this record from peer cache. . */ - insert_ptr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_DELETE; - - /* Delete the resource record one second later. */ - insert_ptr -> nx_mdns_rr_timer_count = NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT; - } - - /* Set the mDNS timer for insert RR. */ - _nx_mdns_timer_set(mdns_ptr, insert_ptr, insert_ptr -> nx_mdns_rr_timer_count); - - /* Service name registered success, invoke the notify function. */ - if (mdns_ptr -> nx_mdns_service_change_notify) - { - - /* Process the service notify function. */ - _nx_mdns_service_change_notify_process(mdns_ptr, insert_ptr, is_present); - } - - /* Return success. */ - return (NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_rr_data_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the packet, and sets the data of */ -/* resource record. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance. */ -/* packet_ptr Pointer to the packet. */ -/* data_ptr Pointer to the data. */ -/* rr_ptr Pointer to the record */ -/* op Operation: */ -/* set answer in local cache. */ -/* or add answer in peer cache.*/ -/* cache_ptr The record buffer. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_name_string_decode Decode the name string */ -/* _nx_mdns_cache_add_string Add the name string */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_rr_data_set(NX_MDNS *mdns_ptr, NX_PACKET *packet_ptr, UCHAR *data_ptr, NX_MDNS_RR *rr_ptr, UINT op) -{ - -UCHAR *string_search = NX_NULL; -UINT cache_type; -UCHAR find_string; -UCHAR continue_process = NX_FALSE; -UINT status = NX_MDNS_UNSUPPORTED_TYPE; -UINT temp_string_length; - - - /* Get cache type and size. */ - if (op == NX_MDNS_RR_OP_LOCAL_SET_ANSWER) - { - cache_type = NX_MDNS_CACHE_TYPE_LOCAL; - find_string = NX_TRUE; - } - else - { - cache_type = NX_MDNS_CACHE_TYPE_PEER; - find_string = NX_FALSE; - } - - /* Set the resource record time to live.*/ - rr_ptr -> nx_mdns_rr_ttl = NX_MDNS_GET_ULONG_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 4); - - /* Set the resource record rdata length. */ - rr_ptr -> nx_mdns_rr_rdata_length = NX_MDNS_GET_USHORT_DATA(data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 8);; - - /* Update the pointer to point at the resource data. */ - data_ptr = data_ptr + _nx_mdns_name_size_calculate(data_ptr) + 10; - - /* Check the type. */ - switch (rr_ptr -> nx_mdns_rr_type) - { - case NX_MDNS_RR_TYPE_A: - { - - /* Get the rdata. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address = NX_MDNS_GET_ULONG_DATA(data_ptr); - rr_ptr -> nx_mdns_rr_rdata_length = 4; - - /* Update the status. */ - status = NX_MDNS_SUCCESS; - break; - } - case NX_MDNS_RR_TYPE_AAAA: - { - - /* Get the rdata. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0] = NX_MDNS_GET_ULONG_DATA(data_ptr); - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1] = NX_MDNS_GET_ULONG_DATA(data_ptr + 4); - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2] = NX_MDNS_GET_ULONG_DATA(data_ptr + 8); - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3] = NX_MDNS_GET_ULONG_DATA(data_ptr + 12); - rr_ptr -> nx_mdns_rr_rdata_length = 16; - - /* Update the status. */ - status = NX_MDNS_SUCCESS; - break; - } - case NX_MDNS_RR_TYPE_TXT: - { - - /* Process the txt string. An empty TXT record contaning zero strings is not allowed. RFC6763, Page12. */ - if (rr_ptr -> nx_mdns_rr_rdata_length == 1) - { - - /* Update the status. */ - status = NX_MDNS_SUCCESS; - } - else if (rr_ptr -> nx_mdns_rr_rdata_length > 1) - { - - /* Add the txt string. */ - if (_nx_mdns_txt_string_decode(data_ptr, rr_ptr -> nx_mdns_rr_rdata_length, temp_string_buffer, NX_MDNS_NAME_MAX) == NX_MDNS_SUCCESS) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Find the same string . */ - if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, - (VOID **)&string_search, find_string, NX_TRUE) == NX_MDNS_SUCCESS) - { - - /* Update the name pointer. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data = string_search; - - /* Calculate the text string.inlcude the one byte label. */ - rr_ptr -> nx_mdns_rr_rdata_length = (USHORT)(temp_string_length + 1); - - /* Update the status. */ - status = NX_MDNS_SUCCESS; - } - } - } - - break; - } - case NX_MDNS_RR_TYPE_SRV: - { - - /* Get the priority. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority = NX_MDNS_GET_USHORT_DATA(data_ptr); - data_ptr += 2; - - /* Get the weights. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights = NX_MDNS_GET_USHORT_DATA(data_ptr); - data_ptr += 2; - - /* Get the port. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port = NX_MDNS_GET_USHORT_DATA(data_ptr); - data_ptr += 2; - - /* Update the rdata length. */ - rr_ptr -> nx_mdns_rr_rdata_length = 6; - - /* Continue to process target name. */ - continue_process = NX_TRUE; - break; - } - case NX_MDNS_RR_TYPE_PTR: -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - case NX_MDNS_RR_TYPE_CNAME: - case NX_MDNS_RR_TYPE_NS: -#endif - { - - /* Update the rdata length. */ - rr_ptr -> nx_mdns_rr_rdata_length = 0; - - /* Continue to process the domain name. */ - continue_process = NX_TRUE; - break; - } -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - case NX_MDNS_RR_TYPE_MX: - { - - /* Set the preference. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference = NX_MDNS_GET_USHORT_DATA(data_ptr); - data_ptr += 2; - - /* Update the rdata length. */ - rr_ptr -> nx_mdns_rr_rdata_length = 2; - - /* Continue to process the domain name. */ - continue_process = NX_TRUE; - break; - } -#endif - } - - /* Check if need to continue process rdata. */ - if(continue_process == NX_TRUE) - { - - /* Process the target/domain name string. */ - if (_nx_mdns_name_string_decode(packet_ptr -> nx_packet_prepend_ptr, - (UINT)(data_ptr - packet_ptr -> nx_packet_prepend_ptr), - temp_string_buffer, NX_MDNS_NAME_MAX)) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the string. */ - if(_nx_mdns_cache_add_string(mdns_ptr, cache_type, temp_string_buffer, temp_string_length, - (VOID **)&string_search, find_string, NX_TRUE) == NX_MDNS_SUCCESS) - { - - /* Update the name pointer for SRV, PTR, etc. */ - rr_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target = string_search; - - /* Calculate the text string. Inlcude the one byte label '.' and null '\0'. */ - rr_ptr -> nx_mdns_rr_rdata_length = (USHORT)(rr_ptr -> nx_mdns_rr_rdata_length + (temp_string_length + 2)); - - /* Update the status. */ - status = NX_MDNS_SUCCESS; - } - } - } - - /* Return success. */ - return (status); -} - - -#ifdef NX_MDNS_ENABLE_ADDRESS_CHECK -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_packet_address_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks the IP address and port of received packet. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to mDNS packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_packet_address_check(NX_PACKET *packet_ptr) -{ - -USHORT mdns_flags; -UINT src_port; -ULONG *udp_header; - -#if !defined NX_DISABLE_IPV4 || defined NX_MDNS_ENABLE_IPV6 -NXD_ADDRESS src_address; -NXD_ADDRESS des_address; -#endif /* !NX_DISABLE_IPV4 || NX_MDNS_ENABLE_IPV6 */ - -#ifndef NX_DISABLE_IPV4 -NX_IPV4_HEADER *ipv4_header; -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 -NX_IPV6_HEADER *ipv6_header; -#endif /* NX_MDNS_ENABLE_IPV6 */ - - - /* Extract the message type which should be the first byte. */ - mdns_flags = NX_MDNS_GET_USHORT_DATA(packet_ptr -> nx_packet_prepend_ptr + NX_MDNS_FLAGS_OFFSET); - -#ifndef NX_DISABLE_IPV4 - /* Get the ip address. */ - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4) - { - - /* Set the IPv4 header. */ - ipv4_header = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_ip_header; - - /* Set the source address. */ - src_address.nxd_ip_version = NX_IP_VERSION_V4; - src_address.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_source_ip; - - /* Set the destination address. */ - des_address.nxd_ip_version = NX_IP_VERSION_V4; - des_address.nxd_ip_address.v4 = ipv4_header -> nx_ip_header_destination_ip; - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - if(packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6) - { - - /* Set the IPv6 header. */ - ipv6_header = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header; - - /* Set the source address. */ - src_address.nxd_ip_version = NX_IP_VERSION_V6; - COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_source_ip, src_address.nxd_ip_address.v6); - - /* Set the destination address. */ - des_address.nxd_ip_version = NX_IP_VERSION_V6; - COPY_IPV6_ADDRESS(ipv6_header -> nx_ip_header_destination_ip, des_address.nxd_ip_address.v6); - } - else -#endif /* NX_MDNS_ENABLE_IPV6 */ - { - - /* Invalid IP version . */ - return(NX_MDNS_ERROR); - } - - /* Pickup the pointer to the head of the UDP packet. */ - udp_header = (ULONG *) (packet_ptr -> nx_packet_prepend_ptr - 8); - - /* Get the source port and destination port. */ - src_port = (UINT) ((*udp_header) >> NX_SHIFT_BY_16); - - /* Check the source UDP port. RFC6762, Section6, Page15. */ - if (src_port != NX_MDNS_UDP_PORT) - { - return(NX_MDNS_UDP_PORT_ERROR); - } - - /* Check the QR bit. */ - if ((mdns_flags & NX_MDNS_RESPONSE_FLAG) == NX_MDNS_RESPONSE_FLAG) - { - - /* Check the response code. */ - if (mdns_flags & NX_MDNS_ERROR_MASK) - { - - /* Release the source packet. */ - return(NX_MDNS_AUTH_ERROR); - } - - /* In response messages for Multicast domains, the AA bit Must be set to one, RFC6762, Page48. */ - if ((mdns_flags & NX_MDNS_AA_FLAG) != NX_MDNS_AA_FLAG) - { - return (NX_MDNS_ERROR); - } - -#ifndef NX_DISABLE_IPV4 - /* Check the interface and destination address. RFC6762, Section 11, Page38,39. */ - if (des_address.nxd_ip_version == NX_IP_VERSION_V4) - { - - /* Local link check, Multicast Address or (I & M) == (P & M). */ - if ((des_address.nxd_ip_address.v4 != NX_MDNS_IPV4_MULTICAST_ADDRESS) && - (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address & packet_ptr ->nx_packet_ip_interface -> nx_interface_ip_network_mask) != - (src_address.nxd_ip_address.v4 & packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) - { - return (NX_MDNS_NOT_LOCAL_LINK); - } - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - if(des_address.nxd_ip_version == NX_IP_VERSION_V6) - { - - /* Destination address is not FF02::FB address or source address not on link, RFC6762, Section 11, Page39. */ - /* Not check the source address. */ - if ((des_address.nxd_ip_address.v6[0] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0]) || - (des_address.nxd_ip_address.v6[1] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1]) || - (des_address.nxd_ip_address.v6[2] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2]) || - (des_address.nxd_ip_address.v6[3] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3])) - { - return (NX_MDNS_DEST_ADDRESS_ERROR); - } - } - else -#endif /* NX_MDNS_ENABLE_IPV6 */ - { - - /* Invalid IP version. */ - return(NX_MDNS_ERROR); - } - } - else - { - -#ifndef NX_DISABLE_IPV4 - /* Check the interface and destination address. RFC6762, Section 11, Page38,39. */ - if (des_address.nxd_ip_version == NX_IP_VERSION_V4) - { - if (des_address.nxd_ip_address.v4 != NX_MDNS_IPV4_MULTICAST_ADDRESS) - { - return (NX_MDNS_DEST_ADDRESS_ERROR); - } - } - else -#endif /* NX_DISABLE_IPV4 */ - -#ifdef NX_MDNS_ENABLE_IPV6 - if(des_address.nxd_ip_version == NX_IP_VERSION_V6) - { - if ((des_address.nxd_ip_address.v6[0] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[0]) || - (des_address.nxd_ip_address.v6[1] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[1]) || - (des_address.nxd_ip_address.v6[2] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[2]) || - (des_address.nxd_ip_address.v6[3] != NX_MDNS_IPV6_MULTICAST_ADDRESS.nxd_ip_address.v6[3])) - { - return (NX_MDNS_DEST_ADDRESS_ERROR); - } - } - else -#endif /* NX_MDNS_ENABLE_IPV6 */ - { - - /* Invalid IP version . */ - return(NX_MDNS_ERROR); - } - } - - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_ENABLE_ADDRESS_CHECK */ - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_address_change_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the address change event. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy Copy the mDNS packet */ -/* nx_packet_release Release the mDNS packet */ -/* nx_udp_socket_send Send the udp packet */ -/* nxd_udp_socket_send Send the udp packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_thread_entry Processing thread for mDNS */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_address_change_process(NX_MDNS *mdns_ptr) -{ - -ULONG *head; -NX_MDNS_RR *p; -UINT i; - - - /* Register the host name. */ - for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) - { - - /* Check if the interface is enabled. */ - if (!mdns_ptr -> nx_mdns_interface_enabled[i]) - continue; - - /* Get the local buffer head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - - if (head) - { - - /* Set the pointer. */ - head = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != i) - continue; - - /* If any of a host's IP addresses change, it MUST re-announce those address records. RFC6762, Section8.4, Page31. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) - { - - /* Send the "goodbye " announcement with RR TTL zero. RFC6762, Section8.4, Page31. */ - p -> nx_mdns_rr_state = NX_MDNS_RR_STATE_GOODBYE; - - /* Clear the retransmit count. */ - p -> nx_mdns_rr_retransmit_count = NX_MDNS_GOODBYE_RETRANSMIT_COUNT; - - /* Set the timer count. 250ms. */ - p -> nx_mdns_rr_timer_count = NX_MDNS_GOODBYE_TIMER_COUNT; - - /* Set the delete flag. */ - p -> nx_mdns_rr_word = (p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_DELETE); - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, p, p -> nx_mdns_rr_timer_count); - } - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) - _nx_mdns_cache_delete_resource_record(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, p); -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - } - } - - /* Second register the host name, the host does not need to repeat the Probing step, Only Announcing the A/AAAA. */ - _nx_mdns_host_name_register(mdns_ptr, NX_FALSE, i); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_conflict_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function process the mDNS conflict. RFC6762, Section9, Page31 */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_rr The resource record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_add_string Add the string */ -/* _nx_mdns_cache_delete_string Delete the string */ -/* _nx_mdns_srv_name_resolve Reslove the service name */ -/* nx_mdns_rr_change_notify Resource record notify */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_conflict_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_rr) -{ - -UINT status; -UCHAR *old_name; -UCHAR *name; -UCHAR *type = NX_NULL; -UCHAR *domain = NX_NULL; -UINT i; -ULONG *head; -NX_MDNS_RR *p; -UCHAR is_host_type; -UINT temp_string_length; -UINT rr_name_length; - - - /* Initialize the value. */ - i = 0; - memset(&temp_string_buffer[0], 0, NX_MDNS_NAME_MAX + 1); - memset(&target_string_buffer[0], 0, NX_MDNS_NAME_MAX + 1); - - /* Get rr type. */ - if((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT)) - { - is_host_type = NX_FALSE; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(record_rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Store the service name. */ - memcpy((CHAR *)&target_string_buffer[0], (const char*)(record_rr -> nx_mdns_rr_name), rr_name_length + 1); - - /* Get Name, Type, Domain. */ - _nx_mdns_service_name_resolve(&target_string_buffer[0], &name, &type, &domain); - } - else if((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA)) - { - is_host_type = NX_TRUE; - name = mdns_ptr -> nx_mdns_host_name; - } - else - { - - /* This is an unsupported or unknown type. */ - return(NX_MDNS_UNSUPPORTED_TYPE); - } - - /* Check the conflict count. */ - if (record_rr -> nx_mdns_rr_conflict_count >= NX_MDNS_CONFLICT_COUNT) - { - - /* Yes, Receive the confilictiong mDNS, Probing failure. */ - if ((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A)) - { - - /* Service name has been registered , invoke the notify function. */ - if (mdns_ptr -> nx_mdns_probing_notify) - { - (mdns_ptr -> nx_mdns_probing_notify)(mdns_ptr, name, NX_MDNS_LOCAL_SERVICE_REGISTERED_FAILURE); - } - } - - /* Return. */ - return (NX_MDNS_ERROR); - } - - /* Record the old name. */ - old_name = record_rr -> nx_mdns_rr_name; - - /* Set the new name and probing it. */ - while ((*name) != '\0') - { - temp_string_buffer[i++] = *name++; - } - - /* The first conflict, only add the " (2)". */ - if (record_rr -> nx_mdns_rr_conflict_count == 0) - { - temp_string_buffer[i++] = ' '; - temp_string_buffer[i++] = '('; - temp_string_buffer[i++] = '2'; - temp_string_buffer[i++] = ')'; - } - - /* Modify the count, eg: " (2)" change to " (3)". */ - else - { - temp_string_buffer[i-2] = (UCHAR)(temp_string_buffer[i-2] + 1); - } - - - if(is_host_type == NX_TRUE) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)temp_string_buffer, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Construct the target host. */ - memcpy((CHAR *)(mdns_ptr -> nx_mdns_host_name), (CHAR *)(temp_string_buffer), temp_string_length); - - temp_string_buffer[i++] = '.'; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)mdns_ptr -> nx_mdns_domain_name, &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the domain. */ - memcpy((CHAR *)(&temp_string_buffer[i]), (CHAR *)mdns_ptr -> nx_mdns_domain_name, temp_string_length); - } - else - { - temp_string_buffer[i++] = '.'; - - /* Set the Type. */ - while ((*type) != '\0') - { - temp_string_buffer[i++] = *type++; - } - - temp_string_buffer[i++] = '.'; - - /* Set the Domain. */ - while ((*domain) != '\0') - { - temp_string_buffer[i++] = *domain++; - } - } - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)&temp_string_buffer[0], &temp_string_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Add the new resource records. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, - &temp_string_buffer[0], temp_string_length, - (VOID **)(&record_rr -> nx_mdns_rr_name), NX_FALSE, NX_TRUE); - - if (status ) - { - - /* No, return error status. */ - return(status); - } - - /* Update the state. */ - record_rr -> nx_mdns_rr_state = NX_MDNS_RR_STATE_PROBING; - record_rr -> nx_mdns_rr_timer_count = mdns_ptr -> nx_mdns_first_probing_delay; - record_rr -> nx_mdns_rr_retransmit_count = NX_MDNS_PROBING_RETRANSMIT_COUNT; - record_rr -> nx_mdns_rr_conflict_count ++; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, record_rr, record_rr -> nx_mdns_rr_timer_count); - - /* Update the PTR/SRV data name. */ - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - if ((((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && (is_host_type == NX_FALSE)) || - ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && (is_host_type == NX_TRUE))) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == old_name)) - { - - /* Add the new resource records. */ - status = _nx_mdns_cache_add_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, &temp_string_buffer[0], temp_string_length, - (VOID **)(&(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name)), NX_FALSE, NX_TRUE); - - /* Delete the rdata name. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, old_name, 0); - } - } - - /* Delete the old name. */ - _nx_mdns_cache_delete_string(mdns_ptr, NX_MDNS_CACHE_TYPE_LOCAL, old_name, 0); - - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_change_notify_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the mDNS service change operation, when the */ -/* service information change, notify the application. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_rr The resource record */ -/* is_present The service type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_service_change_notify_process(NX_MDNS *mdns_ptr, NX_MDNS_RR *new_rr, UCHAR is_present) -{ - -UINT notify_status = 0; -ULONG *head; -NX_MDNS_RR *p; -NX_MDNS_SERVICE temp_service; -UINT rr_name_length; - - - /* Initialize the struct. */ - memset(&temp_service, 0, sizeof(NX_MDNS_SERVICE)); - - /* Compare the RDATA. */ - switch (new_rr -> nx_mdns_rr_type) - { - case NX_MDNS_RR_TYPE_A: - case NX_MDNS_RR_TYPE_AAAA: - { - - /* Get the remote buffer head. */ - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - head = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_peer_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check whether the resource record is valid. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) - continue; - - /* Check the interface. */ - if (p -> nx_mdns_rr_interface_index != new_rr -> nx_mdns_rr_interface_index) - continue; - - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - { - if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target == new_rr -> nx_mdns_rr_name) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - break; - } - - /* Store the Service name. */ - memcpy((CHAR *)(&temp_string_buffer[0]), (CHAR *)(p -> nx_mdns_rr_name), rr_name_length + 1); - - /* Check if the address is updated. */ - if (((is_present == NX_FALSE) && (new_rr -> nx_mdns_rr_ttl != 0)) || - (((is_present == NX_TRUE) && (new_rr -> nx_mdns_rr_ttl == 0)))) - { - notify_status = NX_MDNS_PEER_SERVICE_UPDATED; - } - break; - } - } - } - - break; - } - case NX_MDNS_RR_TYPE_SRV: - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(new_rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - break; - } - - /* Store the Service name. */ - memcpy((CHAR *)&temp_string_buffer[0], (CHAR *)(new_rr -> nx_mdns_rr_name), rr_name_length + 1); - - /* Check if the service is new. */ - if ((is_present == NX_FALSE) && (new_rr -> nx_mdns_rr_ttl != 0)) - { - notify_status = NX_MDNS_PEER_SERVICE_RECEIVED; - } - else if ((is_present == NX_TRUE) && (new_rr -> nx_mdns_rr_ttl == 0)) - { - notify_status = NX_MDNS_PEER_SERVICE_DELETED; - } - break; - } - default: - { - - /* This is an unsupported or unknown type. */ - return; - } - } - - /* Check if need to call then notify function. */ - if (notify_status == 0) - return; - - /* Store the service name. */ - memcpy((CHAR *)(&temp_service.buffer[0]), (CHAR *)(&temp_string_buffer[0]), rr_name_length); - - /* Reslove the service name. */ - if (_nx_mdns_service_name_resolve(&temp_service.buffer[0], &(temp_service.service_name), &(temp_service.service_type), &(temp_service.service_domain))) - return; - - /* Compare the service change type. */ - if (_nx_mdns_service_mask_match(mdns_ptr, temp_service.service_type, mdns_ptr -> nx_mdns_service_notify_mask)) - return; - - /* Get the additional information. */ - _nx_mdns_service_addition_info_get(mdns_ptr, &temp_string_buffer[0], &temp_service, new_rr -> nx_mdns_rr_interface_index); - - /* Call the notify function. */ - (mdns_ptr -> nx_mdns_service_change_notify)(mdns_ptr, &temp_service, notify_status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_addition_info_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into remote buffer, */ -/* mDNS thread send the query message using continuous type. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The service instance */ -/* type The service type */ -/* domain The domain name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* _nx_mdns_query_check Check the query RR */ -/* _nx_mdns_cache_add_string Add the string into buffer */ -/* _nx_mdns_cache_delete_string Delete the string from buffer */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* into buffer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_service_addition_info_get(NX_MDNS *mdns_ptr, UCHAR *srv_name, NX_MDNS_SERVICE *service, UINT interface_index) -{ - -UINT index = 0; -ULONG current_time; -ULONG *head, *tail; -UCHAR i; -NX_MDNS_RR *p; -NX_MDNS_RR *p1; -UINT srv_name_length; -UINT temp_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)srv_name, &srv_name_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_ERROR); - } - - /* Get the current time. */ - current_time = tx_time_get(); - - for(i = 0; i < 2; i++) - { - - /* Set the pointer. */ - if(i == NX_MDNS_CACHE_TYPE_LOCAL) - { -#ifndef NX_MDNS_DISABLE_SERVER - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_SERVER */ - } - else - { -#ifndef NX_MDNS_DISABLE_CLIENT - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; -#else - continue; -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - - if(head == NX_NULL) - continue; - - /* Set the pointer. */ - tail = (ULONG*)(*head); - - /* Check the resource record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p < tail; p++) - { - - /* Check whether the resource record is valid. */ - if ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Check the type and name. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, srv_name, srv_name_length))) - { - - /* Update the elasped timer. */ - p -> nx_mdns_rr_elapsed_time = current_time; - - /* Set the service priority, weight, port and target. */ - service -> service_priority = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority; - service -> service_weight = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights; - service -> service_port = p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port; - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), &temp_length, NX_MDNS_HOST_NAME_MAX)) - { - return(NX_MDNS_ERROR); - } - - /* Store the target host. */ - memcpy((CHAR *)(service -> service_host), - (CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target), - temp_length + 1); - - /* All address records (type "A" and "AAAA") named in the SRV rdata */ - for (p1 = (NX_MDNS_RR*)((UCHAR*)(head + 1)); (ULONG*)p1 < tail; p1++) - { - - /* Update the elasped timer. */ - p1 -> nx_mdns_rr_elapsed_time = current_time; - - /* Check the interface index. */ - if (p1 -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Find the "A" records. */ - if ((p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) && - (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) - { - - /* Set the IPv4 address. */ - service -> service_ipv4 = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address; - } - - /* Find the "AAAA" records. */ - if ((p1 -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA) && - (p1 -> nx_mdns_rr_name == p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) - { - if (index < NX_MDNS_IPV6_ADDRESS_COUNT) - { - - /* Set the IPv6 address. */ - service -> service_ipv6[index][0] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[0]; - service -> service_ipv6[index][1] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[1]; - service -> service_ipv6[index][2] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[2]; - service -> service_ipv6[index][3] = p1 -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address[3]; - index ++; - } - } - } - } - - /* Check the type and name. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) && - (!_nx_mdns_name_match(p -> nx_mdns_rr_name, srv_name, srv_name_length))) - { - - /* Update the elasped timer. */ - p -> nx_mdns_rr_elapsed_time = current_time; - - /* Set the text valid flag. */ - service -> service_text_valid = 1; - - if (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), &temp_length, NX_MDNS_NAME_MAX)) - { - continue; - } - - /* Store the txt. */ - memcpy((CHAR *)(service -> service_text), (const char*)(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_txt.nx_mdns_rr_txt_data), temp_length + 1); - } - } - } - } - - /* Set the interface index. */ - service -> interface_index = (UCHAR)interface_index; - - /* Return a error status. */ - return(NX_MDNS_SUCCESS); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the mDNS remote buffer and local buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* local_cache_ptr Pointer to local cache */ -/* local_cache_size The size of local cache */ -/* peer_cache_ptr Pointer to peer cache */ -/* peer_cache_size The size of peer cache */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_create Initialize the mDNS structure */ -/* _nx_mdns_disable Disable the mDNS function */ -/* _nx_mdns_peer_cache_clear Clear the peer cache */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_initialize(NX_MDNS *mdns_ptr, VOID *local_cache_ptr, UINT local_cache_size, - VOID *peer_cache_ptr, UINT peer_cache_size) -{ - -ULONG *head; -ULONG *tail; - - -#ifndef NX_MDNS_DISABLE_SERVER - /* Check the cache. */ - if (local_cache_ptr) - { - - /* Zero out the cache. */ - memset(local_cache_ptr, 0, local_cache_size); - - /* Set the head. */ - head = (ULONG*)local_cache_ptr; - *head = (ULONG)((ULONG*)local_cache_ptr + 1); - - /* Set the tail. */ - tail = (ULONG*)local_cache_ptr + (local_cache_size >> 2) - 1; - *tail = (ULONG)tail; - - /* Record the info. */ - mdns_ptr -> nx_mdns_local_service_cache = (UCHAR*)local_cache_ptr; - mdns_ptr -> nx_mdns_local_service_cache_size = local_cache_size; - - /* Clear the count. */ - mdns_ptr -> nx_mdns_local_rr_count = 0; - mdns_ptr -> nx_mdns_local_string_count = 0; - mdns_ptr -> nx_mdns_local_string_bytes = 0; - } -#else - NX_PARAMETER_NOT_USED(local_cache_ptr); - NX_PARAMETER_NOT_USED(local_cache_size); -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Check the cache. */ - if (peer_cache_ptr) - { - - /* Zero out the cache. */ - memset(peer_cache_ptr, 0, peer_cache_size); - - /* Set the head. */ - head = (ULONG*)peer_cache_ptr; - *head = (ULONG)((ULONG*)peer_cache_ptr + 1); - - /* Set the tail. */ - tail = (ULONG*)peer_cache_ptr + (peer_cache_size >> 2) - 1; - *tail = (ULONG)tail; - - /* Record the info. */ - mdns_ptr -> nx_mdns_peer_service_cache = (UCHAR*)peer_cache_ptr; - mdns_ptr -> nx_mdns_peer_service_cache_size = peer_cache_size; - - /* Clear the count. */ - mdns_ptr -> nx_mdns_peer_rr_count = 0; - mdns_ptr -> nx_mdns_peer_string_count = 0; - mdns_ptr -> nx_mdns_peer_string_bytes = 0; - } -#else - NX_PARAMETER_NOT_USED(peer_cache_ptr); - NX_PARAMETER_NOT_USED(peer_cache_size); -#endif /* NX_MDNS_DISABLE_CLIENT */ - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_add_resource_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the mDNS resource record into record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_type Cache type: local or peer */ -/* record_ptr Pointer to resource record */ -/* insert_rr Pointer to insert resource */ -/* record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_find_resource_record Find the resource record */ -/* _nx_mdns_cache_delete_string Delete the string from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ -/* _nx_mdns_rr_ptr_add Add PTR resource record */ -/* _nx_mdns_rr_srv_add Add SRV resource record */ -/* _nx_mdns_rr_txt_add Add TXT resource record */ -/* _nx_mdns_query Send query */ -/* _nx_mdns_cache_delete_rr_string Delete the rr string */ -/* _nx_mdns_packet_rr_process Process resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_add_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, NX_MDNS_RR **insert_ptr, UCHAR *is_present) -{ - -UCHAR *cache_ptr; -UINT cache_size; -ULONG *tail; -ULONG *head; -NX_MDNS_RR *p; -NX_MDNS_RR *rr; -UINT rr_name_length; - -#ifndef NX_MDNS_DISABLE_CLIENT -ULONG elapsed_time; -ULONG current_time; -ULONG min_elapsed_time; -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Initialize the parameters. */ - min_elapsed_time = 0; - current_time = tx_time_get(); -#endif /* NX_MDNS_DISABLE_CLIENT */ - - /* Initialize. */ - if (is_present) - *is_present = NX_FALSE; - - /* Check the RR with same rname, rtype, rclass and rdata. */ - if (_nx_mdns_cache_find_resource_record(mdns_ptr, cache_type, record_ptr, NX_MDNS_RR_MATCH_ALL, &rr) == NX_MDNS_SUCCESS) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(rr -> nx_mdns_rr_name), &rr_name_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Copy other informations of record_ptr into insert_rr resource record. */ - memcpy(rr, record_ptr, sizeof(NX_MDNS_RR)); - - /* Special process for _services._dns-sd._udp.local which pointer to same service type. */ - if ((rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) && - (!_nx_mdns_name_match(rr -> nx_mdns_rr_name, (UCHAR *)_nx_mdns_dns_sd, rr_name_length))) - { - rr -> nx_mdns_rr_count ++; - } - - /* Delete the resource record same strings. */ - _nx_mdns_cache_delete_rr_string(mdns_ptr, cache_type, rr); - - /* Set the insert ptr. */ - if(insert_ptr != NX_NULL) - *insert_ptr = rr; - - /* Set the flag. */ - if (is_present) - *is_present = NX_TRUE; - - return(NX_MDNS_SUCCESS); - } - - /* Check the cache type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; - } - else - { - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; - } - - /* Check cache pointer and cache size. */ - if ((cache_ptr == NX_NULL) || (cache_size == 0)) - { - return(NX_MDNS_ERROR); - } - - /* Get head and tail. */ - tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; - tail = (ULONG*)(*tail); - head = (ULONG*)cache_ptr; - head = (ULONG*)(*head); - - /* Set the pointer. */ - rr = NX_NULL; - - /* Find an empty entry before head. */ - for(p = (NX_MDNS_RR*)((ULONG*)cache_ptr + 1); p < (NX_MDNS_RR*)head; p++) - { - if(p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - { - rr = p; - break; - } - } - - if (!rr) - { - - /* Check whether the cache is full. */ - if((head + (sizeof(NX_MDNS_RR) >> 2)) > tail) - { - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - return(NX_MDNS_CACHE_ERROR); - } - else - { - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Find an aging resource reocrd and repalce it. */ - for(p = (NX_MDNS_RR*)((ULONG*)cache_ptr + 1); p < (NX_MDNS_RR*)head; p++) - { - - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) - continue; - - /* Calculate the elapsed time. */ - elapsed_time = current_time - p -> nx_mdns_rr_elapsed_time; - - /* Check the elapsed time to find the aging resource record. */ - if (elapsed_time >= min_elapsed_time) - { - rr = p; - min_elapsed_time = elapsed_time; - } - } - - if (rr) - { - - /* Delete this record. */ - _nx_mdns_cache_delete_resource_record(mdns_ptr, cache_type, rr); - - /* Update the head. */ - head = (ULONG*)cache_ptr; - head = (ULONG*)(*head); - } - else - { - return(NX_MDNS_CACHE_ERROR); - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - } - } - else - { - rr = (NX_MDNS_RR*)head; - } - } - - /* Just copy it to cache_ptr. */ - memcpy(rr, record_ptr, sizeof(NX_MDNS_RR)); - - /* Check the type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - - /* Increase the count. */ - mdns_ptr -> nx_mdns_local_rr_count ++; - } - else - { - - /* Increase the count. */ - mdns_ptr -> nx_mdns_peer_rr_count ++; - } - -#ifndef NX_MDNS_DISABLE_CLIENT - /* Update the peer resource record elapsed time. */ - if (cache_type == NX_MDNS_CACHE_TYPE_PEER) - { - - /* Get the current time to set the elapsed time. */ - rr -> nx_mdns_rr_elapsed_time = current_time; - } -#endif /* NX_MDNS_DISABLE_CLIENT */ - - /* Set the insert ptr. */ - if(insert_ptr != NX_NULL) - *insert_ptr = rr; - - if((ULONG*)rr >= head) - { - - /* Update HEAD when new record is added. */ - head = (ULONG*)cache_ptr; - *head = (ULONG)(rr + 1); - } - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_delete_resource_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS resource record from record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance. */ -/* cache_type Cache type: local or peer */ -/* record_ptr Pointer to resource record. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_delete_string Delete the string from buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_rr_delete Delete the resource record */ -/* _nx_mdns_query Send the one-shot query */ -/* _nx_mdns_timer_event_process Process the timer event */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* _nx_mdns_cache_delete_rr_string Delete the rr string */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_delete_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr) -{ - -UCHAR *cache_ptr; -ULONG *head; - - - /* Delete the resource record strings. */ - _nx_mdns_cache_delete_rr_string(mdns_ptr, cache_type, record_ptr); - - /* Zero out the record. */ - memset(record_ptr, 0, sizeof(NX_MDNS_RR)); - - /* Check the type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - - /* Decrease the count. */ - mdns_ptr -> nx_mdns_local_rr_count --; - - /* Set the cache. */ - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - } - else - { - - /* Decrease the count. */ - mdns_ptr -> nx_mdns_peer_rr_count --; - - /* Set the cache. */ - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - } - - if (cache_ptr == NX_NULL) - { - return(NX_MDNS_CACHE_ERROR); - } - - /* Get head. */ - head = (ULONG*)cache_ptr; - head = (ULONG*)(*head); - - /* Move HEAD if the last RR is deleted. */ - if(record_ptr == ((NX_MDNS_RR*)head - 1)) - { - while(record_ptr -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - { - record_ptr--; - if(record_ptr < (NX_MDNS_RR*)cache_ptr) - break; - } - *((ULONG*)cache_ptr) = (ULONG)(record_ptr + 1); - } - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_find_resource_record PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the mDNS resource record in record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance. */ -/* cache_type Cache type: local or peer */ -/* record_ptr Resource record. */ -/* match_type Match type. */ -/* search_rr The search resource record. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_find_resource_record(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_ptr, UINT match_type, NX_MDNS_RR **search_rr) -{ - -UCHAR *cache_ptr; -ULONG *head; -NX_MDNS_RR *p; -UINT same_rdata; - - - /* Check the cache type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - } - else - { - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - } - - /* Get head. */ - head = (ULONG*)cache_ptr; - head = (ULONG*)(*head); - - /* Find the same record. */ - for(p = (NX_MDNS_RR*)((UCHAR*)cache_ptr + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) - continue; - - /* Check whether the resource record is valid. */ - if(p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check whether the same record it is. RFC6762, Section6, Page13. */ - /* The rules: rrname must match the question name. - rrtype must match the question qtype unless the qtype is "ANY" or the rrtype is "CNAME". - rrclass must match the question qclass unless the qclass is "ANY". */ - if (p -> nx_mdns_rr_name != record_ptr -> nx_mdns_rr_name) - continue; - - /* In the probing state, we need not match the type. */ - if (p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_PROBING) - { - if ((p -> nx_mdns_rr_type != record_ptr -> nx_mdns_rr_type) && - (record_ptr -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_ALL) && - (p -> nx_mdns_rr_type != NX_MDNS_RR_TYPE_CNAME)) - continue; - } - - /* Check the RR class, Ignore the top bit. */ - if ((p -> nx_mdns_rr_class != (record_ptr -> nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK)) && - ((record_ptr -> nx_mdns_rr_class & NX_MDNS_TOP_BIT_MASK) != NX_MDNS_RR_CLASS_ALL)) - continue; - - /* Check if just match the basic info. */ - if (match_type == NX_MDNS_RR_MATCH_EXCEPT_RDATA) - { - - /* Find the same record. */ - *search_rr = p; - return(NX_MDNS_SUCCESS); - } - else - { - - /* Yes, match all information of resource record. */ - - /* Check the state. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY) - continue; - - /* Reset the value. */ - same_rdata = NX_FALSE; - - /* Compare the RDATA. */ - switch (p -> nx_mdns_rr_type) - { - case NX_MDNS_RR_TYPE_A: - { - if(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_a.nx_mdns_rr_a_address) - { - same_rdata = NX_TRUE; - } - break; - } - case NX_MDNS_RR_TYPE_SRV: - { - if((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_priority) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_weights) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_port) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) - { - same_rdata = NX_TRUE; - } - break; - } - case NX_MDNS_RR_TYPE_AAAA: - { - if(!memcmp(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address, record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_aaaa.nx_mdns_rr_aaaa_address, 16)) - { - same_rdata = NX_TRUE; - } - break; - } - case NX_MDNS_RR_TYPE_PTR: - case NX_MDNS_RR_TYPE_TXT: - -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - case NX_MDNS_RR_TYPE_CNAME: - case NX_MDNS_RR_TYPE_NS: -#endif - { - - /* Check the rdata. */ - if(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) - { - same_rdata = NX_TRUE; - } - break; - } -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - case NX_MDNS_RR_TYPE_MX: - { - if((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_name) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_mx.nx_mdns_rr_mx_preference)) - { - same_rdata = NX_TRUE; - } - break; - } -#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - case NX_MDNS_RR_TYPE_NSEC: - { - if ((p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain == record_ptr ->nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_next_domain) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_window_block) && - (p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length) && - (!memcmp(&(p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0]), - &(record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap[0]), - record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_nsec.nx_mdns_rr_nsec_bitmap_length))) - { - same_rdata = NX_TRUE; - } - break; - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - default: - { - - /* This is an unsupported or unknown type. */ - return(NX_MDNS_UNSUPPORTED_TYPE); - } - } - - /* Check the same RR. */ - if (same_rdata == NX_TRUE) - { - - /* Find the same record. */ - *search_rr = p; - return(NX_MDNS_SUCCESS); - } - } - } - - return(NX_MDNS_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_add_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds or finds the mDNS string in the record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_type Cache type: local or peer */ -/* memory_ptr Pointer to the string */ -/* memory_size The size of string. */ -/* insert_rr Pointer to insert string. */ -/* find_string If set, just find the existed */ -/* string, otherwise, insert */ -/* this string if it does not */ -/* exist. */ -/* add_name If set, use name match */ -/* to check the string, */ -/* otherwise, use memcmp. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ -/* _nx_mdns_rr_ptr_add Add PTR resource record */ -/* _nx_mdns_rr_srv_add Add SRV resource record */ -/* _nx_mdns_rr_txt_add Add TXT resource record */ -/* _nx_mdns_query Send query */ -/* _nx_mdns_conflict_process Process the conflict */ -/* _nx_mdns_packet_rr_process Process resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_add_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *memory_ptr, UINT memory_size, VOID **insert_ptr, UCHAR find_string, UCHAR add_name) -{ - -UCHAR *cache_ptr; -UINT cache_size; -ULONG *tail; -ULONG *head; -UINT memory_len; -UINT used_cache_size; -USHORT len, cnt; -USHORT min_len = 0xFFFF; -UCHAR *p, *available, *start; - - - /* Check the cache type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; - } - else - { - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; - } - - /* Check cache pointer and cache size. */ - if ((cache_ptr == NX_NULL) || (cache_size == 0)) - { - return(NX_MDNS_ERROR); - } - - /* Get head and tail. */ - tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; - p = (UCHAR*)tail; - tail = (ULONG*)(*tail); - head = (ULONG*)cache_ptr; - head = (ULONG*)(*head); - - /* Calculate the amount of memory needed to store this string, including CNT and LEN fields. */ - - /* Make the length 4 bytes align. */ - memory_len = memory_size; - - /* Add the length of CNT and LEN fields. */ - memory_len = ((memory_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - available = (UCHAR*)tail; - while(p > (UCHAR*)tail) - { - - /* Get len and cnt. */ - len = *((USHORT*)(p - 2)); - cnt = *((USHORT*)(p - 4)); - start = p - len; - - if((len == memory_len) && - (((add_name == NX_TRUE) && - (!_nx_mdns_name_match(start, memory_ptr, memory_size))) || - ((add_name == NX_FALSE) && - (!memcmp(start, memory_ptr, memory_size))))) - { - - /* The same string exists in the string table. */ - if(insert_ptr) - *insert_ptr = start; - - if(find_string == NX_FALSE) - { - - /* Increase the use count CNT. */ - cnt++; - *((USHORT*)(p - 4)) = cnt; - } - - return(NX_MDNS_SUCCESS); - } - - /* This slot is not being used. The size of the slot is a smaller - fit for this string. */ - if((cnt == 0) && (len >= memory_len) && (len < min_len)) - { - - /* This place is better to insert. */ - available = p; - min_len = len; - } - - /* Move to the next string. */ - p = start; - } - - if(find_string == NX_TRUE) - return(NX_MDNS_ERROR); - - /* If we reach this point, the string needs to be added to the string table. */ - if(available == (UCHAR*)tail) - { - - /* Make sure the service cache still has room to add this string - (without overwriting the RR area.) */ - if(((UCHAR*)tail - memory_len) < (UCHAR*)head ) - { - - /* This service cache does not have room for the string table to grow. */ - /* Invoke user-installed cache full notify function .*/ - if(mdns_ptr -> nx_mdns_cache_full_notify) - { - - /* Calculate the fragment size, RR size, string size, Head and Tail. */ - if(cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - used_cache_size = mdns_ptr -> nx_mdns_local_rr_count * sizeof(NX_MDNS_RR) + mdns_ptr -> nx_mdns_local_string_bytes + 2 * sizeof(ULONG); - } - else - { - used_cache_size = mdns_ptr -> nx_mdns_peer_rr_count * sizeof(NX_MDNS_RR) + mdns_ptr -> nx_mdns_peer_string_bytes + 2 * sizeof(ULONG); - } - - /* Check the cache. */ - if ((used_cache_size + memory_len) <= cache_size) - { - (mdns_ptr -> nx_mdns_cache_full_notify)(mdns_ptr, NX_MDNS_CACHE_STATE_FRAGMENTED, cache_type); - } - else - { - (mdns_ptr -> nx_mdns_cache_full_notify)(mdns_ptr, NX_MDNS_CACHE_STATE_FULL, cache_type); - } - } - - /* The buffer is full. */ - return(NX_MDNS_CACHE_ERROR); - } - - /* Update TAIL. */ - *((ULONG*)cache_ptr + (cache_size >> 2) - 1) = (ULONG)(available - memory_len); - - } - else if(memory_len < min_len) - { - - /* Set the LEN for remaining space. */ - *((USHORT*)(available - 2 - memory_len)) = (USHORT)(min_len - memory_len); - } - - /* Set LEN and CNT. */ - *((USHORT*)(available - 2)) = (USHORT)memory_len; - *((USHORT*)(available - 4)) = 1; - - /* Clear last 4 bytes. */ - *((ULONG*)(available - 8)) = 0; - - /* Insert string to cache. */ - memcpy(available - memory_len, memory_ptr, memory_size); - - /* Set end character 0. */ - *(available - memory_len + memory_size) = 0; - - - /* Check the type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - - /* Increase the count and bytes. */ - mdns_ptr -> nx_mdns_local_string_count ++; - mdns_ptr -> nx_mdns_local_string_bytes += memory_len; - } - else - { - - /* Increase the count and bytes. */ - mdns_ptr -> nx_mdns_peer_string_count ++; - mdns_ptr -> nx_mdns_peer_string_bytes += memory_len; - } - - if(insert_ptr) - *insert_ptr = available - memory_len; - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_delete_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS string from the record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_type Cache type: local or peer */ -/* string_ptr Pointer to the string */ -/* string_len The length of string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_rr_a_aaaa_add Add A/AAAA resource record */ -/* _nx_mdns_rr_ptr_add Add PTR resource record */ -/* _nx_mdns_rr_srv_add Add SRV resource record */ -/* _nx_mdns_rr_txt_add Add TXT resource record */ -/* _nx_mdns_query Send query */ -/* _nx_mdns_conflict_process Process the conflict */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* _nx_mdns_packet_rr_process Process resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_cache_delete_string(NX_MDNS *mdns_ptr, UINT cache_type, VOID *string_ptr, UINT string_len) -{ - -UCHAR *cache_ptr; -UINT cache_size; -ULONG *tail; -ULONG *end; -USHORT cnt; - - - /* Check the cache type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - cache_ptr = mdns_ptr -> nx_mdns_local_service_cache; - cache_size = mdns_ptr -> nx_mdns_local_service_cache_size; - } - else - { - cache_ptr = mdns_ptr -> nx_mdns_peer_service_cache; - cache_size = mdns_ptr -> nx_mdns_peer_service_cache_size; - } - - /* Check cache pointer and cache size. */ - if ((cache_ptr == NX_NULL) || (cache_size == 0)) - { - return(NX_MDNS_ERROR); - } - - /* Validate input parameter. */ - if(string_ptr == NX_NULL) - return(NX_MDNS_PARAM_ERROR); - - /* Check if input the string length. */ - if (string_len == 0) - { - - /* Check string length. */ - if (_nx_utility_string_length_check(string_ptr, &string_len, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - } - - /* Add the length of CNT and LEN fields. */ - /* Also make the total length 4 bytes align. */ - string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - end = (ULONG*)((UCHAR*)string_ptr + string_len); - - /* Get tail. */ - - /* Validate the string table. */ - tail = (ULONG*)cache_ptr + (cache_size >> 2) - 1; - if(end > tail) - { - - /* The end of string exceeds cache_ptr. */ - return(NX_MDNS_CACHE_ERROR); - } - tail = (ULONG*)(*tail); - if((UCHAR*)string_ptr < (UCHAR*)tail) - { - - /* The end of string exceeds cache_ptr. */ - return(NX_MDNS_CACHE_ERROR); - } - - /* Decrease the usage counter value. */ - cnt = *((USHORT*)((UCHAR*)end - 4)); - cnt--; - *((USHORT*)((UCHAR*)end - 4)) = cnt; - - /* Clear the memory if cnt is zero. */ - if(cnt == 0) - { - memset(string_ptr, 0, string_len - 2); - - /* Check the type. */ - if (cache_type == NX_MDNS_CACHE_TYPE_LOCAL) - { - - /* Increase the count and bytes. */ - mdns_ptr -> nx_mdns_local_string_count --; - mdns_ptr -> nx_mdns_local_string_bytes -= string_len; - } - else - { - - /* Increase the count and bytes. */ - mdns_ptr -> nx_mdns_peer_string_count --; - mdns_ptr -> nx_mdns_peer_string_bytes -= string_len; - } - - /* Update the tail pointer if the string at the tail is deleted. */ - if(string_ptr == tail) - { - tail = end; - - while((end < ((ULONG*)cache_ptr + (cache_size >> 2) - 1))) - { - - /* Set the string pt and string length. */ - string_ptr = end; - - /* Check string length. */ - if (_nx_utility_string_length_check(string_ptr, &string_len, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Check the string length. */ - if(string_len == 0) - { - - /* This slot is cleared. */ - while(*((ULONG*)string_ptr) == 0) - string_ptr = (UCHAR*)string_ptr + 4; - - end = (ULONG*)string_ptr + 1; - cnt = *((USHORT*)string_ptr); - } - else - { - - /* Make the length 4 bytes align and add the length of CNT and LEN fields. */ - string_len = ((string_len & 0xFFFFFFFC) + 8) & 0xFFFFFFFF; - - end = (ULONG*)((UCHAR*)string_ptr + string_len); - cnt = *((USHORT*)((UCHAR*)end - 4)); - } - - /* Check whether this slot is never referenced. */ - if(cnt == 0) - tail = end; - else - break; - } - *((ULONG*)cache_ptr + (cache_size >> 2) - 1) = (ULONG)tail; - } - } - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_cache_delete_rr_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the mDNS string from the record buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* cache_type Cache type: local or peer */ -/* string_ptr Pointer to the string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_mdns_cache_delete_string Delete the string from cache */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_cache_add_resource_record Add the resource record */ -/* _nx_mdns_cache_delete_resource_record Delete the resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_mdns_cache_delete_rr_string(NX_MDNS *mdns_ptr, UINT cache_type, NX_MDNS_RR *record_rr) -{ - - /* Delete the name strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, cache_type, record_rr -> nx_mdns_rr_name, 0); - - /* Check if need to release the rdata string. */ - if (record_rr -> nx_mdns_rr_state != NX_MDNS_RR_STATE_QUERY) - { - - if (((record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_PTR) -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_CNAME) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NS) || - (record_rr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_MX) -#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ - ) && - (record_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target)) - { - - /* Delete the same strings. */ - _nx_mdns_cache_delete_string(mdns_ptr, cache_type, record_rr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, 0); - } - } -} - - -#ifndef NX_MDNS_DISABLE_SERVER -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_additional_resource_record_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function find the mDNS additional resource record. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_ptr Pointer to record instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_response_send Send response message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_mdns_additional_resource_record_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr) -{ - -ULONG *head; -NX_MDNS_RR *p; - - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - /* Find the additional resource records according to the type. */ - switch (record_ptr -> nx_mdns_rr_type ) - { - - case NX_MDNS_RR_TYPE_A: - case NX_MDNS_RR_TYPE_AAAA: - { - - /* Recommends AAAA records in the additional section when responding - to rrtype "A" queries, and vice versa. RFC6762, Section19, Page51. */ - _nx_mdns_additional_a_aaaa_find(mdns_ptr, record_ptr -> nx_mdns_rr_name, record_ptr -> nx_mdns_rr_interface_index); - - break; - } - - case NX_MDNS_RR_TYPE_PTR: - { - - /* Find the additional resource record. */ - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface. */ - if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) - continue; - - /* The SRV record(s) named in the PTR rdata. - The TXT record(s) named in the PTR rdata. - All address records (type "A" and "AAAA") named in the SRV rdata. RFC6763, Section12.1, Page30.*/ - - /* The SRV records named in the PTR rdata */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) && - (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) && - ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && - (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && - (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) - { - - /* Set the flag to add this resource records into additional records. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; - - /* All address records (type "A" and "AAAA") named in the SRV rdata */ - _nx_mdns_additional_a_aaaa_find(mdns_ptr, p -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, record_ptr -> nx_mdns_rr_interface_index); - } - - /* The TXT records named in the PTR rdata */ - if (((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) || - (p ->nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC)) && - (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_ptr.nx_mdns_rr_ptr_name) && - ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && - (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && - (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) - { - - /* Set the flag to add this resource records into additional records. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; - } - } - - break; - } - - case NX_MDNS_RR_TYPE_SRV: - case NX_MDNS_RR_TYPE_TXT: - { - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - /* Find the additional resource record. */ - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface. */ - if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) - continue; - - /* The NSEC records named same as SRV/TXT name. */ - if ((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC) && - (p -> nx_mdns_rr_name == record_ptr -> nx_mdns_rr_name) && - ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && - (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && - (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) - { - - /* Set the flag to add this resource records into additional records. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; - } - } -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - - /* All address records (type "A" and "AAAA") named in the SRV rdata */ - if (record_ptr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - _nx_mdns_additional_a_aaaa_find(mdns_ptr, record_ptr -> nx_mdns_rr_rdata.nx_mdns_rr_rdata_srv.nx_mdns_rr_srv_target, record_ptr -> nx_mdns_rr_interface_index); - break; - } - } - - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_additional_a_aaaa_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function find the mDNS additional A/AAAA resource record. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_ptr Pointer to record instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_additional_resource_record_find */ -/* Find additional record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_mdns_additional_a_aaaa_find(NX_MDNS *mdns_ptr, UCHAR *name, UINT interface_index) -{ - -ULONG *head; -NX_MDNS_RR *p; - - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - head = (ULONG*)(*head); - - /* Recommends AAAA records in the additional section when responding - to rrtype "A" queries, and vice versa. RFC6762, Section19, Page51. */ - for (p = (NX_MDNS_RR*)((UCHAR*)mdns_ptr -> nx_mdns_local_service_cache + sizeof(ULONG)); (ULONG*)p < head; p++) - { - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - /* Find the "A" records. */ - if (((p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_A) || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_AAAA || - (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_NSEC))) && - (p -> nx_mdns_rr_name == name) && - ((p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_VALID) || - (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_ANNOUNCING)) && - (p -> nx_mdns_rr_send_flag == NX_MDNS_RR_SEND_FLAG_CLEAR) && - (!(p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_ANSWER))) - { - - /* Set the flag to add this resource records into additional records. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_ADDITIONAL; - } - } -} -#endif /* NX_MDNS_DISABLE_SERVER */ - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_known_answer_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the mDNS known answer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* record_ptr Pointer to record instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_query_send Send query message */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_known_answer_find(NX_MDNS *mdns_ptr, NX_MDNS_RR *record_ptr) -{ - -UINT status = NX_MDNS_NO_KNOWN_ANSWER; -ULONG *head, *tail; -NX_MDNS_RR *p; -UINT i; -UINT name_length; -#ifndef NX_MDNS_DISABLE_SERVER -UINT cache_count = 2; -#else -UINT cache_count = 1; -#endif - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)(record_ptr -> nx_mdns_rr_name), &name_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Loop to find the known answer in cache. */ - for (i = 0; i < cache_count; i++) - { - - /* Set the pointer. */ - if (i == 0) - { - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - } -#ifndef NX_MDNS_DISABLE_SERVER - else - { - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - } -#endif /* NX_MDNS_DISABLE_SERVER */ - tail = (ULONG*)(*head); - - /* Whether this mDNS message response to query. */ - for(p = (NX_MDNS_RR*)(head + 1); (ULONG*)p < tail; p++) - { - - /* Check the state. */ - if(p -> nx_mdns_rr_state != NX_MDNS_RR_STATE_VALID) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != record_ptr -> nx_mdns_rr_interface_index) - continue; - - /* Check whether the Known Answer record it is. */ - if ((!_nx_mdns_name_match(p -> nx_mdns_rr_name, record_ptr -> nx_mdns_rr_name, name_length)) && - (p -> nx_mdns_rr_class == record_ptr -> nx_mdns_rr_class)) - { - - if ((record_ptr -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_ALL) || - (p -> nx_mdns_rr_type == record_ptr -> nx_mdns_rr_type)) - { - - /* Set the additional flag. */ - p -> nx_mdns_rr_word = p -> nx_mdns_rr_word | NX_MDNS_RR_FLAG_KNOWN_ANSWER; - - /* Yes, find the known answer. */ - status = NX_MDNS_SUCCESS; - } - } - } - } - - return(status); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -#ifndef NX_MDNS_DISABLE_CLIENT -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_query_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks whether mDNS querier already has one Unique */ -/* record in the local buffer/remote buffer or one same query in the */ -/* remote buffer. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* name The resource record name */ -/* type The resource record type */ -/* interface_index The interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_query Send the query */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_query_check(NX_MDNS *mdns_ptr, UCHAR *name, USHORT type, UINT one_shot, NX_MDNS_RR **search_rr, UINT interface_index) -{ - -ULONG *head; -NX_MDNS_RR *p; -UCHAR i; -UCHAR same_query = NX_FALSE; -NX_MDNS_RR *rr = NX_NULL; -UCHAR srv_flag = NX_FALSE; -UCHAR txt_flag = NX_FALSE; -UINT name_length; - - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)name, &name_length, NX_MDNS_NAME_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - for(i = 0; i < 2; i++) - { - if(i == NX_MDNS_CACHE_TYPE_LOCAL) - head = (ULONG*)mdns_ptr -> nx_mdns_local_service_cache; - else - head = (ULONG*)mdns_ptr -> nx_mdns_peer_service_cache; - - if(head) - { - for(p = (NX_MDNS_RR*)(head + 1); (ULONG)p < *head; p++) - { - - /* Check whether the resource record is valid. */ - if (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_INVALID) - continue; - - /* Check the interface index. */ - if (p -> nx_mdns_rr_interface_index != interface_index) - continue; - - if (!_nx_mdns_name_match(p -> nx_mdns_rr_name, name, name_length)) - { - if ((p -> nx_mdns_rr_type == type) && (p -> nx_mdns_rr_state == NX_MDNS_RR_STATE_QUERY)) - { - - /* Set the query. */ - same_query = NX_TRUE; - - /* Record the RR potiner. */ - rr = p; - } - - /* Check the rr type. */ - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_SRV) - srv_flag = NX_TRUE; - if (p -> nx_mdns_rr_type == NX_MDNS_RR_TYPE_TXT) - txt_flag = NX_TRUE; - - if ((p -> nx_mdns_rr_type == type) || - ((type == NX_MDNS_RR_TYPE_ALL) && (srv_flag == NX_TRUE) && (txt_flag == NX_TRUE))) - { - if (search_rr) - *search_rr = p; - - /* Check the query type. */ - if (one_shot == NX_TRUE) - return(NX_MDNS_EXIST_SHARED_RR); - - if (p -> nx_mdns_rr_word & NX_MDNS_RR_FLAG_UNIQUE) - return(NX_MDNS_EXIST_UNIQUE_RR); - } - } - } - } - } - - /* Check the same query. */ - if (same_query == NX_TRUE) - { - - /* A multicast DNS querier should also delay the first query of the series by - a randomly chosen amount in the range 20-120ms. */ - rr -> nx_mdns_rr_timer_count = (ULONG)(NX_MDNS_QUERY_DELAY_MIN + (NX_RAND() % NX_MDNS_QUERY_DELAY_RANGE)); - rr -> nx_mdns_rr_retransmit_lifetime = NX_MDNS_TIMER_COUNT_RANGE; - - /* Set the mDNS timer. */ - _nx_mdns_timer_set(mdns_ptr, rr, rr -> nx_mdns_rr_timer_count); - - return (NX_MDNS_EXIST_SAME_QUERY); - } - - /* Return a successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_query_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes mDNS One-shot query timeout and thread */ -/* terminate actions that require the mDNS data structures to be */ -/* cleaned up. */ -/* */ -/* INPUT */ -/* */ -/* thread_ptr Pointer to suspended thread's */ -/* control block */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _tx_thread_system_resume Resume thread service */ -/* */ -/* CALLED BY */ -/* */ -/* _tx_thread_timeout Thread timeout processing */ -/* _tx_thread_terminate Thread terminate processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_mdns_query_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_MDNS *mdns_ptr; - - - NX_CLEANUP_EXTENSION - - /* Setup pointer to UDP socket control block. */ - mdns_ptr = (NX_MDNS *) thread_ptr -> tx_thread_suspend_control_block; - - /* Disable interrupts to remove the suspended thread from the UDP socket. */ - TX_DISABLE - - /* Determine if the cleanup is still required. */ - if ((thread_ptr -> tx_thread_suspend_cleanup) && (mdns_ptr) && - (mdns_ptr -> nx_mdns_id == NX_MDNS_ID)) - { - - /* Yes, we still have thread suspension! */ - - /* Clear the suspension cleanup flag. */ - thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; - - /* Remove the suspended thread from the list. */ - - /* See if this is the only suspended thread on the list. */ - if (thread_ptr == thread_ptr -> tx_thread_suspended_next) - { - - /* Yes, the only suspended thread. */ - - /* Update the head pointer. */ - mdns_ptr -> nx_mdns_rr_receive_suspension_list = NX_NULL; - } - else - { - - /* At least one more thread is on the same suspension list. */ - - /* Update the list head pointer. */ - mdns_ptr -> nx_mdns_rr_receive_suspension_list = thread_ptr -> tx_thread_suspended_next; - - /* Update the links of the adjacent threads. */ - (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = thread_ptr -> tx_thread_suspended_previous; - (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr -> tx_thread_suspended_next; - } - - /* Decrement the suspension count. */ - mdns_ptr -> nx_mdns_rr_receive_suspended_count--; - - /* Now we need to determine if this cleanup is from a terminate, timeout, - or from a wait abort. */ - if (thread_ptr -> tx_thread_state == TX_TCP_IP) - { - - /* Thread still suspended on the UDP socket. Setup return error status and - resume the thread. */ - - /* Setup return status. */ - thread_ptr -> tx_thread_suspend_status = NX_MDNS_NO_RR; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Restore interrupts. */ - TX_RESTORE - - /* Resume the thread! Check for preemption even though we are executing - from the system timer thread right now which normally executes at the - highest priority. */ - _tx_thread_system_resume(thread_ptr); - - /* Finished, just return. */ - return; - } - } - - /* Restore interrupts. */ - TX_RESTORE -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_query_thread_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends a thread on a mDNS client query service */ -/* */ -/* INPUT */ -/* */ -/* suspension_list_head Pointer to the suspension list*/ -/* mutex_ptr Pointer to mutex to release */ -/* suspend_cleanup Suspension cleanup routine */ -/* wait_option Optional timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_put Release protection */ -/* _tx_thread_system_suspend Suspend thread */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_mdns_query_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), - NX_MDNS *mdns_ptr, NX_MDNS_RR **rr, ULONG wait_option) -{ - -TX_INTERRUPT_SAVE_AREA - -TX_THREAD *thread_ptr; - - - /* Lockout interrupts. */ - TX_DISABLE - - /* Pickup thread pointer. */ - thread_ptr = _tx_thread_current_ptr; - - /* Setup suspension list. */ - if (*suspension_list_head) - { - - /* This list is not NULL, add current thread to the end. */ - thread_ptr -> tx_thread_suspended_next = *suspension_list_head; - thread_ptr -> tx_thread_suspended_previous = (*suspension_list_head) -> tx_thread_suspended_previous; - ((*suspension_list_head) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr; - (*suspension_list_head) -> tx_thread_suspended_previous = thread_ptr; - } - else - { - - /* No other threads are suspended. Setup the head pointer and - just setup this threads pointers to itself. */ - *suspension_list_head = thread_ptr; - thread_ptr -> tx_thread_suspended_next = thread_ptr; - thread_ptr -> tx_thread_suspended_previous = thread_ptr; - } - - /* Setup return status. */ - thread_ptr -> tx_thread_suspend_status = NX_MDNS_NO_RR; - - /* Setup cleanup routine pointer. */ - thread_ptr -> tx_thread_suspend_cleanup = suspend_cleanup; - - /* Setup cleanup information, i.e. this pool control block. */ - thread_ptr -> tx_thread_suspend_control_block = (void *)mdns_ptr; - - /* Save the return RR pointer address as well. */ - thread_ptr -> tx_thread_additional_suspend_info = (void *)rr; - - /* Increment the suspended thread count. */ - mdns_ptr -> nx_mdns_rr_receive_suspended_count++; - - /* Set the state to suspended. */ - thread_ptr -> tx_thread_state = TX_TCP_IP; - - /* Set the suspending flag. */ - thread_ptr -> tx_thread_suspending = TX_TRUE; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Save the timeout value. */ - thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; - - /* Restore interrupts. */ - TX_RESTORE - - /* Call actual thread suspension routine. */ - _tx_thread_system_suspend(thread_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_query_thread_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resumes a thread suspended on a mDNS Client query */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* thread_ptr Pointer to suspended thread's */ -/* control block */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _tx_thread_system_resume Resume thread service */ -/* */ -/* CALLED BY */ -/* */ -/* _tx_thread_timeout Thread timeout processing */ -/* _tx_thread_terminate Thread terminate processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_mdns_query_thread_resume(TX_THREAD **suspension_list_head, NX_MDNS *mdns_ptr, NX_MDNS_RR *rr) -{ - -TX_INTERRUPT_SAVE_AREA - -TX_THREAD *thread_ptr; - - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the thread pointer. */ - thread_ptr = *suspension_list_head; - - /* Determine if there still is a thread suspended. */ - if (thread_ptr) - { - - /* Remove the suspended thread from the list. */ - - /* See if this is the only suspended thread on the list. */ - if (thread_ptr == thread_ptr -> tx_thread_suspended_next) - { - - /* Yes, the only suspended thread. */ - - /* Update the head pointer. */ - *suspension_list_head = TX_NULL; - } - else - { - - /* At least one more thread is on the same expiration list. */ - - /* Update the list head pointer. */ - *suspension_list_head = thread_ptr -> tx_thread_suspended_next; - - /* Update the links of the adjacent threads. */ - (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = thread_ptr -> tx_thread_suspended_previous; - (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr -> tx_thread_suspended_next; - } - - /* Decrement the suspension count. */ - mdns_ptr -> nx_mdns_rr_receive_suspended_count--; - - /* Prepare for resumption of the first thread. */ - - /* Clear cleanup routine to avoid timeout. */ - thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Return this block pointer to the suspended thread waiting for - a block. */ - *((NX_MDNS_RR **) thread_ptr -> tx_thread_additional_suspend_info) = rr; - - /* Restore interrupts. */ - TX_RESTORE - - /* Put return status into the thread control block. */ - thread_ptr -> tx_thread_suspend_status = NX_MDNS_SUCCESS; - - /* Resume thread. */ - _tx_thread_system_resume(thread_ptr); - } - else - { - - /* Restore interrupts. */ - TX_RESTORE - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_service_mask_match PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function matchs the mDNS service mask to listen the service */ -/* and notify the application, or ignore the service. */ -/* */ -/* INPUT */ -/* */ -/* mdns_ptr Pointer to mDNS instance */ -/* service_type Pointer to Service type */ -/* service_mask The Service mask */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the mDNS mutex */ -/* tx_mutex_put Put the mDNS mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_service_mask_match(NX_MDNS *mdns_ptr, UCHAR *service_type, ULONG service_mask) -{ - -UINT i; -UINT found; -ULONG mask; -UINT type_length; - - - NX_PARAMETER_NOT_USED(mdns_ptr); - - /* Initialize the parameters. */ - i = 0; - found = 0; - mask = 0x00000001; - - /* Compare the service type. */ - while (nx_mdns_service_types[i]) - { - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)nx_mdns_service_types[i], &type_length, NX_MDNS_TYPE_MAX)) - { - return(NX_MDNS_DATA_SIZE_ERROR); - } - - /* Find the same service type. */ - if (!_nx_mdns_name_match(service_type, (UCHAR *)(nx_mdns_service_types[i]), type_length)) - { - found = 1; - break; - } - i ++; - } - - /* Check the result. */ - if (found) - { - - /* Check service mask. */ - if (service_mask & (mask << i)) - { - return(NX_MDNS_SUCCESS); - } - } - - /* Return status. */ - return(NX_MDNS_SERVICE_TYPE_MISMATCH); -} -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_name_match PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function name string match, the lowercase letters "a" to "z" */ -/* match their uppercase equivalents "A" to "Z". */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_rr_add Add the RR into packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_name_match(UCHAR *src, UCHAR *dst, UINT length) -{ - -UINT index = 0; - - - /* Check the name. */ - while (*dst != '\0') - { - if((*src) != (*dst)) - { - if((((*src) | 0x20) >= 'a') && (((*src) | 0x20) <= 'z')) - { - /* Match the characters, case in-sensitive. */ - if(((*src) | 0x20) != ((*dst) | 0x20)) - return(NX_MDNS_NAME_MISMATCH); - } - else - { - return(NX_MDNS_NAME_MISMATCH); - } - } - src ++; - dst ++; - index ++; - } - - /* Check the scan length. */ - if (index != length) - { - return (NX_MDNS_NAME_MISMATCH); - } - - /* Return success. */ - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_txt_string_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the txt string and adds the txt string into */ -/* packet.the TXT records are formatted in a "key=value" notation */ -/* with ";" acting as separator when more then one key is available. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_rr_add Add the RR into packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_txt_string_encode(UCHAR *ptr, UCHAR *txt) -{ - -UCHAR *length; -UINT count = 1; - - - /* Point to the first character position in the buffer. This will point - to the length of the following name. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - - /* Move through string, copying bytes and updating length. - Whenever a "." is found, start a new string by updating the - pointer to the length and setting the length to zero. */ - while (*txt) - { - - /* Is a dot been found? */ - if (*txt == ';') - { - - - /* Yes, setup a new length pointer. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - txt++; - } - else - { - - /* Copy a character to the destination. */ - *ptr++ = *txt++; - - /* Adjust the length of the current segment. */ - (*length)++; - } - - /* Increment the total count here. */ - count++; - } - - /* Return the count. */ - return(count); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_txt_string_decode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decode the txt string and adds the txt string into */ -/* buffer.the TXT records are formatted in a "key=value" notation */ -/* with ";" acting as separator when more then one key is available. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer to decode */ -/* data_length The length of data */ -/* buffer Pointer to decoded data */ -/* size Size of data buffer to decode */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_mdns_packet_process Process mDNS packet */ -/* _nx_mdns_packet_rr_process Process resource record */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_txt_string_decode(UCHAR *data, UINT data_length, UCHAR *buffer, UINT size) -{ - - - /* Check the buffer size. */ - if (data_length >= size) - { - return (NX_MDNS_CACHE_ERROR); - } - - /* decode the data. */ - while (data_length) - { - - UINT labelSize = *data++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_MDNS_LABEL_MAX) - { - - /* Simple count, check for space and copy the label. */ - while (labelSize > 0) - { - - *buffer++ = *data++; - labelSize--; - data_length--; - } - - /* Now add the ';' */ - *buffer++ = ';'; - data_length--; - } - else - { - return(NX_MDNS_EXCEED_MAX_LABEL); - } - } - - /* Done copying the data, set the last . to a trailing null */ - if (*(buffer - 1) == ';') - { - - buffer--; - } - - /* Null terminate name. */ - *buffer = '\0'; - - /* Return name size. */ - return(NX_MDNS_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_name_size_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the size of the name. */ -/* */ -/* INPUT */ -/* */ -/* name Pointer to the name */ -/* */ -/* OUTPUT */ -/* */ -/* UINT Size of name */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_name_size_calculate(UCHAR *name) -{ - -UINT size = 0; - - - /* As long as we haven't found a zero length terminating label */ - while (*name != '\0') - { - - UINT labelSize = *name++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_MDNS_LABEL_MAX) - { - - /* Simple count, adjust size and skip the label. */ - size += labelSize + 1; - name += labelSize; - } - else if ((labelSize & NX_MDNS_COMPRESS_MASK) == NX_MDNS_COMPRESS_VALUE) - { - - /* This is a pointer size is 2 bytes and this is the end of this name */ - return(size + 2); - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - - /* Adjust size for the final NULL. */ - return(size + 1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_name_string_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a string containing the name as a list of */ -/* labels separated by dots to the encoded list of labels specified */ -/* in RFC1035 for DNS servers. This conversion doesn't handle */ -/* compression and doesn't check on the lengths of the labels or the */ -/* entire name. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to destination */ -/* name Source name string */ -/* */ -/* OUTPUT */ -/* */ -/* count Count of characters encoded */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_name_string_encode(UCHAR *ptr, UCHAR *name) -{ - -UCHAR *length; -UINT count = 1; - - - /* Point to the first character position in the buffer. This will point - to the length of the following name. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - - /* Move through string, copying bytes and updating length. - Whenever a "." is found, start a new string by updating the - pointer to the length and setting the length to zero. */ - while (*name) - { - - /* Is a dot been found? */ - if (*name == '.') - { - - /* Yes, setup a new length pointer. */ - length = ptr++; - - /* Default the length to zero. */ - *length = 0; - name++; - } - else - { - - /* Copy a character to the destination. */ - *ptr++ = *name++; - - /* Adjust the length of the current segment. */ - (*length)++; - } - - /* Increment the total count here. */ - count++; - } - - /* Add the final zero length, like a NULL terminator. */ - *ptr = 0; - - /* Increment the total count. */ - count++; - - /* Return the count. */ - return(count); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_name_string_decode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts from the encoded list of labels as specified */ -/* in RFC 1035 to a string containing the name as a list of labels */ -/* separated by dots. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer to decode */ -/* start Location of start of data */ -/* buffer Pointer to decoded data */ -/* size Size of data buffer to decode */ -/* */ -/* OUTPUT */ -/* */ -/* Size of decoded data */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_name_string_decode(UCHAR *data, UINT start, UCHAR *buffer, UINT size) -{ - -UCHAR *character = data + start; -UINT length = 0; - - - /* As long as there is space in the buffer and we haven't - found a zero terminating label */ - while ((size > length) && (*character != '\0')) - { - - UINT labelSize = *character++; - - /* Is this a compression pointer or a count. */ - if (labelSize <= NX_MDNS_LABEL_MAX) - { - - /* Simple count, check for space and copy the label. */ - while ((size > length) && (labelSize > 0)) - { - - *buffer++ = *character++; - length++; - labelSize--; - } - - /* Now add the '.' */ - *buffer++ = '.'; - length++; - } - else if ((labelSize & NX_MDNS_COMPRESS_MASK) == NX_MDNS_COMPRESS_VALUE) - { - - /* This is a pointer, just adjust the source. */ - character = data + ((labelSize & NX_MDNS_LABEL_MAX) << 8) + *character; - } - else - { - - /* Not defined, just fail */ - return(0); - } - } - - /* Done copying the data, set the last . to a trailing null */ - if (*(buffer - 1) == '.') - { - - buffer--; - length --; - } - - /* Null terminate name. */ - *buffer = '\0'; - - /* Return name size. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_rr_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the size of resource record. */ -/* */ -/* INPUT */ -/* */ -/* resource Pointer to the resource */ -/* */ -/* OUTPUT */ -/* */ -/* size of data */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_mdns_rr_size_get(UCHAR *resource) -{ - -UINT name_size; -UINT data_size; - - /* Resource size is - name size + data size + 2 bytes for type, 2 for class, 4 for time to live and 2 for data length - i.e. name size + data size + 10 bytes overhead. - */ - name_size = _nx_mdns_name_size_calculate(resource); - data_size = NX_MDNS_GET_USHORT_DATA(resource + name_size + 8); - - /* Return resource size. */ - return(name_size + data_size + 10); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_short_to_network_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an unsigned short to network byte order, */ -/* which is big endian. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to the destination */ -/* value Source value */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* DNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static void _nx_mdns_short_to_network_convert(UCHAR *ptr, USHORT value) -{ - - *ptr++ = (UCHAR)(value >> 8); - *ptr = (UCHAR)value; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_mdns_long_to_network_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an unsigned long to network format, which */ -/* big endian. */ -/* */ -/* INPUT */ -/* */ -/* ptr Pointer to the destination */ -/* value Source value */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* DNS component */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static void _nx_mdns_long_to_network_convert(UCHAR *ptr, ULONG value) -{ - - *ptr++ = (UCHAR)(value >> 24); - *ptr++ = (UCHAR)(value >> 16); - *ptr++ = (UCHAR)(value >> 8); - *ptr = (UCHAR)value; -} diff --git a/protocol_handlers/mdns/nxd_mdns.h b/protocol_handlers/mdns/nxd_mdns.h deleted file mode 100644 index 41eaf2f1..00000000 --- a/protocol_handlers/mdns/nxd_mdns.h +++ /dev/null @@ -1,1316 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Multicast Domain Name System (mDNS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_mdns.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Multicast Domain Name System (mDNS) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_MDNS_H -#define NXD_MDNS_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - - - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_api.h" -#include "nx_udp.h" -#include "nx_ip.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_ipv6.h" -#endif /* FEATURE_NX_IPV6 */ - - -/* Define the Multicast DNS ID. */ -#define NX_MDNS_ID 0x4d444e53UL - -/* Define macros that get the data on unaligned address. */ -#define NX_MDNS_GET_USHORT_DATA(data) (USHORT)((*(data) << 8) | (*(data + 1))) -#define NX_MDNS_GET_ULONG_DATA(data) (ULONG)((*(data) << 24) | (*(data + 1) << 16) | (*(data + 2) << 8) | (*(data + 3))) - -/* Disable the mDNS Server functionality. By default mDNS server - function is enabled. To remove the mDNS server function from - the mDNS library, uncomment the following line. */ -/* -#define NX_MDNS_DISABLE_SERVER -*/ - -/* Disable the mDNS Client functionality. By default mDNS client - function is enabled. To remove the mDNS client function from - the mDNS library, uncomment the following line. */ -/* -#define NX_MDNS_DISABLE_CLIENT -*/ - -/* Enable the feature to check the address and port of mDNS message. - By default is enabled. To remove it from the mDNS library, - comment the following line. */ -#define NX_MDNS_ENABLE_ADDRESS_CHECK - -/* Enable the Passive Observation Of Failures feature for Client. - By default is enabled. To remove it from the mDNS library, - comment the following line. - Note: This will have no effect if NX_MDNS_DISABLE_CLIENT is defined. */ -#define NX_MDNS_ENABLE_CLIENT_POOF - -/* Enable the feature for Server to generate the Negative Responses. - By default is enabled. To remove it from the mDNS library, - comment the following line. - Note: This will have no effect if NX_MDNS_DISABLE_SERVER is defined. */ -#define NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - - -/* Enable mDNS IPv6 feature, send/process mDNS message over IPv6 address. - By default mDNS IPv6 function is disabled. To enable this feature, - uncomment the following line. */ -/* -#define NX_MDNS_ENABLE_IPV6 -*/ - -#ifdef NX_MDNS_ENABLE_IPV6 - -#ifndef FEATURE_NX_IPV6 -#error "mDNS IPv6 is not supported if IPv6 is not enabled." -#endif /* FEATURE_NX_IPV6 */ - -#ifndef NX_IPV6_MULTICAST_ENABLE -#error "mDNS IPv6 is not supported if IPv6 multicast is not enabled." -#endif /* NX_IPV6_MULTICAST_ENABLE */ - -#ifndef NX_MDNS_DISABLE_SERVER -#ifndef NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY -#error "mDNS IPv6 is not supported if IPv6 address change notify is not enabled." -#endif /* NX_ENABLE_IPV6_ADDRESS_CHANGE_NOTIFY */ -#endif /* NX_MDNS_DISABLE_SERVER */ - -#endif /* NX_MDNS_ENABLE_IPV6 */ - - -/* Define the IPV6 address count of the host name. */ -#ifndef NX_MDNS_IPV6_ADDRESS_COUNT -#define NX_MDNS_IPV6_ADDRESS_COUNT 2 -#endif /* NX_MDNS_IPV6_ADDRESS_COUNT */ - - -/* Define message and name limits. */ -#define NX_MDNS_TYPE_MAX 21 /* Maximum Type size, ._tcp, may be up to 15 bytes, - plus the underscore and length byte. Including the "_udp" or "_tcp". */ -#define NX_MDNS_LABEL_MAX 63 /* Maximum Label (between two dots) size */ -#define NX_MDNS_NAME_MAX 255 /* Maximum Name size */ -#define NX_MDNS_IP_LOOKUP_SIZE 75 /* IPv6 needs 66 characters for the address plus 8 for the ip6.arpa plus null */ - /* IPv4 needs 12 characters max for the address plus 12 for the IN-ADDR.ARPA plus null */ - - -/* Define the mDNS's host name cache size. Keep four-byte alignment. */ -/* Note: The real host name size plus conflict size (4) - must not exceed NX_MDNS_LABEL_MAX and NX_MDNS_HOST_NAME_MAX. - such as: - the real host name: "NETX-MDNS-HOST" - the conflict name: " (2)" - the final name: "NETX-MDNS-HOST (2)". */ -#ifndef NX_MDNS_HOST_NAME_MAX -#define NX_MDNS_HOST_NAME_MAX 64 -#endif /* NX_MDNS_HOST_NAME_MAX */ - - -/* Define the mDNS's service name cache size. Keep four-byte alignment. */ -/* Note: The real service name size plus conflict size (4) - must not exceed NX_MDNS_LABEL_MAX and NX_MDNS_SERVICE_NAME_MAX. - such as: - the real service name: "NETX-MDNS-SERVICE" - the conflict name: " (2)" - the final service name: "NETX-MDNS-SERVICE (2)". */ -#ifndef NX_MDNS_SERVICE_NAME_MAX -#define NX_MDNS_SERVICE_NAME_MAX 64 -#endif /* NX_MDNS_SERVICE_NAME_MAX */ - - -/* Define the mDNS's domain name max size. */ -#ifndef NX_MDNS_DOMAIN_NAME_MAX -#define NX_MDNS_DOMAIN_NAME_MAX 16 -#endif /* NX_MDNS_DOMAIN_NAME_MAX */ - -/* NX_MDNS_DOMAIN_NAME_MAX must be at leat 5 bytes to hold "local". */ -#if (NX_MDNS_DOMAIN_NAME_MAX < 5) -#error "NX_MDNS_DOMAIN_NAME_MAX must be at least 5 bytes!" -#endif /* (NX_MDNS_DOMAIN_NAME_MAX < 5) */ - - -/* Define the conflict count of service name or host name. */ -/* Note: the confilict count should be less than 8, since we just append " (x)" - between " (2)" and " (9)" during the conflict resolution process. */ -#ifndef NX_MDNS_CONFLICT_COUNT -#define NX_MDNS_CONFLICT_COUNT 8 -#endif/* NX_MDNS_CONFLICT_COUNT */ - - -/* Define the DNS-SD buffer size for storing "_services._dns-sd._udp.local" */ -/* Note: the domain can be updated, so the max size should be NX_MDNS_DOMAIN_NAME_MAX + 23. - "_services._dns-sd._udp." (23) + NX_MDNS_DOMAIN_NAME_MAX. */ -#define NX_MDNS_DNS_SD_MAX (NX_MDNS_DOMAIN_NAME_MAX + 23) - - -/* Define mDNS Multicast Address. */ -#define NX_MDNS_IPV4_MULTICAST_ADDRESS (IP_ADDRESS(224,0,0,251)) - - -/* Define mDNS port. */ -#define NX_MDNS_UDP_PORT 5353 - - -/* Define UDP socket create options. */ -#ifndef NX_MDNS_UDP_TYPE_OF_SERVICE -#define NX_MDNS_UDP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif /* NX_MDNS_UDP_TYPE_OF_SERVICE */ - -#ifndef NX_MDNS_UDP_FRAGMENT_OPTION -#define NX_MDNS_UDP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif /* NX_MDNS_UDP_FRAGMENT_OPTION */ - -#ifndef NX_MDNS_UDP_TIME_TO_LIVE -#define NX_MDNS_UDP_TIME_TO_LIVE 0xFF -#endif /* NX_MDNS_UDP_TIME_TO_LIVE */ - -#ifndef NX_MDNS_UDP_QUEUE_DEPTH -#define NX_MDNS_UDP_QUEUE_DEPTH 4 -#endif /* NX_MDNS_UDP_QUEUE_DEPTH */ - - -/* Define the resource record TTL. In second. */ -/* The recommended TTL value for Multicast DNS resource records with a host name as the resource record's name - (e.g., A, AAAA, HINFO) or a host name contaned within the resource record's rdata (e.g., SRV, reverse mapping PTR record) - should be 120 seconds. The recommended TTL value for other Multicast DNS resource records is 75 minutes. - RFC6762, Section10, Page33. */ -#ifndef NX_MDNS_RR_TTL_HOST -#define NX_MDNS_RR_TTL_HOST 120 -#endif /* NX_MDNS_RR_TTL_HOST */ - -#ifndef NX_MDNS_RR_TTL_OTHER -#define NX_MDNS_RR_TTL_OTHER 4500 /* 75 minutes. */ -#endif /* NX_MDNS_RR_TTL_OTHER */ - - -/* Define the mDNS's probing timer interval, default 250ms in spec. In tick. - should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ -#ifndef NX_MDNS_PROBING_TIMER_COUNT -#define NX_MDNS_PROBING_TIMER_COUNT 25 -#endif /* NX_MDNS_PROBING_TIMER_COUNT */ - - -/* Define the mDNS's announcing timer interval, default 250ms in spec. In tick. - should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ -#ifndef NX_MDNS_ANNOUNCING_TIMER_COUNT -#define NX_MDNS_ANNOUNCING_TIMER_COUNT 25 -#endif /* NX_MDNS_ANNOUNCING_TIMER_COUNT */ - - -/* Define the mDNS's goodbye timer interval, default 250ms in spec. In tick. - should be:250 * NX_IP_PERIODIC_RATE /1000 = 250 * 100 /1000 = 25. */ -#ifndef NX_MDNS_GOODBYE_TIMER_COUNT -#define NX_MDNS_GOODBYE_TIMER_COUNT 25 -#endif /* NX_MDNS_GOODBYE_TIMER_COUNT */ - - -/* Define the mDNS's min query timer interval between two queries, 1 second. In tick. */ -#ifndef NX_MDNS_QUERY_MIN_TIMER_COUNT -#define NX_MDNS_QUERY_MIN_TIMER_COUNT NX_IP_PERIODIC_RATE -#endif /* NX_MDNS_QUERY_MIN_TIMER_COUNT */ - - -/* Define the mDNS's max query timer interval between first two queries, 60 minutes. In tick. */ -#ifndef NX_MDNS_QUERY_MAX_TIMER_COUNT -#define NX_MDNS_QUERY_MAX_TIMER_COUNT (3600 * NX_IP_PERIODIC_RATE) -#endif /* NX_MDNS_QUERY_MAX_TIMER_COUNT */ - - -/* Define the mDNS's query delay timer interval, 20-120ms. In tick. */ -#ifndef NX_MDNS_QUERY_DELAY_MIN -#define NX_MDNS_QUERY_DELAY_MIN 2 -#endif /* NX_MDNS_QUERY_DELAY_MIN */ - -#ifndef NX_MDNS_QUERY_DELAY_RANGE -#define NX_MDNS_QUERY_DELAY_RANGE 10 -#endif /* NX_MDNS_QUERY_DELAY_RANGE */ - - -/* Define the mDNS's response delay time interval for multicast query. */ -/* The time interval, in ticks, in responding to a query to ensure an interval of at least 1s - since the last time the record was multicast. The default value is 100 ticks. */ -#ifndef NX_MDNS_RESPONSE_INTERVAL -#define NX_MDNS_RESPONSE_INTERVAL NX_IP_PERIODIC_RATE -#endif /* NX_MDNS_RESPONSE_INTERVAL */ - - -/* Define the mDNS's response delay time interval for probe message. */ -/* The time interval, in ticks, in responding to a probe queries to ensure an interval of - at least 250ms since the last time the record was multicast. The default value is 25 ticks. */ -#ifndef NX_MDNS_RESPONSE_PROBING_TIMER_COUNT -#define NX_MDNS_RESPONSE_PROBING_TIMER_COUNT 25 -#endif /* NX_MDNS_RESPONSE_PROBING_TIMER_COUNT */ - - -/* Define the mDNS's response delay time interval for unicast query, 10 ms. In tick. */ -#ifndef NX_MDNS_RESPONSE_UNIQUE_DELAY -#define NX_MDNS_RESPONSE_UNIQUE_DELAY 1 -#endif /* NX_MDNS_RESPONSE_UNIQUE_DELAY */ - - -/* Define the mDNS's response delay time interval for shared message, 20-120ms. In tick. */ -#ifndef NX_MDNS_RESPONSE_SHARED_DELAY_MIN -#define NX_MDNS_RESPONSE_SHARED_DELAY_MIN 2 -#endif /* NX_MDNS_RESPONSE_SHARED_DELAY_MIN */ - -#ifndef NX_MDNS_RESPONSE_SHARED_DELAY_RANGE -#define NX_MDNS_RESPONSE_SHARED_DELAY_RANGE 10 -#endif /* NX_MDNS_RESPONSE_SHARED_DELAY_RANGE */ - - -/* Define the mDNS's response delay time interval for query with TC, 400-500 ms. In tick. */ -#ifndef NX_MDNS_RESPONSE_TC_DELAY_MIN -#define NX_MDNS_RESPONSE_TC_DELAY_MIN 40 -#endif /* NX_MDNS_RESPONSE_TC_DELAY_MIN */ - -#ifndef NX_MDNS_RESPONSE_TC_DELAY_RANGE -#define NX_MDNS_RESPONSE_TC_DELAY_RANGE 10 -#endif /* NX_MDNS_RESPONSE_TC_DELAY_RANGE */ - - -/* Define the mDNS's random delay timer count, 120 ms. In tick. */ -/* This value allows a response to include messages that would be sent within - the next 120ms range. */ -#ifndef NX_MDNS_TIMER_COUNT_RANGE -#define NX_MDNS_TIMER_COUNT_RANGE 12 -#endif /* NX_MDNS_TIMER_COUNT_RANGE */ - - -/* Define the mDNS's probing retransmit count. The defaul value is 3. */ -#ifndef NX_MDNS_PROBING_RETRANSMIT_COUNT -#define NX_MDNS_PROBING_RETRANSMIT_COUNT 3 -#endif /* NX_MDNS_PROBING_RETRANSMIT_COUNT */ - - -/* Define the mDNS's goodbye retransmit count. The defaul value is 1. */ -#ifndef NX_MDNS_GOODBYE_RETRANSMIT_COUNT -#define NX_MDNS_GOODBYE_RETRANSMIT_COUNT 1 -#endif /* NX_MDNS_GOODBYE_RETRANSMIT_COUNT */ - - -/* Passive Observation Of Failures. - If a host sees queries, for which a record in its cache would be - expected to be given as an answer in a multicast response, but no - such answer is seen, then the host may take this as an indication - that the record may no longer be valid. - After seesing NX_MDNS_POOF_MIN_COUNT of these queries, and seeing - no multicast response containing the expected answer with in - NX_MDNS_POOF_TIMER_COUNT, delete the RR from the cache. - RFC6762, Section10.5, Page38. */ - -/* Define the Passive Observation Of Failures min count. The defaul value is 2. */ -#ifndef NX_MDNS_POOF_MIN_COUNT -#define NX_MDNS_POOF_MIN_COUNT 2 -#endif /* NX_MDNS_POOF_MIN_COUNT */ - -/* Define the Passive Observation Of Failures timer count, 10 seconds in spec. In tick. */ -#ifndef NX_MDNS_POOF_TIMER_COUNT -#define NX_MDNS_POOF_TIMER_COUNT (10 * NX_IP_PERIODIC_RATE) -#endif /* NX_MDNS_POOF_TIMER_COUNT */ - - -/* Define the RR delete delay timer. */ -/* Queriers receiving a Multicast DNS response with a TTL of zero SHOULD - NOT immediately delete the record from the cache, but instead record - a TTL of 1 and then delete the record one second later. In tick. */ -#ifndef NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT -#define NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT NX_IP_PERIODIC_RATE -#endif /* NX_MDNS_RR_DELETE_DELAY_TIMER_COUNT */ - - -/* Define the default mDNS's announcing value. */ -#define NX_MDNS_ANNOUNCING_PERIOD NX_IP_PERIODIC_RATE -#define NX_MDNS_ANNOUNCING_COUNT 1 -#define NX_MDNS_ANNOUNCING_FACTOR 1 -#define NX_MDNS_ANNOUNCING_RETRANS_INTERVAL 0 -#define NX_MDNS_ANNOUNCING_PERIOD_INTERVAL 0xFFFFFFFF -#define NX_MDNS_ANNOUNCING_MAX_TIME 3 -#define NX_MDNS_ANNOUNCING_FOREVER 0xFF - - -/* Define the max ttl. In second. */ -#define NX_MDNS_RR_MAX_TTL 0xFFFFFFFF/NX_IP_PERIODIC_RATE - - -/* Define the RR update retransmit count. - The querier should plan to issure a query at 80%, 85%, 90%, 95% of the record lifetime. */ -#define NX_MDNS_RR_UPDATE_COUNT 4 - - -/* Define the Address length. */ -#define NX_MDNS_IPV4_ADDRESS_LENGTH 4 -#define NX_MDNS_IPV6_ADDRESS_LENGTH 16 - - -/* Define mDNS event flags. */ -#define NX_MDNS_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags. */ -#define NX_MDNS_PKT_RX_EVENT ((ULONG) 0x00000001) /* Receive the mDNS packet. */ -#define NX_MDNS_QUERY_SEND_EVENT ((ULONG) 0x00000002) /* Send the mDNS Query packet. */ -#define NX_MDNS_RESPONSE_SEND_EVENT ((ULONG) 0x00000004) /* Send the mDNS Response packet. */ -#define NX_MDNS_PROBING_SEND_EVENT ((ULONG) 0x00000008) /* Send the mDNS Probing packet. */ -#define NX_MDNS_ANNOUNCING_SEND_EVENT ((ULONG) 0x00000010) /* Send the mDNS Announcing packet. */ -#define NX_MDNS_GOODBYE_SEND_EVENT ((ULONG) 0x00000020) /* Send the mDNS Goodbye packet. */ -#define NX_MDNS_TIMER_EVENT ((ULONG) 0x00000040) /* Process the mDNS timer event. */ -#define NX_MDNS_ADDRESS_CHANGE_EVENT ((ULONG) 0x00000080) /* Process the mDNS address change event. */ -#define NX_MDNS_RR_ELAPSED_TIMER_EVENT ((ULONG) 0x00000100) /* Process the mDNS rr elapsed tiemr event. */ - - -/* Define return code constants. */ -#define NX_MDNS_SUCCESS 0x00 /* mDNS Success. */ -#define NX_MDNS_ERROR 0xA1 /* mDNS internal error. */ -#define NX_MDNS_PARAM_ERROR 0xA2 /* mDNS parameters error. */ -#define NX_MDNS_CACHE_ERROR 0xA3 /* The Cache size is not enough. */ -#define NX_MDNS_UNSUPPORTED_TYPE 0xA4 /* The unsupported resource record type. */ -#define NX_MDNS_DATA_SIZE_ERROR 0xA5 /* The data size is too big. */ -#define NX_MDNS_AUTH_ERROR 0xA6 /* Attempting to parse too large a data. */ -#define NX_MDNS_PACKET_ERROR 0xA7 /* The packet can not add the resource record. */ -#define NX_MDNS_DEST_ADDRESS_ERROR 0xA9 /* The destination address error. */ -#define NX_MDNS_UDP_PORT_ERROR 0xB0 /* The udp port error. */ -#define NX_MDNS_NOT_LOCAL_LINK 0xB1 /* The message that not originate from the local link. */ -#define NX_MDNS_EXCEED_MAX_LABEL 0xB2 /* The data exceed the max laber size. */ -#define NX_MDNS_EXIST_UNIQUE_RR 0xB3 /* At least one Unqiue record in the cache. */ -#define NX_MDNS_EXIST_SHARED_RR 0xB4 /* At least one shared record in the cache. */ -#define NX_MDNS_EXIST_SAME_QUERY 0xB5 /* Exist the same query record in the cache. */ -#define NX_MDNS_EXIST_SAME_SERVICE 0xB6 /* Exist the same service. */ -#define NX_MDNS_NO_RR 0xB7 /* No response for one-shot query. */ -#define NX_MDNS_NO_KNOWN_ANSWER 0xB8 /* No known answer for query. */ -#define NX_MDNS_NAME_MISMATCH 0xB9 /* The name mismatch. */ -#define NX_MDNS_NOT_STARTED 0xC0 /* mDNS does not start. */ -#define NX_MDNS_HOST_NAME_ERROR 0xC1 /* mDNS host name error. */ -#define NX_MDNS_NO_MORE_ENTRIES 0xC2 /* No more entries be found. */ -#define NX_MDNS_SERVICE_TYPE_MISMATCH 0xC3 /* The service type mismatch */ -#define NX_MDNS_NOT_ENABLED 0xC4 /* mDNS does not enable. */ -#define NX_MDNS_ALREADY_ENABLED 0xC5 /* mDNS already enabled. */ - - -/* Define the local host/service register notify state. */ -#define NX_MDNS_LOCAL_HOST_REGISTERED_SUCCESS 1 /* mDNS Server: Local host registered success. */ -#define NX_MDNS_LOCAL_HOST_REGISTERED_FAILURE 2 /* mDNS Server: Local host registered failure. */ -#define NX_MDNS_LOCAL_SERVICE_REGISTERED_SUCCESS 3 /* mDNS Server: Local service registered success. */ -#define NX_MDNS_LOCAL_SERVICE_REGISTERED_FAILURE 4 /* mDNS Server: Local service registered failure. */ - -/* Define the peer service change notify state. */ -#define NX_MDNS_PEER_SERVICE_RECEIVED 1 /* mDNS Client: Peer service received. */ -#define NX_MDNS_PEER_SERVICE_DELETED 2 /* mDNS Client: Peer service deleted. */ -#define NX_MDNS_PEER_SERVICE_UPDATED 3 /* mDNS Client: Peer service address updated. */ - -/* Define the cache notify state. */ -#define NX_MDNS_CACHE_STATE_FULL 1 /* mDNS Cache is full, and cannot fill the RR. */ -#define NX_MDNS_CACHE_STATE_FRAGMENTED 2 /* mDNS Cache is fragmented, and cannot fill the RR. */ - -/* Define cache type. */ -#define NX_MDNS_CACHE_TYPE_LOCAL 0 /* Local cache. */ -#define NX_MDNS_CACHE_TYPE_PEER 1 /* Peer cache. */ - - -/* Define offsets into the DNS message buffer. */ -#define NX_MDNS_ID_OFFSET 0 /* Offset to ID code in DNS buffer */ -#define NX_MDNS_FLAGS_OFFSET 2 /* Offset to flags in DNS buffer */ -#define NX_MDNS_QDCOUNT_OFFSET 4 /* Offset to Question Count in DNS buffer */ -#define NX_MDNS_ANCOUNT_OFFSET 6 /* Offset to Answer Count in DNS buffer */ -#define NX_MDNS_NSCOUNT_OFFSET 8 /* Offset to Authority Count in DNS buffer */ -#define NX_MDNS_ARCOUNT_OFFSET 10 /* Offset to Additional Info. Count in DNS buffer */ -#define NX_MDNS_QDSECT_OFFSET 12 /* Offset to Question Section in DNS buffer */ - - -/* Define constants for the flags word. */ -#define NX_MDNS_QUERY_MASK 0x0000 -#define NX_MDNS_QUERY_FLAG 0x0000 -#define NX_MDNS_RESPONSE_FLAG 0x8000 -#define NX_MDNS_ERROR_MASK 0x000F -#define NX_MDNS_TOP_BIT_MASK 0x7FFF - -#define NX_MDNS_OPCODE_QUERY (0 << 12) /* Shifted right 12 is still 0 */ -#define NX_MDNS_OPCODE_IQUERY (1 << 12) /* 1 shifted right by 12 */ -#define NX_MDNS_OPCODE_STATUS (2 << 12) /* 2 shifted right by 12 */ - -#define NX_MDNS_AA_FLAG 0x0400 /* Authoritative Answer */ -#define NX_MDNS_TC_FLAG 0x0200 /* Truncated */ -#define NX_MDNS_RD_FLAG 0x0100 /* Recursive Query */ -#define NX_MDNS_RA_FLAG 0x0080 /* Recursion Available */ -#define NX_MDNS_FA_FLAG 0x0010 /* Force Authentication */ - -/* Define name compression masks. */ -#define NX_MDNS_COMPRESS_MASK 0xc0 -#define NX_MDNS_COMPRESS_VALUE 0xc0 -#define NX_MDNS_POINTER_MASK 0xc000 - -/* Define resource record types. */ -#define NX_MDNS_RR_TYPE_A 1 /* Host address */ -#define NX_MDNS_RR_TYPE_NS 2 /* Authoritative name server */ -#define NX_MDNS_RR_TYPE_MD 3 /* Mail destination (Obsolete - use MX) */ -#define NX_MDNS_RR_TYPE_MF 4 /* Mail forwarder (Obsolete - use MX) */ -#define NX_MDNS_RR_TYPE_CNAME 5 /* Canonical name for an alias */ -#define NX_MDNS_RR_TYPE_SOA 6 /* Marks the start of a zone of authority */ -#define NX_MDNS_RR_TYPE_MB 7 /* Mailbox domain name (EXPERIMENTAL) */ -#define NX_MDNS_RR_TYPE_MG 8 /* Mail group member (EXPERIMENTAL) */ -#define NX_MDNS_RR_TYPE_MR 9 /* Mail rename domain name (EXPERIMENTAL) */ -#define NX_MDNS_RR_TYPE_NULL 10 /* Null RR (EXPERIMENTAL) */ -#define NX_MDNS_RR_TYPE_WKS 11 /* Well known service description */ -#define NX_MDNS_RR_TYPE_PTR 12 /* Domain name pointer */ -#define NX_MDNS_RR_TYPE_HINFO 13 /* Host information */ -#define NX_MDNS_RR_TYPE_MINFO 14 /* Mailbox or mail list information */ -#define NX_MDNS_RR_TYPE_MX 15 /* Mail exchange */ -#define NX_MDNS_RR_TYPE_TXT 16 /* Text strings */ -#define NX_MDNS_RR_TYPE_AAAA 28 /* IPv6 Host address */ -#define NX_MDNS_RR_TYPE_SRV 33 /* The location of services */ -#define NX_MDNS_RR_TYPE_NSEC 47 /* The type of NSEC RR. */ - - -/* Define constants for Qtypes (queries). */ -#define NX_MDNS_RR_TYPE_AXFR 252 /* Request for a transfer of an entire zone */ -#define NX_MDNS_RR_TYPE_MAILB 253 /* Request for mailbox-related records (MB, MG or MR) */ -#define NX_MDNS_RR_TYPE_MAILA 254 /* Request for mail agent RRs (Obsolete - see MX) */ -#define NX_MDNS_RR_TYPE_ALL 255 /* Request for all records */ - - -/* Define resource record classes. */ -#define NX_MDNS_RR_CLASS_IN 1 /* Internet */ -#define NX_MDNS_RR_CLASS_CS 2 /* CSNET class (Obsolete) */ -#define NX_MDNS_RR_CLASS_CH 3 /* CHAOS class */ -#define NX_MDNS_RR_CLASS_HS 4 /* Hesiod [Dyer 87] */ -#define NX_MDNS_RR_CLASS_ALL 255 /* Any class */ -#define NX_MDNS_RR_CLASS_TOP_BIT 0x8000 /* The top bit of class. */ - - -/* Define the resource record state value. */ -#define NX_MDNS_RR_STATE_INVALID 0 /* Invalid resource records. */ -#define NX_MDNS_RR_STATE_PROBING 1 /* mDNS Server probing the resource records. */ -#define NX_MDNS_RR_STATE_ANNOUNCING 2 /* mDNS Server announcing the resource records. */ -#define NX_MDNS_RR_STATE_GOODBYE 3 /* mDNS Server send the Goodbye. */ -#define NX_MDNS_RR_STATE_SUSPEND 4 /* mDNS Server suspend the resource record. */ -#define NX_MDNS_RR_STATE_QUERY 5 /* mDNS Client send the initial query. */ -#define NX_MDNS_RR_STATE_UPDATING 6 /* mDNS Client send the query to update the RR. */ -#define NX_MDNS_RR_STATE_DELETE 7 /* mDNS Client delete the resource records. */ -#define NX_MDNS_RR_STATE_POOF_DELETE 8 /* mDNS Client delete the resource records by Passive Observation Of Failures.*/ -#define NX_MDNS_RR_STATE_VALID 9 /* Valid resource records. */ - - -/* Define the sending type of resource records. */ -#define NX_MDNS_RR_SEND_FLAG_CLEAR 0x00 /* Response should not send the Resource records. */ -#define NX_MDNS_RR_SEND_MULTICAST 0x01 /* Send the Resource records via multicast. */ -#define NX_MDNS_RR_SEND_UNICAST 0x02 /* Send the Resource records via unicast. */ -#define NX_MDNS_RR_SEND_FLAG_MASK 0xF0 /* The mask of send flag. */ - - -/* Define resource record owner. */ -#define NX_MDNS_RR_OWNER_LOCAL 0 /* Local Resource records. */ -#define NX_MDNS_RR_OWNER_REMOTE 1 /* Remote Resource records. */ - - -/* Define resource record set. */ -#define NX_MDNS_RR_SET_SHARED 0 /* Shared Resource records. */ -#define NX_MDNS_RR_SET_UNIQUE 1 /* Unique Resource records. */ - - -/* Define the resource record state mask. */ -#define NX_MDNS_RR_FLAG_PEER 0x0001 /* RR owner flag. */ -#define NX_MDNS_RR_FLAG_UNIQUE 0x0002 /* RR set flag. */ -#define NX_MDNS_RR_FLAG_CONTINUOUS_QUERY 0x0004 /* RR query type flag. */ -#define NX_MDNS_RR_FLAG_DUPLICATE_QUERY 0x0008 /* RR duplicate query flag. */ -#define NX_MDNS_RR_FLAG_ADDITIONAL 0x0010 /* RR additional flag. */ -#define NX_MDNS_RR_FLAG_UPDATING 0x0020 /* RR updating flag. */ -#define NX_MDNS_RR_FLAG_DELETE 0x0040 /* RR delete flag. */ -#define NX_MDNS_RR_FLAG_ANSWER 0x0080 /* RR answer flag. */ -#define NX_MDNS_RR_FLAG_KNOWN_ANSWER 0x0100 /* RR known answer flag. */ -#define NX_MDNS_RR_FLAG_AUTHORIY_ANSWER 0x0200 /* RR authority answer flag. */ - - -/* Define the type to search the same resource record. */ -#define NX_MDNS_RR_MATCH_ALL 1 /* Match all data: name, type, class, rdata. */ -#define NX_MDNS_RR_MATCH_EXCEPT_RDATA 2 /* Match the name, type, class, except rdata. */ - - -/* Define the type to set/add the resource record in cache from packet. */ -#define NX_MDNS_RR_OP_LOCAL_SET_QUESTION 0 /* Set resource record question in local cache. */ -#define NX_MDNS_RR_OP_LOCAL_SET_ANSWER 1 /* Set resource record answer in local cache. */ -#define NX_MDNS_RR_OP_PEER_SET_QUESTION 2 /* Set resource record question in peer cache. */ -#define NX_MDNS_RR_OP_PEER_ADD_ANSWER 3 /* Add resource record answer in peer cache. */ - - -/* Define the type for adding question/answer RR into the packet. */ -#define NX_MDNS_PACKET_ADD_RR_QUESTION 1 /* Add the question resource record into packet. */ -#define NX_MDNS_PACKET_ADD_RR_ANSWER 2 /* Add the answer resource record into packet. */ - - -/* Define mDNS packet type. */ -#define NX_MDNS_PACKET_QUERY 1 /* Query packet. */ -#define NX_MDNS_PACKET_PROBING 2 /* Probing packet. Is specific query. */ -#define NX_MDNS_PACKET_RESPONSE 3 /* Response packet. */ - - -/* Define the Add NSEC type. */ -#define NX_MDNS_ADD_NSEC_FOR_HOST 0 /* Add the NSEC for host name. */ -#define NX_MDNS_ADD_NSEC_FOR_SERVICE 1 /* Add the NSEC for service. */ - - -/* Define the RDATA structure. */ - -/* A RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | ADDRESS | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_A_STRUCT -{ - ULONG nx_mdns_rr_a_address; -} NX_MDNS_RR_A; - - -/* NS RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / NSDNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_NS_STRUCT -{ - UCHAR* nx_mdns_rr_ns_name; -} NX_MDNS_RR_NS; - -/* MD RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MADNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MD_STRUCT -{ - UCHAR* nx_mdns_rr_md_name; -} NX_MDNS_RR_MD; - -/* MF RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MADNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MF_STRUCT -{ - UCHAR* nx_mdns_rr_mf_name; -} NX_MDNS_RR_MF; - -/* CNMAE RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / CNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_CNAME_STRUCT -{ - UCHAR* nx_mdns_rr_cname_name; -} NX_MDNS_RR_CNAME; - -/* SOA RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / RNAME / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | SERIAL | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | REFRESH | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | RETRY | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | EXPIRE | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | MINMUM | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_SOA_STRUCT -{ - UCHAR* nx_mdns_rr_soa_mname; - UCHAR* nx_mdns_rr_soa_rname; - ULONG nx_mdns_rr_soa_serial; - ULONG nx_mdns_rr_soa_refresh; - ULONG nx_mdns_rr_soa_retry; - ULONG nx_mdns_rr_soa_expire; - ULONG nx_mdns_rr_soa_minmum; -} NX_MDNS_RR_SOA; - -/* MB RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MADNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MB_STRUCT -{ - UCHAR* nx_mdns_rr_mb_name; -} NX_MDNS_RR_MB; - -/* MG RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / MGMNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MG_STRUCT -{ - UCHAR* nx_mdns_rr_mg_name; -} NX_MDNS_RR_MG; - -/* MR RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / NEWNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MR_STRUCT -{ - UCHAR* nx_mdns_rr_mr_name; -} NX_MDNS_RR_MR; - -/* NULL RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_NULL_STRUCT -{ - UCHAR* nx_mdns_rr_null_ptr; -} NX_MDNS_RR_NULL; - -/* WKS RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | ADDRESS | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PROTOCOL | | - |--+--+--+--+--+--+--+--+ | - / / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_WKS_STRUCT -{ - ULONG nx_mdns_rr_wks_address; - UCHAR nx_mdns_rr_wks_protocol; - UCHAR nx_mdns_rr_wks_reserved[3]; - UCHAR* nx_mdns_rr_wks_bit_map; -} NX_MDNS_RR_WKS; - -/* PTR RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / PTRDNAME / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_PTR_STRUCT -{ - UCHAR* nx_mdns_rr_ptr_name; -} NX_MDNS_RR_PTR; - -/* HINFO RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / CPU / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / OS / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_HINFO_STRUCT -{ - UCHAR* nx_mdns_rr_hinfo_cpu; - UCHAR* nx_mdns_rr_hinfo_os; -} NX_MDNS_RR_HINFO; - -/* MINFO RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / RMAILBX / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / EMAILBX / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MINFO_STRUCT -{ - UCHAR* nx_mdns_rr_minfo_cpu; - UCHAR* nx_mdns_rr_minfo_os; -} NX_MDNS_RR_MINFO; - -/* MX RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PREFERENCE | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / NEWNAME / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_MX_STRUCT -{ - UCHAR* nx_mdns_rr_mx_name; - USHORT nx_mdns_rr_mx_preference; - USHORT nx_mdns_rr_mx_reserved; -} NX_MDNS_RR_MX; - -/* TXT RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / TXT-DATA / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_TXT_STRUCT -{ - UCHAR* nx_mdns_rr_txt_data; -} NX_MDNS_RR_TXT; - -/* AAAA RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | | - | | - | | - | IPv6 ADDRESS | - | | - | | - | | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_AAAA_STRUCT -{ - ULONG nx_mdns_rr_aaaa_address[4]; -} NX_MDNS_RR_AAAA; - -/* SRV RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PRIORITY | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | WEIGHTS | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | PORT | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / TARGET / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_SRV_STRUCT -{ - UCHAR* nx_mdns_rr_srv_target; - USHORT nx_mdns_rr_srv_priority; - USHORT nx_mdns_rr_srv_weights; - USHORT nx_mdns_rr_srv_port; - USHORT nx_mdns_rr_srv_reserved; -} NX_MDNS_RR_SRV; - - -/* NSEC RDATA format - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / Next Domain Name / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / Type Bit Maps / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -typedef struct NX_MDNS_RR_NSEC_STRUCT -{ - UCHAR* nx_mdns_rr_nsec_next_domain; - UCHAR nx_mdns_rr_nsec_window_block; - UCHAR nx_mdns_rr_nsec_bitmap_length; - UCHAR nx_mdns_rr_nsec_bitmap[5]; /* Can match the max rr type 6 * 7 = 42. */ - UCHAR nx_mdns_rr_nsec_additional_send; /* 0 indicate answer, 1 indicate additional. */ -} NX_MDNS_RR_NSEC; - - -/* RR definitions. RFC1035. */ -/* RR Format. - 0 1 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | | - / NAME / - / / - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | TYPE | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | CLASS | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | TTL | - | | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - | RDLENGTH | - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - / RDATA / - / / - |--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| -*/ - -/* The following data structure is used to store the resource records(RRs). */ -typedef struct NX_MDNS_RR_STRUCT -{ - - UCHAR* nx_mdns_rr_name; /* Owner's name,i.e., the name of the node to - which this resource record pertains. */ - - USHORT nx_mdns_rr_type; /* RR TYPE. */ - - USHORT nx_mdns_rr_class; /* RR CLASS. */ - - ULONG nx_mdns_rr_ttl; /* The time interval that the RR may be cached before the source of - the information should again be consulted. */ - - UINT nx_mdns_rr_interface_index; /* RR interface index. */ - - USHORT nx_mdns_rr_rdata_length; /* The length of rdata. nx_mdns_rr_rdata */ - - UCHAR nx_mdns_rr_state; /* The resource records state, Probing, Annoncing, Valid. */ - - UCHAR nx_mdns_rr_retransmit_count; /* Define the count for the retransmit the RR. */ - - ULONG nx_mdns_rr_retransmit_lifetime; /* Define the lifetime for retransmit the RR. */ - - ULONG nx_mdns_rr_timer_count; /* Define the timer count for the retransmit the RR. */ - - ULONG nx_mdns_rr_elapsed_time; /* Define the time elasped for the peer RR. */ - - ULONG nx_mdns_rr_remaining_ticks; /* Define the remaining ticks of the peer RR. */ - - UCHAR nx_mdns_rr_announcing_max_time; /* RR announcing max time. Local RR. */ - - UCHAR nx_mdns_rr_response_interval; /* Define the time interval for two responses. Local RR. */ - - UCHAR nx_mdns_rr_conflict_count; /* The conflict count of service name or host name. Local RR. */ - - UCHAR nx_mdns_rr_poof_count; /* The Passive Observation Of Failures count of resource record. Peer RR.*/ - - UCHAR nx_mdns_rr_count; /* The count of same _services._dns-sd._udp.local PTR resource reocrd. */ - - UCHAR nx_mdns_rr_send_flag; /* The flag for seding resource record. */ - - USHORT nx_mdns_rr_word; - - /* Define the state, owner, flag, set of the resource records. This word contains - the following information: - - bits 0 RR Owner, the owner of resource record, - 0 indicates local RR, 1 indicates peer RR. - bits 1 RR Set, the set of resource record, - 0 indicates shared RR, 1 indicates unique RR. - bits 2 RR query type, the query type of resource record, - 0 indicates query the RR use One-shot method, 1 indicates query the RR use Continuous method. - bits 3 RR additional flag, send this resource record as the additional RR. - bits 4 RR query duplicate flag, this resource record is the duplicate quesiton. - bits 5 RR updating flag, this resource record need to be maintenance. - bits 6 RR delete flag, this resource record need to be deleted. - bits 7 RR answer flag, this resource record has been added in answer section. - bits 8 RR known answer flag, send this resource record as the known answer. - bits 9 RR authority answer flag, send this resource record as the authority answer. - */ - - /* Union that holds resource record data. */ - union nx_mdns_rr_rdata_union - { - NX_MDNS_RR_A nx_mdns_rr_rdata_a; - NX_MDNS_RR_AAAA nx_mdns_rr_rdata_aaaa; - NX_MDNS_RR_PTR nx_mdns_rr_rdata_ptr; - NX_MDNS_RR_SRV nx_mdns_rr_rdata_srv; - NX_MDNS_RR_TXT nx_mdns_rr_rdata_txt; - -#ifdef NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES - NX_MDNS_RR_NSEC nx_mdns_rr_rdata_nsec; -#endif /* NX_MDNS_ENABLE_SERVER_NEGATIVE_RESPONSES */ - -#ifdef NX_MDNS_ENABLE_EXTENDED_RR_TYPES - NX_MDNS_RR_CNAME nx_mdns_rr_rdata_cname; - NX_MDNS_RR_NS nx_mdns_rr_rdata_ns; - NX_MDNS_RR_MX nx_mdns_rr_rdata_mx; -#endif /* NX_MDNS_ENABLE_EXTENDED_RR_TYPES */ - } nx_mdns_rr_rdata; - -}NX_MDNS_RR; - -/* Buffer usage. */ -/* - - |-----------+-----------+-----------+-----------+-----------+------------+-----------+------------+------------| - | HEAD |NX_MDNS_RR |NX_MDNS_RR | ..........| STRING | CNT | LEN | STRING | CNT | LEN | TAIL | - |-----------+-----------+-----------+-----------+-----------+------------+-----------+------------+------------| - - HEAD: First unused memory at the front of cache. The size is 4 bytes. - NX_MDNS_RR: The Resource Record struct, the size is sizeof(NX_MDNS_RR). - TAIL: It points to the last used memory at the back of cache. Its size is 4 bytes. - LEN: It is the length of STRING, plus the CNT and LEN fields. This field takes 2 bytes. - CNT: It is the reference count of STRING. It takes 2 bytes. - STRING: The content of name string and rdata string, must be null-terminated. Padded with 0s to be 4 byte aligned. -*/ - - -/* Define the Service structure. */ -typedef struct NX_MDNS_SERVICE_STRUCT -{ - - UCHAR* service_name; /* Service instance. */ - - UCHAR* service_type; /* Service type. */ - - UCHAR* service_domain; /* Service domain. */ - - UCHAR service_text[NX_MDNS_NAME_MAX+1]; /* Service txt information. */ - - UCHAR service_host[NX_MDNS_HOST_NAME_MAX + 1]; /* The target host of the service. */ - - USHORT service_port; /* Service port. */ - - USHORT service_weight; /* Service weight. */ - - USHORT service_priority; /* Service priority. */ - - UCHAR interface_index; /* Service interface idnex. */ - - UCHAR service_text_valid; /* Flag indicating text fields are valid. */ - - ULONG service_ipv4; /* The IPv4 address for service. */ - - ULONG service_ipv6[NX_MDNS_IPV6_ADDRESS_COUNT][4]; /* The IPv6 address for service.*/ - - UCHAR buffer[NX_MDNS_NAME_MAX+1]; /* The buffer for service instance, type and domain.*/ - -} NX_MDNS_SERVICE; - - -/* Define the basic Multicast DNS data structure. */ - -typedef struct NX_MDNS_STRUCT -{ - ULONG nx_mdns_id; /* Multicast DNS ID. */ - - NX_IP* nx_mdns_ip_ptr; /* Pointer to associated IP structure. */ - - NX_UDP_SOCKET nx_mdns_socket; /* Multicast DNS Socket. */ - - TX_MUTEX nx_mdns_mutex; /* Multicast DNS Mutex. */ - - TX_TIMER nx_mdns_timer; /* Multicast DNS TIMER. */ - - TX_THREAD nx_mdns_thread; /* Multicast DNS processing thread. */ - - TX_EVENT_FLAGS_GROUP nx_mdns_events; /* Multicast DNS event. */ - - NX_PACKET_POOL* nx_mdns_packet_pool_ptr; /* Pointer to the packet pool. */ - - UCHAR nx_mdns_host_name[NX_MDNS_HOST_NAME_MAX]; /* The Embedded Device name supplied at create. */ - - UCHAR nx_mdns_domain_name[NX_MDNS_DOMAIN_NAME_MAX + 1]; /* The mDNS domain name. */ - - UINT nx_mdns_interface_enabled[NX_MAX_PHYSICAL_INTERFACES]; /* Interface enable status. */ - -#ifdef NX_MDNS_ENABLE_IPV6 - UINT nx_mdns_ipv6_address_index[NX_MAX_PHYSICAL_INTERFACES]; /* IPv6 link local address index. */ -#endif /* NX_MDNS_ENABLE_IPV6 */ - - /* Define the UDP receive suspension list head associated with a count of - how many threads are suspended attempting to receive from the same TCP port. */ - TX_THREAD* nx_mdns_rr_receive_suspension_list; /* The suspended thread. */ - - ULONG nx_mdns_rr_receive_suspended_count; /* The suspended count. */ - - UCHAR* nx_mdns_local_service_cache; /* Pointer to the cache. */ - - UINT nx_mdns_local_service_cache_size; /* The size of cache. */ - - UCHAR* nx_mdns_peer_service_cache; /* Pointer to the cache. */ - - UINT nx_mdns_peer_service_cache_size; /* The size of cache. */ - - ULONG nx_mdns_service_ignore_mask; /* The mask specifying services types to be ignored. */ - - ULONG nx_mdns_service_notify_mask; /* The service mask for listen the service and notify the applicaiton. */ - - ULONG nx_mdns_timer_min_count; /* The minimum timer count indicate the intervals between last timer event and next timer event. */ - - USHORT nx_mdns_announcing_period; /* Number of ticks for the initial period. Default value is 1 second. */ - - USHORT nx_mdns_announcing_retrans_interval; /* Number of ticks to wait ticks before sending out repeated announcement message. */ - - ULONG nx_mdns_announcing_period_interval; /* Number of ticks between two announcing period. */ - - UCHAR nx_mdns_announcing_count; /* Number of repetitions between one announcing period. Default value is 1. */ - - UCHAR nx_mdns_announcing_factor; /* Telescopic factor, default value is 0. 2^k. */ - - UCHAR nx_mdns_announcing_max_time; /* Max time of Announcing period, default value is 3. */ - - UCHAR nx_mdns_started; /* mDNS task has been started. */ - - ULONG nx_mdns_local_rr_count; /* The number of resource records in the local cache. */ - - ULONG nx_mdns_local_string_count; /* The number of strings in the local cache. */ - - ULONG nx_mdns_local_string_bytes; /* The number of total bytes in string table in the local cache. */ - - ULONG nx_mdns_peer_rr_count; /* The number of resource records in the peer cache. */ - - ULONG nx_mdns_peer_string_count; /* The number of strings in the peer cache. */ - - ULONG nx_mdns_peer_string_bytes; /* The number of total bytes in string table in the peer cache. */ - - ULONG nx_mdns_first_probing_delay; /* The delay of first probing for unique RR. */ - - VOID (*nx_mdns_probing_notify)(struct NX_MDNS_STRUCT *, UCHAR *, UINT); - - VOID (*nx_mdns_service_change_notify)(struct NX_MDNS_STRUCT *, struct NX_MDNS_SERVICE_STRUCT *, UINT); - - VOID (*nx_mdns_cache_full_notify)(struct NX_MDNS_STRUCT *, UINT, UINT); - -} NX_MDNS; - - -#ifndef NX_MDNS_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map mDNS API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_mdns_create _nx_mdns_create -#define nx_mdns_delete _nx_mdns_delete -#define nx_mdns_enable _nx_mdns_enable -#define nx_mdns_disable _nx_mdns_disable -#define nx_mdns_cache_notify_set _nx_mdns_cache_notify_set -#define nx_mdns_cache_notify_clear _nx_mdns_cache_notify_clear -#define nx_mdns_domain_name_set _nx_mdns_domain_name_set - -#ifndef NX_MDNS_DISABLE_SERVER -#define nx_mdns_service_announcement_timing_set _nx_mdns_service_announcement_timing_set -#define nx_mdns_service_add _nx_mdns_service_add -#define nx_mdns_service_delete _nx_mdns_service_delete -#define nx_mdns_local_cache_clear _nx_mdns_local_cache_clear -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT -#define nx_mdns_service_one_shot_query _nx_mdns_service_one_shot_query -#define nx_mdns_service_continuous_query _nx_mdns_service_continuous_query -#define nx_mdns_service_query_stop _nx_mdns_service_query_stop -#define nx_mdns_service_lookup _nx_mdns_service_lookup -#define nx_mdns_service_ignore_set _nx_mdns_service_ignore_set -#define nx_mdns_service_notify_set _nx_mdns_service_notify_set -#define nx_mdns_service_notify_clear _nx_mdns_service_notify_clear -#define nx_mdns_host_address_get _nx_mdns_host_address_get -#define nx_mdns_peer_cache_clear _nx_mdns_peer_cache_clear -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#else - -#define nx_mdns_create _nxe_mdns_create -#define nx_mdns_delete _nxe_mdns_delete -#define nx_mdns_enable _nxe_mdns_enable -#define nx_mdns_disable _nxe_mdns_disable -#define nx_mdns_cache_notify_set _nxe_mdns_cache_notify_set -#define nx_mdns_cache_notify_clear _nxe_mdns_cache_notify_clear -#define nx_mdns_domain_name_set _nxe_mdns_domain_name_set - -#ifndef NX_MDNS_DISABLE_SERVER -#define nx_mdns_service_announcement_timing_set _nxe_mdns_service_announcement_timing_set -#define nx_mdns_service_add _nxe_mdns_service_add -#define nx_mdns_service_delete _nxe_mdns_service_delete -#define nx_mdns_local_cache_clear _nxe_mdns_local_cache_clear -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT -#define nx_mdns_service_one_shot_query _nxe_mdns_service_one_shot_query -#define nx_mdns_service_continuous_query _nxe_mdns_service_continuous_query -#define nx_mdns_service_query_stop _nxe_mdns_service_query_stop -#define nx_mdns_service_lookup _nxe_mdns_service_lookup -#define nx_mdns_service_ignore_set _nxe_mdns_service_ignore_set -#define nx_mdns_service_notify_set _nxe_mdns_service_notify_set -#define nx_mdns_service_notify_clear _nxe_mdns_service_notify_clear -#define nx_mdns_host_address_get _nxe_mdns_host_address_get -#define nx_mdns_peer_cache_clear _nxe_mdns_peer_cache_clear -#endif /* NX_MDNS_DISABLE_CLIENT */ - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -#endif /* NX_MDNS_SOURCE_CODE */ - - -/* Define Thread function prototypes. */ -UINT _nx_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, - UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, - VOID *local_cache_ptr, UINT local_cache_size, - VOID *peer_cache_ptr, UINT peer_cache_size, - VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)); -UINT _nxe_mdns_create(NX_MDNS *mdns_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool, - UINT priority, VOID *stack_ptr, ULONG stack_size, UCHAR *host_name, - VOID *local_cache_ptr, UINT local_cache_size, - VOID *peer_cache_ptr, UINT peer_cache_size, - VOID (*probing_notify)(NX_MDNS *mdns_ptr, UCHAR *name, UINT probing_state)); -UINT _nx_mdns_delete(NX_MDNS *mdns_ptr); -UINT _nxe_mdns_delete(NX_MDNS *mdns_ptr); -UINT _nx_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index); -UINT _nxe_mdns_enable(NX_MDNS *mdns_ptr, UINT interface_index); -UINT _nx_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index); -UINT _nxe_mdns_disable(NX_MDNS *mdns_ptr, UINT interface_index); -UINT _nx_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT state, UINT cache_type)); -UINT _nxe_mdns_cache_notify_set(NX_MDNS *mdns_ptr, VOID (*cache_full_notify_cb)(NX_MDNS *mdns_ptr, UINT state, UINT cache_type)); -UINT _nx_mdns_cache_notify_clear(NX_MDNS *mdns_ptr); -UINT _nxe_mdns_cache_notify_clear(NX_MDNS *mdns_ptr); -UINT _nx_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name); -UINT _nxe_mdns_domain_name_set(NX_MDNS *mdns_ptr, UCHAR *domain_name); - -#ifndef NX_MDNS_DISABLE_SERVER -UINT _nx_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time); -UINT _nxe_mdns_service_announcement_timing_set(NX_MDNS *mdns_ptr, UINT t, UINT p, UINT k, UINT retrans_interval, ULONG period_interval, UINT max_time); -UINT _nx_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, - USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index); -UINT _nxe_mdns_service_add(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UCHAR *txt, ULONG ttl, - USHORT priority, USHORT weights, USHORT port, UCHAR is_unique, UINT interface_index); -UINT _nx_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nxe_mdns_service_delete(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nx_mdns_local_cache_clear(NX_MDNS *mdns_ptr); -UINT _nxe_mdns_local_cache_clear(NX_MDNS *mdns_ptr); -#endif /* NX_MDNS_DISABLE_SERVER */ - -#ifndef NX_MDNS_DISABLE_CLIENT -UINT _nx_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout); -UINT _nxe_mdns_service_one_shot_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, NX_MDNS_SERVICE *service, UINT timeout); -UINT _nx_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nxe_mdns_service_continuous_query(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nx_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nxe_mdns_service_query_stop(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type); -UINT _nx_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service); -UINT _nxe_mdns_service_lookup(NX_MDNS *mdns_ptr, UCHAR *name, UCHAR *type, UCHAR *sub_type, UINT service_index, NX_MDNS_SERVICE *service); -UINT _nx_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask); -UINT _nxe_mdns_service_ignore_set(NX_MDNS *mdns_ptr, ULONG service_mask); -UINT _nx_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, - VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)); -UINT _nxe_mdns_service_notify_set(NX_MDNS *mdns_ptr, ULONG service_mask, - VOID (*service_change_notify)(NX_MDNS *mdns_ptr, NX_MDNS_SERVICE *service_ptr, UINT state)); -UINT _nx_mdns_service_notify_clear(NX_MDNS *mdns_ptr); -UINT _nxe_mdns_service_notify_clear(NX_MDNS *mdns_ptr); -UINT _nx_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout); -UINT _nxe_mdns_host_address_get(NX_MDNS *mdns_ptr, UCHAR *host_name, ULONG *ipv4_address, ULONG *ipv6_address, UINT timeout); -UINT _nx_mdns_peer_cache_clear(NX_MDNS *mdns_ptr); -UINT _nxe_mdns_peer_cache_clear(NX_MDNS *mdns_ptr); -#endif /* NX_MDNS_DISABLE_CLIENT */ - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_MDNS_H */ - diff --git a/protocol_handlers/mqtt/nxd_mqtt_client.c b/protocol_handlers/mqtt/nxd_mqtt_client.c deleted file mode 100644 index 64b9349d..00000000 --- a/protocol_handlers/mqtt/nxd_mqtt_client.c +++ /dev/null @@ -1,5964 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** MQTT (MQTT) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NXD_MQTT_CLIENT_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "tx_api.h" -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_mqtt_client.h" - -/* Bring in externals for caller checking code. */ - -#define MQTT_ALL_EVENTS ((ULONG)0xFFFFFFFF) -#define MQTT_TIMEOUT_EVENT ((ULONG)0x00000001) -#define MQTT_PACKET_RECEIVE_EVENT ((ULONG)0x00000002) -#define MQTT_START_EVENT ((ULONG)0x00000004) -#define MQTT_DELETE_EVENT ((ULONG)0x00000008) -#define MQTT_PING_TIMEOUT_EVENT ((ULONG)0x00000010) -#define MQTT_NETWORK_DISCONNECT_EVENT ((ULONG)0x00000020) -#define MQTT_TCP_ESTABLISH_EVENT ((ULONG)0x00000040) - -static UINT _nxd_mqtt_client_create_internal(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, - CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority); -static UINT _nxd_mqtt_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr); -static UINT _nxd_mqtt_copy_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, - USHORT packet_id, UCHAR set_duplicate_flag, UINT wait_option); -static VOID _nxd_mqtt_release_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr); -static VOID _nxd_mqtt_release_receive_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr); -static UINT _nxd_mqtt_client_retransmit_message(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); -static UINT _nxd_mqtt_client_connect_packet_send(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_set_fixed_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function writes the fixed header filed in the outgoing */ -/* MQTT packet. */ -/* */ -/* This function follows the logic outlined in 2.2 in MQTT */ -/* specification. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Outgoing MQTT packet */ -/* control_header Control byte */ -/* length Remaining length in bytes */ -/* wait_option Wait option */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_sub_unsub */ -/* _nxd_mqtt_client_connect */ -/* _nxd_mqtt_client_publish */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, UCHAR control_header, UINT length, UINT wait_option) -{ -UCHAR fixed_header[5]; -UCHAR *byte = fixed_header; -UINT count = 0; -UINT ret; - - *byte = control_header; - byte++; - - do - { - if (length & 0xFFFFFF80) - { - *(byte + count) = (UCHAR)((length & 0x7F) | 0x80); - } - else - { - *(byte + count) = length & 0x7F; - } - length = length >> 7; - - count++; - } while (length != 0); - - ret = nx_packet_data_append(packet_ptr, fixed_header, count + 1, - client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - - return(ret); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_read_remaining_length PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the remaining length filed in the incoming */ -/* MQTT packet. */ -/* */ -/* This function follows the logic outlined in 2.2.3 in MQTT */ -/* specification */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Incoming MQTT packet. */ -/* remaining_length remaining length in bytes, */ -/* this is the return value. */ -/* offset Pointer to offset of the */ -/* remaining data */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_process_publish */ -/* _nxd_mqtt_client_message_get */ -/* _nxd_mqtt_process_sub_unsub_ack */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_read_remaining_length(NX_PACKET *packet_ptr, UINT *remaining_length, ULONG *offset_ptr) -{ -UINT value = 0; -UCHAR bytes[4] = {0}; -UINT multiplier = 1; -UINT byte_count = 0; -ULONG bytes_copied; - - if (nx_packet_data_extract_offset(packet_ptr, 1, &bytes, sizeof(bytes), &bytes_copied)) - { - - /* Packet is incomplete. */ - return(NXD_MQTT_PARTIAL_PACKET); - } - - do - { - if (byte_count >= bytes_copied) - { - if (byte_count == 4) - { - return(NXD_MQTT_INTERNAL_ERROR); - } - else - { - - /* Packet is incomplete. */ - return(NXD_MQTT_PARTIAL_PACKET); - } - } - value += (((bytes[byte_count]) & 0x7F) * multiplier); - multiplier = multiplier << 7; - } while ((bytes[byte_count++]) & 0x80); - - if ((1 + byte_count + value) > packet_ptr -> nx_packet_length) - { - - /* Packet is incomplete. */ - /* Remaining length is larger than packet size. */ - return(NXD_MQTT_PARTIAL_PACKET); - } - - *remaining_length = value; - *offset_ptr = (1 + byte_count); - - return(NXD_MQTT_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_sub_unsub PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a subscribe or unsubscribe message to the */ -/* broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* op Subscribe or Unsubscribe */ -/* topic_name Pointer to the topic string */ -/* to subscribe to */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* QoS Expected QoS level */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* _nxd_mqtt_packet_allocate */ -/* _nxd_mqtt_client_set_fixed_header */ -/* _nxd_mqtt_client_append_message */ -/* tx_mutex_put */ -/* nx_tcp_socket_send */ -/* nx_secure_tls_session_send */ -/* nx_packet_release */ -/* _nxd_mqtt_copy_transmit_packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_subscribe */ -/* _nxd_mqtt_client_unsubscribe */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_sub_unsub(NXD_MQTT_CLIENT *client_ptr, UINT op, - CHAR *topic_name, UINT topic_name_length, UINT QoS) -{ - - -NX_PACKET *packet_ptr; -NX_PACKET *transmit_packet_ptr; -UINT status; -UINT length = 0; -UINT ret = NXD_MQTT_SUCCESS; -UCHAR temp_data[2]; - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - - /* Do nothing if the client is already connected. */ - if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED) - { - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_NOT_CONNECTED); - } - - status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); - if (status) - { - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(status); - } - - /* Compute the remaining length field, starting with 2 bytes of packet ID */ - length = 2; - - /* Count the topic. */ - length += (2 + topic_name_length); - - if (op == ((MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02)) - { - /* Count one byte for QoS */ - length++; - } - - /* Write out the control header and remaining length field. */ - ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, (UCHAR )op, length, NX_WAIT_FOREVER); - - if (ret) - { - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - temp_data[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8); - temp_data[1] = (client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF); - - /* Append packet ID. */ - ret = nx_packet_data_append(packet_ptr, temp_data, 2, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_WAIT_FOREVER); - - if (ret) - { - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Append topic name */ - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, topic_name, topic_name_length, NX_WAIT_FOREVER); - - if (ret) - { - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - if (op == ((MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02)) - { - /* Fill in QoS value. */ - temp_data[0] = QoS & 0x3; - - ret = nx_packet_data_append(packet_ptr, temp_data, 1, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_WAIT_FOREVER); - - if (ret) - { - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - } - - /* Copy packet for retransmission. */ - if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, - (USHORT)(client_ptr -> nxd_mqtt_client_packet_identifier), - NX_FALSE, NX_WAIT_FOREVER)) - { - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - if (client_ptr -> message_transmit_queue_head == NX_NULL) - { - client_ptr -> message_transmit_queue_head = transmit_packet_ptr; - } - else - { - client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; - } - client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; - - client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF; - - /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ - if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) - client_ptr -> nxd_mqtt_client_packet_identifier = 1; - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Ready to send the connect message to the server. */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); - } -#else - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); -#endif /* NX_SECURE_ENABLE */ - - - if (status) - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - - ret = NXD_MQTT_COMMUNICATION_FAILURE; - } - - return(ret); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a packet for transmitting MQTT message. */ -/* Special care has to be taken for accommodating IPv4/IPv6 header, */ -/* and possibly TLS record if TLS is being used. On failure, the */ -/* TLS mutex is released and the caller can simply return. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Allocated packet to be */ -/* returned to the caller. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_packet_allocate Allocate packet for MQTT */ -/* over TLS socket */ -/* nx_packet_allocate Allocate a packet for MQTT */ -/* over regular TCP socket */ -/* tx_mutex_put Release a mutex */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_process_publish */ -/* _nxd_mqtt_client_connect */ -/* _nxd_mqtt_client_publish */ -/* _nxd_mqtt_client_subscribe */ -/* _nxd_mqtt_client_unsubscribe */ -/* _nxd_mqtt_client_send_simple_message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_packet_allocate(NXD_MQTT_CLIENT *client_ptr, NX_PACKET **packet_ptr) -{ -UINT status = NXD_MQTT_SUCCESS; - -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - /* Use TLS packet allocate. The TLS packet allocate is able to count for - TLS-related header space including crypto initial vector area. */ - status = nx_secure_tls_packet_allocate(&client_ptr -> nxd_mqtt_tls_session, client_ptr -> nxd_mqtt_client_packet_pool_ptr, - packet_ptr, TX_WAIT_FOREVER); - } - /* Allocate a packet */ - else - { -#endif - if (client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(client_ptr -> nxd_mqtt_client_packet_pool_ptr, packet_ptr, NX_IPv4_TCP_PACKET, - TX_WAIT_FOREVER); - } - else - { - status = nx_packet_allocate(client_ptr -> nxd_mqtt_client_packet_pool_ptr, packet_ptr, NX_IPv6_TCP_PACKET, - TX_WAIT_FOREVER); - } -#ifdef NX_SECURE_ENABLE - } -#endif - - if (status != NX_SUCCESS) - { - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - return(NXD_MQTT_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_tcp_establish_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is installed as TCP connection establish */ -/* callback function. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr The socket that receives */ -/* the message. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_thread_entry */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_tcp_establish_notify(NX_TCP_SOCKET *socket_ptr) -{ -NXD_MQTT_CLIENT *client_ptr; - - client_ptr = (NXD_MQTT_CLIENT *)socket_ptr -> nx_tcp_socket_reserved_ptr; - - if (&(client_ptr -> nxd_mqtt_client_socket) == socket_ptr) - { - - /* Set the event flag. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_TCP_ESTABLISH_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_TCP_ESTABLISH_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_receive_callback PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is installed as TCP receive callback */ -/* function. On receiving a TCP message, the callback function */ -/* sets an event flag to trigger MQTT client to process received */ -/* message. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr The socket that receives */ -/* the message. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_thread_entry */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_receive_callback(NX_TCP_SOCKET *socket_ptr) -{ -NXD_MQTT_CLIENT *client_ptr; - - client_ptr = (NXD_MQTT_CLIENT *)socket_ptr -> nx_tcp_socket_reserved_ptr; - - if (&(client_ptr -> nxd_mqtt_client_socket) == socket_ptr) - { - /* Set the event flag. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_PACKET_RECEIVE_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PACKET_RECEIVE_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_copy_transmit_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function saves a transmit packet. */ -/* A transmit packet is allocated to store QoS 1 and 2 messages. */ -/* Upon a message being properly acknowledged, the packet will */ -/* be released. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the MQTT message */ -/* packet to be saved */ -/* new_packet_ptr Return a copied packet */ -/* packet_id Current packet ID */ -/* set_duplicate_flag Set duplicate flag for fixed */ -/* header or not */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_sub_unsub */ -/* _nxd_mqtt_process_publish */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_copy_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, - USHORT packet_id, UCHAR set_duplicate_flag, UINT wait_option) -{ -UINT status; - - /* Copy current packet. */ - status = nx_packet_copy(packet_ptr, new_packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - if (status) - { - - /* No available packet to be stored. */ - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Save packet_id at the beginning of packet. */ - *((USHORT *)(*new_packet_ptr) -> nx_packet_data_start) = packet_id; - - if (set_duplicate_flag) - { - - /* Update duplicate flag in fixed header. */ - *((*new_packet_ptr) -> nx_packet_prepend_ptr) = (*((*new_packet_ptr) -> nx_packet_prepend_ptr)) | MQTT_PUBLISH_DUP_FLAG; - } - - return(NXD_MQTT_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_release_transmit_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function releases a transmit packet. */ -/* A transmit packet is allocated to store QoS 1 and 2 messages. */ -/* Upon a message being properly acknowledged, the packet can */ -/* be released. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the MQTT message */ -/* packet to be removed */ -/* previous_packet_ptr Pointer to the previous packet*/ -/* or NULL if none exists */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_thread_entry */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_release_transmit_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr) -{ - - if (previous_packet_ptr) - { - previous_packet_ptr -> nx_packet_queue_next = packet_ptr -> nx_packet_queue_next; - } - else - { - client_ptr -> message_transmit_queue_head = packet_ptr -> nx_packet_queue_next; - } - - if (packet_ptr == client_ptr -> message_transmit_queue_tail) - { - client_ptr -> message_transmit_queue_tail = previous_packet_ptr; - } - nx_packet_release(packet_ptr); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_release_receive_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function releases a receive packet. */ -/* A receive packet is allocated to store QoS 1 and 2 messages. */ -/* Upon a message being properly acknowledged, the packet can */ -/* be released. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the MQTT message */ -/* packet to be removed */ -/* previous_packet_ptr Pointer to the previous packet*/ -/* or NULL if none exists */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_thread_entry */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_release_receive_packet(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PACKET *previous_packet_ptr) -{ - - if (previous_packet_ptr) - { - previous_packet_ptr -> nx_packet_queue_next = packet_ptr -> nx_packet_queue_next; - } - else - { - client_ptr -> message_receive_queue_head = packet_ptr -> nx_packet_queue_next; - } - - if (packet_ptr == client_ptr -> message_receive_queue_tail) - { - client_ptr -> message_receive_queue_tail = previous_packet_ptr; - } - - client_ptr -> message_receive_queue_depth--; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_connack PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function processes a CONNACK message from the broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* [nxd_mqtt_connect_notify] User supplied connect */ -/* callback function */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* _nxd_mqtt_client_retransmit_message */ -/* _nxd_mqtt_client_connection_end */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_process_connack(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT ret = NXD_MQTT_COMMUNICATION_FAILURE; -MQTT_PACKET_CONNACK *connack_packet_ptr = (MQTT_PACKET_CONNACK *)(packet_ptr -> nx_packet_prepend_ptr); - - - /* Check the length. */ - if ((packet_ptr -> nx_packet_length != sizeof(MQTT_PACKET_CONNACK)) || - (connack_packet_ptr -> mqtt_connack_packet_header >> 4 != MQTT_CONTROL_PACKET_TYPE_CONNACK)) - { - /* Invalid packet length. Free the packet and process error. */ - ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; - } - else - { - - /* Check remaining length. */ - if (connack_packet_ptr -> mqtt_connack_packet_remaining_length != 2) - { - ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; - } - /* Follow MQTT-3.2.2-1 rule. */ - else if ((client_ptr -> nxd_mqtt_clean_session) && (connack_packet_ptr -> mqtt_connack_packet_ack_flags & MQTT_CONNACK_CONNECT_FLAGS_SP)) - { - - /* Client requested clean session, and server responded with Session Present. This is a violation. */ - ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; - } - else if (connack_packet_ptr -> mqtt_connack_packet_return_code > MQTT_CONNACK_CONNECT_RETURN_CODE_NOT_AUTHORIZED) - { - ret = NXD_MQTT_SERVER_MESSAGE_FAILURE; - } - else if (connack_packet_ptr -> mqtt_connack_packet_return_code > 0) - { - - /* Pass the server return code to the application. */ - ret = (UINT)(NXD_MQTT_ERROR_CONNECT_RETURN_CODE + connack_packet_ptr -> mqtt_connack_packet_return_code); - } - else - { - ret = NXD_MQTT_SUCCESS; - - /* Obtain mutex before we modify client control block. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTED; - - /* Initialize the packet identification field. */ - client_ptr -> nxd_mqtt_client_packet_identifier = NXD_MQTT_INITIAL_PACKET_ID_VALUE; - - /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ - if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) - client_ptr -> nxd_mqtt_client_packet_identifier = 1; - - /* Release mutex */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - } - } - - /* Check callback function. */ - if (client_ptr -> nxd_mqtt_connect_notify) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, ret, client_ptr -> nxd_mqtt_connect_context); - } - - if (ret == NXD_MQTT_SUCCESS) - { - - /* If client doesn't start with Clean Session, and there are un-acked PUBLISH messages, - we shall re-publish these messages. */ - if ((client_ptr -> nxd_mqtt_clean_session != NX_TRUE) && (client_ptr -> message_transmit_queue_head)) - { - - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - /* There are messages from the previous session that has not been acknowledged. */ - ret = _nxd_mqtt_client_retransmit_message(client_ptr, wait_option); - - /* Release mutex */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - } - } - else - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - } - - return(ret); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_publish_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function processes a packet and parses topic and */ -/* message. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to the packet */ -/* topic_offset_ptr Return topic offset */ -/* topic_length_ptr Return topic length */ -/* message_offset_ptr Return message offset */ -/* message_length_ptr Return message length */ -/* */ -/* OUTPUT */ -/* */ -/* Status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_read_remaining_length */ -/* nx_packet_data_extract_offset */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_process_publish */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_process_publish_packet(NX_PACKET *packet_ptr, ULONG *topic_offset_ptr, USHORT *topic_length_ptr, - ULONG *message_offset_ptr, ULONG *message_length_ptr) -{ -UCHAR QoS; -UINT remaining_length = 0; -UINT topic_length; -ULONG offset; -UCHAR bytes[2]; -ULONG bytes_copied; - - - QoS = (UCHAR)((*(packet_ptr -> nx_packet_prepend_ptr) & MQTT_PUBLISH_QOS_LEVEL_FIELD) >> 1); - - if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) - { - return(NXD_MQTT_INVALID_PACKET); - } - - if (remaining_length < 2) - { - return(NXD_MQTT_INVALID_PACKET); - } - - /* Get topic length fields. */ - if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || - (bytes_copied != sizeof(bytes))) - { - return(NXD_MQTT_INVALID_PACKET); - } - - topic_length = (UINT)(*(bytes) << 8) | (*(bytes + 1)); - - if (topic_length > remaining_length - 2u) - { - return(NXD_MQTT_INVALID_PACKET); - } - - *topic_offset_ptr = offset + 2; - *topic_length_ptr = (USHORT)topic_length; - - remaining_length = remaining_length - topic_length - 2; - if ((QoS == 1) || (QoS == 2)) - { - offset += 2 + 2 + topic_length; - - if (remaining_length < 2) - { - return(NXD_MQTT_INVALID_PACKET); - } - remaining_length = remaining_length - 2; - } - else - { - offset += 2 + topic_length; - } - - *message_offset_ptr = offset; - *message_length_ptr = (ULONG)remaining_length; - - /* Return */ - return(NXD_MQTT_SUCCESS); -} -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_publish PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process a publish message from the broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE - packet is consumed */ -/* NX_FALSE - packet is not consumed */ -/* */ -/* CALLS */ -/* */ -/* [receive_notify] User supplied receive */ -/* callback function */ -/* _nxd_mqtt_packet_allocate */ -/* nx_tcp_socket_send */ -/* nx_packet_release */ -/* nx_secure_tls_session_send */ -/* _nxd_mqtt_process_publish_packet */ -/* _nxd_mqtt_copy_transmit_packet */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_process_publish(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ -MQTT_PACKET_PUBLISH_RESPONSE *pubresp_ptr; -UINT status; -USHORT packet_id = 0; -UCHAR QoS; -UINT enqueue_message = 0; -NX_PACKET *transmit_packet_ptr; -UINT remaining_length = 0; -UINT packet_consumed = NX_FALSE; -UCHAR fixed_header; -USHORT transmit_packet_id; -UINT topic_length; -ULONG offset; -UCHAR bytes[2]; -ULONG bytes_copied; - - QoS = (UCHAR)((*(packet_ptr -> nx_packet_prepend_ptr) & MQTT_PUBLISH_QOS_LEVEL_FIELD) >> 1); - - if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) - { - return(NX_FALSE); - } - - if (remaining_length < 2) - { - return(NXD_MQTT_INVALID_PACKET); - } - - /* Get topic length fields. */ - if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || - (bytes_copied != sizeof(bytes))) - { - return(NXD_MQTT_INVALID_PACKET); - } - - topic_length = (UINT)(*(bytes) << 8) | (*(bytes + 1)); - - if (topic_length > remaining_length - 2u) - { - return(NXD_MQTT_INVALID_PACKET); - } - - if (QoS == 0) - { - enqueue_message = 1; - } - else - { - /* QoS 1 or QoS 2 messages. */ - /* Get packet id fields. */ - if (nx_packet_data_extract_offset(packet_ptr, offset + 2 + topic_length, &bytes, sizeof(bytes), &bytes_copied)) - { - return(NXD_MQTT_INVALID_PACKET); - } - - packet_id = (USHORT)(((*bytes) << 8) | (*(bytes + 1))); - - /* Look for an existing transmit packets with the same packet id */ - transmit_packet_ptr = client_ptr -> message_transmit_queue_head; - - while (transmit_packet_ptr) - { - fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); - transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); - if ((transmit_packet_id == packet_id) && - ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_PUBREC << 4))) - { - - /* Found a packet containing the packet_id */ - break; - } - transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; - } - - if (transmit_packet_ptr) - { - /* This published data is already in our system. No need to deliver this message to the application. */ - enqueue_message = 0; - } - else - { - enqueue_message = 1; - } - } - - if (enqueue_message) - { - if (packet_ptr -> nx_packet_length > (offset + remaining_length)) - { - - /* This packet contains multiple messages. */ - if (nx_packet_copy(packet_ptr, &packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, NX_NO_WAIT)) - { - - /* No packet is available. */ - return(NX_FALSE); - } - } - else - { - packet_consumed = NX_TRUE; - } - - /* Increment the queue depth counter. */ - client_ptr -> message_receive_queue_depth++; - - if (client_ptr -> message_receive_queue_head == NX_NULL) - { - client_ptr -> message_receive_queue_head = packet_ptr; - } - else - { - client_ptr -> message_receive_queue_tail -> nx_packet_queue_next = packet_ptr; - } - client_ptr -> message_receive_queue_tail = packet_ptr; - - /* Invoke the user-defined receive notify function if it is set. */ - if (client_ptr -> nxd_mqtt_client_receive_notify) - { - (*(client_ptr -> nxd_mqtt_client_receive_notify))(client_ptr, client_ptr -> message_receive_queue_depth); - } - } - - /* If the message QoS level is 0, we are done. */ - if (QoS == 0) - { - /* Return */ - return(packet_consumed); - } - - /* Send out proper ACKs for QoS 1 and 2 messages. */ - /* Allocate a new packet so we can send out a response. */ - status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); - if (status) - { - /* Packet allocation fails. */ - return(packet_consumed); - } - - /* Fill in the packet ID */ - pubresp_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)(packet_ptr -> nx_packet_prepend_ptr); - pubresp_ptr -> mqtt_publish_response_packet_remaining_length = 2; - pubresp_ptr -> mqtt_publish_response_packet_packet_identifier_msb = (UCHAR)(packet_id >> 8); - pubresp_ptr -> mqtt_publish_response_packet_packet_identifier_lsb = (UCHAR)(packet_id & 0xFF); - - if (QoS == 1) - { - - pubresp_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBACK << 4; - } - else - { - pubresp_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBREC << 4; - } - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(MQTT_PACKET_PUBLISH_RESPONSE); - packet_ptr -> nx_packet_length = sizeof(MQTT_PACKET_PUBLISH_RESPONSE); - - if (QoS == 2) - { - - /* Copy packet for checking duplicate publish packet. */ - if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, - packet_id, NX_FALSE, NX_WAIT_FOREVER)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(packet_consumed); - } - if (client_ptr -> message_transmit_queue_head == NX_NULL) - { - client_ptr -> message_transmit_queue_head = transmit_packet_ptr; - } - else - { - client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; - } - client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; - } - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); - } -#else - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); - -#endif /* NX_SECURE_ENABLE */ - - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - else - { - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - } - - /* Return */ - return(packet_consumed); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_publish_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process a publish response messages. */ -/* Publish Response messages are: PUBACK, PUBREC, PUBREL */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* Status */ -/* */ -/* CALLS */ -/* */ -/* [nxd_mqtt_client_receive_notify] User supplied publish */ -/* callback function */ -/* _nxd_mqtt_release_transmit_packet */ -/* nx_tcp_socket_send */ -/* nx_secure_tls_session_send */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_process_publish_response(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ -MQTT_PACKET_PUBLISH_RESPONSE *response_ptr; -USHORT packet_id; -NX_PACKET *previous_packet_ptr; -NX_PACKET *transmit_packet_ptr; -NX_PACKET *response_packet; -UINT ret; -UCHAR fixed_header; -USHORT transmit_packet_id; - - response_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Validate the packet. */ - if (response_ptr -> mqtt_publish_response_packet_remaining_length != 2) - { - /* Invalid remaining_length value. Return 1 so the caller can release - the packet. */ - - return(1); - } - - packet_id = (USHORT)((response_ptr -> mqtt_publish_response_packet_packet_identifier_msb << 8) | - (response_ptr -> mqtt_publish_response_packet_packet_identifier_lsb)); - - /* Search all the outstanding transmitted packets for a match. */ - previous_packet_ptr = NX_NULL; - transmit_packet_ptr = client_ptr -> message_transmit_queue_head; - while (transmit_packet_ptr) - { - fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); - transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); - if (transmit_packet_id == packet_id) - { - - /* Found the matching packet id */ - if (((response_ptr -> mqtt_publish_response_packet_header) >> 4) == MQTT_CONTROL_PACKET_TYPE_PUBACK) - { - - /* PUBACK is the response to a PUBLISH packet with QoS Level 1*/ - /* Therefore we verify that packet contains PUBLISH packet with QoS level 1*/ - if ((fixed_header & 0xF6) == ((MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4) | MQTT_PUBLISH_QOS_LEVEL_1)) - { - /* QoS Level1 message receives an ACK. */ - /* This message can be released. */ - _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); - - /* Return with value 1, so the caller will release packet_ptr */ - return(1); - } - } - else if (((response_ptr -> mqtt_publish_response_packet_header) >> 4) == MQTT_CONTROL_PACKET_TYPE_PUBREL) - { - - /* QoS 2 publish Release received, part 2. */ - /* Therefore we verify that packet contains PUBLISH packet with QoS level 2*/ - if ((fixed_header & 0xF6) == (MQTT_CONTROL_PACKET_TYPE_PUBREC << 4)) - { - - /* QoS Level2 message receives an ACK. */ - /* This message can be released. */ - /* Send PUBCOMP */ - - /* Allocate a packet to send the response. */ - ret = _nxd_mqtt_packet_allocate(client_ptr, &response_packet); - if (ret) - { - return(1); - } - - if (4u > ((ULONG)(response_packet -> nx_packet_data_end) - (ULONG)(response_packet -> nx_packet_append_ptr))) - { - nx_packet_release(response_packet); - - /* Packet buffer is too small to hold the message. */ - return(NX_SIZE_ERROR); - } - - response_ptr = (MQTT_PACKET_PUBLISH_RESPONSE *)response_packet -> nx_packet_prepend_ptr; - - response_ptr -> mqtt_publish_response_packet_header = MQTT_CONTROL_PACKET_TYPE_PUBCOMP << 4; - response_ptr -> mqtt_publish_response_packet_remaining_length = 2; - - /* Fill in packet ID */ - response_packet -> nx_packet_prepend_ptr[3] = packet_ptr -> nx_packet_prepend_ptr[3]; - response_packet -> nx_packet_prepend_ptr[4] = packet_ptr -> nx_packet_prepend_ptr[4]; - response_packet -> nx_packet_append_ptr = response_packet -> nx_packet_prepend_ptr + 4; - response_packet -> nx_packet_length = 4; - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - ret = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), response_packet, NX_WAIT_FOREVER); - } - else - { - ret = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, response_packet, NX_WAIT_FOREVER); - } -#else - ret = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, response_packet, NX_WAIT_FOREVER); - -#endif /* NX_SECURE_ENABLE */ - - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - if (ret) - { - nx_packet_release(response_packet); - } - - /* This packet can be released. */ - _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); - - /* Return with value 1, so the caller will release packet_ptr */ - return(1); - } - } - } - - /* Move on to the next packet */ - previous_packet_ptr = transmit_packet_ptr; - transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; - } - - /* nothing is found. Return 1 to release the packet.*/ - return(1); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_sub_unsub_ack PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process an ACK message for subscribe */ -/* or unsubscribe request. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* Status */ -/* */ -/* CALLS */ -/* */ -/* [nxd_mqtt_client_receive_notify] User supplied publish */ -/* callback function */ -/* _nxd_mqtt_release_transmit_packet */ -/* Release the memory block */ -/* _nxd_mqtt_read_remaining_length Skip the remaining length */ -/* field */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_process_sub_unsub_ack(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ - -USHORT packet_id; -NX_PACKET *previous_packet_ptr; -NX_PACKET *transmit_packet_ptr; -UCHAR response_header; -UCHAR fixed_header; -USHORT transmit_packet_id; -UINT remaining_length; -ULONG offset; -UCHAR bytes[2]; -ULONG bytes_copied; - - - response_header = *(packet_ptr -> nx_packet_prepend_ptr); - - if (_nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset)) - { - - /* Unable to process the sub/unsub ack. Simply return and release the packet. */ - return(NXD_MQTT_INVALID_PACKET); - } - - /* Get packet id fields. */ - if (nx_packet_data_extract_offset(packet_ptr, offset, &bytes, sizeof(bytes), &bytes_copied) || - (bytes_copied != sizeof(bytes))) - { - return(NXD_MQTT_INVALID_PACKET); - } - - packet_id = (USHORT)(((*bytes) << 8) | (*(bytes + 1))); - - /* Search all the outstanding transmitted packets for a match. */ - previous_packet_ptr = NX_NULL; - transmit_packet_ptr = client_ptr -> message_transmit_queue_head; - while (transmit_packet_ptr) - { - fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); - transmit_packet_id = *((USHORT *)transmit_packet_ptr -> nx_packet_data_start); - if (transmit_packet_id == packet_id) - { - - /* Found the matching packet id */ - if (((response_header >> 4) == MQTT_CONTROL_PACKET_TYPE_SUBACK) && - ((fixed_header >> 4) == MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE)) - { - /* Validate the packet. */ - if (remaining_length != 3) - { - /* Invalid remaining_length value. */ - return(1); - } - - /* Release the transmit packet. */ - _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); - - return(1); - } - else if (((response_header >> 4) == MQTT_CONTROL_PACKET_TYPE_UNSUBACK) && - ((fixed_header >> 4) == MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE)) - { - /* Validate the packet. */ - if (remaining_length != 2) - { - /* Invalid remaining_length value. */ - return(1); - } - - /* Unsubscribe succeeded. */ - /* Release the transmit packet. */ - _nxd_mqtt_release_transmit_packet(client_ptr, transmit_packet_ptr, previous_packet_ptr); - - return(1); - } - } - - /* Move on to the next packet */ - previous_packet_ptr = transmit_packet_ptr; - transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; - } - return(1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_pingresp PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process a PINGRESP message. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* Status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* callback function */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_process_pingresp(NXD_MQTT_CLIENT *client_ptr) -{ - - - /* If there is an outstanding ping, mark it as responded. */ - if (client_ptr -> nxd_mqtt_ping_not_responded == NX_TRUE) - { - client_ptr -> nxd_mqtt_ping_not_responded = NX_FALSE; - - client_ptr -> nxd_mqtt_ping_sent_time = 0; - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_process_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process a DISCONNECT message. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_send */ -/* nx_tcp_socket_disconnect */ -/* nx_tcp_client_socket_unbind */ -/* _nxd_mqtt_release_transmit_packet */ -/* _nxd_mqtt_release_receive_packet */ -/* _nxd_mqtt_client_connection_end */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_packet_receive_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_process_disconnect(NXD_MQTT_CLIENT *client_ptr) -{ -NX_PACKET *previous = NX_NULL; -NX_PACKET *current; -NX_PACKET *next; -UINT disconnect_callback = NX_FALSE; -UINT status; -UCHAR fixed_header; - - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) - { - /* State changes from CONNECTED TO IDLE. Call disconnect notify callback - if the function is set. */ - disconnect_callback = NX_TRUE; - } - else if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTING) - { - - /* If state isn't CONNECTED or CONNECTING, just return. */ - return; - } - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NXD_MQTT_SOCKET_TIMEOUT); - - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); - - /* Free up sub/unsub packets on the transmit queue. */ - current = client_ptr -> message_transmit_queue_head; - - while (current) - { - next = current -> nx_packet_queue_next; - fixed_header = *(current -> nx_packet_prepend_ptr); - - if (((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4)) || - ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE << 4))) - { - _nxd_mqtt_release_transmit_packet(client_ptr, current, previous); - } - else - { - previous = current; - } - current = next; - } - - /* If a callback notification is defined, call it now. */ - if ((disconnect_callback == NX_TRUE) && (client_ptr -> nxd_mqtt_disconnect_notify)) - { - client_ptr -> nxd_mqtt_disconnect_notify(client_ptr); - } - - /* If a connect callback notification is defined and is still in connecting stage, call it now. */ - if ((disconnect_callback == NX_FALSE) && (client_ptr -> nxd_mqtt_connect_notify)) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, NXD_MQTT_CONNECT_FAILURE, client_ptr -> nxd_mqtt_connect_context); - } - - if (status == TX_SUCCESS) - { - /* Remove all the packets in the receive queue. */ - while (client_ptr -> message_receive_queue_head) - { - _nxd_mqtt_release_receive_packet(client_ptr, client_ptr -> message_receive_queue_head, NX_NULL); - } - client_ptr -> message_receive_queue_depth = 0; - - /* Clear the MQTT_PACKET_RECEIVE_EVENT */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, ~MQTT_PACKET_RECEIVE_EVENT, TX_AND); -#else - nx_cloud_module_event_clear(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PACKET_RECEIVE_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - } - - /* Clear flags if keep alive is enabled. */ - if (client_ptr -> nxd_mqtt_keepalive) - { - client_ptr -> nxd_mqtt_ping_not_responded = 0; - client_ptr -> nxd_mqtt_ping_sent_time = 0; - } - - /* Clean up the information when disconnecting. */ - client_ptr -> nxd_mqtt_client_username = NX_NULL; - client_ptr -> nxd_mqtt_client_password = NX_NULL; - client_ptr -> nxd_mqtt_client_will_topic = NX_NULL; - client_ptr -> nxd_mqtt_client_will_message = NX_NULL; - client_ptr -> nxd_mqtt_client_will_qos_retain = 0; - - /* Release current processing packet. */ - if (client_ptr -> nxd_mqtt_client_processing_packet) - { - nx_packet_release(client_ptr -> nxd_mqtt_client_processing_packet); - client_ptr -> nxd_mqtt_client_processing_packet = NX_NULL; - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_packet_receive_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function process MQTT message. */ -/* NOTE: MQTT Mutex is NOT obtained on entering this function. */ -/* Therefore it shouldn't hold the mutex when it exists this function. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_receive */ -/* nx_tcp_socket_receive */ -/* _nxd_mqtt_process_publish */ -/* _nxd_mqtt_process_publish_response */ -/* _nxd_mqtt_process_sub_unsub_ack */ -/* _nxd_mqtt_process_pingresp */ -/* _nxd_mqtt_process_disconnect */ -/* nx_packet_release */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_packet_receive_process(NXD_MQTT_CLIENT *client_ptr) -{ -NX_PACKET *packet_ptr; -NX_PACKET *previous_packet_ptr; -UINT status; -UCHAR packet_type; -UINT remaining_length; -UINT packet_consumed; -ULONG offset; -ULONG bytes_copied; -ULONG packet_length; - - for (;;) - { - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Make a receive call. */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_receive(&(client_ptr -> nxd_mqtt_tls_session), &packet_ptr, NX_NO_WAIT); - } - else - { - status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, NX_NO_WAIT); - } -#else - status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, NX_NO_WAIT); -#endif /* NX_SECURE_ENABLE */ - - if (status != NX_SUCCESS) - { - if (status != NX_NO_PACKET) - { - - /* Network issue. Close the MQTT session. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_NETWORK_DISCONNECT_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_NETWORK_DISCONNECT_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - } - - break; - } - - /* Obtain the mutex. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - /* Is there a packet waiting for processing? */ - if (client_ptr -> nxd_mqtt_client_processing_packet) - { - - /* Yes. Link received packet to existing one. */ - if (client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last) - { - client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last -> nx_packet_next = packet_ptr; - } - else - { - client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_next = packet_ptr; - } - if (packet_ptr -> nx_packet_last) - { - client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last = packet_ptr -> nx_packet_last; - } - else - { - client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_last = packet_ptr; - } - client_ptr -> nxd_mqtt_client_processing_packet -> nx_packet_length += packet_ptr -> nx_packet_length; - - /* Start to process existing packet. */ - packet_ptr = client_ptr -> nxd_mqtt_client_processing_packet; - client_ptr -> nxd_mqtt_client_processing_packet = NX_NULL; - } - - /* Check notify function. */ - if (client_ptr -> nxd_mqtt_packet_receive_notify) - { - - /* Call notify function. Return NX_TRUE if the packet has been consumed. */ - if (client_ptr -> nxd_mqtt_packet_receive_notify(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_packet_receive_context) == NX_TRUE) - { - continue; - } - } - - packet_consumed = NX_FALSE; - while (packet_ptr) - { - /* Parse the incoming packet. */ - status = _nxd_mqtt_read_remaining_length(packet_ptr, &remaining_length, &offset); - if (status == NXD_MQTT_PARTIAL_PACKET) - { - - /* We only have partial MQTT message. - * Put it to waiting list for more packets. */ - client_ptr -> nxd_mqtt_client_processing_packet = packet_ptr; - packet_consumed = NX_TRUE; - break; - } - else if (status) - { - - /* Invalid packet. */ - break; - } - - /* Get packet type. */ - if (nx_packet_data_extract_offset(packet_ptr, 0, &packet_type, 1, &bytes_copied)) - { - - /* Unable to read packet type. */ - break; - } - - /* Right shift 4 bits to get the packet type. */ - packet_type = packet_type >> 4; - - /* Process based on packet type. */ - switch (packet_type) - { - case MQTT_CONTROL_PACKET_TYPE_CONNECT: - /* Client does not accept connections. Nothing needs to be done. */ - break; - case MQTT_CONTROL_PACKET_TYPE_CONNACK: - _nxd_mqtt_process_connack(client_ptr, packet_ptr, NX_NO_WAIT); - break; - - case MQTT_CONTROL_PACKET_TYPE_PUBLISH: - packet_consumed = _nxd_mqtt_process_publish(client_ptr, packet_ptr); - break; - - case MQTT_CONTROL_PACKET_TYPE_PUBACK: - case MQTT_CONTROL_PACKET_TYPE_PUBREL: - _nxd_mqtt_process_publish_response(client_ptr, packet_ptr); - break; - - case MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE: - case MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE: - /* Client should not process subscribe or unsubscribe message. */ - break; - - case MQTT_CONTROL_PACKET_TYPE_SUBACK: - case MQTT_CONTROL_PACKET_TYPE_UNSUBACK: - _nxd_mqtt_process_sub_unsub_ack(client_ptr, packet_ptr); - break; - - - case MQTT_CONTROL_PACKET_TYPE_PINGREQ: - /* Client is not supposed to receive ping req. Ignore it. */ - break; - - case MQTT_CONTROL_PACKET_TYPE_PINGRESP: - _nxd_mqtt_process_pingresp(client_ptr); - break; - - case MQTT_CONTROL_PACKET_TYPE_DISCONNECT: - _nxd_mqtt_process_disconnect(client_ptr); - break; - - /* Publisher sender message type for QoS 2. Not supported. */ - case MQTT_CONTROL_PACKET_TYPE_PUBREC: - case MQTT_CONTROL_PACKET_TYPE_PUBCOMP: - default: - /* Unknown type. */ - break; - } - - if (packet_consumed) - { - break; - } - - /* Trim current packet. */ - offset += remaining_length; - packet_length = packet_ptr -> nx_packet_length; - if (packet_length > offset) - { - - /* Multiple MQTT message in one packet. */ - packet_length = packet_ptr -> nx_packet_length - offset; - while ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) <= offset) - { - offset -= (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); - - /* Current packet can be released. */ - previous_packet_ptr = packet_ptr; - packet_ptr = packet_ptr -> nx_packet_next; - previous_packet_ptr -> nx_packet_next = NX_NULL; - nx_packet_release(previous_packet_ptr); - if (packet_ptr == NX_NULL) - { - - /* Invalid packet. */ - break; - } - } - - if (packet_ptr) - { - - /* Adjust current packet. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + offset; - packet_ptr -> nx_packet_length = packet_length; - } - } - else - { - - /* All messages in current packet is processed. */ - break; - } - } - - if (!packet_consumed) - { - nx_packet_release(packet_ptr); - } - } - - /* No more data in the receive queue. Return. */ - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_tcp_establish_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes MQTT TCP connection establish event. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_start */ -/* _nxd_mqtt_client_connection_end */ -/* _nxd_mqtt_client_connect_packet_send */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_tcp_establish_process(NXD_MQTT_CLIENT *client_ptr) -{ -UINT status; - - - /* TCP connection is established. */ - - /* If TLS is enabled, start TLS */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_start(&(client_ptr -> nxd_mqtt_tls_session), &(client_ptr -> nxd_mqtt_client_socket), NX_NO_WAIT); - - if (status != NX_CONTINUE) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - /* Check callback function. */ - if (client_ptr -> nxd_mqtt_connect_notify) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); - } - - return; - } - - /* TLS in progress. */ - client_ptr -> nxd_mqtt_tls_in_progress = NX_TRUE; - - return; - } -#endif /* NX_SECURE_ENABLE */ - - /* Start to send MQTT connect packet. */ - status = _nxd_mqtt_client_connect_packet_send(client_ptr, NX_NO_WAIT); - - /* Check status. */ - if (status) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - /* Check callback function. */ - if (client_ptr -> nxd_mqtt_connect_notify) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); - } - } -} - - -#ifdef NX_SECURE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_tls_establish_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes TLS connection establish event. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_secure_tls_handshake_process */ -/* _nxd_mqtt_client_connect_packet_send */ -/* _nxd_mqtt_client_connection_end */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_tls_establish_process(NXD_MQTT_CLIENT *client_ptr) -{ -UINT status; - - - /* Directly call handshake process for async mode. */ - status = _nx_secure_tls_handshake_process(&(client_ptr -> nxd_mqtt_tls_session), NX_NO_WAIT); - if (status == NX_SUCCESS) - { - - /* TLS session established. */ - client_ptr -> nxd_mqtt_tls_in_progress= NX_FALSE; - - /* Start to send MQTT connect packet. */ - status = _nxd_mqtt_client_connect_packet_send(client_ptr, NX_NO_WAIT); - - /* Check status. */ - if (status) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - /* Check callback function. */ - if (client_ptr -> nxd_mqtt_connect_notify) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); - } - } - } - else if (status != NX_CONTINUE) - { - - /* Error. */ - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - /* Check callback function. */ - if (client_ptr -> nxd_mqtt_connect_notify) - { - client_ptr -> nxd_mqtt_connect_notify(client_ptr, status, client_ptr -> nxd_mqtt_connect_context); - } - } - - return; -} -#endif /* NX_SECURE_ENABLE */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_append_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function writes the message length and message in the outgoing */ -/* MQTT packet. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Outgoing MQTT packet */ -/* message Pointer to the message */ -/* length Length of the message */ -/* wait_option Wait option */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_sub_unsub */ -/* _nxd_mqtt_client_connect */ -/* _nxd_mqtt_client_publish */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_append_message(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, CHAR *message, UINT length, ULONG wait_option) -{ -UINT ret = 0; -UCHAR len[2]; - - len[0] = (length >> 8) & 0xFF; - len[1] = length & 0xFF; - - /* Append message length field. */ - ret = nx_packet_data_append(packet_ptr, len, 2, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - - if (ret) - { - return(ret); - } - - if (length) - { - /* Copy the string into the packet. */ - ret = nx_packet_data_append(packet_ptr, message, length, - client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - } - - return(ret); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_connection_end PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used to end the MQTT connection. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* wait_option Wait option */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_end End TLS session */ -/* nx_secure_tls_session_delete Delete TLS session */ -/* nx_tcp_socket_disconnect Close TCP connection */ -/* nx_tcp_client_socket_unbind Unbind TCP socket */ -/* tx_timer_delete Delete timer */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_connect */ -/* _nxd_mqtt_process_disconnect */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nxd_mqtt_client_connection_end(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) -{ - - /* Obtain the mutex. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - /* Mark the session as terminated. */ - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_end(&(client_ptr -> nxd_mqtt_tls_session), wait_option); - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif - nx_tcp_socket_disconnect(&(client_ptr -> nxd_mqtt_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nxd_mqtt_client_socket)); - - /* Disable timer if timer has been started. */ - if (client_ptr -> nxd_mqtt_keepalive) - { - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - } -} - - -static UINT _nxd_mqtt_send_simple_message(NXD_MQTT_CLIENT *client_ptr, UCHAR header_value); - - -/* MQTT internal function */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_periodic_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is passed to MQTT client socket create call. */ -/* This callback function notifies MQTT client thread when the TCP */ -/* connection is lost. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to TCP socket that */ -/* disconnected. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* TCP socket disconnect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_periodic_timer_entry(ULONG client) -{ -/* Check if it is time to send out a ping message. */ -NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)client; - - /* If an outstanding ping response has not been received, and the client exceeds the time waiting for ping response, - the client shall disconnect from the server. */ - if (client_ptr -> nxd_mqtt_ping_not_responded) - { - /* If current time is greater than the ping timeout */ - if ((tx_time_get() - client_ptr -> nxd_mqtt_ping_sent_time) >= client_ptr -> nxd_mqtt_ping_timeout) - { - /* Ping timed out. Need to terminate the connection. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_PING_TIMEOUT_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_PING_TIMEOUT_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - return; - } - } - - /* About to timeout? */ - if ((client_ptr -> nxd_mqtt_timeout - tx_time_get()) <= client_ptr -> nxd_mqtt_timer_value) - { - /* Set the flag so the MQTT thread can send the ping. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_TIMEOUT_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_TIMEOUT_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - } - - /* If keepalive is not enabled, just return. */ - return; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_event_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function serves as the entry point for the MQTT */ -/* client thread. */ -/* */ -/* INPUT */ -/* */ -/* mqtt_client Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_release_transmit_packet */ -/* _nxd_mqtt_release_receive_packet */ -/* _nxd_mqtt_send_simple_message */ -/* _nxd_mqtt_process_disconnect */ -/* _nxd_mqtt_packet_receive_process */ -/* tx_timer_delete */ -/* tx_event_flags_delete */ -/* nx_tcp_socket_delete */ -/* tx_timer_delete */ -/* tx_mutex_delete */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_create */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_client_event_process(VOID *mqtt_client, ULONG common_events, ULONG module_own_events) -{ -NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)mqtt_client; - - - /* Obtain the mutex. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); - - /* Process common events. */ - NX_PARAMETER_NOT_USED(common_events); - - /* Process module own events. */ - if (module_own_events & MQTT_START_EVENT) - { - - /* Move MQTT Client state to STARTED */ - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; - } - - if (module_own_events & MQTT_TIMEOUT_EVENT) - { - /* Send out PING only if the client is connected. */ - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) - { - _nxd_mqtt_send_simple_message(client_ptr, MQTT_CONTROL_PACKET_TYPE_PINGREQ); - } - } - - if (module_own_events & MQTT_TCP_ESTABLISH_EVENT) - { - _nxd_mqtt_tcp_establish_process(client_ptr); - } - - if (module_own_events & MQTT_PACKET_RECEIVE_EVENT) - { -#ifdef NX_SECURE_ENABLE - /* TLS in progress on async mode. */ - if (client_ptr -> nxd_mqtt_tls_in_progress) - { - _nxd_mqtt_tls_establish_process(client_ptr); - } - else -#endif /* NX_SECURE_ENABLE */ - - _nxd_mqtt_packet_receive_process(client_ptr); - } - - if (module_own_events & MQTT_PING_TIMEOUT_EVENT) - { - /* The server/broker didn't respond to our ping request message. Disconnect from the server. */ - _nxd_mqtt_process_disconnect(client_ptr); - } - if (module_own_events & MQTT_NETWORK_DISCONNECT_EVENT) - { - /* The server closed TCP socket. We shall go through the disconnect code path. */ - _nxd_mqtt_process_disconnect(client_ptr); - } - - if (module_own_events & MQTT_DELETE_EVENT) - { - - /* Stop the client and disconnect from the server. */ - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) - { - _nxd_mqtt_process_disconnect(client_ptr); - } - - /* Delete the timer. Check first if it is already deleted. */ - if ((client_ptr -> nxd_mqtt_timer).tx_timer_id != 0) - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - -#ifndef NXD_MQTT_CLOUD_ENABLE - /* Delete the event flag. Check first if it is already deleted. */ - if ((client_ptr -> nxd_mqtt_events).tx_event_flags_group_id != 0) - tx_event_flags_delete(&client_ptr -> nxd_mqtt_events); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Release all the messages on the receive queue. */ - while (client_ptr -> message_receive_queue_head) - { - _nxd_mqtt_release_receive_packet(client_ptr, client_ptr -> message_receive_queue_head, NX_NULL); - } - client_ptr -> message_receive_queue_depth = 0; - - /* Delete all the messages sitting in the receive and transmit queue. */ - while (client_ptr -> message_transmit_queue_head) - { - _nxd_mqtt_release_transmit_packet(client_ptr, client_ptr -> message_transmit_queue_head, NX_NULL); - } - - /* Release mutex */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - -#ifndef NXD_MQTT_CLOUD_ENABLE - /* Delete the mutex. */ - tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Deleting the socket, (the socket ID is cleared); this signals it is ok to delete this thread. */ - nx_tcp_socket_delete(&client_ptr -> nxd_mqtt_client_socket); - } - else - { - - /* Release mutex */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - } -} - - -#ifndef NXD_MQTT_CLOUD_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function serves as the entry point for the MQTT */ -/* client thread. */ -/* */ -/* INPUT */ -/* */ -/* mqtt_client Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get */ -/* _nxd_mqtt_client_event_process */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_create */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nxd_mqtt_thread_entry(ULONG mqtt_client) -{ -NXD_MQTT_CLIENT *client_ptr; -ULONG events; - - client_ptr = (NXD_MQTT_CLIENT *)mqtt_client; - - /* Loop to process events on the MQTT client */ - for (;;) - { - - tx_event_flags_get(&client_ptr -> nxd_mqtt_events, MQTT_ALL_EVENTS, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Call the event processing routine. */ - _nxd_mqtt_client_event_process(client_ptr, NX_NULL, events); - - if (events & MQTT_DELETE_EVENT) - { - break; - } - } -} -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _mqtt_client_disconnect_callback PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is passed to MQTT client socket create call. */ -/* This callback function notifies MQTT client thread when the TCP */ -/* connection is lost. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to TCP socket that */ -/* disconnected. */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* TCP socket disconnect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _mqtt_client_disconnect_callback(NX_TCP_SOCKET *socket_ptr) -{ -NXD_MQTT_CLIENT *client_ptr = (NXD_MQTT_CLIENT *)(socket_ptr -> nx_tcp_socket_reserved_ptr); - - /* Set the MQTT_NETWORK_DISCONNECT event. This event indicates - that the disconnect is initiated from the network. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_NETWORK_DISCONNECT_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_NETWORK_DISCONNECT_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an instance for MQTT Client. It initializes */ -/* MQTT Client control block, creates a thread, mutex and event queue */ -/* for MQTT Client, and creates the TCP socket for MQTT messaging. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* client_id Client ID for this instance */ -/* client_id_length Length of Client ID, in bytes */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* stack_ptr Client thread's stack pointer */ -/* stack_size Client thread's stack size */ -/* mqtt_thread_priority Priority for MQTT thread */ -/* memory_ptr Deprecated and not used */ -/* memory_size Deprecated and not used */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_create_internal Create mqtt client */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, - CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, - VOID *memory_ptr, ULONG memory_size) -{ - -UINT status; - - - NX_PARAMETER_NOT_USED(memory_ptr); - NX_PARAMETER_NOT_USED(memory_size); - - /* Create MQTT client. */ - status = _nxd_mqtt_client_create_internal(client_ptr, client_name, client_id, client_id_length, ip_ptr, - pool_ptr, stack_ptr, stack_size, mqtt_thread_priority); - - /* Check status. */ - if (status) - { - return(status); - } - -#ifdef NXD_MQTT_CLOUD_ENABLE - - /* Create cloud helper. */ - status = nx_cloud_create(&(client_ptr -> nxd_mqtt_client_cloud), "Cloud Helper", stack_ptr, stack_size, mqtt_thread_priority); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ - - /* Delete socket. */ - nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); - - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Save the cloud pointer. */ - client_ptr -> nxd_mqtt_client_cloud_ptr = &(client_ptr -> nxd_mqtt_client_cloud); - - /* Save the mutex pointer. */ - client_ptr -> nxd_mqtt_client_mutex_ptr = &(client_ptr -> nxd_mqtt_client_cloud.nx_cloud_mutex); - - /* Register MQTT on cloud helper. */ - status = nx_cloud_module_register(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module), client_name, NX_CLOUD_MODULE_MQTT_EVENT, - _nxd_mqtt_client_event_process, client_ptr); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Delete own created cloud. */ - nx_cloud_delete(&(client_ptr -> nxd_mqtt_client_cloud)); - - /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ - - /* Delete socket. */ - nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); - - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Set start event to start MQTT. */ - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_START_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Return. */ - return(NXD_MQTT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_create_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an instance for MQTT Client. It initializes */ -/* MQTT Client control block, creates a thread, mutex and event queue */ -/* for MQTT Client, and creates the TCP socket for MQTT messaging. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* client_id Client ID for this instance */ -/* client_id_length Length of Client ID, in bytes */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* stack_ptr Client thread's stack pointer */ -/* stack_size Client thread's stack size */ -/* mqtt_thread_priority Priority for MQTT thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_create Create a thread */ -/* tx_mutex_create Create mutex */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* tx_event_flag_create Create event flag */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_client_create_internal(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, - CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority) -{ -UINT status; - -#ifdef NXD_MQTT_CLOUD_ENABLE - NX_PARAMETER_NOT_USED(stack_ptr); - NX_PARAMETER_NOT_USED(stack_size); - NX_PARAMETER_NOT_USED(mqtt_thread_priority); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Clear the MQTT Client control block. */ - NXD_MQTT_SECURE_MEMSET((void *)client_ptr, 0, sizeof(NXD_MQTT_CLIENT)); - -#ifndef NXD_MQTT_CLOUD_ENABLE - - /* Create MQTT mutex. */ - status = tx_mutex_create(&client_ptr -> nxd_mqtt_protection, client_name, TX_NO_INHERIT); - - /* Determine if an error occurred. */ - if (status != TX_SUCCESS) - { - - return(NXD_MQTT_INTERNAL_ERROR); - } - client_ptr -> nxd_mqtt_client_mutex_ptr = &(client_ptr -> nxd_mqtt_protection); - - /* Now create MQTT client thread */ - status = tx_thread_create(&(client_ptr -> nxd_mqtt_thread), client_name, _nxd_mqtt_thread_entry, - (ULONG)client_ptr, stack_ptr, stack_size, mqtt_thread_priority, mqtt_thread_priority, - NXD_MQTT_CLIENT_THREAD_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred. */ - if (status != TX_SUCCESS) - { - /* Delete the mutex. */ - tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); - - /* Return error code. */ - return(NXD_MQTT_INTERNAL_ERROR); - } - - status = tx_event_flags_create(&(client_ptr -> nxd_mqtt_events), client_name); - - if (status != TX_SUCCESS) - { - /* Delete the mutex. */ - tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); - - /* Delete the thread. */ - tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); - - /* Return error code. */ - return(NXD_MQTT_INTERNAL_ERROR); - } -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Record the client ID information. */ - client_ptr -> nxd_mqtt_client_id = client_id; - client_ptr -> nxd_mqtt_client_id_length = client_id_length; - client_ptr -> nxd_mqtt_client_ip_ptr = ip_ptr; - client_ptr -> nxd_mqtt_client_packet_pool_ptr = pool_ptr; - client_ptr -> nxd_mqtt_client_name = client_name; - - /* Create the socket. */ - status = nx_tcp_socket_create(client_ptr -> nxd_mqtt_client_ip_ptr, &(client_ptr -> nxd_mqtt_client_socket), client_ptr -> nxd_mqtt_client_name, - NX_IP_NORMAL, NX_DONT_FRAGMENT, 0x80, NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE, - NX_NULL, _mqtt_client_disconnect_callback); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { -#ifndef NXD_MQTT_CLOUD_ENABLE - /* Delete the mutex. */ - tx_mutex_delete(&client_ptr -> nxd_mqtt_protection); - - /* Delete the event flags. */ - tx_event_flags_delete(&(client_ptr -> nxd_mqtt_events)); - - /* Delete the thread. */ - tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Record the client_ptr in the socket structure. */ - client_ptr -> nxd_mqtt_client_socket.nx_tcp_socket_reserved_ptr = (VOID *)client_ptr; - - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_INITIALIZE; - -#ifndef NXD_MQTT_CLOUD_ENABLE - /* Start MQTT thread. */ - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_START_EVENT, TX_OR); - tx_thread_resume(&(client_ptr -> nxd_mqtt_thread)); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - return(NXD_MQTT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_login_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets optional MQTT username and password. Note */ -/* if the broker requires username and password, this information */ -/* must be set prior to calling nxd_mqtt_client_connect or */ -/* nxd_mqtt_client_secure_connect. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* username User name, or NULL if user */ -/* name is not required */ -/* username_length Length of the user name, or */ -/* 0 if user name is NULL */ -/* password Password string, or NULL if */ -/* password is not required */ -/* password_length Length of the password, or */ -/* 0 if password is NULL */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, - CHAR *username, UINT username_length, CHAR *password, UINT password_length) -{ -UINT status; - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - client_ptr -> nxd_mqtt_client_username = username; - client_ptr -> nxd_mqtt_client_username_length = (USHORT)username_length; - client_ptr -> nxd_mqtt_client_password = password; - client_ptr -> nxd_mqtt_client_password_length = (USHORT)password_length; - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_will_message_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets optional MQTT will topic and will message. */ -/* Note that if will message is needed, application must set will */ -/* message prior to calling nxd_mqtt_client_connect or */ -/* nxd_mqtt_client_secure_connect. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* will_topic Will topic string. */ -/* will_topic_length Length of the will topic. */ -/* will_message Will message string. */ -/* will_message_length Length of the will message. */ -/* will_retain_flag Whether or not the will */ -/* message is to be retained */ -/* when it is published. */ -/* Valid values are NX_TRUE */ -/* NX_FALSE */ -/* will_QoS QoS level to be used when */ -/* publishing will message. */ -/* Valid values are 0, 1, 2 */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, - const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, - UINT will_message_length, UINT will_retain_flag, UINT will_QoS) -{ -UINT status; - - if (will_QoS == 2) - { - return(NXD_MQTT_QOS2_NOT_SUPPORTED); - } - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - - client_ptr -> nxd_mqtt_client_will_topic = will_topic; - client_ptr -> nxd_mqtt_client_will_topic_length = will_topic_length; - client_ptr -> nxd_mqtt_client_will_message = will_message; - client_ptr -> nxd_mqtt_client_will_message_length = will_message_length; - - if (will_retain_flag == NX_TRUE) - { - client_ptr -> nxd_mqtt_client_will_qos_retain = 0x80; - } - client_ptr -> nxd_mqtt_client_will_qos_retain = (UCHAR)(client_ptr -> nxd_mqtt_client_will_qos_retain | will_QoS); - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_will_message_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the */ -/* nxd_mqtt_client_will_message_set call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* will_topic Will topic string. */ -/* will_topic_length Length of the will topic. */ -/* will_message Will message string. */ -/* will_message_length Length of the will message. */ -/* will_retain_flag Whether or not the will */ -/* message is to be retained */ -/* when it is published. */ -/* Valid values are NX_TRUE */ -/* NX_FALSE */ -/* will_QoS QoS level to be used when */ -/* publishing will message. */ -/* Valid values are 0, 1, 2 */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_will_message_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, - const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, - UINT will_message_length, UINT will_retain_flag, UINT will_QoS) -{ - - if (client_ptr == NX_NULL) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - /* Valid will_topic string. The will topic string cannot be NULL. */ - if ((will_topic == NX_NULL) || (will_topic_length == 0)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - if ((will_retain_flag != NX_TRUE) && (will_retain_flag != NX_FALSE)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - if (will_QoS > 2) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - return(_nxd_mqtt_client_will_message_set(client_ptr, will_topic, will_topic_length, will_message, - will_message_length, will_retain_flag, will_QoS)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_login_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the nxd_mqtt_client_login call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* username User name, or NULL if user */ -/* name is not required */ -/* username_length Length of the user name, or */ -/* 0 if user name is NULL */ -/* password Password string, or NULL if */ -/* password is not required */ -/* password_length Length of the password, or */ -/* 0 if password is NULL */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_login_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, - CHAR *username, UINT username_length, CHAR *password, UINT password_length) -{ - if (client_ptr == NX_NULL) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - /* Username and username length don't match, - or password and password length don't match. */ - if (((username == NX_NULL) && (username_length != 0)) || - ((password == NX_NULL) && (password_length != 0))) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - return(_nxd_mqtt_client_login_set(client_ptr, username, username_length, password, password_length)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_retransmit_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retransmit QoS1 messages upon reconnection, if the */ -/* connection is not set CLEAN_SESSION. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* wait_option Timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* nx_secure_tls_session_send */ -/* nx_tcp_socket_send */ -/* nx_packet_release */ -/* tx_time_get */ -/* nx_packet_copy */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_client_retransmit_message(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) -{ -NX_PACKET *transmit_packet_ptr; -NX_PACKET *packet_ptr; -UINT status = NXD_MQTT_SUCCESS; -UINT mutex_status; -UCHAR fixed_header; - - transmit_packet_ptr = client_ptr -> message_transmit_queue_head; - - while (transmit_packet_ptr) - { - fixed_header = *(transmit_packet_ptr -> nx_packet_prepend_ptr); - - if ((fixed_header & 0xF0) == (MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4)) - { - - /* Retransmit publish packet only. */ - /* Obtain a NetX Packet. */ - status = nx_packet_copy(transmit_packet_ptr, &packet_ptr, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - - if (status != NXD_MQTT_SUCCESS) - { - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Send the packet. */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - } -#else - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - -#endif /* NX_SECURE_ENABLE */ - - if (status) - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - - status = NXD_MQTT_COMMUNICATION_FAILURE; - } - /* Obtain the mutex. */ - mutex_status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, wait_option); - - if (mutex_status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - if (status) - { - return(status); - } - } - transmit_packet_ptr = transmit_packet_ptr -> nx_packet_queue_next; - } - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function makes an initial connection to the MQTT server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* server_ip Server IP address structure */ -/* server_port Server port number, in host */ -/* byte order */ -/* keepalive Keepalive flag */ -/* clean_session Clean session flag */ -/* wait_option Timeout value */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* nx_tcp_socket_create Create TCP socket */ -/* nx_tcp_socket_receive_notify */ -/* nx_tcp_client_socket_bind */ -/* nxd_tcp_client_socket_connect */ -/* nx_tcp_client_socket_unbind */ -/* tx_mutex_put */ -/* nx_secure_tls_session_start */ -/* nx_secure_tls_session_send */ -/* nx_secure_tls_session_receive */ -/* _nxd_mqtt_packet_allocate */ -/* _nxd_mqtt_client_set_fixed_header */ -/* _nxd_mqtt_client_append_message */ -/* nx_tcp_socket_send */ -/* nx_packet_release */ -/* nx_tcp_socket_receive */ -/* tx_event_flag_set */ -/* _nxd_mqtt_release_transmit_packet */ -/* tx_timer_create */ -/* nx_secure_tls_session_receive */ -/* _nxd_mqtt_client_connection_end */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT keepalive, UINT clean_session, ULONG wait_option) -{ -NX_PACKET *packet_ptr; -UINT status; - - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif /* NX_SECURE_ENABLE */ - - return(NXD_MQTT_MUTEX_FAILURE); - } - - /* Do nothing if the client is already connected. */ - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_CONNECTED) - { - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_ALREADY_CONNECTED); - } - -#if defined(NX_SECURE_ENABLE) && defined(NXD_MQTT_REQUIRE_TLS) - if (!client_ptr -> nxd_mqtt_client_use_tls) - { - - /* NXD_MQTT_REQUIRE_TLS is defined but the application does not use TLS. - This is security violation. Return with failure code. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_CONNECT_FAILURE); - } -#endif /* NX_SECURE_ENABLE && NXD_MQTT_REQUIRE_TLS*/ - - /* Record the keepalive value, converted to TX timer ticks. */ - client_ptr -> nxd_mqtt_keepalive = keepalive * NX_IP_PERIODIC_RATE; - if (keepalive) - { - client_ptr -> nxd_mqtt_timer_value = NXD_MQTT_KEEPALIVE_TIMER_RATE; - client_ptr -> nxd_mqtt_ping_timeout = NXD_MQTT_PING_TIMEOUT_DELAY; - - /* Create timer */ - status = tx_timer_create(&(client_ptr -> nxd_mqtt_timer), "MQTT Timer", _nxd_mqtt_periodic_timer_entry, (ULONG)client_ptr, - client_ptr -> nxd_mqtt_timer_value, client_ptr -> nxd_mqtt_timer_value, TX_AUTO_ACTIVATE); - if (status) - { -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif /* NX_SECURE_ENABLE */ - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_INTERNAL_ERROR); - } - } - else - { - client_ptr -> nxd_mqtt_timer_value = 0; - client_ptr -> nxd_mqtt_ping_timeout = 0; - } - - /* Record the clean session flag. */ - client_ptr -> nxd_mqtt_clean_session = clean_session; - - /* Set TCP connection establish notify for non-blocking mode. */ - if (wait_option == 0) - { - status = nx_tcp_socket_establish_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_tcp_establish_notify); - - /* Check status. */ - if (status != NX_SUCCESS) - { -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif /* NX_SECURE_ENABLE */ - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(status); - } - - /* Set the receive callback. */ - nx_tcp_socket_receive_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_receive_callback); - } - else - { - - /* Clean receive callback. */ - client_ptr -> nxd_mqtt_client_socket.nx_tcp_receive_callback = NX_NULL; - } - - /* Release mutex */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* First attempt to bind the client socket. */ - status = nx_tcp_client_socket_bind(&(client_ptr -> nxd_mqtt_client_socket), NX_ANY_PORT, wait_option); - - if (status != NX_SUCCESS) - { -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif /* NX_SECURE_ENABLE */ - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Obtain the mutex. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - /* Make state as NXD_MQTT_CLIENT_STATE_CONNECTING. */ - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_CONNECTING; - - /* Release mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Connect to the MQTT server */ - status = nxd_tcp_client_socket_connect(&(client_ptr -> nxd_mqtt_client_socket), server_ip, server_port, wait_option); - if ((status != NX_SUCCESS) && (status != NX_IN_PROGRESS)) - { - - /* Obtain the mutex. */ - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - /* Make state as NXD_MQTT_CLIENT_STATE_IDLE. */ - client_ptr -> nxd_mqtt_client_state = NXD_MQTT_CLIENT_STATE_IDLE; - - /* Release mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - nx_secure_tls_session_delete(&(client_ptr -> nxd_mqtt_tls_session)); - } -#endif /* NX_SECURE_ENABLE */ - nx_tcp_client_socket_unbind(&(client_ptr -> nxd_mqtt_client_socket)); - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - return(NXD_MQTT_CONNECT_FAILURE); - } - - /* Just return for non-blocking mode. */ - if (status == NX_IN_PROGRESS) - { - return(NX_IN_PROGRESS); - } - - /* If TLS is enabled, start TLS */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - - status = nx_secure_tls_session_start(&(client_ptr -> nxd_mqtt_tls_session), &(client_ptr -> nxd_mqtt_client_socket), wait_option); - - if (status != NX_SUCCESS) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - return(NXD_MQTT_CONNECT_FAILURE); - } - } -#endif /* NX_SECURE_ENABLE */ - - /* Start to send connect packet. */ - status = _nxd_mqtt_client_connect_packet_send(client_ptr, wait_option); - - if (status != NX_SUCCESS) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - - return(NXD_MQTT_CONNECT_FAILURE); - } - -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_receive(&(client_ptr -> nxd_mqtt_tls_session), &packet_ptr, wait_option); - } - else - { - status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, wait_option); - } -#else - status = nx_tcp_socket_receive(&client_ptr -> nxd_mqtt_client_socket, &packet_ptr, wait_option); -#endif /* NX_SECURE_ENABLE */ - - /* Check status. */ - if (status) - { - - /* End connection. */ - _nxd_mqtt_client_connection_end(client_ptr, NX_NO_WAIT); - return(NXD_MQTT_COMMUNICATION_FAILURE); - } - - /* Process CONNACK message. */ - status = _nxd_mqtt_process_connack(client_ptr, packet_ptr, wait_option); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Check status. */ - if (status == NX_SUCCESS) - { - - /* Set the receive callback. */ - nx_tcp_socket_receive_notify(&client_ptr -> nxd_mqtt_client_socket, _nxd_mqtt_receive_callback); - } - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_connect_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends CONNECT packet to MQTT server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* keepalive Keepalive flag */ -/* clean_session Clean session flag */ -/* wait_option Timeout value */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release */ -/* nx_tcp_socket_send */ -/* nx_secure_tls_session_send */ -/* _nxd_mqtt_packet_allocate */ -/* _nxd_mqtt_release_transmit_packet */ -/* _nxd_mqtt_client_connection_end */ -/* _nxd_mqtt_client_set_fixed_header */ -/* _nxd_mqtt_client_append_message */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_connect */ -/* _nxd_mqtt_tcp_establish_process */ -/* _nxd_mqtt_tls_establish_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_connect_packet_send(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option) -{ -NX_PACKET *packet_ptr; -UINT status; -UINT length = 0; -UCHAR connection_flags = 0; -UINT ret = NXD_MQTT_SUCCESS; -UCHAR temp_data[4]; -UINT keepalive = (client_ptr -> nxd_mqtt_keepalive/NX_IP_PERIODIC_RATE); - - - /* Construct connect flags by taking the connect flag user supplies, or'ing the username and - password bits, if they are supplied. */ - if (client_ptr -> nxd_mqtt_client_username) - { - connection_flags |= MQTT_CONNECT_FLAGS_USERNAME; - - /* Add the password flag only if username is supplied. */ - if (client_ptr -> nxd_mqtt_client_password) - { - connection_flags |= MQTT_CONNECT_FLAGS_PASSWORD; - } - } - - if (client_ptr -> nxd_mqtt_client_will_topic) - { - connection_flags = connection_flags | MQTT_CONNECT_FLAGS_WILL_FLAG; - - - if (client_ptr -> nxd_mqtt_client_will_qos_retain & 0x80) - { - connection_flags = connection_flags | MQTT_CONNECT_FLAGS_WILL_RETAIN; - } - - connection_flags = (UCHAR)(connection_flags | ((client_ptr -> nxd_mqtt_client_will_qos_retain & 0x3) << 3)); - } - - if (client_ptr -> nxd_mqtt_clean_session == NX_TRUE) - { - connection_flags = connection_flags | MQTT_CONNECT_FLAGS_CLEAN_SESSION; - - /* Clear any transmit blocks from the previous session. */ - while (client_ptr -> message_transmit_queue_head) - { - _nxd_mqtt_release_transmit_packet(client_ptr, client_ptr -> message_transmit_queue_head, NX_NULL); - } - } - - /* Set the length of the packet. */ - length = 10; - - /* Add the size of the client Identifier. */ - length += (client_ptr -> nxd_mqtt_client_id_length + 2); - - /* Add the will topic, if present. */ - if (connection_flags & MQTT_CONNECT_FLAGS_WILL_FLAG) - { - length += (client_ptr -> nxd_mqtt_client_will_topic_length + 2); - length += (client_ptr -> nxd_mqtt_client_will_message_length + 2); - } - if (connection_flags & MQTT_CONNECT_FLAGS_USERNAME) - { - length += (UINT)(client_ptr -> nxd_mqtt_client_username_length + 2); - } - if (connection_flags & MQTT_CONNECT_FLAGS_PASSWORD) - { - length += (UINT)(client_ptr -> nxd_mqtt_client_password_length + 2); - } - - /* Check for invalid length. */ - if (length > (127 * 127 * 127 * 127)) - { - return(NXD_MQTT_INTERNAL_ERROR); - } - - status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); - if (status) - { - - return(status); - } - - /* Construct MQTT CONNECT message. */ - temp_data[0] = ((MQTT_CONTROL_PACKET_TYPE_CONNECT << 4) & 0xF0); - - /* Fill in fixed header. */ - ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, temp_data[0], length, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, "MQTT", 4, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Fill in protocol level, */ - temp_data[0] = MQTT_PROTOCOL_LEVEL; - - /* Fill in byte 8: connect flags */ - temp_data[1] = connection_flags; - - /* Fill in byte 9 and 10: keep alive */ - temp_data[2] = (keepalive >> 8) & 0xFF; - temp_data[3] = (keepalive & 0xFF); - - ret = nx_packet_data_append(packet_ptr, temp_data, 4, client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Fill in payload area, in the order of: client identifier, will topic, will message, - user name, and password. */ - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_id, - client_ptr -> nxd_mqtt_client_id_length, wait_option); - - /* Next fill will topic and will message if the will flag is set. */ - if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_WILL_FLAG)) - { - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, (CHAR *)client_ptr -> nxd_mqtt_client_will_topic, - client_ptr -> nxd_mqtt_client_will_topic_length, wait_option); - - if (!ret) - { - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, (CHAR *)client_ptr -> nxd_mqtt_client_will_message, - client_ptr -> nxd_mqtt_client_will_message_length, wait_option); - } - } - - /* Fill username if username flag is set */ - if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_USERNAME)) - { - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_username, - client_ptr -> nxd_mqtt_client_username_length, wait_option); - } - - /* Fill password if password flag is set */ - if (!ret && (connection_flags & MQTT_CONNECT_FLAGS_PASSWORD)) - { - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, client_ptr -> nxd_mqtt_client_password, - client_ptr -> nxd_mqtt_client_password_length, wait_option); - } - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Ready to send the connect message to the server. */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - } -#else - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - -#endif /* NX_SECURE_ENABLE */ - - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_secure_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function makes an initial secure (TLS) connection to */ -/* the MQTT server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* server_ip Server IP address structure */ -/* server_port Server port number, in host */ -/* byte order */ -/* tls_setup User-supplied callback */ -/* function to set up TLS */ -/* parameters. */ -/* username User name, or NULL if user */ -/* name is not required */ -/* username_length Length of the user name, or */ -/* 0 if user name is NULL */ -/* password Password string, or NULL if */ -/* password is not required */ -/* password_length Length of the password, or */ -/* 0 if password is NULL */ -/* connection_flag Flag passed to the server */ -/* timeout Timeout value */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_connect Actual MQTT Client connect */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifdef NX_SECURE_ENABLE -UINT _nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, - NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), - UINT keepalive, UINT clean_session, ULONG wait_option) -{ -UINT ret; - - /* Set up TLS session information. */ - ret = (*tls_setup)(client_ptr, &client_ptr -> nxd_mqtt_tls_session, - &client_ptr -> nxd_mqtt_tls_certificate, - &client_ptr -> nxd_mqtt_tls_trusted_certificate); - - if (ret) - { - return(ret); - } - - /* Mark the connection as secure. */ - client_ptr -> nxd_mqtt_client_use_tls = 1; - - ret = _nxd_mqtt_client_connect(client_ptr, server_ip, server_port, keepalive, clean_session, wait_option); - - return(ret); -} - -#endif /* NX_SECURE_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created MQTT client instance. */ -/* If the NXD_MQTT_SOCKET_TIMEOUT is set to NX_WAIT_FOREVER, this may */ -/* suspend infinitely. This is because the MQTT Client must */ -/* disconnect with the server, and if the network link is disabled or */ -/* the server is not responding, this will blocks this function from */ -/* completing. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr) -{ - - - /* Set the event flag for DELETE. Next time when the MQTT client thread - wakes up, it will perform the deletion process. */ -#ifndef NXD_MQTT_CLOUD_ENABLE - tx_event_flags_set(&client_ptr -> nxd_mqtt_events, MQTT_DELETE_EVENT, TX_OR); -#else - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_DELETE_EVENT); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - /* Check if the MQTT client thread has completed. */ - while((client_ptr -> nxd_mqtt_client_socket).nx_tcp_socket_id != 0) - { - tx_thread_sleep(NX_IP_PERIODIC_RATE); - } - -#ifndef NXD_MQTT_CLOUD_ENABLE - /* Now we can delete the Client instance. */ - tx_thread_delete(&(client_ptr -> nxd_mqtt_thread)); -#else - /* Deregister mqtt module from cloud helper. */ - nx_cloud_module_deregister(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module)); - - /* Delete own created cloud. */ - if (client_ptr -> nxd_mqtt_client_cloud.nx_cloud_id == NX_CLOUD_ID) - nx_cloud_delete(&(client_ptr -> nxd_mqtt_client_cloud)); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - - return(NXD_MQTT_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_publish_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a publish packet to the connected broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* packet_ptr Pointer to publish packet */ -/* packet_id Current packet ID */ -/* QoS Quality of service */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* nx_tcp_socket_send */ -/* nx_secure_tls_session_send */ -/* nx_packet_release */ -/* _nxd_mqtt_copy_transmit_packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_publish */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, - USHORT packet_id, UINT QoS, ULONG wait_option) -{ - -UINT status; -UINT ret = NXD_MQTT_SUCCESS; - - if (QoS != 0) - { - /* This packet needs to be stored locally for possible retransmission. */ - NX_PACKET *transmit_packet_ptr; - - /* Copy packet for retransmission. */ - if (_nxd_mqtt_copy_transmit_packet(client_ptr, packet_ptr, &transmit_packet_ptr, - packet_id, NX_TRUE, wait_option)) - { - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - nx_packet_release(transmit_packet_ptr); - return(NXD_MQTT_MUTEX_FAILURE); - } - - if (client_ptr -> message_transmit_queue_head == NX_NULL) - { - client_ptr -> message_transmit_queue_head = transmit_packet_ptr; - } - else - { - client_ptr -> message_transmit_queue_tail -> nx_packet_queue_next = transmit_packet_ptr; - } - client_ptr -> message_transmit_queue_tail = transmit_packet_ptr; - } - else - { - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - } - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - /* Ready to send the connect message to the server. */ -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, wait_option); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - } -#else - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, wait_option); - -#endif /* NX_SECURE_ENABLE */ - - if (status) - { - ret = NXD_MQTT_COMMUNICATION_FAILURE; - } - - return(ret); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_publish PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function publishes a message to the connected broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Name of the topic */ -/* topic_name_length Length of the topic name */ -/* message Message string */ -/* message_length Length of the message, */ -/* in bytes */ -/* retain The retain flag, whether */ -/* or not the broker should */ -/* store this message */ -/* QoS Expected QoS level */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* _nxd_mqtt_packet_allocate */ -/* _nxd_mqtt_client_set_fixed_header */ -/* _nxd_mqtt_client_append_message */ -/* tx_mutex_put */ -/* nx_packet_release */ -/* _nxd_mqtt_client_publish_packet_send */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, - CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG wait_option) -{ - -NX_PACKET *packet_ptr; -UINT status; -UINT length = 0; -UCHAR flags; -USHORT packet_id = 0; -UINT ret = NXD_MQTT_SUCCESS; - - if (QoS == 2) - { - return(NXD_MQTT_QOS2_NOT_SUPPORTED); - } - - - /* Do nothing if the client is already connected. */ - if (client_ptr -> nxd_mqtt_client_state != NXD_MQTT_CLIENT_STATE_CONNECTED) - { - return(NXD_MQTT_NOT_CONNECTED); - } - - status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); - - if (status != NXD_MQTT_SUCCESS) - { - return(NXD_MQTT_PACKET_POOL_FAILURE); - } - - flags = (UCHAR)((MQTT_CONTROL_PACKET_TYPE_PUBLISH << 4) | (QoS << 1)); - - if (retain) - { - flags = flags | MQTT_PUBLISH_RETAIN; - } - - - /* Compute the remaining length. */ - - /* Topic Name. */ - /* Compute Topic Name length. */ - length = topic_name_length + 2; - - /* Count packet ID for QoS 1 or QoS 2 message. */ - if ((QoS == 1) || (QoS == 2)) - { - length += 2; - } - - /* Count message. */ - if ((message != NX_NULL) && (message_length != 0)) - { - length += message_length; - } - - /* Write out the control header and remaining length field. */ - ret = _nxd_mqtt_client_set_fixed_header(client_ptr, packet_ptr, flags, length, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_INTERNAL_ERROR); - } - - - /* Write out topic */ - ret = _nxd_mqtt_client_append_message(client_ptr, packet_ptr, topic_name, topic_name_length, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Append Packet Identifier for QoS level 1 or 2 MQTT 3.3.2.2 */ - if ((QoS == 1) || (QoS == 2)) - { - UCHAR identifier[2]; - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - if (status != TX_SUCCESS) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - - packet_id = (USHORT)client_ptr -> nxd_mqtt_client_packet_identifier; - identifier[0] = (UCHAR)(client_ptr -> nxd_mqtt_client_packet_identifier >> 8); - identifier[1] = (client_ptr -> nxd_mqtt_client_packet_identifier & 0xFF); - - /* Update packet id. */ - client_ptr -> nxd_mqtt_client_packet_identifier = (client_ptr -> nxd_mqtt_client_packet_identifier + 1) & 0xFFFF; - - /* Prevent packet identifier from being zero. MQTT-2.3.1-1 */ - if(client_ptr -> nxd_mqtt_client_packet_identifier == 0) - client_ptr -> nxd_mqtt_client_packet_identifier = 1; - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - ret = nx_packet_data_append(packet_ptr, identifier, 2, - client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_INTERNAL_ERROR); - } - } - - /* Append message. */ - if ((message != NX_NULL) && (message_length) != 0) - { - - /* Use nx_packet_data_append to move user-supplied message data into the packet. - nx_packet_data_append uses chained packet if the additional storage space is - needed. */ - ret = nx_packet_data_append(packet_ptr, message, message_length, - client_ptr -> nxd_mqtt_client_packet_pool_ptr, wait_option); - if(ret) - { - /* Unable to obtain a new packet to store the message. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return(NXD_MQTT_INTERNAL_ERROR); - } - } - - /* Send publish packet. */ - ret = _nxd_mqtt_client_publish_packet_send(client_ptr, packet_ptr, packet_id, QoS, wait_option); - - if (ret) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - return(ret); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_subscribe PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a subscribe message to the broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Pointer to the topic string */ -/* to subscribe to */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* QoS Expected QoS level */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_sub_unsub The actual routine that */ -/* performs the sub/unsub */ -/* action. */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS) -{ - - if (QoS == 2) - { - return(NXD_MQTT_QOS2_NOT_SUPPORTED); - } - - return(_nxd_mqtt_client_sub_unsub(client_ptr, (MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE << 4) | 0x02, - topic_name, topic_name_length, QoS)); -} - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_unsubscribe PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function unsubscribes a topic from the broker. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Pointer to the topic string */ -/* to subscribe to */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_sub_unsub */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length) -{ - return(_nxd_mqtt_client_sub_unsub(client_ptr, (MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE << 4) | 0x02, - topic_name, topic_name_length, 0)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_send_simple_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function handles the transmission of PINGREQ or */ -/* DISCONNECT message. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* header_value Value to be programmed into */ -/* MQTT header. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* _nxd_mqtt_packet_allocate */ -/* tx_mutex_put */ -/* nx_tcp_socket_send */ -/* nx_secure_tls_session_send */ -/* nx_packet_release */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_mqtt_client_ping */ -/* _nxd_mqtt_client_disconnect */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nxd_mqtt_send_simple_message(NXD_MQTT_CLIENT *client_ptr, UCHAR header_value) -{ - -NX_PACKET *packet_ptr; -UINT status; -UINT status_mutex; -UCHAR *byte; - - status = _nxd_mqtt_packet_allocate(client_ptr, &packet_ptr); - if (status) - { - return(NXD_MQTT_INTERNAL_ERROR); - } - - if (2u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) - { - nx_packet_release(packet_ptr); - - /* Packet buffer is too small to hold the message. */ - return(NX_SIZE_ERROR); - } - - byte = packet_ptr -> nx_packet_prepend_ptr; - - *byte = (UCHAR)(header_value << 4); - *(byte + 1) = 0; - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = 2; - - - /* Release MQTT protection before making NetX/TLS calls. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); -#ifdef NX_SECURE_ENABLE - if (client_ptr -> nxd_mqtt_client_use_tls) - { - status = nx_secure_tls_session_send(&(client_ptr -> nxd_mqtt_tls_session), packet_ptr, NX_WAIT_FOREVER); - } - else - { - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); - } -#else - - status = nx_tcp_socket_send(&client_ptr -> nxd_mqtt_client_socket, packet_ptr, NX_WAIT_FOREVER); - -#endif /* NX_SECURE_ENABLE */ - - status_mutex = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - status = NXD_MQTT_COMMUNICATION_FAILURE; - } - if (status_mutex) - { - return(NXD_MQTT_MUTEX_FAILURE); - } - - if (header_value == MQTT_CONTROL_PACKET_TYPE_PINGREQ) - { - /* Do not update the ping sent time if the outstanding ping has not been responded yet */ - if (client_ptr -> nxd_mqtt_ping_not_responded != 1) - { - /* Record the time we send out the PINGREG */ - client_ptr -> nxd_mqtt_ping_sent_time = tx_time_get(); - client_ptr -> nxd_mqtt_ping_not_responded = 1; - } - } - - /* Update the timeout value. */ - client_ptr -> nxd_mqtt_timeout = tx_time_get() + client_ptr -> nxd_mqtt_keepalive; - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disconnects the MQTT client from a server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_send_simple_message */ -/* _nxd_mqtt_process_disconnect */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr) -{ -UINT status; - - /* Obtain the mutex. */ - status = tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, TX_WAIT_FOREVER); - if (status != TX_SUCCESS) - { - /* Disable timer if timer has been started. */ - if (client_ptr -> nxd_mqtt_keepalive) - { - tx_timer_delete(&(client_ptr -> nxd_mqtt_timer)); - } - - return(NXD_MQTT_MUTEX_FAILURE); - } - - /* Let the server know we are ending the MQTT session. */ - _nxd_mqtt_send_simple_message(client_ptr, MQTT_CONTROL_PACKET_TYPE_DISCONNECT); - - /* Call the disconnect routine to disconnect the socket, - release transmit packets, release received packets, - and delete the client timer. */ - _nxd_mqtt_process_disconnect(client_ptr); - - /* Release the mutex. */ - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_receive_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function installs the MQTT client publish notify callback */ -/* function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* mqtt_client_receive_notify User-supplied callback */ -/* function, which is invoked */ -/* upon receiving a publish */ -/* message. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, - VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)) -{ - - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - - client_ptr -> nxd_mqtt_client_receive_notify = receive_notify; - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - - return(NXD_MQTT_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_message_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves a published MQTT message. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_buffer Pointer to the topic buffer */ -/* where topic is copied to */ -/* topic_buffer_size Size of the topic buffer. */ -/* actual_topic_length Number of bytes copied into */ -/* topic_buffer */ -/* message_buffer Pointer to the buffer where */ -/* message is copied to */ -/* message_buffer_size Size of the message_buffer */ -/* actual_message_length Number of bytes copied into */ -/* the message buffer. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_disconnect Actual MQTT Client disconnect */ -/* call */ -/* _nxd_mqtt_read_remaining_length Skip the remaining length */ -/* field */ -/* tx_mutex_get */ -/* tx_mutex_put */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, - UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length) -{ - -UINT status; -NX_PACKET *packet_ptr; -ULONG topic_offset; -USHORT topic_length; -ULONG message_offset; -ULONG message_length; - - tx_mutex_get(client_ptr -> nxd_mqtt_client_mutex_ptr, NX_WAIT_FOREVER); - while (client_ptr -> message_receive_queue_depth) - { - packet_ptr = client_ptr -> message_receive_queue_head; - status = _nxd_mqtt_process_publish_packet(packet_ptr, &topic_offset, &topic_length, &message_offset, &message_length); - if (status == NXD_MQTT_SUCCESS) - { - if ((topic_buffer_size < topic_length) || - (message_buffer_size < message_length)) - { - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_INSUFFICIENT_BUFFER_SPACE); - } - } - - client_ptr -> message_receive_queue_head = packet_ptr -> nx_packet_queue_next; - if (client_ptr -> message_receive_queue_tail == packet_ptr) - { - client_ptr -> message_receive_queue_tail = NX_NULL; - } - client_ptr -> message_receive_queue_depth--; - - if (status == NXD_MQTT_SUCCESS) - { - nx_packet_data_extract_offset(packet_ptr, topic_offset, topic_buffer, - topic_length, (ULONG *)actual_topic_length); - nx_packet_data_extract_offset(packet_ptr, message_offset, message_buffer, - message_length, (ULONG *)actual_message_length); - nx_packet_release(packet_ptr); - - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_SUCCESS); - } - nx_packet_release(packet_ptr); - } - tx_mutex_put(client_ptr -> nxd_mqtt_client_mutex_ptr); - return(NXD_MQTT_NO_MESSAGE); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in nxd_mqt_client_create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* client_name Name string used in by the */ -/* client */ -/* client_id Client ID used by the client */ -/* client_id_length Length of Client ID, in bytes */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* stack_ptr Client thread's stack pointer */ -/* stack_size Client thread's stack size */ -/* mqtt_thread_priority Priority for MQTT thread */ -/* memory_ptr Deprecated and not used */ -/* memory_size Deprecated and not used */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, - VOID *memory_ptr, ULONG memory_size) -{ - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (stack_ptr == NX_NULL) || (stack_size == 0) || (pool_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - return(_nxd_mqtt_client_create(client_ptr, client_name, client_id, client_id_length, ip_ptr, - pool_ptr, stack_ptr, stack_size, mqtt_thread_priority, - memory_ptr, memory_size)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* server_ip Server IP address structure */ -/* server_port Server port number, in host */ -/* byte order */ -/* keepalive The MQTT keepalive timer */ -/* clean_session Clean session flag */ -/* wait_option Suspension option */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_connect Actual MQTT Client connect */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT keepalive, UINT clean_session, ULONG wait_option) -{ - -UINT status; - - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (server_ip == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Test for IP version flag. */ - if ((server_ip -> nxd_ip_version != 4) && (server_ip -> nxd_ip_version != 6)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - if (server_port == 0) - { - return(NX_INVALID_PORT); - } - - - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_INITIALIZE) - { - return(NXD_MQTT_CLIENT_NOT_RUNNING); - } - - status = _nxd_mqtt_client_connect(client_ptr, server_ip, server_port, keepalive, clean_session, wait_option); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_secure_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client TLS secure connect. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* server_ip Server IP address structure */ -/* server_port Server port number, in host */ -/* byte order */ -/* tls_setup User-supplied callback */ -/* function to set up TLS */ -/* parameters. */ -/* keepalive The MQTT keepalive timer */ -/* wait_option Suspension option */ -/* */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_connect Actual MQTT Client connect */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifdef NX_SECURE_ENABLE - -UINT _nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, - NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), - UINT keepalive, UINT clean_session, ULONG wait_option) -{ - -UINT status; - - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (server_ip == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (server_port == 0) - { - return(NX_INVALID_PORT); - } - - if (client_ptr -> nxd_mqtt_client_state == NXD_MQTT_CLIENT_STATE_INITIALIZE) - { - return(NXD_MQTT_CLIENT_NOT_RUNNING); - } - - status = _nxd_mqtt_client_secure_connect(client_ptr, server_ip, server_port, tls_setup, - keepalive, clean_session, wait_option); - - return(status); -} -#endif /* NX_SECURE_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_delete Actual MQTT Client delete */ -/* call. */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr) -{ - -UINT status; - - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - status = _nxd_mqtt_client_delete(client_ptr); - - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_publish PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking to the publish service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Name of the topic */ -/* topic_name_length Length of the topic name */ -/* message Message string */ -/* message_length Length of the message, */ -/* in bytes */ -/* retain The retain flag, whether */ -/* or not the broker should */ -/* store this message */ -/* QoS Expected QoS level */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, - CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG wait_option) -{ - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Validate topic_name */ - if ((topic_name == NX_NULL) || (topic_name_length == 0)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - /* Validate message length. */ - if (message && (message_length == 0)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - /* Validate QoS value. */ - if (QoS > 3) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - return(_nxd_mqtt_client_publish(client_ptr, topic_name, topic_name_length, message, message_length, retain, QoS, wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_subscribe PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking to the subscribe service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Pointer to the topic string */ -/* to subscribe to */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* */ -/* OUTPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Pointer to the topic string */ -/* to subscribe to */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* QoS Expected QoS level */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_subscribe */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS) -{ - - - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Validate topic_name */ - if ((topic_name == NX_NULL) || (topic_name_length == 0)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - /* Validate QoS value. */ - if (QoS > 2) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - return(_nxd_mqtt_client_subscribe(client_ptr, topic_name, topic_name_length, QoS)); -} - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_unsubscribe PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking to the unsubscribe service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_name Pointer to the topic string */ -/* to unsubscribe */ -/* topic_name_length Length of the topic string */ -/* in bytes */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length) -{ - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Validate topic_name */ - if ((topic_name == NX_NULL) || (topic_name_length == 0)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - return(_nxd_mqtt_client_unsubscribe(client_ptr, topic_name, topic_name_length)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client disconnect call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_disconnect Actual MQTT Client disconnect */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr) -{ - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - return(_nxd_mqtt_client_disconnect(client_ptr)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_message_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client message get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* topic_buffer Pointer to the topic buffer */ -/* where topic is copied to */ -/* topic_buffer_size Size of the topic buffer. */ -/* actual_topic_length Number of bytes copied into */ -/* topic_buffer */ -/* message_buffer Pointer to the buffer where */ -/* message is copied to */ -/* message_buffer_size Size of the message_buffer */ -/* actual_message_length Number of bytes copied into */ -/* the message buffer. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_message_get */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, - UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length) -{ - - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Topic and topic_length can be NULL if caller does not care the topic string. */ - - /* Validate message. Message_length can be NULL if caller does not care message length. */ - if ((message_buffer == NX_NULL) || (topic_buffer == NX_NULL)) - { - return(NXD_MQTT_INVALID_PARAMETER); - } - - - return(_nxd_mqtt_client_message_get(client_ptr, topic_buffer, topic_buffer_size, actual_topic_length, - message_buffer, message_buffer_size, actual_message_length)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_receive_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in MQTT client publish notify call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* receive_notify User-supplied callback */ -/* function, which is invoked */ -/* upon receiving a publish */ -/* message. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_receive_notify_set */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, - VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)) -{ - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - if (receive_notify == NX_NULL) - { - return(NX_PTR_ERROR); - } - - return(_nxd_mqtt_client_receive_notify_set(client_ptr, receive_notify)); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_disconnect_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the notify function for the disconnect event. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* disconnect_notify The notify function to be */ -/* used when the client is */ -/* disconnected from the */ -/* server. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)) -{ - - client_ptr -> nxd_mqtt_disconnect_notify = disconnect_notify; - - return(NXD_MQTT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_mqtt_client_disconnect_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in setting MQTT client disconnect */ -/* callback function. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* disconnect_callback The callback function to be */ -/* used when an on-going */ -/* connection is disconnected. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_disconnect_notify_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)) -{ - - /* Validate client_ptr */ - if (client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - return(_nxd_mqtt_client_disconnect_notify_set(client_ptr, disconnect_notify)); -} - - -#ifdef NXD_MQTT_CLOUD_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_mqtt_client_cloud_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates mqtt client running on cloud helper thread. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to MQTT Client */ -/* client_name Name string used in by the */ -/* client */ -/* client_id Client ID used by the client */ -/* client_id_length Length of Client ID, in bytes */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* cloud_ptr Pointer to Cloud instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_mqtt_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_mqtt_client_cloud_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_CLOUD *cloud_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (pool_ptr == NX_NULL) || (cloud_ptr == NX_NULL) || (cloud_ptr -> nx_cloud_id != NX_CLOUD_ID)) - { - return(NX_PTR_ERROR); - } - - /* Create MQTT client. */ - status = _nxd_mqtt_client_create_internal(client_ptr, client_name, client_id, client_id_length, ip_ptr, - pool_ptr, NX_NULL, 0, 0); - - /* Check status. */ - if (status) - { - return(status); - } - - /* Save the cloud pointer. */ - client_ptr -> nxd_mqtt_client_cloud_ptr = cloud_ptr; - - /* Save the mutex pointer. */ - client_ptr -> nxd_mqtt_client_mutex_ptr = &(cloud_ptr -> nx_cloud_mutex); - - /* Register MQTT on cloud helper. */ - status = nx_cloud_module_register(client_ptr -> nxd_mqtt_client_cloud_ptr, &(client_ptr -> nxd_mqtt_client_cloud_module), client_name, NX_CLOUD_MODULE_MQTT_EVENT, - _nxd_mqtt_client_event_process, client_ptr); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Delete internal resource created in _nxd_mqtt_client_create_internal(). */ - - /* Delete socket. */ - nx_tcp_socket_delete(&(client_ptr -> nxd_mqtt_client_socket)); - - return(NXD_MQTT_INTERNAL_ERROR); - } - - /* Set start event to start MQTT. */ - nx_cloud_module_event_set(&(client_ptr -> nxd_mqtt_client_cloud_module), MQTT_START_EVENT); - - return(NXD_MQTT_SUCCESS); -} -#endif /* NXD_MQTT_CLOUD_ENABLE */ diff --git a/protocol_handlers/mqtt/nxd_mqtt_client.h b/protocol_handlers/mqtt/nxd_mqtt_client.h deleted file mode 100644 index f9be3d0b..00000000 --- a/protocol_handlers/mqtt/nxd_mqtt_client.h +++ /dev/null @@ -1,510 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** MQTT (MQTT) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_mqtt_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX MQTT Client component, including all */ -/* data types and external references. It is assumed that nx_api.h */ -/* and nx_port.h have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef _NXD_MQTT_CLIENT_H_ -#define _NXD_MQTT_CLIENT_H_ - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#ifdef NX_SECURE_ENABLE -#include "nx_secure_tls_api.h" -#endif /* NX_SECURE_ENABLE */ - -#ifdef NXD_MQTT_CLOUD_ENABLE -#include "nx_cloud.h" -#endif /* NXD_MQTT_CLOUD_ENABLE */ - -#ifdef NXD_MQTT_REQUIRE_TLS -#ifndef NX_SECURE_ENABLE -#error "The feature NXD_MQTT_REQUIRE_TLS requires NX_SECURE_ENABLE." -#endif /* NX_SECURE_ENABLE */ -#endif /* NXD_MQTT_REQUIRE_TLS */ - -/* Define memcpy, memset and memcmp functions used internal. */ -#ifndef NXD_MQTT_SECURE_MEMCPY -#define NXD_MQTT_SECURE_MEMCPY memcpy -#endif /* NXD_MQTT_SECURE_MEMCPY */ - -#ifndef NXD_MQTT_SECURE_MEMCMP -#define NXD_MQTT_SECURE_MEMCMP memcmp -#endif /* NXD_MQTT_SECURE_MEMCMP */ - -#ifndef NXD_MQTT_SECURE_MEMSET -#define NXD_MQTT_SECURE_MEMSET memset -#endif /* NXD_SECURE_MEMSET */ - -#ifndef NXD_MQTT_SECURE_MEMMOVE -#define NXD_MQTT_SECURE_MEMMOVE memmove -#endif /* NXD_MQTT_SECURE_MEMMOVE */ - -/* Define the default MQTT Non-TLS (Non-secure) port number */ -#define NXD_MQTT_PORT 1883 - - -/* Define the default TCP socket window size. */ -#ifndef NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE -#define NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE 8192 -#endif /* NXD_MQTT_CLIENT_SOCKET_WINDOW_SIZE */ - -/* Define the default MQTT Thread time slice. */ -#ifndef NXD_MQTT_CLIENT_THREAD_TIME_SLICE -#define NXD_MQTT_CLIENT_THREAD_TIME_SLICE 2 -#endif - -/* Set the default timer rate for the keepalive timer, in ThreadX timer ticks. - THe default is one second. */ -#ifndef NXD_MQTT_KEEPALIVE_TIMER_RATE -#define NXD_MQTT_KEEPALIVE_TIMER_RATE (NX_IP_PERIODIC_RATE) -#endif - -/* Set the default timeout for PING response. */ -/* After sending out the MQTT Ping Request, if the client does not receive Ping Response within this - time, the client shall disconnect from the server. The default is one second. */ -#ifndef NXD_MQTT_PING_TIMEOUT_DELAY -#define NXD_MQTT_PING_TIMEOUT_DELAY (NX_IP_PERIODIC_RATE) -#endif - - -/* Deprecated. This symbol is defined for compatibility. */ -#ifndef NXD_MQTT_MAX_TOPIC_NAME_LENGTH -#define NXD_MQTT_MAX_TOPIC_NAME_LENGTH 12 -#endif - -/* Deprecated. This symbol is defined for compatibility. */ -#ifndef NXD_MQTT_MAX_MESSAGE_LENGTH -#define NXD_MQTT_MAX_MESSAGE_LENGTH 32 -#endif - -#ifndef NXD_MQTT_INITIAL_PACKET_ID_VALUE -#define NXD_MQTT_INITIAL_PACKET_ID_VALUE 1 -#endif - -/* Set a timeout for socket operations (send, receive, disconnect). */ -#ifndef NXD_MQTT_SOCKET_TIMEOUT -#define NXD_MQTT_SOCKET_TIMEOUT NX_WAIT_FOREVER -#endif - -/* Define the default MQTT TLS (secure) port number */ -#define NXD_MQTT_TLS_PORT 8883 - - -#define MQTT_PROTOCOL_LEVEL 4 - -/* Define bit fields and constant values used in the CONNECT packet. */ -#define MQTT_CONNECT_FLAGS_USERNAME (1 << 7) -#define MQTT_CONNECT_FLAGS_PASSWORD (1 << 6) -#define MQTT_CONNECT_FLAGS_WILL_RETAIN (1 << 5) -#define MQTT_CONNECT_FLAGS_WILL_QOS_0 0 -#define MQTT_CONNECT_FLAGS_WILL_QOS_1 (1 << 3) -#define MQTT_CONNECT_FLAGS_WILL_QOS_2 (2 << 3) -#define MQTT_CONNECT_FLAGS_WILL_FLAG (1 << 2) -#define MQTT_CONNECT_FLAGS_CLEAN_SESSION (1 << 1) -#define MQTT_CONNECT_FLAGS_WILL_QOS_FIELD (3 << 3) - -/* Define bit fields and constant values used in the CONNACK packet. */ -#define MQTT_CONNACK_CONNECT_FLAGS_SP (1) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_ACCEPTED (0) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_UNACCEPTABLE_PROTOCOL_VERSION (1) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_IDENTIFIER_REJECTED (2) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_SERVER_UNAVAILABLE (3) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_BAD_USERNAME_PASSWORD (4) -#define MQTT_CONNACK_CONNECT_RETURN_CODE_NOT_AUTHORIZED (5) - -/* Define bit fields and constant values used in the PUBLISH packet. */ -#define MQTT_PUBLISH_DUP_FLAG (1 << 3) -#define MQTT_PUBLISH_QOS_LEVEL_0 (0) -#define MQTT_PUBLISH_QOS_LEVEL_1 (1 << 1) -#define MQTT_PUBLISH_QOS_LEVEL_2 (2 << 1) -#define MQTT_PUBLISH_QOS_LEVEL_FIELD (3 << 1) -#define MQTT_PUBLISH_RETAIN (1) - -#define MQTT_CONTROL_PACKET_TYPE_FIELD 0xF0 - -#define MQTT_FIXED_HEADER_SIZE 2 - - -#define MQTT_CONTROL_PACKET_TYPE_CONNECT (1) -#define MQTT_CONTROL_PACKET_TYPE_CONNACK (2) -#define MQTT_CONTROL_PACKET_TYPE_PUBLISH (3) -#define MQTT_CONTROL_PACKET_TYPE_PUBACK (4) -#define MQTT_CONTROL_PACKET_TYPE_PUBREC (5) -#define MQTT_CONTROL_PACKET_TYPE_PUBREL (6) -#define MQTT_CONTROL_PACKET_TYPE_PUBCOMP (7) -#define MQTT_CONTROL_PACKET_TYPE_SUBSCRIBE (8) -#define MQTT_CONTROL_PACKET_TYPE_SUBACK (9) -#define MQTT_CONTROL_PACKET_TYPE_UNSUBSCRIBE (10) -#define MQTT_CONTROL_PACKET_TYPE_UNSUBACK (11) -#define MQTT_CONTROL_PACKET_TYPE_PINGREQ (12) -#define MQTT_CONTROL_PACKET_TYPE_PINGRESP (13) -#define MQTT_CONTROL_PACKET_TYPE_DISCONNECT (14) -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ - - -typedef struct MQTT_PACKET_CONNACK_STRUCT -{ - - UCHAR mqtt_connack_packet_header; - UCHAR mqtt_connack_packet_remaining_length; - UCHAR mqtt_connack_packet_ack_flags; - UCHAR mqtt_connack_packet_return_code; -} MQTT_PACKET_CONNACK; - -typedef struct MQTT_PACKET_PUBLISH_STRUCT -{ - UCHAR mqtt_publish_packet_header; - UCHAR mqtt_publish_packet_remaining_length; -} MQTT_PACKET_PUBLISH; - -typedef struct MQTT_PACKET_PUBLISH_RESPONSE_STRUCT -{ - UCHAR mqtt_publish_response_packet_header; - UCHAR mqtt_publish_response_packet_remaining_length; - UCHAR mqtt_publish_response_packet_packet_identifier_msb; - UCHAR mqtt_publish_response_packet_packet_identifier_lsb; -} MQTT_PACKET_PUBLISH_RESPONSE; - - -typedef struct MQTT_PACKET_SUBSCRIBE_STRUCT -{ - UCHAR mqtt_subscribe_packet_header; - UCHAR mqtt_subscribe_packet_remaining_length; - UCHAR mqtt_subscribe_packet_packet_identifier_msb; - UCHAR mqtt_subscribe_packet_packet_identifier_lsb; -} MQTT_PACKET_SUBSCRIBE; - -typedef struct MQTT_PACKET_PING_STRUCT -{ - UCHAR mqtt_ping_packet_header; - UCHAR mqtt_ping_packet_remaining_length; -} MQTT_PACKET_PING; - -typedef struct MQTT_PACKET_DISCONNECT_STRUCT -{ - UCHAR mqtt_disconnect_packet_header; - UCHAR mqtt_disconnect_packet_remaining_length; -} MQTT_PACKET_DISCONNECT; - - -/* Define the NetX MQTT CLIENT ID. */ -#define NXD_MQTT_CLIENT_ID 0x4D515454 - -/* Define the default MQTT Non-TLS (Non-secure) port number */ -#define NXD_MQTT_CLIENT_NONTLS_PORT 1883 - -/* Define the default MQTT TLS (secure) port number */ -#define NXD_MQTT_CLIENT_TLS_PORT 8883 - - -#define NXD_MQTT_CLIENT_STATE_INITIALIZE 0 -#define NXD_MQTT_CLIENT_STATE_IDLE 1 -#define NXD_MQTT_CLIENT_STATE_CONNECTING 2 -#define NXD_MQTT_CLIENT_STATE_CONNECTED 3 - - -#define NXD_MQTT_SUCCESS 0x0 -#define NXD_MQTT_ALREADY_CONNECTED 0x10001 -#define NXD_MQTT_NOT_CONNECTED 0x10002 -#define NXD_MQTT_MUTEX_FAILURE 0x10003 -#define NXD_MQTT_INTERNAL_ERROR 0x10004 -#define NXD_MQTT_CONNECT_FAILURE 0x10005 -#define NXD_MQTT_PACKET_POOL_FAILURE 0x10006 -#define NXD_MQTT_COMMUNICATION_FAILURE 0x10007 -#define NXD_MQTT_SERVER_MESSAGE_FAILURE 0x10008 -#define NXD_MQTT_INVALID_PARAMETER 0x10009 -#define NXD_MQTT_NO_MESSAGE 0x1000A -#define NXD_MQTT_PACKET_POOL_EMPTY 0x1000B -#define NXD_MQTT_QOS2_NOT_SUPPORTED 0x1000C -#define NXD_MQTT_INSUFFICIENT_BUFFER_SPACE 0x1000D -#define NXD_MQTT_CLIENT_NOT_RUNNING 0x1000E -#define NXD_MQTT_INVALID_PACKET 0x1000F -#define NXD_MQTT_PARTIAL_PACKET 0x10010 - -/* The following error codes match the Connect Return code in CONNACK message. */ -#define NXD_MQTT_ERROR_CONNECT_RETURN_CODE 0x10080 -#define NXD_MQTT_ERROR_UNACCEPTABLE_PROTOCOL 0x10081 -#define NXD_MQTT_ERROR_IDENTIFYIER_REJECTED 0x10082 -#define NXD_MQTT_ERROR_SERVER_UNAVAILABLE 0x10083 -#define NXD_MQTT_ERROR_BAD_USERNAME_PASSWORD 0x10084 -#define NXD_MQTT_ERROR_NOT_AUTHORIZED 0x10085 - - -/* Define the basic MQTT Client control block. */ -typedef struct NXD_MQTT_CLIENT_STRUCT -{ - CHAR *nxd_mqtt_client_name; - CHAR *nxd_mqtt_client_id; - UINT nxd_mqtt_client_id_length; - CHAR *nxd_mqtt_client_username; - USHORT nxd_mqtt_client_username_length; - CHAR *nxd_mqtt_client_password; - USHORT nxd_mqtt_client_password_length; - UCHAR nxd_mqtt_client_will_qos_retain; - const UCHAR *nxd_mqtt_client_will_topic; - UINT nxd_mqtt_client_will_topic_length; - const UCHAR *nxd_mqtt_client_will_message; - UINT nxd_mqtt_client_will_message_length; - NX_IP *nxd_mqtt_client_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nxd_mqtt_client_packet_pool_ptr; /* Pointer to client packet pool */ - TX_MUTEX *nxd_mqtt_client_mutex_ptr; /* Pointer to client mutex */ - TX_TIMER nxd_mqtt_timer; -#ifndef NXD_MQTT_CLOUD_ENABLE - TX_MUTEX nxd_mqtt_protection; - TX_THREAD nxd_mqtt_thread; - TX_EVENT_FLAGS_GROUP nxd_mqtt_events; -#else - NX_CLOUD *nxd_mqtt_client_cloud_ptr; /* Pointer to associated CLOUD structure. */ - NX_CLOUD nxd_mqtt_client_cloud; /* MQTT cloud. */ - NX_CLOUD_MODULE nxd_mqtt_client_cloud_module; /* Define mqtt module that running on cloud helper thread. */ -#endif /* NXD_MQTT_CLOUD_ENABLE */ - UINT nxd_mqtt_ping_timeout; - UINT nxd_mqtt_ping_not_responded; /* Flag indicating the ping has been responded or not. */ - UINT nxd_mqtt_ping_sent_time; /* TX Timer tick when the ping message was sent. */ - UINT nxd_mqtt_timeout; /* TX Timer tick when the next timeout happens. */ - UINT nxd_mqtt_timer_value; /* MQTT Client periodic timer tick value. */ - UINT nxd_mqtt_keepalive; /* Keepalive value, converted to TX ticks. */ - UINT nxd_mqtt_clean_session; /* Clean session flag. */ - UINT nxd_mqtt_client_state; /* Record client state */ - NX_TCP_SOCKET nxd_mqtt_client_socket; - struct NXD_MQTT_CLIENT_STRUCT *nxd_mqtt_client_next; - UINT nxd_mqtt_client_packet_identifier; - NX_PACKET *nxd_mqtt_client_processing_packet; - NX_PACKET *message_transmit_queue_head; - NX_PACKET *message_transmit_queue_tail; - NX_PACKET *message_receive_queue_head; - NX_PACKET *message_receive_queue_tail; - UINT message_receive_queue_depth; - VOID (*nxd_mqtt_client_receive_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, UINT number_of_messages); - VOID (*nxd_mqtt_connect_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, UINT status, VOID *context); - VOID *nxd_mqtt_connect_context; - VOID (*nxd_mqtt_disconnect_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr); - UINT (*nxd_mqtt_packet_receive_notify)(struct NXD_MQTT_CLIENT_STRUCT *client_ptr, NX_PACKET *packet_ptr, VOID *context); - VOID *nxd_mqtt_packet_receive_context; -#ifdef NX_SECURE_ENABLE - UINT nxd_mqtt_client_use_tls; - UINT (*nxd_mqtt_tls_setup)(struct NXD_MQTT_CLIENT_STRUCT *, NX_SECURE_TLS_SESSION *, - NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *); - NX_SECURE_X509_CERT nxd_mqtt_tls_certificate; - NX_SECURE_X509_CERT nxd_mqtt_tls_trusted_certificate; - NX_SECURE_TLS_SESSION nxd_mqtt_tls_session; - UINT nxd_mqtt_tls_in_progress; -#endif -} NXD_MQTT_CLIENT; - - - -#ifndef NXD_MQTT_CLIENT_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -#define nxd_mqtt_client_create _nxd_mqtt_client_create -#define nxd_mqtt_client_login_set _nxd_mqtt_client_login_set -#define nxd_mqtt_client_will_message_set _nxd_mqtt_client_will_message_set -#define nxd_mqtt_client_delete _nxd_mqtt_client_delete -#define nxd_mqtt_client_connect _nxd_mqtt_client_connect -#define nxd_mqtt_client_secure_connect _nxd_mqtt_client_secure_connect -#define nxd_mqtt_client_publish _nxd_mqtt_client_publish -#define nxd_mqtt_client_subscribe _nxd_mqtt_client_subscribe -#define nxd_mqtt_client_unsubscribe _nxd_mqtt_client_unsubscribe -#define nxd_mqtt_client_disconnect _nxd_mqtt_client_disconnect -#define nxd_mqtt_client_receive_notify_set _nxd_mqtt_client_receive_notify_set -#define nxd_mqtt_client_message_get _nxd_mqtt_client_message_get -#define nxd_mqtt_client_disconnect_notify_set _nxd_mqtt_client_disconnect_notify_set -#else /* if !NXD_MQTT_CLIENT_SOURCE_CODE */ - -#define nxd_mqtt_client_create _nxde_mqtt_client_create -#define nxd_mqtt_client_login_set _nxde_mqtt_client_login_set -#define nxd_mqtt_client_will_message_set _nxde_mqtt_client_will_message_set -#define nxd_mqtt_client_delete _nxde_mqtt_client_delete -#define nxd_mqtt_client_connect _nxde_mqtt_client_connect -#define nxd_mqtt_client_secure_connect _nxde_mqtt_client_secure_connect -#define nxd_mqtt_client_publish _nxde_mqtt_client_publish -#define nxd_mqtt_client_subscribe _nxde_mqtt_client_subscribe -#define nxd_mqtt_client_unsubscribe _nxde_mqtt_client_unsubscribe -#define nxd_mqtt_client_disconnect _nxde_mqtt_client_disconnect -#define nxd_mqtt_client_receive_notify_set _nxde_mqtt_client_receive_notify_set -#define nxd_mqtt_client_message_get _nxde_mqtt_client_message_get -#define nxd_mqtt_client_disconnect_notify_set _nxde_mqtt_client_disconnect_notify_set -#endif /* NX_DISABLE_ERROR_CHECKING */ - - -UINT nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, - VOID *memory_ptr, ULONG memory_size); - -UINT nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT keepalive, UINT clean_session, ULONG timeout); - -UINT nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, - CHAR *username, UINT username_length, CHAR *password, UINT password_length); - -UINT nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, - const UCHAR *will_topic, UINT will_topic_length, UCHAR *will_message, UINT will_message_length, - UINT will_retain_flag, UINT will_QoS); -#ifdef NX_SECURE_ENABLE -UINT nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), - UINT keepalive, UINT clean_session, ULONG timeout); -#endif /* NX_SECURE_ENABLE */ -UINT nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, CHAR *message, UINT message_length, - UINT retain, UINT QoS, ULONG timeout); -UINT nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *mqtt_client_pr, CHAR *topic_name, UINT topic_name_length, UINT QoS); -UINT nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *mqtt_client_pr, CHAR *topic_name, UINT topic_name_length); -UINT nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, - VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT number_of_messages)); -UINT nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, - UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); -UINT nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); - -UINT nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); -UINT nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); - -#else /* ifdef NXD_MQTT_CLIENT_SOURCE_CODE */ - -UINT _nxd_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT keepalive, UINT clean_session, ULONG wait_option); -UINT _nxd_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, - CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, - VOID *memory_ptr, ULONG memory_size); -UINT _nxd_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); -UINT _nxd_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); -UINT _nxd_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); -UINT _nxd_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, - CHAR *username, UINT username_length, CHAR *password, UINT password_length); -UINT _nxd_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, - UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); -UINT _nxd_mqtt_client_publish_packet_send(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, - USHORT packet_id, UINT QoS, ULONG wait_option); -UINT _nxd_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, - CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG timeout); -UINT _nxd_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, - VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)); -UINT _nxd_mqtt_client_release_callback_set(NXD_MQTT_CLIENT *client_ptr, VOID (*memory_release_function)(CHAR *, UINT)); -UINT _nxd_mqtt_client_sub_unsub(NXD_MQTT_CLIENT *client_ptr, UINT op, - CHAR *topic_name, UINT topic_name_length, UINT QoS); -UINT _nxd_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS); -UINT _nxd_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length); -UINT _nxd_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, - const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, - UINT will_message_length, UINT will_retain_flag, UINT will_QoS); -UINT _nxd_mqtt_read_remaining_length(NX_PACKET *packet_ptr, UINT *remaining_length, ULONG *offset_ptr); -UINT _nxd_mqtt_client_set_fixed_header(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, UCHAR control_header, UINT length, UINT wait_option); -UINT _nxd_mqtt_client_append_message(NXD_MQTT_CLIENT *client_ptr, NX_PACKET *packet_ptr, CHAR *message, UINT length, ULONG wait_option); -VOID _nxd_mqtt_client_connection_end(NXD_MQTT_CLIENT *client_ptr, ULONG wait_option); -UINT _nxd_mqtt_process_publish_packet(NX_PACKET *packet_ptr, ULONG *topic_offset_ptr, USHORT *topic_length_ptr, - ULONG *message_offset_ptr, ULONG *message_length_ptr); - -UINT _nxde_mqtt_client_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT keepalive, UINT clean_session, ULONG timeout); -UINT _nxde_mqtt_client_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT mqtt_thread_priority, - VOID *memory_ptr, ULONG memory_size); -UINT _nxde_mqtt_client_delete(NXD_MQTT_CLIENT *client_ptr); -UINT _nxde_mqtt_client_disconnect_notify_set(NXD_MQTT_CLIENT *client_ptr, VOID (*disconnect_notify)(NXD_MQTT_CLIENT *)); -UINT _nxde_mqtt_client_disconnect(NXD_MQTT_CLIENT *client_ptr); -UINT _nxde_mqtt_client_login_set(NXD_MQTT_CLIENT *client_ptr, - CHAR *username, UINT username_length, CHAR *password, UINT password_length); -UINT _nxde_mqtt_client_message_get(NXD_MQTT_CLIENT *client_ptr, UCHAR *topic_buffer, UINT topic_buffer_size, UINT *actual_topic_length, - UCHAR *message_buffer, UINT message_buffer_size, UINT *actual_message_length); -UINT _nxde_mqtt_client_publish(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, - CHAR *message, UINT message_length, UINT retain, UINT QoS, ULONG timeout); -UINT _nxde_mqtt_client_receive_notify_set(NXD_MQTT_CLIENT *client_ptr, - VOID (*receive_notify)(NXD_MQTT_CLIENT *client_ptr, UINT message_count)); -UINT _nxde_mqtt_client_release_callback_set(NXD_MQTT_CLIENT *client_ptr, VOID (*release_callback)(CHAR *, UINT)); -UINT _nxde_mqtt_client_subscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length, UINT QoS); -UINT _nxde_mqtt_client_unsubscribe(NXD_MQTT_CLIENT *client_ptr, CHAR *topic_name, UINT topic_name_length); -UINT _nxde_mqtt_client_will_message_set(NXD_MQTT_CLIENT *client_ptr, - const UCHAR *will_topic, UINT will_topic_length, const UCHAR *will_message, - UINT will_message_length, UINT will_retain_flag, UINT will_QoS); - -#ifdef NX_SECURE_ENABLE -UINT _nxd_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, - NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), - UINT keepalive, UINT clean_session, ULONG wait_option); -UINT _nxde_mqtt_client_secure_connect(NXD_MQTT_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NXD_MQTT_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *, - NX_SECURE_X509_CERT *, NX_SECURE_X509_CERT *), - UINT keepalive, UINT clean_session, ULONG timeout); -#endif /* NX_SECURE_ENABLE */ - -#endif /* ifndef NXD_MQTT_CLIENT_SOURCE_CODE */ - -#ifdef NXD_MQTT_CLOUD_ENABLE -/* MQTT create function based on cloud helper. */ -UINT _nxd_mqtt_client_cloud_create(NXD_MQTT_CLIENT *client_ptr, CHAR *client_name, - CHAR *client_id, UINT client_id_length, - NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, NX_CLOUD *cloud_ptr); -#endif /* NXD_MQTT_CLOUD_ENABLE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus -} -#endif - - -#endif /* NXD_MQTT_CLIENT_H */ - diff --git a/protocol_handlers/nat/nx_nat.c b/protocol_handlers/nat/nx_nat.c deleted file mode 100644 index 0013d157..00000000 --- a/protocol_handlers/nat/nx_nat.c +++ /dev/null @@ -1,4542 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** Network Address Translation Protocol (NAT) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -#define NX_NAT_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - - -#include "tx_api.h" -#include "tx_thread.h" -#include "nx_api.h" -#include "nx_nat.h" -#include "nx_udp.h" -#include "nx_tcp.h" -#include "nx_icmp.h" -#include "nx_packet.h" -#include "nx_system.h" - -#ifdef NX_NAT_ENABLE -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - -/* Define */ -NX_NAT_DEVICE *nat_server_ptr; - - -/* Define internal NAT services. */ - -static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process); -static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr); -static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr); -static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address); -static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address); -static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address); -static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, ULONG local_ip_address, ULONG peer_ip_address, - USHORT local_port, USHORT external_port, USHORT peer_port, ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr); -static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr); -static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr, UCHAR direction, UINT skip_static_entries); -static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr); -static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg); -static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port); -static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port); -static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port); -static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port); -static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *destination_port); -static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length); - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create NAT service. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* ip_ptr Pointer to NAT IP instance */ -/* global_interface_index Index of global interface */ -/* dynamic_cache_memory Pointer to dynamic entry cache */ -/* dynamic_cache_size The size of dynamic entry cache */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_NAT_PARAM_ERROR Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_create Creates the NAT instance service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size) -{ - -UINT status; - - - /* Check for valid input pointers. */ - if ((!nat_ptr) || (!ip_ptr)) - { - - /* Return pointer error. */ - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (ip_ptr -> nx_ip_id != NX_IP_ID) - { - - /* Return pointer error. */ - return(NX_NAT_PARAM_ERROR); - } - - /* Check the interface index. */ - if (global_interface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - /* Return pointer error. */ - return(NX_NAT_PARAM_ERROR); - } - - /* Make sure entry cache is 4-byte aligned. */ - if ((((UINT)dynamic_cache_memory & 0x3) != 0) || - ((dynamic_cache_size & 0x3) != 0)) - { - - /* Return error status. */ - return(NX_NAT_CACHE_ERROR); - } - - /* Check the cache size. */ - if (dynamic_cache_size < (NX_NAT_MIN_ENTRY_COUNT * sizeof (NX_NAT_TRANSLATION_ENTRY))) - { - - /* Return error status. */ - return(NX_NAT_CACHE_ERROR); - } - - /* Call the actual NAT create service. */ - status = _nx_nat_create(nat_ptr, ip_ptr, global_interface_index, dynamic_cache_memory, dynamic_cache_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the NetX NAT instance and various NAT */ -/* configuration options, it also creates the NAT mutex. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* ip_ptr Pointer to NAT IP instance */ -/* global_interface_index Index of global interface */ -/* dynamic_cache_memory Pointer to dynamic entry cache */ -/* dynamic_cache_size The size of dynamic entry cache */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion */ -/* NX_NAT_OVERLAPPING_SUBNET_ERROR Invalid NAT network interfaces */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_create Create NAT flag group mutex */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size) -{ - -UINT i; -UINT dynamic_entries; -NX_NAT_TRANSLATION_ENTRY *entry_ptr; - - - /* First clear memory for setting up the NAT server instance. */ - memset(nat_ptr, 0, sizeof(NX_NAT_DEVICE)); - - /* Bind the IP instance and related parameters. */ - nat_ptr -> nx_nat_ip_ptr = ip_ptr; - nat_ptr -> nx_nat_global_interface_index = (UCHAR)global_interface_index; - - /* Clear the entry cache. */ - memset((void *) dynamic_cache_memory, 0, dynamic_cache_size); - - /* Pickup starting address of the available entry list. */ - entry_ptr = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory; - - /* Determine how many NAT daynamic entries will fit in this cache area. */ - dynamic_entries = dynamic_cache_size / sizeof(NX_NAT_TRANSLATION_ENTRY); - - /* Initialize the pointers of available NAT entries. */ - for (i = 0; i < (dynamic_entries - 1); i++) - { - /* Setup each entry to point to the next entry. */ - entry_ptr -> next_entry_ptr = entry_ptr + 1; - entry_ptr ++; - } - - /* Setup the head pointers of the available and dynamic (active) lists in the NAT Device. */ - nat_ptr -> nx_nat_dynamic_available_entry_head = (NX_NAT_TRANSLATION_ENTRY *) dynamic_cache_memory; - nat_ptr -> nx_nat_dynamic_active_entry_head = NX_NULL; - nat_ptr -> nx_nat_dynamic_available_entries = dynamic_entries; - nat_ptr -> nx_nat_dynamic_active_entries = 0; - nat_ptr -> nx_nat_static_active_entries = 0; - - /* Load the NAT ID field in the NAT control block. */ - nat_ptr -> nx_nat_id = NX_NAT_ID; - - /* Define a global NAT pointer. NetX forwards all packets to _nx_nat_process_packet if _nx_ip_packet_forward() is defined as such. - The latter service can only send the current NX_IP and NX_PACKET pointer, so _nx_nat_process_packet() - requries this global pointer. */ - /* Set the pointer of global variable NAT. */ - nat_server_ptr = nat_ptr; - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the delete NAT service. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_delete Deletes a NAT instance */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_delete(NX_NAT_DEVICE *nat_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual NAT delete service. */ - status = _nx_nat_delete(nat_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the specified NetX NAT instance. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server to delete */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_delete Delete NAT mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_delete(NX_NAT_DEVICE *nat_ptr) -{ - - /* Clear the NAT ID to make it invalid. */ - nat_ptr -> nx_nat_id = 0; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the resume NAT thread */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr Pointer to IP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_enable Actual enable NAT server */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_enable(NX_NAT_DEVICE *nat_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) - return(NX_PTR_ERROR); - - /* Call the actual service. */ - status = _nx_nat_enable(nat_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables the NAT server. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server to resume */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get IP mutex */ -/* tx_mutex_put Put IP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_enable(NX_NAT_DEVICE *nat_ptr) -{ - - - /* Get the IP mutex. */ - tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Setup the IP nat processing routine pointer for NAT services. */ - nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = _nx_nat_process_packet; - - /* Setup the IP nat free port check for NAT services. */ - nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_port_verify = _nx_nat_entry_port_verify; - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the disable NAT service. */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_enable Actual enable NAT server */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_disable(NX_NAT_DEVICE *nat_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID)) - return(NX_PTR_ERROR); - - /* Call the actual service. */ - status = _nx_nat_disable(nat_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disables the NAT server. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server to resume */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get IP mutex */ -/* tx_mutex_put Put IP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_disable(NX_NAT_DEVICE *nat_ptr) -{ - - /* Get the IP mutex. */ - tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Clear the IP nat processing routine pointer. */ - nat_ptr -> nx_nat_ip_ptr -> nx_ip_nat_packet_process = NX_NULL; - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the NAT cache full notify */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_cache_notify_set Actual cache notify set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (!nat_ptr) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (nat_ptr -> nx_nat_id != NX_NAT_ID) - { - return(NX_NAT_PARAM_ERROR); - } - - /* Call actual NAT cache notify set function. */ - status = _nx_nat_cache_notify_set(nat_ptr, cache_full_notify_cb); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_cache_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the cache full notify function. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to nat instance */ -/* cache_full_notify Cache full notify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get IP mutex */ -/* tx_mutex_put Put IP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)) -{ - - - /* Get the IP mutex. */ - tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the cache notify. */ - nat_ptr -> nx_nat_cache_full_notify = cache_full_notify_cb; - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_inbound_entry_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create NAT translation */ -/* inbound entry service. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* entry_ptr Pointer to entry to add to table */ -/* local_ip_address Entry local IP address */ -/* external_port Entry external port */ -/* local_port Entry local port */ -/* protocol Entry network protocol */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_NAT_PARAM_ERROR Invalid non pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_inbound_entry_create Calls actual create entry service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, - ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (!entry_ptr)) - { - return (NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if ((!local_ip_address) || (!protocol)) - { - - /* Return ptr error. */ - return (NX_NAT_PARAM_ERROR); - } - - /* Call the actual service. */ - status = _nx_nat_inbound_entry_create(nat_ptr, entry_ptr, local_ip_address, external_port, local_port, protocol); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_inbound_entry_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a inbound NAT translation entry and adds it to */ -/* the NAT entry list. This is allows an external host to initiate */ -/* a session with a private host (typically a server). */ -/* */ -/* This entry can never expire. To remove the entry, use the */ -/* nx_nat_inbound_entry_delete() service. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* entry_ptr Pointer to entry to add to table */ -/* local_ip_address Entry local IP address */ -/* external_port Entry external port */ -/* local_port Entry local port */ -/* protocol Table entry network protocol */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get IP mutex */ -/* tx_mutex_put Put IP mutex */ -/* _nx_nat_entry_add Add entry to table linked list */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, - ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol) -{ - -UINT bound; - - /* Get the IP mutex. */ - tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check whether this port has been used by NAT entry. */ - bound = _nx_nat_entry_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port); - - /* Check the status. */ - if (bound == NX_TRUE) - { - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return error status. */ - return(NX_NAT_PORT_UNAVAILABLE); - } - - /* Check whether this port has been used by NetXDuo socket. */ - bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, external_port); - - /* Check the status. */ - if (bound == NX_TRUE) - { - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return error status. */ - return(NX_NAT_PORT_UNAVAILABLE); - } - - /* Initialize the entry to NULL. */ - memset(entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); - - /* Assign the entry attributes. */ - entry_ptr -> local_ip_address = local_ip_address; - entry_ptr -> external_port = external_port; - entry_ptr -> local_port = local_port; - entry_ptr -> protocol = protocol; - - /* Set the transaction type. */ - entry_ptr -> translation_type = NX_NAT_STATIC_ENTRY; - - /* Add the entry to the table. */ - _nx_nat_entry_add(nat_ptr, entry_ptr); - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_nat_inbound_entry_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the delete NAT translation */ -/* inbound entry service. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* remove_entry_ptr Pointer to NAT translation entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_inbound_entry_delete Actual table entry delete service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_nat_inbound_entry_delete( NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((nat_ptr == NX_NULL) || (nat_ptr -> nx_nat_id != NX_NAT_ID) || (delete_entry_ptr == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Check the entry tranlation type. */ - if (delete_entry_ptr ->translation_type != NX_NAT_STATIC_ENTRY) - { - return(NX_NAT_ENTRY_TYPE_ERROR); - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual NAT entry delete service. */ - status = _nx_nat_inbound_entry_delete(nat_ptr, delete_entry_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_inbound_entry_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the specified static entry from the NAT */ -/* translation list. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* remove_entry_ptr Pointer to NAT translation entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr) -{ - -NX_NAT_TRANSLATION_ENTRY *entry_ptr; -NX_NAT_TRANSLATION_ENTRY *previous_ptr; -NX_NAT_TRANSLATION_ENTRY *next_entry_ptr; - - - /* Get the IP mutex. */ - tx_mutex_get(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Get a pointer to the start of the entries in the translation table. */ - entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - - /* Initialize the previous pointer. */ - previous_ptr = NX_NULL; - - /* We need to loop through the translation table again so we - can remove the entry to delete and connect the previous and - next entries around it. */ - while (entry_ptr) - { - - /* Set a pointer to the next entry in the table. */ - next_entry_ptr = entry_ptr -> next_entry_ptr; - - /* Is this the entry we want to delete? */ - if (entry_ptr == delete_entry_ptr) - { - - /* Yes; check if this is the first entry in the list). */ - if (previous_ptr) - { - - /* It is not, so link the previous entry around the entry we are deleting. */ - previous_ptr -> next_entry_ptr = next_entry_ptr; - } - else - { - - /* It is the first entry, so set the next pointer as the starting translation table entry. */ - nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr; - } - - /* Update the static active entry count. */ - nat_ptr -> nx_nat_static_active_entries --; - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* We're done here. */ - return NX_SUCCESS; - } - - /* We didn't delete the current entry, so now it is the previous entry. */ - previous_ptr = entry_ptr; - - /* Get the next entry in the table. */ - entry_ptr = next_entry_ptr; - } - - /* Release the IP mutex. */ - tx_mutex_put(&(nat_ptr -> nx_nat_ip_ptr -> nx_ip_protection)); - - /* Return error status. */ - return (NX_NAT_ENTRY_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives packets to forward from both public and */ -/* private networks on either side of NAT if IP forwarding is enabled */ -/* and this function is specified as the packet handler. It determines */ -/* packet direction (e.g. out to the public internet or inbound to a */ -/* host on the private network) and forwards it to the appropriate */ -/* handler. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr Pointer to IP instance */ -/* packet_ptr Pointer to packet to forward */ -/* packet_process The flag for packet processing */ -/* NX_TRUE or NX_FALSE */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Packet is consumed by NAT */ -/* NX_FALSE Packet is not consumed by NAT */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release the packet */ -/* _nx_ip_route_find Find the outgoing interface */ -/* _nx_nat_process_outbound_packet Forward packet to public Internet */ -/* _nx_nat_process_inbound_packet Forward packet to private host */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ipv4_packet_receive Netx forwards packet to NAT first */ -/* if forwarding is enabled. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_packet(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_process) -{ - -UINT status; -UINT protocol; -ULONG header_size = sizeof(NX_IPV4_HEADER); -UINT global_interface_index; -ULONG next_hop_address; -NX_IPV4_HEADER *ip_header_ptr; -NX_INTERFACE *interface_ptr; - - - /* Check the NAT's IP instance. */ - if (nat_server_ptr -> nx_nat_ip_ptr != ip_ptr) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Pickup the packet header. */ - ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; - - /* Determine what protocol the current IP datagram is. */ - protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; - - /* Check the protocol. */ - if ((protocol != NX_PROTOCOL_ICMP) && (protocol != NX_PROTOCOL_UDP) && (protocol != NX_PROTOCOL_TCP)) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - -#ifndef NX_DISABLE_RX_SIZE_CHECKING - /* Check the next protocol. */ - if (protocol == NX_PROTOCOL_ICMP) - { - header_size += sizeof(NX_ICMP_HEADER); - } - else if (protocol == NX_PROTOCOL_UDP) - { - header_size += sizeof(NX_UDP_HEADER); - } - else - { - header_size += sizeof(NX_TCP_HEADER); - } - - /* Check for valid packet length. */ - if (packet_ptr -> nx_packet_length < header_size) - { - -#ifndef NX_DISABLE_IP_INFO - /* Increment the IP invalid packet error. */ - ip_ptr -> nx_ip_invalid_packets++; - - /* Increment the IP receive packets dropped count. */ - ip_ptr -> nx_ip_receive_packets_dropped++; -#endif - - /* Invalid packet length, just release it. */ - _nx_packet_release(packet_ptr); - - /* Return NX_TRUE to indicate this packet has been processed. */ - return (NX_TRUE); - } -#endif /* NX_DISABLE_RX_SIZE_CHECKING */ - - /* Set the packet interface pointer and NAT's global interface index. */ - interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr; - global_interface_index = nat_server_ptr -> nx_nat_global_interface_index; - - /* Check if the direction of the translation is inbound. */ - if (interface_ptr == &(ip_ptr -> nx_ip_interface[global_interface_index])) - { - - /* Yes, this packet is received on NAT's external interface (an inbound packet). */ - - /* Check the destination ip address against NAT's external IP address. */ - if (ip_header_ptr -> nx_ip_header_destination_ip != interface_ptr -> nx_interface_ip_address) - { - - /* NAT cannot process this packet. Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Check if the caller wants NAT to process this packet. */ - if (packet_process == NX_TRUE) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Yes, so update the count. */ - nat_server_ptr -> forwarded_packets_received ++; -#endif - - /* Try to deliver the packet to the local host. */ - status = _nx_nat_process_inbound_packet(nat_server_ptr, packet_ptr); - - /* Check the status. */ - if (status == NX_NAT_PACKET_CONSUMED_FAILED) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - } - } - else - { - - /* Check the destination ip address. */ - if ( - - /* Check for zero address. */ - (ip_header_ptr -> nx_ip_header_destination_ip == 0) || - - /* Check for limited broadcast. */ - (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) || - - /* Check for multicast address*/ - ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) || - - /* Check for loopback address. */ - ((ip_header_ptr -> nx_ip_header_destination_ip >= NX_IP_LOOPBACK_FIRST) && - (ip_header_ptr -> nx_ip_header_destination_ip <= NX_IP_LOOPBACK_LAST))) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Clear the packet interface. */ - interface_ptr = NX_NULL; - - /* Find the suitable interface and next hop address according to the destination ip. */ - if(_nx_ip_route_find(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, &interface_ptr, &next_hop_address) != NX_SUCCESS) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Check the NAT forward interface. */ - if (interface_ptr != &(ip_ptr -> nx_ip_interface[global_interface_index])) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Check for IP broadcast. */ - if(((ip_header_ptr -> nx_ip_header_destination_ip & interface_ptr -> nx_interface_ip_network_mask) == - interface_ptr -> nx_interface_ip_network) && - ((ip_header_ptr -> nx_ip_header_destination_ip & ~(interface_ptr -> nx_interface_ip_network_mask)) == - ~(interface_ptr -> nx_interface_ip_network_mask))) - { - - /* Let IP packet receive process this packet. */ - return (NX_FALSE); - } - - /* Check if NAT need to process this packet. */ - if (packet_process == NX_TRUE) - { - - /* Set the packet interface as global interface. */ - packet_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr; - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_server_ptr -> forwarded_packets_received ++; -#endif - - /* Deliver the packet to the outbound packet handler. */ - _nx_nat_process_outbound_packet(nat_server_ptr, packet_ptr); - } - } - - /* Return NX_TRUE to indicate packet has been processed by NAT. */ - return (NX_TRUE); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_inbound_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a packet from the external network for */ -/* forwarding to the private network. It sends each packet to a */ -/* protocol handler for protocol specific processing. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_INVALID_PROTOCOL Unknown packet protocol */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_process_inbound_TCP_packet */ -/* Process external host's TCP packet */ -/* _nx_nat_process_inbound_UDCP_packet */ -/* Process external host's UDP packet */ -/* _nx_nat_process_inbound_ICMP_packet */ -/* Process external host's ICMP packet */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_packet Process packet from external host */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_inbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr) -{ - - -UINT status = NX_SUCCESS; -UCHAR protocol; -NX_IPV4_HEADER *ip_header_ptr; -NX_NAT_TRANSLATION_ENTRY translation_entry; - - - /* Pick a pointer to the IP header. */ - ip_header_ptr = (NX_IPV4_HEADER *) packet_ptr -> nx_packet_prepend_ptr; - - /* Determine what protocol the current IP datagram is. */ - protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; - - /* Set up the search criteria in the NAT translation table. */ - memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); - translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_source_ip; - translation_entry.protocol = protocol; - - /* Choose which packet handler by protocol. */ - switch (protocol) - { - - case NX_PROTOCOL_TCP: - status = _nx_nat_process_inbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - - case NX_PROTOCOL_UDP: - status = _nx_nat_process_inbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - - case NX_PROTOCOL_ICMP: - status = _nx_nat_process_inbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - } - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_inbound_TCP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the local IP address:port for an incoming packet */ -/* in the NAT translation table and replaces the global packet */ -/* destination IP address and port with the local IP address and port. */ -/* If none is found, it rejects the packet. Otherwise it updates the TCP*/ -/* checksum with the changed IP address and port. The packet is then */ -/* sent to private host. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* (packet is not necessarily */ -/* forwarded) */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_packet Process inbound packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_inbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - -UINT status; -UINT entry_found; -USHORT old_port; -USHORT new_port; -ULONG old_address; -ULONG new_address; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_TCP_HEADER *tcp_header_ptr; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Initialize local variables. */ - compute_checksum = 1; - record_entry = NX_NULL; - entry_found = NX_TRUE; - - /* Pickup the pointer to the head of the TCP packet. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* For little endian processors, adjust byte order for big endianness. */ - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); - - /* Find the inbound entry, set the packet private interface and next hop address. */ - status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Check the status. */ - if (status == NX_NAT_ENTRY_NOT_FOUND) - { - - /* Set the entry found flag. */ - entry_found = NX_FALSE; - } - else - { - - /* Release the packet */ - nx_packet_release(packet_ptr); - - /* Return completion status. */ - return NX_SUCCESS; - } - } - else - { - - /* Check the inbound packet destination port, and update the TCP header. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Replace the destination port with the local (source) port of the preceding outbound packet. */ - - tcp_header_ptr -> nx_tcp_header_word_0 = ((ULONG)(tcp_header_ptr -> nx_tcp_header_word_0 & ~NX_LOWER_16_MASK)) | - ((ULONG) record_entry -> local_port); - } - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - if(compute_checksum) - { - - /* Get the old checksum. */ - checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16); - - /* Check whether the port is updated. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Set the old port and new port. */ - old_port = record_entry -> external_port; - new_port = record_entry -> local_port; - - /* Adjust the checksum for port. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - } - - /* Set the old address and new address. */ - old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - new_address = record_entry -> local_ip_address; - - /* Adjust the checksum for address. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); - - /* OK to clear the TCP checksum field to zero before the checksum update. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16); - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* OK to clear the TCP checksum field to zero before the checksum update. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - } - - /* Swap endianness back before sending. */ - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); - - /* Check the entry found flag. */ - if (entry_found == NX_FALSE) - { - - /* Stop processing, recover packet length to Let NetXDuo process this packet. */ - packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); - - /* Let NetXDuo process this pcaket. */ - return(NX_NAT_PACKET_CONSUMED_FAILED); - } - - /* Send the TCP packet onto the private host. */ - _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_inbound_UDP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the local IP address:port for an incoming packet */ -/* in the NAT translation table and replaces the global packet */ -/* destination IP address and port with the local IP address andport. */ -/* If none is found, it rejects the packet. Otherwise it updates the UDP*/ -/* checksum with the changed IP address and port. The packet is then */ -/* sent to private host. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_INVALID_IP_HEADER Invalid IP header */ -/* NX_NAT_BAD_UDP_CHECKSUM UDP checksum is invalid */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_packet Process inbound packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_inbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - -UINT status; -UINT entry_found; -USHORT old_port; -USHORT new_port; -ULONG old_address; -ULONG new_address; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_UDP_HEADER *udp_header_ptr; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Initialize local variables. */ - compute_checksum = 1; - record_entry = NX_NULL; - entry_found = NX_TRUE; - - /* Pickup the pointer to the head of the UDP packet. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* For little endian processors, adjust byte order for big endianness. */ - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - - /* Find the inbound entry, set the packet private interface and next hop address. */ - status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Check the status. */ - if (status == NX_NAT_ENTRY_NOT_FOUND) - { - - /* Set the entry found flag. */ - entry_found = NX_FALSE; - } - else - { - - /* Release the packet */ - nx_packet_release(packet_ptr); - - /* Return completion status. */ - return NX_SUCCESS; - } - } - else - { - - /* Update the destination port if the NAT device mapped it to another port. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Translate the destination UDP port to the private host port. If translation - does not involve port number this will essentially be the original port number. */ - udp_header_ptr -> nx_udp_header_word_0 = ((ULONG) (udp_header_ptr -> nx_udp_header_word_0 & ~NX_LOWER_16_MASK)) | - ((ULONG) record_entry -> local_port); - } - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Get the checksum. */ - checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK; - - /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */ - if (checksum == 0) - compute_checksum = 0; - - /* Check the checksum. */ - if(compute_checksum) - { - - /* Check whether the port is updated. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Set the old port and new port. */ - old_port = record_entry -> external_port; - new_port = record_entry -> local_port; - - /* Adjust the checksum for port. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - } - - /* Set the old address and new address. */ - old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - new_address = record_entry -> local_ip_address; - - /* Adjust the checksum for address. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); - - /* OK to clear the UDP checksum field to zero before the checksum update. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* OK to clear the UDP checksum field to zero before the checksum update. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - } - - /* Swap UDP header byte order back to big endian before sending. For big endian processors, - this will have no effect. */ - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - - /* Check the packet consumed flag. */ - if (entry_found == NX_FALSE) - { - - /* Stop processing, recover packet length to Let NetXDuo process this packet. */ - packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); - - /* Let NetXDuo process this pcaket. */ - return(NX_NAT_PACKET_CONSUMED_FAILED); - } - - /* Send the UDP packet onto the private host. */ - _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_inbound_ICMP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the local IP address:port for an incoming packet */ -/* in the NAT translation table and replaces the global packet */ -/* IP address and queryID with the local IP address and queryID. */ -/* If none is found, rejects the packet. Otherwise it updates the ICMP */ -/* checksum with the changed IP address and port. The packet is then */ -/* sent to private host. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* (packet is not necessarily */ -/* forwarded) */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_packet Process inbound packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_inbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ -UINT status; -UINT entry_found; -ULONG sequence; -UINT type; -USHORT old_port; -USHORT new_port; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_ICMP_HEADER *icmp_header_ptr; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Initialize local variables. */ - compute_checksum = 1; - record_entry = NX_NULL; - entry_found = NX_TRUE; - - /* Get a pointer to the ICMP header. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Adjust ICMP header byte order for endianness. */ - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); - - /* Extract the ICMP type and code. */ - type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; - - /* Find the inbound entry, set the packet private interface and next hop address. */ - status = _nx_nat_inbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Check the status. */ - if (status == NX_NAT_ENTRY_NOT_FOUND) - { - - /* Set the entry found flag. */ - entry_found = NX_FALSE; - } - else - { - - /* Release the packet */ - nx_packet_release(packet_ptr); - - /* Return completion status. */ - return NX_SUCCESS; - } - } - else - { - - /* Check the type. */ - if ((type != NX_ICMP_ECHO_REPLY_TYPE) && - (type != NX_ICMP_ECHO_REQUEST_TYPE)) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Unknown ICMP packet. Drop the packet and bail! */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - nx_packet_release(packet_ptr); - - return NX_SUCCESS; - } - - /* Now we have to translate the packet destination for private host address and - update packet header checksum. */ - if ((type == NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port)) - { - - /* Restore the local host ICMP Query ID. */ - sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK; - - /* Restore the local host ICMP Query ID from the 'source port' field in the NAT table entry. */ - icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG)(record_entry -> local_port << NX_SHIFT_BY_16) | sequence; - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - if(compute_checksum) - { - - /* Set the old checksum. */ - checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK; - - /* Set the old port and new port. */ - old_port = entry_ptr -> external_port; - new_port = record_entry -> local_port; - - /* Adjust the checksum. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - - /* Ok to zero out the checksum because we'll replace it with an updated checksum. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* Set the checksum to zero. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - } - } - - /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match - that of the data area. */ - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); - - /* Check the packet consumed flag. */ - if (entry_found == NX_FALSE) - { - - /* Stop processing, recover packet length to Let NetXDuo process this packet. */ - packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); - - /* Let NetXDuo process this pcaket. */ - return(NX_NAT_PACKET_CONSUMED_FAILED); - } - - /* Send the ICMP packet onto the private host. */ - _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_INBOUND_PACKET, next_hop_address); - - /* Return packet send completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_outbound_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a packet from a local host bound for the */ -/* external network. If a matching entry for the private host is not */ -/* found in the NAT translation table, one is created. Packets are then*/ -/* directed to protocol specific handlers for detailed processing of the*/ -/* packet before sending out on the external network. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_INVALID_PROTOCOL Unknown/unsupported protocol status*/ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_process_outbound_TCP_packet */ -/* Handler for outbound TCP packets */ -/* _nx_nat_process_outbound_UDP_packet */ -/* Handler for outbound UDP packets */ -/* _nx_nat_process_outbound_ICMP_packet */ -/* Handler for outbound ICMP packets */ -/* nx_packet_release Release packet back to packet pool */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_packet_process Process packets forwarded to NAT by*/ -/* Netx */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_outbound_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR protocol; -NX_IPV4_HEADER *ip_header_ptr; -NX_NAT_TRANSLATION_ENTRY translation_entry; - - - /* Set up an actual IP header pointer. */ - ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Determine what protocol the current IP datagram is. */ - protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; - - /* Set up the search criteria in the NAT translation table. */ - memset(&translation_entry, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); - translation_entry.local_ip_address = ip_header_ptr -> nx_ip_header_source_ip; - translation_entry.peer_ip_address = ip_header_ptr -> nx_ip_header_destination_ip; - translation_entry.protocol = protocol; - - /* Direct the packet to a protocol specific handler. */ - switch (protocol) - { - - case NX_PROTOCOL_TCP: - /* Process the packet for TCP protocol. */ - _nx_nat_process_outbound_TCP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - - case NX_PROTOCOL_UDP: - /* Process the packet for UDP protocol. */ - _nx_nat_process_outbound_UDP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - - case NX_PROTOCOL_ICMP: - /* Process the packet for ICMP (including error message packets) protocol. */ - _nx_nat_process_outbound_ICMP_packet(nat_ptr, packet_ptr, &translation_entry); - break; - - default: - { - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Toss the IP packet since we don't know what to do with it! */ - nx_packet_release(packet_ptr); - - return NX_NAT_INVALID_PROTOCOL; - } - } - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_outbound_TCP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a TCP packet from a local host on the private*/ -/* network destined for the external network with a global IP address */ -/* and port. The source IP address and port are replaced by NAT with a */ -/* global IP address:port. NAT then updates the TCP header checksum. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_outbound_TCP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - -UINT status; -USHORT old_port; -USHORT new_port; -ULONG old_address; -ULONG new_address; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_TCP_HEADER *tcp_header_ptr; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Initialize local variables. */ - compute_checksum = 1; - - /* Pickup the pointer to the head of the UDP packet. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - tcp_header_ptr = (NX_TCP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Adjust byte order for endianness. */ - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); - - /* Find the outbound entry, set the packet global interface and next hop address. */ - status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Increase the session count of dropped forwarded packets. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Release the packet back to the packet pool. */ - nx_packet_release(packet_ptr); - - /* Return the error status. */ - return status; - } - - /* Update the source port if the NAT device mapped it to another port. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Yes, write to the upper bits of the TCP word. */ - tcp_header_ptr -> nx_tcp_header_word_0 = (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK) | - (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16); - } - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - if(compute_checksum) - { - - /* Get the old checksum. */ - checksum = (USHORT)(tcp_header_ptr -> nx_tcp_header_word_4 >> NX_SHIFT_BY_16); - - /* Check whether the port is updated. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Set the old port and new port. */ - old_port = record_entry -> local_port; - new_port = record_entry -> external_port; - - /* Adjust the checksum for port. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - } - - /* Set the old address and new address. */ - old_address = record_entry -> local_ip_address; - new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - - /* Adjust the checksum for address. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); - - /* OK to clear the TCP checksum field to zero before the checksum update. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 | (ULONG)(checksum << NX_SHIFT_BY_16); - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* OK to clear the TCP checksum field to zero before the checksum update. */ - tcp_header_ptr -> nx_tcp_header_word_4 = tcp_header_ptr -> nx_tcp_header_word_4 & NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Swap byte order back to big endian before sending if little endian is specified. */ - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_sequence_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_acknowledgment_number); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_3); - NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); - - /* Send the TCP packet onto the global host. */ - _nx_nat_ip_packet_send(nat_ptr,packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_outbound_UDP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a UDP packet from a local host destined for */ -/* the external network; NAT replaces the private IP address:port with a*/ -/* global IP address:port. NAT updates the UDP header checksum field for*/ -/* all packets having a non zero UDP packet checksum. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_ZERO_UDP_CHECKSUM Illegal zero UDP header checksum */ -/* NX_NAT_BAD_UDP_CHECKSUM UDP header checksum is invalid */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_outbound_UDP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - -UINT status; -USHORT old_port; -USHORT new_port; -ULONG old_address; -ULONG new_address; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_UDP_HEADER *udp_header_ptr; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - /* Initialize local variables. */ - compute_checksum = 1; - - /* Pickup the pointer to the head of the UDP packet. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - udp_header_ptr = (NX_UDP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* For little endian processors, swap byte order to little endian. */ - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - - /* Find the outbound entry, set the packet global interface and next hop address. */ - status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Increase the session count of dropped forwarded packets. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Release the packet back to the packet pool. */ - nx_packet_release(packet_ptr); - - /* Return the error status. */ - return status; - } - - /* OK to zero out the checksum field so we can update the header with a new checksum later. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; - - /* Did NAT assign a global UDP source port? */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Yes, so replace local host UDP port with NAT global inside UDP port in the header. */ - udp_header_ptr -> nx_udp_header_word_0 = (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK) | - (((ULONG) (record_entry -> external_port)) << NX_SHIFT_BY_16); - } - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Get the old checksum. */ - checksum = udp_header_ptr -> nx_udp_header_word_1 & NX_LOWER_16_MASK; - - /* UDP headers with 0 checksum should not be modified, RFC3022, Section4.1, Page8. */ - if (checksum == 0) - compute_checksum = 0; - - /* Compute the checksum. */ - if(compute_checksum) - { - - /* Check whether the port is updated. */ - if (record_entry -> external_port != record_entry -> local_port) - { - - /* Set the old port and new port. */ - old_port = record_entry -> local_port; - new_port = record_entry -> external_port; - - /* Adjust the checksum for port. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - } - - /* Set the old address and new address. */ - old_address = record_entry -> local_ip_address; - new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - - /* Adjust the checksum for address. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); - - /* OK to clear the UDP checksum field to zero before the checksum update. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* OK to clear the UDP checksum field to zero before the checksum update. */ - udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 & ~NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match - that of the data area. */ - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); - - /* Send the UDP packet onto the global host. */ - _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); - - /* Return packet send completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_process_outbound_ICMP_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a ICMP packet from a local network host for */ -/* sending out onto the external network. NAT replaces the private */ -/* source IP address and local query ID with a global source IP address */ -/* and query ID. NAT then recomputes the ICMP header checksum. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to the NAT server */ -/* packet_ptr Pointer to the packet to process */ -/* entry_ptr Pointer to the entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_BAD_ICMP_CHECKSUM Packet failed ICMP checksum check */ -/* NX_NAT_INVALID_IP_HEADER Packet has an invalid IP header */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* _nx_nat_ip_packet_send Send packet to private interface */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_process_outbound_ICMP_packet(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - -UINT status; -ULONG sequence; -UINT is_icmp_error_msg; -NX_ICMP_HEADER *icmp_header_ptr; -UINT type; -USHORT old_port; -USHORT new_port; -USHORT checksum; -ULONG compute_checksum; -ULONG next_hop_address; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Initialize local variables. */ - compute_checksum = 1; - - /* Pickup the pointer to the head of the ICMP packet. */ - packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length -= sizeof(NX_IPV4_HEADER); - icmp_header_ptr = (NX_ICMP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Swap ENDian-ness for our ICMP header. We've only swapped the IP header data so far. */ - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); - - /* Extract the ICMP type and code. */ - type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; - - /* Determine if this outbound packet an ICMP error message packet. */ - _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); - - /* Is the this an error message packet? */ - if (is_icmp_error_msg) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Drop the packet and bail! */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return completion status. */ - return NX_SUCCESS; - } - - /* Find the outbound entry, set the packet global interface and next hop address. */ - status = _nx_nat_outbound_entry_find(nat_ptr, packet_ptr, entry_ptr, &record_entry, &next_hop_address); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Increase the session count of dropped forwarded packets. */ - nat_ptr -> forwarded_packets_dropped++; -#endif - - /* Release the packet back to the packet pool. */ - nx_packet_release(packet_ptr); - - /* Return the error status. */ - return status; - } - - /* Update the ICMP Query ID ("port") if the NAT device mapped it to another Query ID - but not if this is a local host responding to a REQUEST ICMP packet, in which case - it must keep the same Query ID. */ - if ((type != NX_ICMP_ECHO_REPLY_TYPE) && (record_entry -> external_port != record_entry -> local_port)) - { - - /* Pick up the ICMP sequence number. */ - sequence = icmp_header_ptr -> nx_icmp_header_word_1 & NX_LOWER_16_MASK; - - /* Set the ICMP Query ID in the ICMP header. */ - icmp_header_ptr -> nx_icmp_header_word_1 = (ULONG) (record_entry -> external_port << NX_SHIFT_BY_16) | sequence; - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - if(compute_checksum) - { - - /* Set the old checksum. */ - checksum = icmp_header_ptr -> nx_icmp_header_word_0 & NX_LOWER_16_MASK; - - /* Set the old port and new port. */ - old_port = record_entry -> local_port; - new_port = record_entry -> external_port; - - /* Adjust the checksum. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_port, sizeof(USHORT), (UCHAR *)&new_port, sizeof(USHORT)); - - /* Ok to zero out the checksum because we'll replace it with an updated checksum. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; - - /* Place the checksum into the first header word. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 | checksum; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* Set the checksum to zero. */ - icmp_header_ptr -> nx_icmp_header_word_0 = icmp_header_ptr -> nx_icmp_header_word_0 & ~NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - } - - /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match - that of the data area. */ - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_0); - NX_CHANGE_ULONG_ENDIAN(icmp_header_ptr -> nx_icmp_header_word_1); - - /* Send the ICMP packet onto the global host. */ - _nx_nat_ip_packet_send(nat_ptr, packet_ptr, record_entry, NX_NAT_OUTBOUND_PACKET, next_hop_address); - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_ip_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the NAT equivalent of nx_ip_packet_send. It handles */ -/* all packets inbound or outbound of any protocol and forwards them */ -/* directly to the driver. */ -/* */ -/* This function also handles fragmented datagrams. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server */ -/* packet_ptr Pointer to packet */ -/* entry_ptr Pointer to NAT entry */ -/* packet_type Packet type(inbound/outbound) */ -/* next_hop_address Next hop address to target */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status. */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_FRAGMENT_QUEUE_NOT_FOUND Fragment queue for datagram */ -/* not found */ -/* CALLS */ -/* */ -/* nx_packet_release Release the packet */ -/* _nx_packet_data_append Append the overflow data */ -/* _nx_nat_checksum_adjust Adjust checksum for NAT changes */ -/* to IP header */ -/* _nx_ip_driver_packet_send Forward packet to driver to send*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */ -/* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */ -/* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */ -/* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */ -/* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */ -/* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_nat_ip_packet_send(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, UCHAR packet_type, ULONG next_hop_address) -{ - -ULONG fragment_bits; -ULONG old_address; -ULONG new_address; -ULONG old_fragment; -ULONG new_fragment; -USHORT checksum; -ULONG compute_checksum = 1; -ULONG destination_ip; -UINT status; -NX_IPV4_HEADER *ip_header_ptr; - - - /* Pickup the pointer to the head of the ICMP packet. */ - packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_IPV4_HEADER); - packet_ptr -> nx_packet_length += sizeof(NX_IPV4_HEADER); - ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Check the packet type. */ - if (packet_type == NX_NAT_OUTBOUND_PACKET) - { - - /* Update the source ip address. */ - ip_header_ptr -> nx_ip_header_source_ip = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - - /* Set the local address and external address. */ - old_address = entry_ptr -> local_ip_address; - new_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - } - else - { - /* Update the destination ip address. */ - ip_header_ptr -> nx_ip_header_destination_ip = entry_ptr -> local_ip_address; - - /* Set the old address and new address. */ - old_address = nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index].nx_interface_ip_address; - new_address = entry_ptr -> local_ip_address; - } - - /* Record the destination IP address. */ - destination_ip = ip_header_ptr -> nx_ip_header_destination_ip; - - /* Record the fragment bit. */ - fragment_bits = (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_DONT_FRAGMENT); - old_fragment = ip_header_ptr -> nx_ip_header_word_1 & NX_LOWER_16_MASK; - new_fragment = old_fragment; - - /* Check if the packet is fragmented and if the fragment field is not zero. */ - if ((fragment_bits != NX_IP_DONT_FRAGMENT) && (old_fragment != 0)) - { - - /* Clear the fragment field. */ - ip_header_ptr -> nx_ip_header_word_1 = ip_header_ptr -> nx_ip_header_word_1 & ~NX_LOWER_16_MASK; - new_fragment = 0; - } - -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - if(packet_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM) - compute_checksum = 0; - else - compute_checksum = 1; -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Compute the checksum. */ - if(compute_checksum) - { - - /* Get the checksum. */ - checksum = ip_header_ptr -> nx_ip_header_word_2 & NX_LOWER_16_MASK; - - /* Adjust the checksum for address. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_address, sizeof(LONG), (UCHAR *)&new_address, sizeof(LONG)); - - /* Check if the fragment field is updated. */ - if (old_fragment != new_fragment) - { - - /* Adjust the checksum for fragment field. */ - _nx_nat_checksum_adjust((UCHAR *)&checksum, (UCHAR *)&old_fragment, sizeof(LONG), (UCHAR *)&new_fragment, sizeof(LONG)); - } - - /* Clear the checksum value. */ - ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK; - - /* Place the checksum into the header word. */ - ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | checksum; - } -#ifdef NX_ENABLE_INTERFACE_CAPABILITY - else - { - - /* Clear the checksum value. */ - ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK; - - /* Set the flag. */ - packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_IPV4_TX_CHECKSUM; - } -#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ - - /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will - swap the endian of the IP header. */ - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip); - NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip); - - /* Check if the packet can fill physical header. */ - status = _nx_packet_data_adjust(packet_ptr, NX_PHYSICAL_HEADER); - - /* Check status. */ - if (status) - { - -#ifndef NX_DISABLE_NAT_INFO - /* Update the count. */ - nat_ptr -> forwarded_packets_dropped ++; -#endif - - /* Release the packet. */ - _nx_packet_release(packet_ptr); - return; - } - -#ifndef NX_DISABLE_NAT_INFO - /* Update the packet sent count. */ - nat_ptr -> forwarded_packets_sent++; -#endif - - /* Call the function to directly forward the packet. */ - _nx_ip_driver_packet_send(nat_ptr -> nx_nat_ip_ptr, packet_ptr, destination_ip, fragment_bits, next_hop_address); - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_inbound_entry_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the inbound entry in NAT translation entry list, */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server */ -/* packet_ptr Pointer to packet */ -/* entry_ptr Pointer to NAT entry */ -/* entry_ptr Pointer to the matched entry */ -/* next_hop_address The next hop address for route */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_utility_get_source_port Extract source port from packet */ -/* _nx_nat_utility_get_destination_port */ -/* Extract destination port from */ -/* packet */ -/* _nx_nat_entry_create Create entry for packet in NAT */ -/* translation table */ -/* _nx_nat_entry_find Find the entry */ -/* _nx_ip_route_find Find the suitable interface */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_TCP_packet Process outbound TCP packet */ -/* _nx_nat_process_inbound_UDP_packet Process outbound UDP packet */ -/* _nx_nat_process_inbound_ICMP_packet Process outbound ICMP packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_inbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, - NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address) -{ - -UINT status; -ULONG timeout; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Check the protocol. */ - if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP)) - { - - /* Get sender's source port. */ - _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> peer_port); - } - - /* Get the destination port from header data. */ - _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &entry_ptr -> external_port); - - /* Check the timeout for all dynamic entries. */ - _nx_nat_entry_timeout_check(nat_ptr); - - /* Now search the table for a matching NAT translation entry. */ - _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_TRUE); - - /* Was a matching entry found in our translation table? */ - if (!record_entry) - { - - /* Next see if the destination is a local host server. */ - - /* Find a 'server' for packet destination IP address and port */ - _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_INBOUND_PACKET, NX_FALSE); - - /* Check the record entry. */ - if (record_entry) - { - - /* We found a matching server entry in the table. Now create an - entry specifically for this packet. */ - - /* Get the private IP address from the entry we just found, and apply to the new entry we're creating. */ - entry_ptr -> local_ip_address = record_entry -> local_ip_address; - - /* Check the private inside port. */ - if (record_entry -> local_port == 0) - { - - /* Set the private inside port same as global inside port. */ - entry_ptr -> local_port = entry_ptr -> external_port; - } - else - { - - /* Set private inside port. */ - entry_ptr -> local_port = record_entry -> local_port; - } - - /* Set the entry expiration timeout. */ - if (entry_ptr -> protocol == NX_PROTOCOL_TCP) - { - - /* TCP session. */ - timeout = NX_NAT_TCP_SESSION_TIMEOUT; - } - else - { - - /* Non-TCP session. */ - timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT; - } - - /* Now create the entry. */ - status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol, - entry_ptr -> local_ip_address, - entry_ptr -> peer_ip_address, - entry_ptr -> local_port, - entry_ptr -> external_port, - entry_ptr -> peer_port, - timeout, - &record_entry); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return status.*/ - return status; - } - } - else - { - - /* Return status.*/ - return (NX_NAT_ENTRY_NOT_FOUND); - } - } - - /* Clear the packet interface as private interface. */ - packet_ptr -> nx_packet_address.nx_packet_interface_ptr = NX_NULL; - - /* Set the inbound interface and next hop address. */ - if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> local_ip_address, - &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS) - { - - /* No suitable private interface configured. */ - - /* Return the error status. */ - return (NX_NAT_ROUTE_FIND_ERROR); - } - - /* Set the matched entry pointer. */ - *matched_entry_ptr = record_entry; - - /* Return success. */ - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_outbound_entry_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the outbound entry in NAT translation entry list.*/ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server */ -/* packet_ptr Pointer to packet */ -/* entry_ptr Pointer to NAT entry */ -/* entry_ptr Pointer to the matched entry */ -/* next_hop_address The next hop address for route */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_utility_get_source_port Extract source port from packet */ -/* _nx_nat_utility_get_destination_port */ -/* Extract destination port from */ -/* packet */ -/* _nx_nat_entry_create Create entry for packet in NAT */ -/* translation table */ -/* _nx_nat_entry_find Find the entry */ -/* _nx_ip_route_find Find the suitable interface */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_outbound_TCP_packet Process outbound TCP packet */ -/* _nx_nat_process_outbound_UDP_packet Process outbound UDP packet */ -/* _nx_nat_process_outbound_ICMP_packet Process outbound ICMP packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_outbound_entry_find(NX_NAT_DEVICE *nat_ptr, NX_PACKET *packet_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, - NX_NAT_TRANSLATION_ENTRY **matched_entry_ptr, ULONG *next_hop_address) -{ - -UINT status; -ULONG timeout; -NX_NAT_TRANSLATION_ENTRY *record_entry; - - - /* Get source ports from the header. */ - _nx_nat_utility_get_source_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> local_port)); - - /* Check the protocol. */ - if ((entry_ptr -> protocol == NX_PROTOCOL_TCP) || (entry_ptr -> protocol == NX_PROTOCOL_UDP)) - { - - /* Get destination port from the header. */ - _nx_nat_utility_get_destination_port(packet_ptr, entry_ptr -> protocol, &(entry_ptr -> peer_port)); - } - - /* Check the timeout for all dynamic entries. */ - _nx_nat_entry_timeout_check(nat_ptr); - - /* Search the table for a match. */ - _nx_nat_entry_find(nat_ptr, entry_ptr, &record_entry, NX_NAT_OUTBOUND_PACKET, NX_TRUE); - - /* Was a matching table entry found? */ - if (!record_entry) - { - - /* Find the available port. */ - status = _nx_nat_find_available_port(nat_ptr, entry_ptr -> protocol, &entry_ptr -> external_port); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set the entry expiration timeout. */ - if (entry_ptr -> protocol == NX_PROTOCOL_TCP) - { - - /* TCP session. */ - timeout = NX_NAT_TCP_SESSION_TIMEOUT; - } - else - { - - /* Non-TCP session. */ - timeout = NX_NAT_NON_TCP_SESSION_TIMEOUT; - } - - /* Create an entry with NAT translation for IP address/port. */ - status = _nx_nat_entry_create(nat_ptr, entry_ptr -> protocol, - entry_ptr -> local_ip_address, - entry_ptr -> peer_ip_address, - entry_ptr -> local_port, - entry_ptr -> external_port, - entry_ptr -> peer_port, - timeout, - &record_entry); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - } - - /* Set the packet interface as global interface. */ - packet_ptr -> nx_packet_address.nx_packet_interface_ptr = &(nat_ptr -> nx_nat_ip_ptr -> nx_ip_interface[nat_ptr -> nx_nat_global_interface_index]); - - /* Set the next hop address. */ - if(_nx_ip_route_find(nat_ptr -> nx_nat_ip_ptr, record_entry -> peer_ip_address, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr, next_hop_address) != NX_SUCCESS) - { - - /* No suitable private interface configured. */ - - /* Return the error status. */ - return (NX_NAT_ROUTE_FIND_ERROR); - } - - /* Set the matched entry pointer. */ - *matched_entry_ptr = record_entry; - - /* Return success. */ - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_entry_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function dynamically creates a NAT translation table entry */ -/* and appends the entry to the translation list. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* protocol Protocol of packets matching entry*/ -/* local_ip_address Entry's private IP address */ -/* peer_ip_address Entry's external host IP */ -/* local_port Entry's private port */ -/* external_port Entry's global port */ -/* peer_port Entry's external port (optional) */ -/* response_timeout Entry expiration timeout */ -/* match_entry_ptr Pointer to entry created */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_TRANSLATION_TABLE_FULL Table is full (max capacity) */ -/* NX_NAT_INVALID_TABLE_ENTRY Invalid criteria for table entry */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_entry_add Add entry to linked list of entries*/ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_entry_create(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, - ULONG local_ip_address, ULONG peer_ip_address, - USHORT local_port, USHORT external_port, USHORT peer_port, - ULONG response_timeout, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr) -{ - -NX_NAT_TRANSLATION_ENTRY *insert_entry_ptr = NX_NULL; - -#ifdef NX_NAT_ENABLE_REPLACEMENT -NX_NAT_TRANSLATION_ENTRY *insert_previous_ptr = NX_NULL; -NX_NAT_TRANSLATION_ENTRY *entry_ptr = NX_NULL; -NX_NAT_TRANSLATION_ENTRY *previous_ptr = NX_NULL; -#endif /* NX_NAT_ENABLE_REPLACEMENT */ - - - /* Initialize result to not found. */ - *match_entry_ptr = NX_NULL; - - /* Perform some simple sanity checks on this entry. */ - - /* Was an invalid IP address submitted? */ - if ((peer_ip_address == 0x0) || - (local_ip_address == 0x0)) - { - - return (NX_NAT_INVALID_ENTRY); - } - - /* Check available entries. */ - if (nat_ptr -> nx_nat_dynamic_available_entries) - { - - /* Get one available entry. */ - insert_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head; - - /* Update the entry head. */ - nat_ptr -> nx_nat_dynamic_available_entry_head = insert_entry_ptr -> next_entry_ptr; - } - else - { -#ifdef NX_NAT_ENABLE_REPLACEMENT - - /* Get a pointer to the start of the entries in the translation table. */ - entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - - /* Search the whole entry list to find the oldest non-TCP entry. */ - while (entry_ptr) - { - - /* Check the entry type and protocol. */ - if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) || (entry_ptr -> protocol == NX_PROTOCOL_TCP)) - { - - /* Ingore this entry, Get the next entry in the table. */ - previous_ptr = entry_ptr; - entry_ptr = entry_ptr -> next_entry_ptr; - continue; - } - else - { - - /* Check if set the insert_entry_ptr(oldest entry). */ - if (insert_entry_ptr == NX_NULL) - { - - /* Assume the first entry is the oldest entry. */ - insert_entry_ptr = entry_ptr; - insert_previous_ptr = previous_ptr; - } - else - { - - /* Compare the timestamp. */ - if (((INT)insert_entry_ptr -> response_timestamp - (INT)entry_ptr -> response_timestamp) > 0) - { - - /* entry_ptr is an older entry, so update the insert_entry_ptr. */ - insert_entry_ptr = entry_ptr; - insert_previous_ptr = previous_ptr; - } - } - - /* Get the next entry in the table. */ - previous_ptr = entry_ptr; - entry_ptr = entry_ptr -> next_entry_ptr; - } - } - - /* Check if found the oldest non-TCP entry. */ - if (insert_entry_ptr) - { - - /* Yes, found it. Check if this is the first entry in the list. */ - if (insert_previous_ptr) - { - - /* It is not, so link the previous entry around the entry we are deleting. */ - insert_previous_ptr -> next_entry_ptr = insert_entry_ptr -> next_entry_ptr; - } - else - { - - /* It is the first entry, so set the next pointer as the starting translation table entry. */ - nat_ptr -> nx_nat_dynamic_active_entry_head = insert_entry_ptr -> next_entry_ptr; - } - - /* Update the entry count. */ - nat_ptr -> nx_nat_dynamic_active_entries --; - nat_ptr -> nx_nat_dynamic_available_entries ++; - } - else - { -#endif /* NX_NAT_ENABLE_REPLACEMENT */ - - /* This service cache does not have room for the entry. */ - /* Invoke user-installed cache full notify function .*/ - if(nat_ptr -> nx_nat_cache_full_notify) - { - - /* Call the callback function. */ - (nat_ptr -> nx_nat_cache_full_notify)(nat_ptr); - } - - /* Return error status. */ - return (NX_NAT_CACHE_FULL); - -#ifdef NX_NAT_ENABLE_REPLACEMENT - } -#endif /* NX_NAT_ENABLE_REPLACEMENT */ - } - - /* Initialize the allocated memory to NULL. */ - memset(insert_entry_ptr, 0, sizeof(NX_NAT_TRANSLATION_ENTRY)); - - /* Assign the entry attributes. */ - insert_entry_ptr -> protocol = protocol; - insert_entry_ptr -> local_ip_address = local_ip_address; - insert_entry_ptr -> peer_ip_address = peer_ip_address; - insert_entry_ptr -> local_port = local_port; - insert_entry_ptr -> external_port = external_port; - insert_entry_ptr -> peer_port = peer_port; - insert_entry_ptr -> response_timeout = response_timeout; - - /* Set the entry timestamp. */ - insert_entry_ptr -> response_timestamp = tx_time_get(); - - /* Set entry type to dynamically created. */ - insert_entry_ptr -> translation_type = NX_NAT_DYNAMIC_ENTRY; - - /* Append to the table. */ - _nx_nat_entry_add(nat_ptr, insert_entry_ptr); - - /* Set a pointer to the newly created entry. */ - *match_entry_ptr = insert_entry_ptr; - - /* Return successful completion status. */ - return (NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_entry_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a NAT translation entry to the NAT entry list */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* entry_ptr Pointer to NAT translation entry */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_create Create inbound entry to NAT table */ -/* before starting the NAT server */ -/* _nx_nat_entry_create Create and add entry to NAT table */ -/* after starting the NAT server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_entry_add(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr) -{ - - - /* Add this entry onto the table entry list. */ - entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr; - - /* Update the entry count. */ - if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY) - { - - /* Update the entry count. */ - nat_ptr -> nx_nat_dynamic_active_entries ++; - nat_ptr -> nx_nat_dynamic_available_entries --; - } - else - nat_ptr -> nx_nat_static_active_entries ++; - - /* Return success status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_entry_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to find an entry in the NAT translation list */ -/* that matches the entry submitted by the caller. If none is found it*/ -/* returns a null pointer. There is an option to skip entries */ -/* designated for local hosts accepting packets from external hosts */ -/* (e.g. servers). */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server */ -/* entry_to_match Pointer to entry to match in the list */ -/* match_entry_ptr Pointer to matching entry in the list */ -/* direction Forward direction(inbound/outbound) */ -/* skip_inbound_init_entries Skip entries for local hosts allowing */ -/* initial packet from external source */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_time_get Get the system time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_nat_entry_find(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_to_match, NX_NAT_TRANSLATION_ENTRY **match_entry_ptr, - UCHAR direction, UINT skip_static_entries) -{ - -NX_NAT_TRANSLATION_ENTRY *entry_ptr; -NX_NAT_TRANSLATION_ENTRY *previous_ptr; - - - /* Initialize the search result to null (no match found). */ - *match_entry_ptr = 0x0; - - /* Check the inbound entry. */ - if ((direction == NX_NAT_INBOUND_PACKET) && - (!entry_to_match -> peer_ip_address)) - { - - /* Return. */ - return; - } - - /* Check the outbound entry. */ - if ((direction == NX_NAT_OUTBOUND_PACKET) && - ((!entry_to_match -> local_ip_address) || (!entry_to_match -> peer_ip_address))) - { - - /* Return. */ - return ; - } - - /* Initialize the previous pointer. */ - previous_ptr = NX_NULL; - - /* Get a pointer to the start of the entries in the translation table. */ - entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - - /* Search the whole table until a match is found. */ - while (entry_ptr) - { - - /* Check the entry type, (e.g. accepts packets from external hosts) ?*/ - if ((entry_ptr -> translation_type == NX_NAT_STATIC_ENTRY) && (skip_static_entries == NX_TRUE)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* Ingore the static entry, get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - - /* Do sender and entry protocols match? */ - if (entry_ptr -> protocol != entry_to_match -> protocol) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* Get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - - /* Continue matching IP address and port criteria. */ - - /* Do external IP addresses, if specified, match? */ - if ((entry_ptr -> peer_ip_address) && - (entry_ptr -> peer_ip_address != entry_to_match -> peer_ip_address)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* No, get the next entry. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - - /* Do external ports, if specified match? */ - if ((entry_ptr -> peer_port) && - (entry_ptr -> peer_port != entry_to_match -> peer_port)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* No, get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - - /* Check the inbound entry. */ - if (direction == NX_NAT_INBOUND_PACKET) - { - - /* Does the inside host global port, if specified, match? */ - if ((entry_ptr -> external_port) && - (entry_ptr -> external_port != entry_to_match -> external_port)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* No, get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - } - else - { - - /* Do private inside IP addresses, if specified, match? */ - if ((entry_ptr -> local_ip_address) && - (entry_ptr -> local_ip_address != entry_to_match -> local_ip_address)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* No, get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - - /* Does the inside host private port, if specified, match? */ - if ((entry_ptr -> local_port) && - (entry_ptr -> local_port != entry_to_match -> local_port)) - { - - /* Set the previous entry pointer. */ - previous_ptr = entry_ptr; - - /* No, get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - - continue; - } - } - - /* If we got this far, all criteria matched up. Set a pointer to - this entry in the table. */ - *match_entry_ptr = entry_ptr; - - /* The entry is active, reset the timeout to the present. */ - entry_ptr -> response_timestamp = tx_time_get(); - - /* Yes; check if this is the first entry in the list. */ - if (previous_ptr) - { - - /* It is not. Put this entry at the head of the list to improve searching effectiveness. */ - previous_ptr -> next_entry_ptr = entry_ptr -> next_entry_ptr; - entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - nat_ptr -> nx_nat_dynamic_active_entry_head = entry_ptr; - } - break; - } - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_entry_timeout_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to check the entry's timeout, and remove the */ -/* expiration entries from dynamic active translation list. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_time_get Get the system time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_nat_entry_timeout_check(NX_NAT_DEVICE *nat_ptr) -{ - -ULONG current_time; -ULONG elapsed_time; -NX_NAT_TRANSLATION_ENTRY *entry_ptr; -NX_NAT_TRANSLATION_ENTRY *previous_ptr; -NX_NAT_TRANSLATION_ENTRY *next_entry_ptr; - - - /* Get the current time. */ - current_time = tx_time_get(); - - /* Get a pointer to the start of the entries in the translation table. */ - entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - - /* Initialize the previous pointer. */ - previous_ptr = NX_NULL; - - /* Search thru the whole entry list. */ - while (entry_ptr) - { - - /* Set a pointer to the next entry in the table. */ - next_entry_ptr = entry_ptr -> next_entry_ptr; - - /* Check the entry type and update the time. */ - if (entry_ptr -> translation_type == NX_NAT_DYNAMIC_ENTRY) - { - - /* Calculate the elapsed time. */ - elapsed_time = current_time - entry_ptr -> response_timestamp; - - /* Update the time remaining. */ - if (elapsed_time >= entry_ptr -> response_timeout) - { - - /* Delete this entry from active entry list. */ - - /* Check if this is the first entry in the list). */ - if (previous_ptr) - { - - /* It is not, so link the previous entry around the entry we are deleting. */ - previous_ptr -> next_entry_ptr = next_entry_ptr; - } - else - { - - /* It is the first entry, so set the next pointer as the starting translation table entry. */ - nat_ptr -> nx_nat_dynamic_active_entry_head = next_entry_ptr; - } - - /* Add the entry onto available entry list. */ - entry_ptr -> next_entry_ptr = nat_ptr -> nx_nat_dynamic_available_entry_head; - nat_ptr -> nx_nat_dynamic_available_entry_head = entry_ptr; - - /* Update the entry count. */ - nat_ptr -> nx_nat_dynamic_active_entries --; - nat_ptr -> nx_nat_dynamic_available_entries ++; - } - else - { - - /* Set the previous entry. */ - previous_ptr = entry_ptr; - } - } - else - { - - /* Set the previous entry. */ - previous_ptr = entry_ptr; - } - - /* Get the next entry in the table. */ - entry_ptr = next_entry_ptr; - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_utility_get_destination_port PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the destination port from the packet's */ -/* protocol header. In the case of ICMP packets, it extracts the ICMP */ -/* header identifier (ID) instead. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet with destination port */ -/* protocol Packet protocol (TCP, UDP etc) */ -/* peer_port Pointer to external (destination) port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_packet_is_icmp_error_message */ -/* Indicate if ICMP packet is query or */ -/* error message packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_utility_get_destination_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *peer_port) -{ - -NX_TCP_HEADER *tcp_header_ptr; -NX_UDP_HEADER *udp_header_ptr; -NX_ICMP_HEADER *icmp_header_ptr; -UINT is_icmp_error_msg; - - - /* Is this a TCP packet? */ - if (protocol == NX_PROTOCOL_TCP) - { - - /* Pickup the pointer to the head of the TCP packet. */ - tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the destination TCP port. */ - *peer_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK); - } - /* Is this a UDP packet? */ - else if (protocol == NX_PROTOCOL_UDP) - { - - /* Pickup the pointer to the head of the UDP packet. */ - udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the destination UDP port. */ - *peer_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK); - } - /* Is this an ICMP packet? */ - else if (protocol == NX_PROTOCOL_ICMP) - { - - /* Determin type of ICMP message. */ - _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); - - /* Is this an ICMP error message? */ - if (is_icmp_error_msg ) - { - - /* Yes, these don't have query ID fields. */ - *peer_port = 0; - } - else - { - - /* Setup the pointer to the ICMP header located in the data area after the IP header. */ - icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the ICMP identifier which we will call the 'source port'. */ - *peer_port = (USHORT) (icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16); - } - } - else - { - - /* Unknown or unsupported packet protocol. */ - *peer_port = 0; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_utility_get_source_port PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the source port from the packet's protocol */ -/* header. In the case of ICMP packets, it extracts the query identifier*/ -/* (ID) instead. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet to get source port */ -/* protocol Packet protocol (TCP, UDP etc) */ -/* source_port Pointer to packet source port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_nat_packet_is_icmp_error_message */ -/* Indicate if ICMP packet is query or */ -/* error message ICMP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_inbound_entry_find Find inbound entry in entry list */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_utility_get_source_port(NX_PACKET *packet_ptr, UCHAR protocol, USHORT *source_port) -{ - -NX_TCP_HEADER *tcp_header_ptr; -NX_UDP_HEADER *udp_header_ptr; -NX_ICMP_HEADER *icmp_header_ptr; -UINT is_icmp_error_msg; - - if (protocol == NX_PROTOCOL_TCP) - { - - /* Pickup the pointer to the head of the TCP packet. */ - tcp_header_ptr = (NX_TCP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the source TCP port. */ - *source_port = (USHORT) (tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16); - } - else if (protocol == NX_PROTOCOL_UDP) - { - - /* Pickup the pointer to the head of the UDP packet. */ - udp_header_ptr = (NX_UDP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the source UDP port. */ - *source_port = (USHORT) (udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16); - } - else if (protocol == NX_PROTOCOL_ICMP) - { - - /* Determine type of ICMP message. */ - _nx_nat_packet_is_icmp_error_message(packet_ptr, &is_icmp_error_msg); - - /* Is this an ICMP error message? */ - if (is_icmp_error_msg ) - { - - /* Yes, return a zero query ID (error messages have no Query ID). */ - *source_port = 0; - } - else - { - - /* Setup the pointer to the ICMP header located in the data area after the IP header. */ - icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Pickup the ICMP Query ID which is used in place of a source port. */ - *source_port = (USHORT)(icmp_header_ptr -> nx_icmp_header_word_1 >> NX_SHIFT_BY_16); - } - } - else - /* Unknown or unsupported protocol. */ - *source_port = 0; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_find_available_port PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds an available a ICMP query identifier (ID) or */ -/* or TCP/UDP port when NAT is configured to share a global IP address */ -/* among its local hosts and consequently must use the query ID/port */ -/* field to uniquely identify. */ -/* */ -/* INPUT */ -/* */ -/* nat_ptr Pointer to NAT instance */ -/* protocol Network protocol(TCP, UDP, ICMP) */ -/* port Pointer to an unused port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_NAT_NO_FREE_PORT_AVAILABLE No free port found status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_outbound_entry_find Find outbound entry in entry list */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_find_available_port(NX_NAT_DEVICE *nat_ptr, UCHAR protocol, USHORT *port) -{ - -UINT bound; -USHORT start_port; -USHORT end_port; -NX_NAT_TRANSLATION_ENTRY *entry_ptr; - - - /* Start at the lowest of number for translated query ID/port for NAT. */ - if (protocol == NX_PROTOCOL_TCP) - { - start_port = NX_NAT_START_TCP_PORT; - end_port = NX_NAT_END_TCP_PORT; - } - else if(protocol == NX_PROTOCOL_UDP) - { - start_port = NX_NAT_START_UDP_PORT; - end_port = NX_NAT_END_UDP_PORT; - } - else - { - start_port = NX_NAT_START_ICMP_QUERY_ID; - end_port = NX_NAT_END_ICMP_QUERY_ID; - } - - /* Set the start port. */ - *port = start_port; - - /* Search for a Query ID not found in the translation table. */ - while(*port < end_port) - { - - /* Initialize the bound flag. */ - bound = NX_FALSE; - - /* Serach dynamic entries. */ - entry_ptr = nat_ptr -> nx_nat_dynamic_active_entry_head; - - /* Loop through the whole translation table. */ - while(entry_ptr) - { - - /* Check the protocol. */ - if (entry_ptr -> protocol == protocol) - { - - /* Does this entry have a matching port ID. */ - if (entry_ptr -> external_port == *port) - { - - /* Set the flag so we can abort the current search. */ - bound = NX_TRUE; - break; - } - } - - /* Get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - } - - /* Check if we got through the entire table with no bound port. */ - if ((bound == NX_FALSE) && - ((protocol == NX_PROTOCOL_TCP) || (protocol == NX_PROTOCOL_UDP))) - { - - /* Yes, check the NetXDuo TCP/UDP socket. */ - bound = _nx_nat_socket_port_verify(nat_ptr -> nx_nat_ip_ptr, protocol, *port); - } - - /* Check if we found a socket with a matching port. */ - if (bound == NX_FALSE) - { - - /* We did not. OK to use this port. */ - return NX_SUCCESS; - } - - /* Found a match. This port is not available. */ - - /* Bump the port up one. */ - (*port)++; - } - - /* If we got here we could not find a free port. */ - return (NX_NAT_NO_FREE_PORT_AVAILABLE); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_entry_port_verify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function verifies whether the supplied port is bound. lookup */ -/* all NAT translation entries, If same ports are found, return */ -/* NX_TRUE, else return NX_FALSE. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr IP instance pointer */ -/* protocol Protocol */ -/* port Port */ -/* */ -/* OUTPUT */ -/* */ -/* bound Completion status */ -/* NX_TRUE: port is bound */ -/* NX_FALSE: port is not bound */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_entry_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port) -{ - -UINT bound; -NX_NAT_TRANSLATION_ENTRY *entry_ptr; - - NX_PARAMETER_NOT_USED(ip_ptr); - - /* Initialize the return value. */ - bound = NX_FALSE; - - /* Serach dynamic entries. */ - entry_ptr = nat_server_ptr -> nx_nat_dynamic_active_entry_head; - - /* Loop through the whole translation table. */ - while(entry_ptr) - { - - /* Check the protocol. */ - if (entry_ptr -> protocol == protocol) - { - - /* Does this entry have a matching port ID. */ - if (entry_ptr -> external_port == port) - { - - /* Set the flag so we can abort the current search. */ - bound = NX_TRUE; - break; - } - } - - /* Get the next entry in the table. */ - entry_ptr = entry_ptr -> next_entry_ptr; - } - - /* Return status to the caller. */ - return(bound); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_socket_port_verify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function verifies whether the supplied port is bound. Search */ -/* all TCP/UDP sockets, and if the port is found, return NX_TRUE, */ -/* else return NX_TRUE. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr IP instance pointer */ -/* protocol Protocol */ -/* port Port */ -/* */ -/* OUTPUT */ -/* */ -/* bound Completion status */ -/* NX_TRUE: port is bound */ -/* NX_FALSE: port is not bound */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_socket_port_verify(NX_IP *ip_ptr, UINT protocol, UINT port) -{ - -UINT index; -UINT bound; -NX_TCP_SOCKET *tcp_search_ptr; -NX_TCP_SOCKET *tcp_end_ptr; -NX_UDP_SOCKET *udp_search_ptr; -NX_UDP_SOCKET *udp_end_ptr; - - - /* Initialize the return value. */ - bound = NX_FALSE; - - /* Check the protocol. */ - if (protocol == NX_PROTOCOL_TCP) - { - - /* Calculate the hash index in the TCP port array of the associated IP instance. */ - index = (UINT) ((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); - - /* Pickup the head of the TCP ports bound list. */ - tcp_search_ptr = ip_ptr -> nx_ip_tcp_port_table[index]; - - /* Determine if we need to perform a list search. */ - if (tcp_search_ptr) - { - - /* Walk through the circular list of UDP sockets that are already bound. */ - tcp_end_ptr = tcp_search_ptr; - do - { - - /* Determine if this entry is the same as the requested port. */ - if (tcp_search_ptr -> nx_tcp_socket_port == port) - { - - /* Yes, the port has already been bound. */ - bound = NX_TRUE; - break; - } - - /* Move to the next entry in the list. */ - tcp_search_ptr = tcp_search_ptr -> nx_tcp_socket_bound_next; - - } while (tcp_search_ptr != tcp_end_ptr); - } - } - else - { - - /* Calculate the hash index in the UDP port array of the associated IP instance. */ - index = (UINT) ((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK); - - /* Pickup the head of the UDP ports bound list. */ - udp_search_ptr = ip_ptr -> nx_ip_udp_port_table[index]; - - /* Determine if we need to perform a list search. */ - if (udp_search_ptr) - { - - /* Walk through the circular list of UDP sockets that are already bound. */ - udp_end_ptr = udp_search_ptr; - do - { - - /* Determine if this entry is the same as the requested port. */ - if (udp_search_ptr -> nx_udp_socket_port == port) - { - - /* Yes, the port has already been bound. */ - bound = NX_TRUE; - break; - } - - /* Move to the next entry in the list. */ - udp_search_ptr = udp_search_ptr -> nx_udp_socket_bound_next; - - } while (udp_search_ptr != udp_end_ptr); - } - } - - /* Return success to the caller. */ - return(bound); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_packet_is_icmp_error_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if an ICMP packet is a query message or an */ -/* error message. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to ICMP packet to parse */ -/* is_icmp_error_msg Indicates if packet is an error */ -/* message packet */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_ICMP_packet Forward inbound ICMP packets */ -/* _nx_nat_process_outbound_ICMP_packet Forward outbound ICMP packets */ -/* _nx_nat_utility_get_source_port Extract source port from header*/ -/* _nx_nat_utility_get_destination_port Extract destination port from */ -/* header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_nat_packet_is_icmp_error_message(NX_PACKET *packet_ptr, UINT *is_icmp_error_msg) -{ - -UINT type; -UINT protocol; -NX_IPV4_HEADER *ip_header_ptr; -NX_ICMP_HEADER *icmp_header_ptr; - - - /* Initialize the result to non error message type. */ - *is_icmp_error_msg = NX_FALSE; - - /* Set up an IP header pointer to the packet. */ - ip_header_ptr = (NX_IPV4_HEADER *) (packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IPV4_HEADER)); - - /* Set up an ICMP header pointer to the packet. */ - icmp_header_ptr = (NX_ICMP_HEADER *) (packet_ptr -> nx_packet_prepend_ptr); - - /* Determine what protocol the current IP datagram is. */ - protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF; - - /* Is this an ICMP packet? */ - if (protocol == NX_PROTOCOL_ICMP) - { - - /* Extract the ICMP type and code. */ - type = icmp_header_ptr -> nx_icmp_header_word_0 >> 24; - - /* Determine if this is an error message. */ - if (type != NX_ICMP_ECHO_REPLY_TYPE && - type != NX_ICMP_ECHO_REQUEST_TYPE && - type < NX_ICMP_TIMESTAMP_REQ_TYPE) - { - - /* It is. Set the flag to true. */ - *is_icmp_error_msg = NX_TRUE; - } - } - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_nat_checksum_adjust PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is an optimization for recomputing a checksum by just */ -/* computing the difference where a small amount of data has changed. */ -/* NAT uses this optimization when, for example, it is only changing an */ -/* IP address or port. */ -/* */ -/* INPUT */ -/* old_checksum Pointer to the old checksum */ -/* old_data Pointer to the data being changed*/ -/* new_data Pointer to new data replacing the*/ -/* old data */ -/* data_adjustment_length Size of data being changed */ -/* adjusted_checksum Pointer to the updated checksum */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_nat_process_inbound_TCP_packet Send TCP packet to local host */ -/* _nx_nat_process_inbound_UDP_packet Send UDP packet to local host */ -/* _nx_nat_process_inbound_ICMP_packet Send ICMP packet to local host */ -/* _nx_nat_process_outbound_TCP_packet Send TCP packet to external host */ -/* _nx_nat_process_outbound_UDP_packet Send UDP packet to external host */ -/* _nx_nat_process_outbound_ICMP_packet Send ICMP packet to external host*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_nat_checksum_adjust(UCHAR *checksum, UCHAR *old_data, INT old_data_length, UCHAR *new_data, INT new_data_length) -{ - -LONG x, old_value, new_value; -INT i,j; - -#ifdef NX_LITTLE_ENDIAN - i = 1; - j = 0; -#else - i = 0; - j = 1; -#endif - - /* Checksum Adjustment, RFC 3022, Section 4.2, Page 9. */ - - /* Get the old checksum. */ - x = checksum[i] * 256 + checksum[j]; - x = ~x & 0xFFFF; - - /* Update the checksum for old data. */ - while (old_data_length) - { - - /* Get the old data. */ - old_value = old_data[i] * 256 + old_data[j]; - - /* Update the old data pointer. */ - old_data += 2; - - /* Update the checksum. */ - x -= old_value & 0xFFFF; - - /* Check the value. */ - if (x <= 0) - { - - /* Update the value. */ - x --; - x &= 0xFFFF; - } - - /* Update the old data length. */ - old_data_length -= 2; - } - - /* Update the checksum for new data. */ - while (new_data_length) - { - - /* Get the new data. */ - new_value = new_data[i] * 256 + new_data[j]; - - /* Update the new data pointer. */ - new_data += 2; - - /* Update the checksum. */ - x += new_value & 0xFFFF; - - /* Check the value. */ - if (x & 0x10000) - { - - /* Update the value. */ - x ++; - x &= 0xFFFF; - } - - /* Update the new data length. */ - new_data_length -= 2; - } - - /* Update the value. */ - x = ~x & 0xFFFF; - - /* Update the checksum. */ - checksum[i] = (UCHAR)(x /256); - checksum[j] = (UCHAR)(x & 0xFF); - - /* Return. */ - return; -} -#endif diff --git a/protocol_handlers/nat/nx_nat.h b/protocol_handlers/nat/nx_nat.h deleted file mode 100644 index 260a4a50..00000000 --- a/protocol_handlers/nat/nx_nat.h +++ /dev/null @@ -1,302 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX NAT Component */ -/** */ -/** Network Address Translation Protocol (NAT) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_nat.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Network Address Translation Protocol */ -/* (NAT) component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_NAT_H -#define NX_NAT_H - - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_system.h" - -#ifdef NX_NAT_ENABLE - -/* Thread ID for identifying as an NAT device. */ - -#define NX_NAT_ID 0x4E4154UL - - -/* Internal error processing codes. */ - -#define NX_NAT_ERROR_CONSTANT 0xD00 - -#define NX_NAT_PARAM_ERROR (NX_NAT_ERROR_CONSTANT | 0x01) /* Invalid parameter for NAT service */ -#define NX_NAT_CACHE_ERROR (NX_NAT_ERROR_CONSTANT | 0x02) /* NAT translation cache currently is full. */ -#define NX_NAT_NOT_ENABLED (NX_NAT_ERROR_CONSTANT | 0x03) /* NAT is not enabled. */ -#define NX_NAT_ENTRY_NOT_FOUND (NX_NAT_ERROR_CONSTANT | 0x04) /* Did not find the entry in NAT entry list. */ -#define NX_NAT_INVALID_PROTOCOL (NX_NAT_ERROR_CONSTANT | 0x05) /* Invalid network protocol specified for translation entry. */ -#define NX_NAT_ROUTE_FIND_ERROR (NX_NAT_ERROR_CONSTANT | 0x06) /* Nat can not find the suitable interface to send the packet. */ -#define NX_NAT_INVALID_ENTRY (NX_NAT_ERROR_CONSTANT | 0x07) /* Invalid entry submitted for translation entry list. (e.g. invalid address). */ -#define NX_NAT_CACHE_FULL (NX_NAT_ERROR_CONSTANT | 0x08) /* NAT translation cache currently is full. */ -#define NX_NAT_NO_FREE_PORT_AVAILABLE (NX_NAT_ERROR_CONSTANT | 0x09) /* NAT unable to provide a unique public source port for outbound packet. */ -#define NX_NAT_ZERO_UDP_CHECKSUM (NX_NAT_ERROR_CONSTANT | 0x0A) /* UDP header checksum is zero but NAT not is configured to accept packets with zero UDP checksum. */ -#define NX_NAT_PACKET_CONSUMED_FAILED (NX_NAT_ERROR_CONSTANT | 0x0B) /* NAT sonsumed the packets failed. */ -#define NX_NAT_ENTRY_TYPE_ERROR (NX_NAT_ERROR_CONSTANT | 0x0C) /* The entry translation type error. */ -#define NX_NAT_PORT_UNAVAILABLE (NX_NAT_ERROR_CONSTANT | 0x0D) /* The port is unavailable. */ - - -/* Define the NAT entry attribute, */ -#define NX_NAT_STATIC_ENTRY 1 -#define NX_NAT_DYNAMIC_ENTRY 2 - -/* NetX NAT translation entry's transaction status levels. */ - -/* Define packet type based on direction (inbound, outbound, local). */ - -#define NX_NAT_INBOUND_PACKET 1 /* Inbound packet with local host destination on private network */ -#define NX_NAT_OUTBOUND_PACKET 2 /* Outbound packet with external host destination on external network */ - - -/* Define the minimum count of NAT entries. */ - -#ifndef NX_NAT_MIN_ENTRY_COUNT -#define NX_NAT_MIN_ENTRY_COUNT 3 -#endif - - -/* Set the default expiration timeout (sec) for translation entries, - 24 hours for TCP sessions, 4 minutes for non-TCP sessions. - RFC 2663, Section2.6, Page5. */ - -#ifndef NX_NAT_TCP_SESSION_TIMEOUT -#define NX_NAT_TCP_SESSION_TIMEOUT (86400 * NX_IP_PERIODIC_RATE) -#endif - -/* For backward compatibility, map the symbol NX_NAT_ENTRY_RESPONSE_TIMEOUT to NX_NAT_NON_TCP_SESSION_TIMEOUT. */ -#ifdef NX_NAT_ENTRY_RESPONSE_TIMEOUT -#define NX_NAT_NON_TCP_SESSION_TIMEOUT NX_NAT_ENTRY_RESPONSE_TIMEOUT -#endif /* NX_NAT_ENTRY_RESPONSE_TIMEOUT */ - -#ifndef NX_NAT_NON_TCP_SESSION_TIMEOUT -#define NX_NAT_NON_TCP_SESSION_TIMEOUT (240 * NX_IP_PERIODIC_RATE) -#endif /* NX_NAT_NON_TCP_SESSION_TIMEOUT */ - -/* Defined, this option enables automatic replacement when NAT cache is full. - Notice: only replace the oldest non-TCP session. */ -/* -#define NX_NAT_ENABLE_REPLACEMENT -*/ - - -/* Set the ICMP query identifier/port for assigning to outbound ICMP/UDP/TCP packets - on NAT devices configured for port overloading (sharing a single global IP - address). Note this number must be high enough not to exceed with the local host - ICMP, UDP, TCP packet query IDs/port. */ - -/* Set the minimum TCP port for assigning to outbound TCP packets. */ -#ifndef NX_NAT_START_TCP_PORT -#define NX_NAT_START_TCP_PORT 20000 -#endif - -/* Set the maximum TCP port for assigning to outbound TCP packets. */ - -#ifndef NX_NAT_END_TCP_PORT -#define NX_NAT_END_TCP_PORT (NX_NAT_START_TCP_PORT + 10000) -#endif - -/* Set the minimum UDP port for assigning to outbound UDP packets. */ -#ifndef NX_NAT_START_UDP_PORT -#define NX_NAT_START_UDP_PORT 20000 -#endif - -/* Set the maximum UDP port for assigning to outbound UDP packets. */ - -#ifndef NX_NAT_END_UDP_PORT -#define NX_NAT_END_UDP_PORT (NX_NAT_START_UDP_PORT + 10000) -#endif - -/* Set the minimum ICMP query identifier for assigning to outbound ICMP packets. */ -#ifndef NX_NAT_START_ICMP_QUERY_ID -#define NX_NAT_START_ICMP_QUERY_ID 20000 -#endif - -/* Set the maximum ICMP query identifier for assigning to outbound ICMP packets. */ - -#ifndef NX_NAT_END_ICMP_QUERY_ID -#define NX_NAT_END_ICMP_QUERY_ID (NX_NAT_START_ICMP_QUERY_ID + 10000) -#endif - - -/* Configure NAT to disable record the packet forward counter. */ -/* -#define NX_DISABLE_NAT_INFO -*/ - -/* Define the NAT translation table entry structure. */ -typedef struct NX_NAT_TRANSLATION_ENTRY_STRUCT -{ - - /* - Local Network External Network - |----------------| - | | external port> peer port> - | | - | | - |----------------| - */ - struct NX_NAT_TRANSLATION_ENTRY_STRUCT *next_entry_ptr; /* Pointer to the next translation entry in table */ - ULONG peer_ip_address; /* IP address of an external host sending/receiving packets through NAT. */ - ULONG local_ip_address; /* IP address of the local (private) host. */ - USHORT peer_port; /* Source port of an external host sending/receiving packets through NAT. */ - USHORT external_port; /* The external port of local (private) host. */ - USHORT local_port; /* Port of the local (private) host. */ - UCHAR translation_type; /* Translation type (static or dynamic). */ - UCHAR protocol; /* Packet's network sub protocol (TCP, UDP etc). */ - ULONG response_timeout; /* Expiration timeout for the entry. */ - ULONG response_timestamp; /* The last timestamp for entry used. */ -} NX_NAT_TRANSLATION_ENTRY; - - -/* Define the NAT device structure. */ -typedef struct NX_NAT_DEVICE_STRUCT -{ - - ULONG nx_nat_id; /* NAT Server thread ID */ - NX_IP *nx_nat_ip_ptr; /* IP instance for NAT's network. */ - UCHAR nx_nat_global_interface_index; /* NAT's global network. */ - UCHAR reserved[3]; /* Reserved. */ -#ifndef NX_DISABLE_NAT_INFO - ULONG forwarded_packets_received; /* Total number of packets received by NAT. */ - ULONG forwarded_packets_dropped; /* Total number of packets which cannot be forwarded. */ - ULONG forwarded_packets_sent; /* Total number of packets sent by NAT. */ -#endif - NX_NAT_TRANSLATION_ENTRY *nx_nat_dynamic_available_entry_head;/* Define the head pointer of available dynamic entries list. */ - NX_NAT_TRANSLATION_ENTRY *nx_nat_dynamic_active_entry_head; /* Define the head pointer of active dynamic entries list. */ - UINT nx_nat_dynamic_available_entries; /* Define the number of available dynamic entries. */ - UINT nx_nat_dynamic_active_entries; /* Define the number of active dynamic entries. */ - UINT nx_nat_static_active_entries; /* Define the number of active static entries. */ - VOID (*nx_nat_cache_full_notify)(struct NX_NAT_DEVICE_STRUCT *); -} NX_NAT_DEVICE; - - -#ifndef NX_NAT_SOURCE_CODE - - -/* Define the system API mappings based on the error checking - selected by the user. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - - -#ifdef NX_NAT_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_nat_create _nx_nat_create -#define nx_nat_delete _nx_nat_delete -#define nx_nat_enable _nx_nat_enable -#define nx_nat_disable _nx_nat_disable -#define nx_nat_cache_notify_set _nx_nat_cache_notify_set -#define nx_nat_inbound_entry_create _nx_nat_inbound_entry_create -#define nx_nat_inbound_entry_delete _nx_nat_inbound_entry_delete - -#else - -/* Services with error checking. */ - -#define nx_nat_create _nxe_nat_create -#define nx_nat_delete _nxe_nat_delete -#define nx_nat_enable _nxe_nat_enable -#define nx_nat_disable _nxe_nat_disable -#define nx_nat_cache_notify_set _nxe_nat_cache_notify_set -#define nx_nat_inbound_entry_create _nxe_nat_inbound_entry_create -#define nx_nat_inbound_entry_delete _nxe_nat_inbound_entry_delete - -#endif /* NX_NAT_DISABLE_ERROR_CHECKING */ - -/* Define API services available for NAT applications. */ - -UINT nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); -UINT nx_nat_delete(NX_NAT_DEVICE *nat_ptr); -UINT nx_nat_enable(NX_NAT_DEVICE *nat_ptr); -UINT nx_nat_disable(NX_NAT_DEVICE *nat_ptr); -UINT nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); -UINT nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, UINT external_port, USHORT local_port, UCHAR protocol); -UINT nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); - -#else /* NX_NAT_SOURCE_CODE */ - -/* NAT source code is being compiled, do not perform any API mapping. */ - -UINT _nx_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); -UINT _nxe_nat_create(NX_NAT_DEVICE *nat_ptr, NX_IP *ip_ptr, UINT global_interface_index, VOID *dynamic_cache_memory, UINT dynamic_cache_size); -UINT _nx_nat_delete(NX_NAT_DEVICE *nat_ptr); -UINT _nxe_nat_delete(NX_NAT_DEVICE *nat_ptr); -UINT _nx_nat_enable(NX_NAT_DEVICE *nat_ptr); -UINT _nxe_nat_enable(NX_NAT_DEVICE *nat_pt); -UINT _nx_nat_disable(NX_NAT_DEVICE *nat_ptr); -UINT _nxe_nat_disable(NX_NAT_DEVICE *nat_ptr); -UINT _nx_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); -UINT _nxe_nat_cache_notify_set(NX_NAT_DEVICE *nat_ptr, VOID (*cache_full_notify_cb)(NX_NAT_DEVICE *nat_ptr)); -UINT _nx_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol); -UINT _nxe_nat_inbound_entry_create(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *entry_ptr, ULONG local_ip_address, USHORT external_port, USHORT local_port, UCHAR protocol); -UINT _nx_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); -UINT _nxe_nat_inbound_entry_delete(NX_NAT_DEVICE *nat_ptr, NX_NAT_TRANSLATION_ENTRY *delete_entry_ptr); -#endif - -#endif /* NX_NAT_ENABLE */ - -/* If a C++ compiler is being used....*/ -#ifdef __cplusplus - } -#endif - -#endif /* NX_NAT_H */ - diff --git a/protocol_handlers/pop3/nxd_pop3_client.c b/protocol_handlers/pop3/nxd_pop3_client.c deleted file mode 100644 index 0b704148..00000000 --- a/protocol_handlers/pop3/nxd_pop3_client.c +++ /dev/null @@ -1,3227 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX POP3 Client Component */ -/** */ -/** Post Office Protocol Version 3 (POP3) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_pop3_client.c PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Post Office Protocol (POP3) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#define NX_POP3_CLIENT_SOURCE_CODE - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - - -#include "nx_api.h" -#include "nx_md5.h" -#include "nx_ip.h" -#include "nxd_pop3_client.h" -#include "nx_ipv6.h" -#include - -/* The following array of state handlers is indexed by the state. */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create POP3 client */ -/* service (IPv4 only). */ -/* */ -/* Note: The string lengths of client_name and client_password are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* APOP_authentication 1=enable APOP; 0=disable APOP */ -/* ip_ptr Pointer to client IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* server_ip_address POP3 server IP address */ -/* server_port POP3 server port */ -/* client_name Client POP3 user name */ -/* client_password Client POP3 password */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_create Creates the POP3 client */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, - NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, - CHAR *client_password) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for valid input pointers. */ - if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL) || (client_name == NX_NULL) || - (client_password == NX_NULL)) - { - - /* Return pointer error. */ - return(NX_PTR_ERROR); - } - - if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (server_ip_address == 0) || (server_port == 0)) - { - - return NX_POP3_PARAM_ERROR; - } - - /* Call the actual client create service. */ - status = _nx_pop3_client_create(client_ptr, - APOP_authentication, - ip_ptr, packet_pool_ptr, - server_ip_address, server_port, client_name, - client_password); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(APOP_authentication); - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - NX_PARAMETER_NOT_USED(server_ip_address); - NX_PARAMETER_NOT_USED(server_port); - NX_PARAMETER_NOT_USED(client_name); - NX_PARAMETER_NOT_USED(client_password); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a POP3 Client on the specified IP instance. */ -/* */ -/* Note: The string lengths of client_name and client_password are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* APOP_authentication 1=enable APOP; 0=disable APOP */ -/* ip_ptr Pointer to client IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* server_ip_address POP3 server IP address */ -/* server_port POP3 server port */ -/* client_name Client POP3 user name */ -/* client_password Client POP3 password */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* _nxd_pop3_client_create Duo Client POP3 create service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, - NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, - CHAR *client_password) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_address; - - server_address.nxd_ip_address.v4 = server_ip_address; - server_address.nxd_ip_version = NX_IP_VERSION_V4; - - status = _nxd_pop3_client_create(client_ptr, - APOP_authentication, - ip_ptr, packet_pool_ptr, - &server_address, server_port, client_name, - client_password); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(APOP_authentication); - NX_PARAMETER_NOT_USED(ip_ptr); - NX_PARAMETER_NOT_USED(packet_pool_ptr); - NX_PARAMETER_NOT_USED(server_ip_address); - NX_PARAMETER_NOT_USED(server_port); - NX_PARAMETER_NOT_USED(client_name); - NX_PARAMETER_NOT_USED(client_password); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_pop3_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the create POP3 client */ -/* service (supports IPv6 and IPv4). */ -/* */ -/* Note: The string lengths of client_name and client_password are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* APOP_authentication 1=enable APOP; 0=disable APOP */ -/* ip_ptr Pointer to client IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* server_duo_address POP3 server IPv6/IPv4 address */ -/* server_port POP3 server port */ -/* client_name Client POP3 user name */ -/* client_password Client POP3 password */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_pop3_client_create Creates the POP3 client */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, - NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port, CHAR *client_name, - CHAR *client_password) -{ - -UINT status; - - - /* Check for valid input pointers. */ - if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL) || (server_ip_address == NX_NULL) || - (client_name == NX_NULL) || (client_password == NX_NULL)) - { - - /* Return pointer error. */ - return(NX_PTR_ERROR); - } - - if ((ip_ptr -> nx_ip_id != NX_IP_ID) || (server_port == 0)) - { - - return NX_POP3_PARAM_ERROR; - } - - /* Call the actual client create service. */ - status = _nxd_pop3_client_create(client_ptr, - APOP_authentication, - ip_ptr, packet_pool_ptr, - server_ip_address, server_port, client_name, - client_password); - - /* Return completion status. */ - return(status); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_pop3_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a POP3 Client on the specified IP instance. */ -/* This supports both IPv6 and IPv4 POP3 server connections. */ -/* */ -/* Note: The string lengths of client_name and client_password are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* APOP_authentication 1=enable APOP; 0=disable APOP */ -/* ip_ptr Pointer to client IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* server_ip_address POP3 server IP address */ -/* server_port POP3 server port */ -/* client_name Client POP3 user name */ -/* client_password Client POP3 password */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create NetX TCP socket create service */ -/* _nxd_pop3_client_connect Connect POP3 Client to Server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, - NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port, CHAR *client_name, - CHAR *client_password) - -{ - -UINT status; -UINT client_name_length; -UINT client_password_length; - - - client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; - - if (_nx_utility_string_length_check(client_name, &client_name_length, NX_POP3_MAX_USERNAME) || - _nx_utility_string_length_check(client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) - { - - return NX_POP3_PARAM_ERROR; - } - - /* Null the members of NX_POP3_CLIENT. */ - memset(client_ptr, 0, sizeof(NX_POP3_CLIENT)); - - /* Configure Client identification. */ - memset(client_ptr -> nx_pop3_client_name, 0, NX_POP3_MAX_USERNAME); - memcpy(client_ptr -> nx_pop3_client_name, client_name, client_name_length); - memset(client_ptr -> nx_pop3_client_password, 0, NX_POP3_MAX_PASSWORD); - memcpy(client_ptr -> nx_pop3_client_password, client_password, client_password_length); - - /* Configure Client POP3 authentication options. */ - client_ptr -> nx_pop3_client_enable_APOP_authentication = APOP_authentication; - - /* Create a tcp socket to send/receive POP3 data. */ - status = nx_tcp_socket_create(ip_ptr, &client_ptr -> nx_pop3_client_tcp_socket, "POP3 Client socket", - NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, - NX_POP3_CLIENT_TCP_WINDOW_SIZE, - NX_NULL, NX_NULL); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Configure Client NetX and TCP/IP options. */ - client_ptr -> nx_pop3_client_packet_pool_ptr = packet_pool_ptr; - - status = _nxd_pop3_client_connect(client_ptr, server_ip_address, server_port); - - /* Return successful completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the POP3 Client delete */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_delete Actual Client delete service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_delete(NX_POP3_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for valid input parameter. */ - if (client_ptr == NX_NULL) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - /* Call client create function. */ - status = _nx_pop3_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the specified POP3 Client. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_disconnect Closes the TCP connection */ -/* nx_tcp_client_socket_unbind Releases (unbinds) the TCP port */ -/* nx_tcp_socket_delete Deletes unbound TCP socket */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr) -{ - - if (client_ptr -> nx_pop3_client_message_ptr) - { - nx_packet_release(client_ptr -> nx_pop3_client_message_ptr); - } - - /* Yes, so disconnect client socket from server. */ - nx_tcp_socket_disconnect(&client_ptr -> nx_pop3_client_tcp_socket, NX_POP3_CLIENT_DISCONNECT_TIMEOUT); - - /* Unbind the port from client socket. */ - nx_tcp_client_socket_unbind(&client_ptr -> nx_pop3_client_tcp_socket); - - /* Release client socket. */ - nx_tcp_socket_delete(&client_ptr -> nx_pop3_client_tcp_socket); - - /* Clear the members of NX_POP3_CLIENT. */ - memset(client_ptr, 0, sizeof(NX_POP3_CLIENT)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_mail_items_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get mail items in */ -/* client mailbox service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* number_mail_items Pointer to items in mailbox */ -/* maildrop_total_size Pointer to total mailbox size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_pop3_client_mail_items_get Actual get mail items service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size) -{ - -UINT status; - - - /* Check for invalid pointer inpu. */ - if ((client_ptr == NX_NULL) || (number_mail_items == NX_NULL) || (maildrop_total_size == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - status = _nx_pop3_client_mail_items_get(client_ptr, number_mail_items, maildrop_total_size); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_mail_items_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the number of items and total size in bytes */ -/* of mail data in the Client's mailbox. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* number_mail_items Pointer to items in mailbox */ -/* maildrop_total_size Pointer to total mailbox size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size) -{ - -UINT status; -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer; -CHAR argument[10]; -UINT packet_type; - - /* Determine type of packet to allocate. */ - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - /* Check for sufficient packet buffer size for command. */ - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_STAT) - 1) + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Send the STAT command. */ - buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); - - memcpy(buffer, NX_POP3_COMMAND_STAT, (sizeof(NX_POP3_COMMAND_STAT) - 1)); - packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_STAT) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_STAT) - 1); - buffer += (sizeof(NX_POP3_COMMAND_STAT) - 1); - - memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Clear existing Client maildrop data. */ - client_ptr -> nx_pop3_client_total_message_size = 0; - client_ptr -> nx_pop3_client_maildrop_items = 0; - - /* Receive server reply. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to server error received. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* Yes. Clear memory for parsing the mail item count. */ - memset(argument, 0, 5); - - /* Get the number of messages. */ - _nx_pop3_parse_response(buffer, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Check if argument parsed successfully. */ - if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) - { - - /* It was; update session maildrop items. */ - client_ptr -> nx_pop3_client_maildrop_items = strtoul(argument, NULL, 10); - - /* Get total mail message data next. */ - memset(argument, 0, 5); - - /* Get the size in bytes of message data. */ - _nx_pop3_parse_response(buffer, 3, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Check if argument parsed successfully. */ - if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) - { - - /* It was; update total message data. */ - client_ptr -> nx_pop3_client_total_message_size = strtoul(argument, NULL, 10); - - status = NX_SUCCESS; - } - } - } - - *maildrop_total_size = client_ptr -> nx_pop3_client_total_message_size; - *number_mail_items = client_ptr -> nx_pop3_client_maildrop_items; - - nx_packet_release(recv_packet_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_get_mail_item PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get mail item size */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_item Index into POP3 mailbox */ -/* item_size Pointer to mail size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_get_mail_size Actual get mail size service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((client_ptr == NX_NULL) || (size == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - /* Check for an invalid index. */ - if (mail_item == 0) - { - return NX_POP3_CLIENT_INVALID_INDEX; - } - - status = _nx_pop3_client_mail_item_size_get(client_ptr, mail_item, size); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_mail_item_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a LIST command for the specified mail item and */ -/* processes the server response for size of the requested item. Note */ -/* that there is considerable discrepancy between reported size and */ -/* actual size, with the reported size usually 15% or more larger than */ -/* actual. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_item Index into POP3 mailbox */ -/* size Pointer to mail item size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* _nx_pop3_server_number_convert Convert integer to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size) -{ - -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer_ptr; -UINT num_size; -UINT status; -CHAR argument[10]; -UINT packet_type; - - - /* Initialize mail box to having zero items. */ - *size = 0; - - /* Verify mail_item is valid index (less than total number items in mailbox. */ - if (mail_item > client_ptr -> nx_pop3_client_maildrop_items) - { - return NX_POP3_INVALID_MAIL_ITEM; - } - - /* Determine which packet type to allocate. */ - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - num_size = _nx_pop3_server_number_convert(mail_item, &argument[0]); - - /* Determine if the packet payload is large enough for LIST command. */ - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_LIST) - 1) + 1 + - num_size + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Send LIST mail_item query to server */ - memcpy(buffer_ptr, NX_POP3_COMMAND_LIST, (sizeof(NX_POP3_COMMAND_LIST) - 1)); - packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_LIST) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_LIST) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_LIST) - 1); - - memcpy(buffer_ptr, " ", 1); - packet_ptr -> nx_packet_length++; - packet_ptr -> nx_packet_append_ptr++; - buffer_ptr++; - - memcpy(buffer_ptr, &argument[0], num_size); - packet_ptr -> nx_packet_length += num_size; - packet_ptr -> nx_packet_append_ptr += num_size; - buffer_ptr += num_size; - - memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Initialize status to bad reply error condition. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* Clear memory for parsing the mail item count. */ - memset(argument, 0, 5); - - /* Extact the message size. */ - _nx_pop3_parse_response(buffer_ptr, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Check if argument parsed successfully. */ - if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) - { - - /* It was; verify it matches the input mail index. */ - UINT server_maildrop_items = strtoul(argument, NULL, 10); - - if (mail_item == server_maildrop_items) - { - - /* It does. Parse the message size. */ - _nx_pop3_parse_response(buffer_ptr, 3, recv_packet_ptr -> nx_packet_length, - (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) - { - - *size = strtoul(argument, NULL, 10); - - status = NX_SUCCESS; - } - } - } - } - - /* Done with the server response, delete the packet. */ - nx_packet_release(recv_packet_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_mail_item_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get mail item */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_item Index into POP3 mailbox */ -/* item_size Pointer to mail size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_mail_item_get Actual get mail service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if ((client_ptr == NX_NULL) || (item_size == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - /* Check for an invalid index. */ - if (mail_item == 0) - { - return NX_POP3_CLIENT_INVALID_INDEX; - } - - status = _nx_pop3_client_mail_item_get(client_ptr, mail_item, item_size); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_mail_item_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the RETR command to the server for the specified*/ -/* mail item, and returns the server response. If accepted, it will */ -/* parse the mail item size as well. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_item Index into POP3 mailbox */ -/* item_size Pointer to mail size */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* _nx_pop3_server_number_convert Convert integer to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size) -{ - -UINT status; -UINT size; -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer; -CHAR argument[10]; -UINT packet_type; - - - client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; - - /* Verify mail_item is valid index (less than total number items in mailbox. */ - if (mail_item > client_ptr -> nx_pop3_client_maildrop_items) - { - return NX_POP3_INVALID_MAIL_ITEM; - } - - /* Allocate a packet. */ - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - /* Check packet payload can hold the Client message. . */ - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_RETR) - 1) + 1) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); - - /* Send a RETR command to the server. */ - memcpy(packet_ptr -> nx_packet_prepend_ptr, NX_POP3_COMMAND_RETR, (sizeof(NX_POP3_COMMAND_RETR) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_RETR) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_RETR) - 1); - buffer += (sizeof(NX_POP3_COMMAND_RETR) - 1); - - memcpy(buffer, " ", 1); - packet_ptr -> nx_packet_length++; - packet_ptr -> nx_packet_append_ptr++; - buffer++; - - /* Convert the mail item index to ascii. */ - size = _nx_pop3_server_number_convert(mail_item, &argument[0]); - if ((buffer + size + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= (CHAR *)packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - memcpy(buffer, &argument[0], size); - packet_ptr -> nx_packet_length += size; - packet_ptr -> nx_packet_append_ptr += size; - buffer += size; - - memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply over Client socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, - sizeof(argument), NX_FALSE, NX_FALSE); - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - client_ptr -> nx_pop3_client_ready_to_download = NX_TRUE; - *item_size = 0; - - /* Yes. Clear memory for parsing the mail item size. */ - memset(argument, 0, sizeof(argument)); - - /* Get the number of szie of the message. . */ - _nx_pop3_parse_response(buffer, 2, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, - sizeof(argument) - 1, NX_FALSE, NX_FALSE); - - /* Check if argument parsed successfully. */ - if ((argument[0] >= 0x30) && (argument[0] <= 0x39)) - { - - /* It was; set the size of th e mail item. */ - *item_size = strtoul(argument, NULL, 10); - } - - while (((ULONG)buffer < ((ULONG)recv_packet_ptr -> nx_packet_append_ptr - 1)) && - ((*buffer != 0x0D) || (*(buffer + 1) != 0x0A))) - { - buffer++; - } - - buffer += 2; - - if ((UCHAR *)buffer == recv_packet_ptr -> nx_packet_append_ptr) - { - nx_packet_release(recv_packet_ptr); - } - else - { - client_ptr -> nx_pop3_client_message_ptr = recv_packet_ptr; - recv_packet_ptr -> nx_packet_length -= - (ULONG)buffer - (ULONG)recv_packet_ptr -> nx_packet_prepend_ptr; - recv_packet_ptr -> nx_packet_prepend_ptr = (UCHAR *)buffer; - } - - return NX_SUCCESS; - } - else - { - nx_packet_release(recv_packet_ptr); - return NX_POP3_SERVER_ERROR_STATUS; - } - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_mail_item_message_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get message data */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* recv_packet_ptr Pointer to received PP3 packet */ -/* bytes_retrieved Size of message data in packet */ -/* final_packet Indicates if last packet */ -/* NX_FALSE = not the last packet */ -/* NX_TRUE = is the last packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_mail_item_message_data_get */ -/* Actual get message data service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet) -{ - -UINT status; - - - if ((client_ptr == NX_NULL) || (recv_packet_ptr == NX_NULL) || (bytes_retrieved == NX_NULL) || (final_packet == NX_NULL)) - { - - return NX_PTR_ERROR; - } - - status = _nx_pop3_client_mail_item_message_get(client_ptr, recv_packet_ptr, bytes_retrieved, final_packet); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_mail_item_message_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves message packets from the POP3 Client TCP */ -/* socket and returns them to the caller without further processing. */ -/* It is up to the caller to strip off the trailing end of message tag */ -/* \r\n.\r\n if one is appended to the message. Note the end of */ -/* message is included in the packet length. */ -/* */ -/* When packets are received with only the end of message tag (EOM), */ -/* this function returns zero bytes retrieved and sets final_packet to */ -/* true. */ -/* */ -/* If the status return is NX_SUCCESS, the caller MUST release the */ -/* packet, even if there bytes_retrieved is set to zero. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* recv_packet_ptr Pointer to received packet */ -/* bytes_retrieved Received packet length */ -/* final_packet If last packet of message */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet) -{ -UINT status; -UINT index; -CHAR *buffer_ptr; - - /* Initialize results to no data retrieved, or if the received packet is the last in the message. */ - *final_packet = NX_FALSE; - *bytes_retrieved = 0; - - /* Verify client is ready to download mail messages. */ - if (client_ptr -> nx_pop3_client_ready_to_download == NX_FALSE) - { - - return NX_POP3_CLIENT_INVALID_STATE; - } - - if (client_ptr -> nx_pop3_client_message_ptr) - { - status = NX_SUCCESS; - *recv_packet_ptr = client_ptr -> nx_pop3_client_message_ptr; - client_ptr -> nx_pop3_client_message_ptr = NX_NULL; - } - else - { - - /* Retrieve the next data packet. */ - status = nx_tcp_socket_receive(&client_ptr -> nx_pop3_client_tcp_socket, recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - } - - if (status == NX_SUCCESS) - { - - /* Update the bytes_retrieved with amount of data in the packet. */ - *bytes_retrieved = (*recv_packet_ptr) -> nx_packet_length; - - /* Check for end of message tag in this packet. */ - if (*bytes_retrieved > (sizeof(NX_POP3_END_OF_MESSAGE) - 1)) - { - buffer_ptr = (CHAR *)(*recv_packet_ptr) -> nx_packet_prepend_ptr; - - index = *bytes_retrieved - (sizeof(NX_POP3_END_OF_MESSAGE) - 1); - - /* Determine if the end of the data contains the terminating \r\n.\r\n marker. */ - if (memcmp((buffer_ptr + index), NX_POP3_END_OF_MESSAGE, (sizeof(NX_POP3_END_OF_MESSAGE) - 1)) == 0) - { - - /* It does; indicate this is the end of the mail download. */ - *final_packet = NX_TRUE; - - /* Client cannot download any data for this particular mail item. */ - client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; - } - } - else - { - - if ( - (memcmp((*recv_packet_ptr) -> nx_packet_prepend_ptr, NX_POP3_END_OF_MESSAGE, (sizeof(NX_POP3_END_OF_MESSAGE) - 1))== 0) || - (memcmp((*recv_packet_ptr) -> nx_packet_prepend_ptr, NX_POP3_END_OF_MESSAGE_TAG, (sizeof(NX_POP3_END_OF_MESSAGE_TAG) - 1))== 0) - ) - { - - /* Yes, but this is not considered part of the message. Indicate this with the bytes retrieved. */ - *bytes_retrieved = 0; - - /* It does; indicate this is the end of the mail download. */ - *final_packet = NX_TRUE; - - /* Client cannot download any data for this particular mail item. */ - client_ptr -> nx_pop3_client_ready_to_download = NX_FALSE; - } - } - } - - return status; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_mail_item_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the delete mail item */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_index Index of mail item to delete */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_mail_item_delete Actual delete mail service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Check for invalid mail item input. */ - if (mail_index == 0) - { - - return NX_POP3_CLIENT_INVALID_INDEX; - } - - status = _nx_pop3_client_mail_item_delete(client_ptr, mail_index); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_mail_item_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the DELE command for the specified mail item */ -/* and verifies the server will delete the item. Note that for some */ -/* servers, items marked for deletion are not deleted immediately, in */ -/* some cases only if they receive the QUIT command. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* mail_item Index into POP3 mailbox */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_POP3_INVALID_MAIL_ITEM Invalid mail index input */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* _nx_pop3_server_number_convert Convert integer to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index) -{ - -UINT status; -UINT size; -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer_ptr; -CHAR argument[10]; -UINT packet_type; - - - /* Allocate a packet. */ - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Convert the ascii word to a number. */ - size = _nx_pop3_server_number_convert(mail_index, &argument[0]); - - /* Check packet payload is large enough for DEL request. */ - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_DELE) - 1) + 1 + size + - (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - /* Send the DELE command. */ - memcpy(buffer_ptr, NX_POP3_COMMAND_DELE, (sizeof(NX_POP3_COMMAND_DELE) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_DELE) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_DELE) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_DELE) - 1); - - - memcpy(buffer_ptr, " ", 1); - packet_ptr -> nx_packet_length++; - packet_ptr -> nx_packet_append_ptr++; - buffer_ptr++; - - memcpy(buffer_ptr, &argument[0], size); - packet_ptr -> nx_packet_length += size; - packet_ptr -> nx_packet_append_ptr += size; - buffer_ptr += size; - - memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the DELE command out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply to DELE command. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to server error status received. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* Yes, set status to successful completion. */ - status = NX_SUCCESS; - } - - nx_packet_release(recv_packet_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pop3_client_quit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* The service performs error checking for the send QUIT service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to POP3 Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application thread */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_quit Actual send QUIT command service */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pop3_client_quit(NX_POP3_CLIENT *client_ptr) -{ - -UINT status; - - if (client_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - status = _nx_pop3_client_quit(client_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_quit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* The service sends a QUIT command to the Client POP3 server. The */ -/* QUIT command takes no arguments and can be called at any time during*/ -/* the Client session. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to POP3 Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application thread */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer_ptr; -CHAR argument[10]; -UINT packet_type; - - - /* Allocate a packet. */ - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Check packet payload will hold the QUIT request. */ - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_QUIT) - 1) + 1 + - (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - memcpy(buffer_ptr, NX_POP3_COMMAND_QUIT, (sizeof(NX_POP3_COMMAND_QUIT) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_QUIT) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_QUIT) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_QUIT) - 1); - - memcpy(buffer_ptr, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to bad reply error condition. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* Yes, set status to successful completion. */ - status = NX_SUCCESS; - } - - nx_packet_release(recv_packet_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_digest_authenticate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an MD5 digest based on input string which per */ -/* POP3 protocol is the process ID and secret (e.g. Client password). */ -/* This digest is used in APOP commands for the Client to authenticate */ -/* itself without clear texting it's password. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr POP3 Client pointer */ -/* process_ID_ptr Pointer to process_ID string */ -/* process_ID_length Process ID string length */ -/* result Pointer to MD5 digest */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_md5_initialize Initialize MD5 algorithm */ -/* _nx_md5_update Update MD5 digest */ -/* _nx_md5_digest_calculate Complete the MD5 algorithm */ -/* _nx_pop3_hex_ascii_convert Convert digest to ascii */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pop3_client_apop Send APOP cmd to Server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_digest_authenticate(NX_POP3_CLIENT *client_ptr, CHAR *process_ID_ptr, UINT process_ID_length, CHAR *result) -{ - -CHAR md5_binary[NX_POP3_MAX_BINARY_MD5]; - - /* Initialize the Client session MD5 data. */ - _nx_md5_initialize(&client_ptr -> nx_pop3_client_md5data); - - - _nx_md5_update(&client_ptr -> nx_pop3_client_md5data, (unsigned char *)process_ID_ptr, process_ID_length); - - /* Finish calculation of the MD5 digest. */ - _nx_md5_digest_calculate(&client_ptr -> nx_pop3_client_md5data, (unsigned char *)&md5_binary[0]); - - /* Convert digest to ASCII Hex representation. */ - _nx_pop3_hex_ascii_convert(&md5_binary[0], NX_POP3_MAX_BINARY_MD5, result); - - /* Return successful completion */ - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_parse_process_id PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts the process ID in the greeting from server. */ -/* If found the Server is indicating we may use APOP to secure (open) */ -/* the mailbox. The process ID is saved to the POP3 Client instance. If*/ -/* no process ID is found, this field is set to NULL. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* buffer Pointer to server reply buffer */ -/* buffer_length Size of server reply buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_pop3_client_connect Connect and authenticate with server*/ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pop3_parse_process_id(NX_POP3_CLIENT *client_ptr, CHAR *buffer, UINT buffer_length) -{ - -CHAR c; -UINT index; -UINT pid_index; - - - /* Set a pointer to the start of the buffer to search. */ - index = 0; - - /* Clear memory for parsing the server process ID. */ - memset(&client_ptr -> nx_pop3_server_process_id[0], 0, NX_POP3_SERVER_PROCESS_ID_SIZE); - - while(index < buffer_length) - { - c = *buffer; - if (c == '<') - { - - /* Found the start of the process ID. Now save it to the session instance including the angle brackets. */ - pid_index = 0; - - /* Check that we don't go over the size of the process ID buffer or off the end of the packet data. */ - while ((pid_index < NX_POP3_SERVER_PROCESS_ID_SIZE) && (index < buffer_length)) - { - - /* Copy the next character and advance the counters and buffer pointer. */ - client_ptr -> nx_pop3_server_process_id[pid_index] = *buffer; - - /* Check if this is the end of the time stamp which is included in the process id string. . */ - if (*buffer == '>') - { - - /* This is the enclosing bracket. We're done. */ - return; - } - - index++; - pid_index++; - buffer++; - } - - } - index++; - buffer++; - } - - /* If we got here, we did not find any process IDs. */ - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_parse_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service parses the specified argument from the input buffer */ -/* and returns a pointer to the argument if found, else the a NULL */ -/* pointer. Dashes are handled as word separators. */ -/* */ -/* crlf_are_word_breaks indicates if CR LF's should be handled as word */ -/* separators. convert_to_uppercase indicates if the argument should be*/ -/* converted to uppercase. */ -/* */ -/* This service removes CR LF's at the end of the message. It does not*/ -/* allocate or clear argument memory, but does. */ -/* */ -/* INPUT */ -/* */ -/* buffer Pointer to buffer to parse */ -/* argument_index Index of argument to parse */ -/* buffer_length Buffer size */ -/* argument Pointer to argument parsed */ -/* argument_length Argument buffer size */ -/* convert_to_uppercase Convert argument to uppercase */ -/* crlf_are_word_breaks Handle CR LF's as word breaks */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_pop3_parse_response(CHAR *buffer, UINT argument_index, UINT buffer_length, CHAR *argument, UINT argument_length, - UINT convert_to_uppercase, UINT crlf_are_word_breaks) -{ - -UINT i = 0; -UINT j = 0; -UINT argument_char_count; - - - /* Check for invalid input. */ - if ((buffer == NX_NULL)|| (buffer[0] == 0x0) || (argument == NX_NULL) || (buffer_length == 0) || - (argument_length == 0) || (argument_index == 0)) - { - - /* Return with argument not found status. */ - return; - } - - /* Initialize the argument to not found with NULL character. */ - *argument = (CHAR)0x0; - argument_char_count = 0; - - /* Is this the first argument? */ - if (argument_index == 1) - { - - /* Yes, search each character up to the end of the buffer for the first separator. */ - while (i < buffer_length) - { - - /* Did we find it? */ - if (*buffer == ' ') - { - - /* Yes, we're done with this loop! */ - break; - } - - /* Treat a hyphen as word breaks if it is between words, not if it is the first char. */ - if (*buffer == '-' && i > 0) - { - - /* Yes, we're done with this loop! */ - break; - } - - /* Did we go past the argument size limit? */ - if (argument_char_count >= argument_length) - { - - /* Yes, no argument found. */ - break; - } - - /* Copy the next character into the argument, converting - to uppercase if the caller requested this. */ - *argument++ = convert_to_uppercase ? (CHAR)toupper((INT)(*buffer)) : *buffer; - - argument_char_count++; - - /* Move to the next character. */ - i++; - buffer++; - } - - /* Are we at the end of the buffer? */ - if (i == buffer_length) - { - - /* Yes, is there a line terminator? */ - if (*(argument - 2) == 0x0D && *(argument - 1) == 0x0A) - { - - /* Yes, remove it with a null character */ - *(argument - 2) = (CHAR) 0x0; - } - } - } - else - { - /* No, we're not parsing the first argument. */ - - /* Mark the start of the argument at the separator after the end of the previous argument. */ - while (j < argument_index && i < buffer_length) - { - - /* Keep track of the number of separators in the buffer */ - - /* Did we hit a line terminator? */ - if ((*buffer == 0x0D) && (*(buffer + 1) == 0x0A)) - { - - /* Yes, Update the count of separators. */ - j++; - - /* Are line terminators as word breaks? */ - if (!crlf_are_word_breaks) - { - - /* No, treat as the end of the search string buffer. */ - break; - } - - buffer++; - } - - /* Did we hit a space or a dash in the first argument? */ - else if (*buffer == ' ' || - (*buffer == '-' && j == 0)) - { - - /* These are counted as separators (note that - dashes found in arguments after the first arg - are NOT considered separators */ - j++; - } - else - { - - if (j == argument_index - 1) - { - - /* Have we exceeded the limit on the argument size? */ - if (argument_char_count < argument_length) - { - - /* No, copy the next character into the argument. */ - argument_char_count++; - - /* Convert to uppercase if the caller requests. */ - *argument++ = convert_to_uppercase ? (CHAR)toupper((INT)*buffer) : *buffer; - } - } - } - - /* Get the next character */ - i++; - buffer++; - } - } - - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_hex_ascii_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts hexadecimal characters into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* source Source hex string */ -/* source_length Length of source string */ -/* destination Pointer to destination string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pop3_utility_digest_authenticate Create digest for */ -/* authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pop3_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) -{ - -UINT i,j; -CHAR digit; - - - /* Setup destination index. */ - j = 0; - - /* Loop to process the entire source string. */ - for (i = 0; i < source_length; i++) - { - - /* Pickup the first nibble. */ - digit = (source[i] >> 4) & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - - /* Pickup the second nibble. */ - digit = source[i] & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - } - - /* Place a NULL in the destination string. */ - destination[j] = (CHAR) NX_NULL; - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_server_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number into an ASCII string and returns the*/ -/* size of the string holding the number. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* string_to_convert Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* _nx_pop3_client_mail_item_get Get mail item size */ -/* _nx_pop3_client_mail_item_delete Delete mail item */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_server_number_convert(UINT number, CHAR *string_to_convert) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < 9) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string_to_convert[j] = string_to_convert[j - 1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - string_to_convert[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Make the string NULL terminated. */ - string_to_convert[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string_to_convert[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_pop3_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function binds the Client socket to the POP3 port and connects */ -/* to the POP3 server. If the connection is made, this function */ -/* processes the server greeting, and initiates the APOP/USER */ -/* authentication with the sever. */ -/* */ -/* This supports both IPv6 and IPv4 POP3 server connections. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* server_ip_address Pointer to POP3 server IP address */ -/* server_port POP3 server port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_POP3_PARAM_ERROR Invalid Client user or password */ -/* NX_POP3_CANNOT_PARSE_REPLY Unable to parse server reply */ -/* status TCP service completion status */ -/* */ -/* CALLED BY */ -/* */ -/* _nxd_pop3_client_create Create POP3 Client and socket */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_client_socket_bind NetX TCP socket bind service */ -/* nxd_tcp_client_socket_connect NetX TCP socket connect service */ -/* nx_tcp_socket_receive NetX TCP socket receive service */ -/* _nx_pop3_parse_response Parse Server reply code */ -/* _nx_pop3_parse_process_id Parse server ID for APOP digest */ -/* _nx_pop3_client_apop Send Authenticated user/pass */ -/* _nx_pop3_client_user_pass Send User Pass in clear text */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_pop3_client_connect(NX_POP3_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port) -{ - -UINT status; -NX_PACKET *recv_packet_ptr; -CHAR *buffer_ptr; -CHAR argument[10]; - - - /* Check for client name/password/shared secret too long for allotted buffer. */ - if ((_nx_utility_string_length_check(&client_ptr -> nx_pop3_client_name[0], NX_NULL, NX_POP3_MAX_USERNAME)) || - (_nx_utility_string_length_check(&client_ptr -> nx_pop3_client_password[0], NX_NULL, NX_POP3_MAX_PASSWORD))) - { - - return NX_POP3_PARAM_ERROR; - } - - status = nx_tcp_client_socket_bind(&client_ptr -> nx_pop3_client_tcp_socket, 4228, NX_IP_PERIODIC_RATE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - return status; - } - - status = nxd_tcp_client_socket_connect(&client_ptr -> nx_pop3_client_tcp_socket, - server_ip_address, - server_port, - NX_POP3_CLIENT_CONNECTION_TIMEOUT); - - if (status != NX_SUCCESS) - { - return status; - } - - /* Receive server reply over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer_ptr = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer_ptr, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to bad reply error condition. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - if (client_ptr -> nx_pop3_client_enable_APOP_authentication) - { - - /* Attempt to extract the server process ID in the greeting. */ - _nx_pop3_parse_process_id(client_ptr, buffer_ptr, recv_packet_ptr -> nx_packet_length); - - /* Did we find a process ID? */ - if (client_ptr -> nx_pop3_server_process_id[0] != 0) - { - - /* Do APOP authentication. */ - status = _nx_pop3_client_apop(client_ptr); - - if (status == NX_SUCCESS) - { - return status; - } - else if (status != NX_POP3_SERVER_ERROR_STATUS) - { - - /* Another error encountered (packet pool depletion, broken connection, etc*/ - return status; - } - } - else - { - /* Possibly the server doesn't like APOP. Try User Pass */ - client_ptr -> nx_pop3_client_enable_APOP_authentication = NX_FALSE; - } - } - - /* Try USER PASS authentication. */ - status = _nx_pop3_client_user_pass(client_ptr); - } - - nx_packet_release(recv_packet_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_apop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to authenticate the POP3 client with the POP3*/ -/* server. If successful returns NX_SUCCESS. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Authentication accepted by server */ -/* NX_POP3_APOP_FAILED_MD5_DIGEST Error creating digest */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* _nx_pop3_digest_authenticate Create authentication string */ -/* */ -/* CALLED BY */ -/* */ -/* nxd_pop3_client_connect Connect with POP3 server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_apop(NX_POP3_CLIENT *client_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr, *recv_packet_ptr; -CHAR *buffer; -CHAR argument[10]; -CHAR md5_digest_buffer[NX_POP3_MAX_ASCII_MD5 + 1]; -UINT packet_type; -UINT index; -CHAR userid_buffer[100]; -UINT server_process_id_length; -UINT client_password_length; -UINT client_name_length; -UINT md5_digest_buffer_length; - - - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - /* Create the APOP digest. */ - memset(&userid_buffer[0],0,sizeof(userid_buffer)); - - /* Validate copy size. */ - if (_nx_utility_string_length_check(client_ptr -> nx_pop3_server_process_id, &server_process_id_length, NX_POP3_SERVER_PROCESS_ID_SIZE) || - _nx_utility_string_length_check(client_ptr -> nx_pop3_client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) - { - nx_packet_release(packet_ptr); - return(NX_POP3_INSUFFICIENT_PACKET_PAYLOAD); - } - if((server_process_id_length + client_password_length) > sizeof(userid_buffer)) - { - nx_packet_release(packet_ptr); - return(NX_POP3_INSUFFICIENT_PACKET_PAYLOAD); - } - - memcpy(&userid_buffer[0], &client_ptr -> nx_pop3_server_process_id[0], server_process_id_length); - index = server_process_id_length; - memcpy(&userid_buffer[index], &client_ptr -> nx_pop3_client_password[0], client_password_length); - status = _nx_pop3_digest_authenticate(client_ptr, &userid_buffer[0], (server_process_id_length + client_password_length), &md5_digest_buffer[0]); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Return failed APOP attempt error condition. */ - return NX_POP3_APOP_FAILED_MD5_DIGEST; - } - - /* Verify the packet payload will hold the APOP command. */ - if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_name, &client_name_length, NX_POP3_MAX_USERNAME) || - _nx_utility_string_length_check(md5_digest_buffer, &md5_digest_buffer_length, NX_POP3_MAX_ASCII_MD5)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_APOP) - 1) - + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1) + 2 - + client_name_length - + md5_digest_buffer_length) >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - buffer = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Create the APOP command. */ - memcpy(buffer, NX_POP3_COMMAND_APOP, (sizeof(NX_POP3_COMMAND_APOP) - 1)); - buffer += (sizeof(NX_POP3_COMMAND_APOP) - 1); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_APOP) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_APOP) - 1); - - memcpy(buffer, " ", 1); - buffer++; - packet_ptr -> nx_packet_append_ptr++; - packet_ptr -> nx_packet_length++; - - memcpy(buffer, client_ptr -> nx_pop3_client_name, client_name_length); - buffer += client_name_length; - packet_ptr -> nx_packet_length += client_name_length; - packet_ptr -> nx_packet_append_ptr += client_name_length; - - memcpy(buffer, " ", 1); - buffer++; - packet_ptr -> nx_packet_append_ptr++; - packet_ptr -> nx_packet_length++; - - memcpy(buffer, &md5_digest_buffer[0], md5_digest_buffer_length); - buffer += md5_digest_buffer_length; - packet_ptr -> nx_packet_length += md5_digest_buffer_length; - packet_ptr -> nx_packet_append_ptr += md5_digest_buffer_length; - - memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to bad reply error condition. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* APOP command accepted. */ - status = NX_SUCCESS; - } - - nx_packet_release(recv_packet_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pop3_client_user_pass PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to login using client sername and password */ -/* with the POP3 server. If successful returns NX_SUCCESS. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Login accepted by server */ -/* NX_POP3_INSUFFICIENT_PACKET_PAYLOAD */ -/* Packet too small for command */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_tcp_socket_send Send packet out TCP socket */ -/* nx_tcp_socket_receive Retrieve packet from TCP socket */ -/* _nx_pop3_parse_response Extract word from server response */ -/* _nx_pop3_digest_authenticate Create authentication string */ -/* */ -/* CALLED BY */ -/* */ -/* nxd_pop3_client_connect Connect with POP3 server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pop3_client_user_pass(NX_POP3_CLIENT *client_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr, *recv_packet_ptr, *next_recv_packet_ptr; -CHAR *buffer; -CHAR argument[10]; -UINT packet_type; -UINT client_name_length; -UINT client_password_length; - - - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - /* Verify the packet payload will hold the user command message. */ - if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_name, &client_name_length, NX_POP3_MAX_USERNAME)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_USER) - 1) + - 1 + client_name_length + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) - >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - buffer = (CHAR *)(packet_ptr -> nx_packet_prepend_ptr); - - - memcpy(buffer, NX_POP3_COMMAND_USER, (sizeof(NX_POP3_COMMAND_USER) - 1)); - packet_ptr -> nx_packet_length = (sizeof(NX_POP3_COMMAND_USER) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_USER) - 1); - buffer += (sizeof(NX_POP3_COMMAND_USER) - 1); - - memcpy(buffer, " ", 1); - packet_ptr -> nx_packet_length++; - packet_ptr -> nx_packet_append_ptr++; - buffer++; - - memcpy(buffer, client_ptr -> nx_pop3_client_name, client_name_length); - packet_ptr -> nx_packet_length += client_name_length; - packet_ptr -> nx_packet_append_ptr += client_name_length; - buffer += client_name_length; - - memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply to Client username over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer = (CHAR *)(recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer, 1, recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Initialize status to bad reply error condition. */ - status = NX_POP3_SERVER_ERROR_STATUS; - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - /* We are done with this packet. */ - nx_packet_release(recv_packet_ptr); - - if (client_ptr -> nx_pop3_client_tcp_socket.nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate another packet. */ - status = nx_packet_allocate(client_ptr -> nx_pop3_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_POP3_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return(status); - } - - /* Verify the packet payload will hold the password request. */ - if (_nx_utility_string_length_check(client_ptr -> nx_pop3_client_password, &client_password_length, NX_POP3_MAX_PASSWORD)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - if ((packet_ptr -> nx_packet_prepend_ptr + (sizeof(NX_POP3_COMMAND_PASS) - 1) + - 1 + client_password_length + (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)) - >= packet_ptr -> nx_packet_data_end) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_POP3_INSUFFICIENT_PACKET_PAYLOAD; - } - - buffer = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - memcpy(buffer, NX_POP3_COMMAND_PASS, (sizeof(NX_POP3_COMMAND_PASS) - 1)); - buffer += (sizeof(NX_POP3_COMMAND_PASS) - 1); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_PASS) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_PASS) - 1); - - memcpy(buffer, " ", 1); - buffer++; - packet_ptr -> nx_packet_length++; - packet_ptr -> nx_packet_append_ptr++; - - memcpy(buffer, client_ptr -> nx_pop3_client_password, client_password_length); - buffer += client_password_length; - packet_ptr -> nx_packet_length += client_password_length; - packet_ptr -> nx_packet_append_ptr += client_password_length; - - memcpy(buffer, NX_POP3_COMMAND_TERMINATION, (sizeof(NX_POP3_COMMAND_TERMINATION) - 1)); - buffer += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_length += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - packet_ptr -> nx_packet_append_ptr += (sizeof(NX_POP3_COMMAND_TERMINATION) - 1); - - /* Send the next Client message out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_pop3_client_tcp_socket, packet_ptr, NX_POP3_TCP_SOCKET_SEND_WAIT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return the error condition. */ - return(status); - } - - /* Receive server reply to Client password over session socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_pop3_client_tcp_socket), &next_recv_packet_ptr, NX_POP3_SERVER_REPLY_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (next_recv_packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(next_recv_packet_ptr); - return(NX_INVALID_PACKET); - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set a pointer to the packet data. */ - buffer = (CHAR *)(next_recv_packet_ptr -> nx_packet_prepend_ptr); - - /* Parse the first argument of the server reply. */ - _nx_pop3_parse_response(buffer, 1, next_recv_packet_ptr -> nx_packet_length, (CHAR *)&argument, 10, NX_FALSE, NX_FALSE); - - /* Did the server accept the Client command? */ - if (memcmp(argument, NX_POP3_POSITIVE_STATUS, (sizeof(NX_POP3_POSITIVE_STATUS) - 1)) == 0x0) - { - - status = NX_SUCCESS; - } - - /* We are done with this packet. */ - nx_packet_release(next_recv_packet_ptr); - } - else - { - - /* Server rejected the Client message. */ - nx_packet_release(recv_packet_ptr); - } - - return status; -} - diff --git a/protocol_handlers/pop3/nxd_pop3_client.h b/protocol_handlers/pop3/nxd_pop3_client.h deleted file mode 100644 index 776d7424..00000000 --- a/protocol_handlers/pop3/nxd_pop3_client.h +++ /dev/null @@ -1,277 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX POP3 Client Component */ -/** */ -/** Post Office Protocol Version 3 (POP3) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_pop3_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Post Office Protocol Version 3 (POP3) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, nx_port.h, */ -/* fx_api.h and fx_port.h have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_POP3_CLIENT_H -#define NX_POP3_CLIENT_H - - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -#include "nx_md5.h" -#include "nx_api.h" - -#define NX_POP3_CLIENT_ERROR_CONSTANT 0xB0 - -#define NX_POP3_PARAM_ERROR (NX_POP3_CLIENT_ERROR_CONSTANT | 0x1) /* Invalid non pointer parameter passed */ -#define NX_POP3_INVALID_MAIL_ITEM (NX_POP3_CLIENT_ERROR_CONSTANT | 0x2) /* Client block pool not large enough to store packet payload. */ -#define NX_POP3_APOP_FAILED_MD5_DIGEST (NX_POP3_CLIENT_ERROR_CONSTANT | 0x3) /* Client authentication failed; MD5 digest of server ID and password failed. */ -#define NX_POP3_SERVER_ERROR_STATUS (NX_POP3_CLIENT_ERROR_CONSTANT | 0x4) /* Server reply appears to missing expected argument(s). */ -#define NX_POP3_MAIL_BUFFER_OVERFLOW (NX_POP3_CLIENT_ERROR_CONSTANT | 0x5) /* Mail data extraction has filled up mail buffer before extraction complete. */ -#define NX_POP3_INSUFFICIENT_PACKET_PAYLOAD (NX_POP3_CLIENT_ERROR_CONSTANT | 0x6) /* Client mail spool callback is not successful. */ -#define NX_POP3_CLIENT_INVALID_STATE (NX_POP3_CLIENT_ERROR_CONSTANT | 0x7)/* Client not in proper state for specific POP3 action or command. */ -#define NX_POP3_CLIENT_INVALID_INDEX (NX_POP3_CLIENT_ERROR_CONSTANT | 0x8) /* Client command refers to an out of bounds mail index. */ - - - -#define NX_POP3_MAX_BINARY_MD5 16 -#define NX_POP3_MAX_ASCII_MD5 32 - -#define NX_POP3_SERVER_PROCESS_ID_SIZE 75 - -/* POP3 Server replies */ -#define NX_POP3_POSITIVE_STATUS "+OK" -#define NX_POP3_NEGATIVE_STATUS "-ERR" - - -/* Set the maximum size for Client command and Server reply text. */ - -#define NX_POP3_MAX_SERVER_REPLY 512 -#define NX_POP3_MAX_CLIENT_COMMAND 150 - -/* Create symbols for common POP3 sequences. */ -#define NX_POP3_COMMAND_TERMINATION "\r\n" -#define NX_POP3_END_OF_MESSAGE_TAG ".\r\n" -#define NX_POP3_DOT "." -#define NX_POP3_END_OF_MESSAGE "\r\n.\r\n" - -/* Enumerate the server POP3 replies. */ -#define NX_POP3_CODE_INVALID 0 -#define NX_POP3_CODE_OK 1 -#define NX_POP3_CODE_ERR 2 - - -/* Define POP3 Client commands strings. */ - -#define NX_POP3_COMMAND_GREETING "GREETING" -#define NX_POP3_COMMAND_USER "USER" -#define NX_POP3_COMMAND_APOP "APOP" -#define NX_POP3_COMMAND_PASS "PASS" -#define NX_POP3_COMMAND_STAT "STAT" -#define NX_POP3_COMMAND_RETR "RETR" -#define NX_POP3_COMMAND_DELE "DELE" -#define NX_POP3_COMMAND_QUIT "QUIT" -#define NX_POP3_COMMAND_LIST "LIST" -#define NX_POP3_COMMAND_RSET "RSET" -#define NX_POP3_COMMAND_NOOP "NOOP" - -/* Determine the maximum size buffer to store messages in. This need not be - limited to a single packet payload of message data, since the POP3 Client - will receive one or more packets till it sees an end of message symbol, - and appends each packet message data to this buffer. */ - -#ifndef NX_POP3_CLIENT_MAIL_BUFFER_SIZE -#define NX_POP3_CLIENT_MAIL_BUFFER_SIZE 2000 -#endif - - - -#ifndef NX_POP3_CLIENT_PACKET_TIMEOUT -#define NX_POP3_CLIENT_PACKET_TIMEOUT (1 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_POP3_TCP_SOCKET_SEND_WAIT -#define NX_POP3_TCP_SOCKET_SEND_WAIT (10 * NX_IP_PERIODIC_RATE) -#endif - - - -#ifndef NX_POP3_CLIENT_CONNECTION_TIMEOUT -#define NX_POP3_CLIENT_CONNECTION_TIMEOUT (30 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_POP3_CLIENT_DISCONNECT_TIMEOUT -#define NX_POP3_CLIENT_DISCONNECT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_POP3_SERVER_REPLY_TIMEOUT -#define NX_POP3_SERVER_REPLY_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_POP3_MAX_USERNAME -#define NX_POP3_MAX_USERNAME 40 -#endif - -#ifndef NX_POP3_MAX_PASSWORD -#define NX_POP3_MAX_PASSWORD 20 -#endif - -/* Set the size of the POP3 Client window size. This should leave room - for the IP and TCP headers within the IP instance MTU. */ -#ifndef NX_POP3_CLIENT_TCP_WINDOW_SIZE -#define NX_POP3_CLIENT_TCP_WINDOW_SIZE 1460 -#endif - - -/* Define the POP3 Client structure */ - -typedef struct NX_POP3_CLIENT_STRUCT -{ - CHAR nx_pop3_client_name[NX_POP3_MAX_USERNAME + 1]; /* Client name (also used in authentication) */ - CHAR nx_pop3_client_password[NX_POP3_MAX_PASSWORD + 1]; /* Client password for authentication */ - NX_TCP_SOCKET nx_pop3_client_tcp_socket; /* NetX TCP client socket. */ - NX_PACKET_POOL *nx_pop3_client_packet_pool_ptr; /* Packet pool for allocating packets for transmitting POP3 messages */ - UINT nx_pop3_client_enable_APOP_authentication; /* Enable client for APOP authentication */ - UINT nx_pop3_client_mail_status; /* Indication if the mail item was retrieved successfully */ - UINT nx_pop3_client_maildrop_items; /* Number of mail messages waiting in client (user) maildrop. */ - UINT nx_pop3_client_maildrop_index; /* Index of current mail item. */ - ULONG nx_pop3_client_total_message_size; /* Size of message data in bytes sitting in client (user) maildrop. */ - UINT nx_pop3_client_ready_to_download; /* Indicate POP3 Client can download mail data (e.g. RETR accepted by server). */ - CHAR nx_pop3_server_process_id[NX_POP3_SERVER_PROCESS_ID_SIZE + 1]; - NX_MD5 nx_pop3_client_md5data; - NX_PACKET *nx_pop3_client_message_ptr; -} NX_POP3_CLIENT; - - -#ifndef NX_POP3_CLIENT_SOURCE_CODE - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - - -#define nx_pop3_client_create _nx_pop3_client_create -#define nxd_pop3_client_create _nxd_pop3_client_create -#define nx_pop3_client_mail_items_get _nx_pop3_client_mail_items_get -#define nx_pop3_client_mail_item_size_get _nx_pop3_client_mail_item_size_get -#define nx_pop3_client_mail_item_message_get _nx_pop3_client_mail_item_message_get -#define nx_pop3_client_mail_item_get _nx_pop3_client_mail_item_get -#define nx_pop3_client_mail_item_delete _nx_pop3_client_mail_item_delete -#define nx_pop3_client_quit _nx_pop3_client_quit -#define nx_pop3_client_delete _nx_pop3_client_delete - -#else - -/* Services with error checking. */ - -#define nx_pop3_client_create _nxe_pop3_client_create -#define nxd_pop3_client_create _nxde_pop3_client_create -#define nx_pop3_client_mail_items_get _nxe_pop3_client_mail_items_get -#define nx_pop3_client_mail_item_size_get _nxe_pop3_client_mail_item_size_get -#define nx_pop3_client_mail_item_message_get _nxe_pop3_client_mail_item_message_get -#define nx_pop3_client_mail_item_get _nxe_pop3_client_mail_item_get -#define nx_pop3_client_mail_item_delete _nxe_pop3_client_mail_item_delete -#define nx_pop3_client_quit _nxe_pop3_client_quit -#define nx_pop3_client_delete _nxe_pop3_client_delete - -#endif /* if NX_DISABLE_ERROR_CHECKING */ - - - -UINT nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); -UINT nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); -UINT nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); -UINT nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); -UINT nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); -UINT nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr); -UINT nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr); - - -#else /* if NX_POP3_CLIENT_SOURCE_CODE */ - - -/* Client and session specific functions. */ - -UINT _nx_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT _nxe_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, ULONG server_ip_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT _nxd_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT _nxde_pop3_client_create(NX_POP3_CLIENT *client_ptr, UINT APOP_authentication, NX_IP *ip_ptr, NX_PACKET_POOL *packet_pool_ptr, NXD_ADDRESS *server_duo_address, ULONG server_port, CHAR *client_name, CHAR *client_password); -UINT _nx_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); -UINT _nxe_pop3_client_mail_items_get(NX_POP3_CLIENT *client_ptr, UINT *number_mail_items, ULONG *maildrop_total_size); -UINT _nx_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); -UINT _nxe_pop3_client_mail_item_size_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *size); -UINT _nx_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); -UINT _nxe_pop3_client_mail_item_message_get(NX_POP3_CLIENT *client_ptr, NX_PACKET **recv_packet_ptr, ULONG *bytes_retrieved, UINT *final_packet); -UINT _nx_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); -UINT _nxe_pop3_client_mail_item_get(NX_POP3_CLIENT *client_ptr, UINT mail_item, ULONG *item_size); -UINT _nx_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); -UINT _nxe_pop3_client_mail_item_delete(NX_POP3_CLIENT *client_ptr, UINT mail_index); -UINT _nx_pop3_client_delete(NX_POP3_CLIENT *client_ptr); -UINT _nxe_pop3_client_delete(NX_POP3_CLIENT *client_ptr); -UINT _nx_pop3_client_quit(NX_POP3_CLIENT *client_ptr); -UINT _nxe_pop3_client_quit(NX_POP3_CLIENT *client_ptr); - -#endif - -/* NetX POP3 Client internal functions */ - -UINT _nx_pop3_digest_authenticate(NX_POP3_CLIENT *client_ptr, CHAR *process_ID_ptr, UINT process_ID_length, CHAR *result); -VOID _nx_pop3_parse_process_id(NX_POP3_CLIENT *client_ptr, CHAR *buffer, UINT buffer_length); -VOID _nx_pop3_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); -UINT _nxd_pop3_client_connect(NX_POP3_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, ULONG server_port); -UINT _nx_pop3_server_number_convert(UINT number, CHAR *string_to_convert); -VOID _nx_pop3_parse_response(CHAR *buffer, UINT argument_index, UINT buffer_length, CHAR *argument, UINT argument_length, UINT convert_to_uppercase, UINT include_crlf); -UINT _nx_pop3_client_user_pass(NX_POP3_CLIENT *client_ptr); -UINT _nx_pop3_client_apop(NX_POP3_CLIENT *client_ptr); - - -/* If a C++ compiler is being used....*/ -#ifdef __cplusplus - } -#endif - - -#endif /* NX_POP3_CLIENT_H */ diff --git a/protocol_handlers/ppp/nx_ppp.c b/protocol_handlers/ppp/nx_ppp.c deleted file mode 100644 index 7c1eda85..00000000 --- a/protocol_handlers/ppp/nx_ppp.c +++ /dev/null @@ -1,12044 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Point-to-Point Protocol (PPP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_PPP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -#ifndef TX_DISABLE_ERROR_CHECKING -#define TX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_ppp.h" -#ifndef NX_PPP_DISABLE_CHAP -#include "nx_md5.h" -#endif - -/* Define global PPP variables and data structures. */ - -/* Define the PPP created list head pointer and count. */ - -NX_PPP *_nx_ppp_created_ptr = NX_NULL; -ULONG _nx_ppp_created_count = 0; - - -/* Define the CRC lookup table. This is used to improve the - CRC calculation performance. */ - -const USHORT _nx_ppp_crc_table[256] = -{ - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all PPP processing, including assembly of */ -/* PPP requests and dispatching them. */ -/* */ -/* INPUT */ -/* */ -/* ppp_addr Address of PPP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Get PPP event flags */ -/* nx_packet_release Release packet */ -/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ -/* _nx_ppp_lcp_state_machine_update Update LCP state machine */ -/* _nx_ppp_process_deferred_ip_packet_send */ -/* Process deferred IP packet */ -/* send */ -/* _nx_ppp_process_deferred_raw_string_send */ -/* Process deferred raw string */ -/* send */ -/* _nx_ppp_receive_packet_get Get PPP receive packet */ -/* _nx_ppp_receive_packet_process Process received PPP packet */ -/* _nx_ppp_timeout Process PPP timeout */ -/* [_nx_ppp_debug_log_capture] Optional PPP debug log */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_thread_entry(ULONG ppp_addr) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_PPP *ppp_ptr; -ULONG ppp_events; -NX_PACKET *packet_ptr; -NX_PACKET *next_packet_ptr; -ULONG count; - - - /* Setup the PPP pointer. */ - ppp_ptr = (NX_PPP *) ppp_addr; - - /* Loop to continue processing incoming bytes. */ - while(NX_FOREVER) - { - - -#ifdef NX_PPP_DEBUG_LOG_PRINT_PROTOCOL - /* Display debug output of PPP protocol status. */ - _nx_ppp_debug_log_capture_protocol(ppp_ptr); -#endif - - /* Wait for PPP event(s). The timeout on the wait will drive PPP timeout processing - as well. */ - tx_event_flags_get(&(ppp_ptr -> nx_ppp_event), (ULONG) 0xFFFFFFFF, TX_OR_CLEAR, &ppp_events, NX_WAIT_FOREVER); - - /* Check for PPP stop event. */ - if (ppp_events & NX_PPP_EVENT_STOP) - { - - /* Is PPP already stopped? */ - if (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) - { - - /* No, stop this PPP instance an prepare for the next start operation. */ - - /* Set state to stopped. */ - ppp_ptr -> nx_ppp_state = NX_PPP_STOPPED; - - /* Clean up resources and prepare for next PPP start. */ - - /* Release any packets queued up for the PPP instance. */ - - /* Release any partial receive packets. */ - if (ppp_ptr -> nx_ppp_receive_partial_packet) - nx_packet_release(ppp_ptr -> nx_ppp_receive_partial_packet); - - /* Clear the saved receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Setup the receive buffer processing. */ - ppp_ptr -> nx_ppp_serial_buffer_write_index = 0; - ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; - ppp_ptr -> nx_ppp_serial_buffer_byte_count = 0; - -#ifdef NX_PPP_PPPOE_ENABLE - - /* Loop to release all packets in the deferred processing queue.. */ - while (ppp_ptr -> nx_ppp_deferred_received_packet_head) - { - - /* Restore interrupts. */ - TX_RESTORE - - /* Pickup the packet. */ - packet_ptr = ppp_ptr -> nx_ppp_deferred_received_packet_head; - - /* Move the head pointer to the next packet. */ - ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; - - /* Check for end of deferred processing queue. */ - if (ppp_ptr -> nx_ppp_deferred_received_packet_head == NX_NULL) - { - - /* Yes, the queue is empty. Set the tail pointer to NULL. */ - ppp_ptr -> nx_ppp_deferred_received_packet_tail = NX_NULL; - } - - /* Release all packets in the raw packet queue. */ - TX_DISABLE - - /* Release packet. */ - nx_packet_release(packet_ptr); - } -#endif /* NX_PPP_PPPOE_ENABLE */ - - /* Release all packets in the IP packet queue. */ - TX_DISABLE - - /* Pickup the head pointer and count. */ - packet_ptr = ppp_ptr -> nx_ppp_ip_packet_queue_head; - - /* Set the list head and tail pointers to NULL. */ - ppp_ptr -> nx_ppp_ip_packet_queue_head = NX_NULL; - ppp_ptr -> nx_ppp_ip_packet_queue_tail = NX_NULL; - - /* Pickup the count. */ - count = ppp_ptr -> nx_ppp_ip_packet_queue_count; - - /* Clear the count. */ - ppp_ptr -> nx_ppp_ip_packet_queue_count = 0; - - /* Restore interrupts. */ - TX_RESTORE - - /* Loop to release all packets. */ - while (count) - { - /* Pickup next packet. */ - next_packet_ptr = packet_ptr -> nx_packet_queue_next; - - /* Release packet. */ - nx_packet_release(packet_ptr); - - /* Move to next packet. */ - packet_ptr = next_packet_ptr; - - /* Decrement the count. */ - count--; - } - - /* Release all packets in the raw packet queue. */ - TX_DISABLE - - /* Pickup the head pointer and count. */ - packet_ptr = ppp_ptr -> nx_ppp_raw_packet_queue_head; - - /* Set the list head and tail pointers to NULL. */ - ppp_ptr -> nx_ppp_raw_packet_queue_head = NX_NULL; - ppp_ptr -> nx_ppp_raw_packet_queue_tail = NX_NULL; - - /* Pickup the count. */ - count = ppp_ptr -> nx_ppp_raw_packet_queue_count; - - /* Clear the count. */ - ppp_ptr -> nx_ppp_raw_packet_queue_count = 0; - - /* Restore interrupts. */ - TX_RESTORE - - /* Loop to release all packets. */ - while (count) - { - /* Pickup next packet. */ - next_packet_ptr = packet_ptr -> nx_packet_queue_next; - - /* Release packet. */ - nx_packet_release(packet_ptr); - - /* Move to next packet. */ - packet_ptr = next_packet_ptr; - - /* Decrement the count. */ - count--; - } - - /* Reset all state machines. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_INITIAL_STATE; - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_INITIAL_STATE; - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_INITIAL_STATE; - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_INITIAL_STATE; - - /* Determine how to setup the initial authenticated field. */ - if ((ppp_ptr -> nx_ppp_pap_verify_login) || - (ppp_ptr -> nx_ppp_pap_generate_login) || - (ppp_ptr -> nx_ppp_chap_get_verification_values)) - { - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - } - else - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Clear the IP address. */ - nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, 0, 0); - - /* Clear the local information for PPP client. */ - if (ppp_ptr -> nx_ppp_server == NX_FALSE) - { - - /* Clear the IP addresses. */ - ppp_ptr -> nx_ppp_ipcp_local_ip[0] = 0; - ppp_ptr -> nx_ppp_ipcp_local_ip[1] = 0; - ppp_ptr -> nx_ppp_ipcp_local_ip[2] = 0; - ppp_ptr -> nx_ppp_ipcp_local_ip[3] = 0; - ppp_ptr -> nx_ppp_ipcp_peer_ip[0] = 0; - ppp_ptr -> nx_ppp_ipcp_peer_ip[1] = 0; - ppp_ptr -> nx_ppp_ipcp_peer_ip[2] = 0; - ppp_ptr -> nx_ppp_ipcp_peer_ip[3] = 0; - - /* Clear the DNS addresses. */ - ppp_ptr -> nx_ppp_primary_dns_address = 0; - ppp_ptr -> nx_ppp_secondary_dns_address = 0; - } - } - } - - /* Check for PPP start event. */ - if (ppp_events & NX_PPP_EVENT_START) - { - - /* Is PPP in a stopped state? */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) - { - - /* Update the PPP state. */ - ppp_ptr -> nx_ppp_state = NX_PPP_STARTED; - - /* Yes, move to the initial LCP state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_START_STATE; - - /* Initiate the PPP protocol. */ - _nx_ppp_lcp_state_machine_update(ppp_ptr, NX_NULL); - } - } - - /* Check for PPP raw packet send request. */ - if (ppp_events & NX_PPP_EVENT_RAW_STRING_SEND) - { - - /* Process deferred raw string send requests. */ - _nx_ppp_process_deferred_raw_string_send(ppp_ptr); - } - - /* Check for deferred IP transmit requests. */ - if (ppp_events & NX_PPP_EVENT_IP_PACKET_SEND) - { - - /* Process deferred IP transmit packets. */ - _nx_ppp_process_deferred_ip_packet_send(ppp_ptr); - } - -#ifndef NX_PPP_DISABLE_CHAP - - /* Check for CHAP challenge event. */ - if (ppp_events & NX_PPP_EVENT_CHAP_CHALLENGE) - { - - /* Determine if CHAP is in a completed state. */ - if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_COMPLETED_STATE) - { - - /* Move the state to the new challenge state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_NEW_STATE; - - /* Now update the CHAP state machine in order to force the - new CHAP challenge out. */ - _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); - } - } -#endif - - /* Now check for timeout processing. */ - if (ppp_events & NX_PPP_EVENT_TIMEOUT) - { - - /* Timeout occurred. Is there are PPP timeout active? */ - if (ppp_ptr -> nx_ppp_timeout) - { - - /* Decrement the timeout count. */ - ppp_ptr -> nx_ppp_timeout--; - - /* Has the timeout expired? */ - if (ppp_ptr -> nx_ppp_timeout == 0) - { - - /* Process timeout request. */ - _nx_ppp_timeout(ppp_ptr); - } - } - - /* Increment the receive timeout processing. */ - ppp_ptr -> nx_ppp_receive_timeouts++; - } - - /* Check for PPP Packet receive event. */ - if (ppp_events & NX_PPP_EVENT_PACKET_RECEIVE) - { - - /* Pickup the next PPP packet from serial port to process. This is called whether an event was set or not - simply to handle the case when a non-PPP frame is received. */ - _nx_ppp_receive_packet_get(ppp_ptr, &packet_ptr); - - /* Now determine if there is a packet to process. */ - if (packet_ptr) - { - -#ifdef NX_PPP_DEBUG_LOG_ENABLE - - /* Insert an entry into the PPP frame debug log. */ - _nx_ppp_debug_log_capture(ppp_ptr, 'R', packet_ptr); -#endif - - /* Yes, call the PPP packet processing routine. */ - _nx_ppp_receive_packet_process(ppp_ptr, packet_ptr); - } - } - -#ifdef NX_PPP_PPPOE_ENABLE - - /* Check for PPP Packet receive event. */ - if (ppp_events & NX_PPP_EVENT_PPPOE_PACKET_RECEIVE) - { - - /* Loop to process all deferred packet requests. */ - while (ppp_ptr -> nx_ppp_deferred_received_packet_head) - { - - /* Remove the first packet and process it! */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the first packet. */ - packet_ptr = ppp_ptr -> nx_ppp_deferred_received_packet_head; - - /* Move the head pointer to the next packet. */ - ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; - - /* Check for end of deferred processing queue. */ - if (ppp_ptr -> nx_ppp_deferred_received_packet_head == NX_NULL) - { - - /* Yes, the queue is empty. Set the tail pointer to NULL. */ - ppp_ptr -> nx_ppp_deferred_received_packet_tail = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - -#ifdef NX_PPP_DEBUG_LOG_ENABLE - - /* Insert an entry into the PPP frame debug log. */ - _nx_ppp_debug_log_capture(ppp_ptr, 'R', packet_ptr); -#endif - - /* Yes, call the PPP packet processing routine. */ - _nx_ppp_receive_packet_process(ppp_ptr, packet_ptr); - } - } -#endif /* NX_PPP_PPPOE_ENABLE */ - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_driver PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function provides the basic interface to the NetX TCP/IP */ -/* network stack. */ -/* */ -/* INPUT */ -/* */ -/* driver_req_ptr NetX driver request structure */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_transmit_release Release transmit packet */ -/* tx_event_flags_set Set PPP events */ -/* tx_thread_resume Resume PPP thread */ -/* tx_timer_activate Activate PPP timer */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_IP *ip_ptr; -NX_INTERFACE *interface_ptr; -NX_PPP *ppp_ptr; -NX_PACKET *packet_ptr; -UINT i; - - - /* Setup the IP pointer from the driver request. */ - ip_ptr = driver_req_ptr -> nx_ip_driver_ptr; - - /* Pickup the interface pointer. */ - interface_ptr = driver_req_ptr -> nx_ip_driver_interface; - - /* Default to successful return. */ - driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS; - - /* Process according to the driver request type in the driver control - block. */ - switch (driver_req_ptr -> nx_ip_driver_command) - { - - case NX_LINK_INTERFACE_ATTACH: - { - - /* First, we need to find the PPP instance that is mapped to - this IP instance and that doesn't have its interface attach - complete yet. This requires that PPP is created prior to - IP creation. */ - ppp_ptr = _nx_ppp_created_ptr; - i = 0; - while (i < _nx_ppp_created_count) - { - - /* Does this PPP instance point to the current IP instance? */ - if ((ppp_ptr -> nx_ppp_ip_ptr == ip_ptr) && (ppp_ptr -> nx_ppp_interface_ptr == NX_NULL)) - { - - /* Yes, we found an un-attached PPP instance for this IP interface instance. Get out of - the search loop. */ - break; - } - - /* Move the next PPP instance. */ - ppp_ptr = ppp_ptr -> nx_ppp_created_next; - - /* Increment counter. */ - i++; - } - - /* Determine if a PPP instance was found. */ - if (i >= _nx_ppp_created_count) - { - - /* Return an error to NetX. */ - driver_req_ptr -> nx_ip_driver_status = NX_IP_INTERNAL_ERROR; - return; - } - - /* Now find interface index. */ - i = 0; - while (i < NX_MAX_PHYSICAL_INTERFACES) - { - - /* Is this the interface index? */ - if (&(ip_ptr -> nx_ip_interface[i]) == interface_ptr) - { - - /* Found the index, get out of the loop. */ - break; - } - - /* Move to next interface. */ - i++; - } - - /* Determine if the interface index was found. */ - if (i >= NX_MAX_PHYSICAL_INTERFACES) - { - - /* Return an error to NetX. */ - driver_req_ptr -> nx_ip_driver_status = NX_IP_INTERNAL_ERROR; - return; - } - - /* Otherwise, we have everything we need to perform the attachment. */ - - /* Remember the PPP instance pointer in the IP interface pointer. */ - interface_ptr -> nx_interface_additional_link_info = (void *) ppp_ptr; - - /* Remember the interface pointer and index in the PPP structure. */ - ppp_ptr -> nx_ppp_interface_ptr = interface_ptr; - ppp_ptr -> nx_ppp_interface_index = i; - break; - } - - case NX_LINK_INITIALIZE: - { - - /* Process driver initialization. */ - - - /* Otherwise, we have found the PPP instance, continue initialization. */ - - /* Pickup the associated PPP instance address. */ - ppp_ptr = (NX_PPP *) interface_ptr-> nx_interface_additional_link_info; - - /* Setup the link maximum transfer unit. */ - interface_ptr -> nx_interface_ip_mtu_size = NX_PPP_MRU; - - /* Clear the hardware physical address, since there is no - such thing in PPP. */ - interface_ptr -> nx_interface_physical_address_msw = 0; - interface_ptr -> nx_interface_physical_address_lsw = 0; - - /* Indicate to the IP software that IP to physical mapping - is not required in PPP. */ - interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; - - /* Set the link up to false. */ - interface_ptr -> nx_interface_link_up = NX_FALSE; - - /* Resume the PPP thread. */ - tx_thread_resume(&(ppp_ptr -> nx_ppp_thread)); - - /* Activate the PPP timer. */ - tx_timer_activate(&(ppp_ptr -> nx_ppp_timer)); - break; - } - - - case NX_LINK_ENABLE: - { - - /* Pickup the associated PPP instance address. */ - ppp_ptr = (NX_PPP *) interface_ptr-> nx_interface_additional_link_info; - - /* Now set event flag to start PPP. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); - break; - } - - case NX_LINK_DISABLE: - { - - /* Process driver link disable. */ - - /* Pickup the associated PPP instance address. */ - ppp_ptr = (NX_PPP*) interface_ptr-> nx_interface_additional_link_info; - - /* Now set event flag to start PPP. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - break; - } - - case NX_LINK_PACKET_SEND: - { - - /* Pickup the associated PPP instance address. */ - ppp_ptr = (NX_PPP*) interface_ptr -> nx_interface_additional_link_info; - - /* Pickup packet pointer. */ - packet_ptr = driver_req_ptr -> nx_ip_driver_packet; - - /* Determine if the interface link is still up. */ - if (interface_ptr -> nx_interface_link_up == NX_FALSE) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the transmit frames dropped counter. */ - ppp_ptr -> nx_ppp_transmit_frames_dropped++; -#endif - /* No, release the packet. */ - nx_packet_transmit_release(packet_ptr); - break; - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Determine if the transmit queue is empty. */ - if (ppp_ptr -> nx_ppp_ip_packet_queue_count++) - { - - /* Not empty, simply link the new packet to the tail and update the tail. */ - (ppp_ptr -> nx_ppp_ip_packet_queue_tail) -> nx_packet_queue_next = packet_ptr; - ppp_ptr -> nx_ppp_ip_packet_queue_tail = packet_ptr; - } - else - { - - /* List is empty, set the head and tail to this packet. */ - ppp_ptr -> nx_ppp_ip_packet_queue_head = packet_ptr; - ppp_ptr -> nx_ppp_ip_packet_queue_tail = packet_ptr; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Set event flag to wake up PPP thread for processing. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_IP_PACKET_SEND, TX_OR); - break; - } - - case NX_LINK_GET_STATUS: - { - - /* Return the link status in the supplied return pointer. */ - *(driver_req_ptr -> nx_ip_driver_return_ptr) = interface_ptr -> nx_interface_link_up; - break; - } - - case NX_LINK_UNINITIALIZE: - { - - break; - } - - default: - { - - /* Invalid driver request. */ - - /* Return the unhandled command status. */ - driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_receive_packet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function assembles the PPP frame, which involves moving bytes */ -/* from the serial buffer, converting the escape sequences, and */ -/* returning the formed PPP packet to the caller. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* return_packet_ptr Return packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_check_crc Check HDLC frame CRC */ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_receive_packet_get(NX_PPP *ppp_ptr, NX_PACKET **return_packet_ptr) -{ - -TX_INTERRUPT_SAVE_AREA -NX_PACKET *packet_head_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN -NX_PACKET *next_packet_ptr; -#endif -UCHAR byte; -UCHAR *buffer_ptr; -ULONG buffer_size; -ULONG timeouts; -NX_PACKET *packet_ptr; -UINT status; - - - /* Default the return packet pointer NULL. */ - *return_packet_ptr = NX_NULL; - - /* Pickup the current working packet. */ - packet_ptr = ppp_ptr -> nx_ppp_receive_partial_packet; - - /* Determine if there is a working receive packet. */ - if (packet_ptr == NX_NULL) - { - - /* No, setup new working receive packet. */ - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Save the working receive packet pointer. */ - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup the packet head pointer. */ - packet_head_ptr = packet_ptr; - ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; - - /* Setup packet payload pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Setup packet size. */ - buffer_size = 0; - - /* Initialize the timeout counter. */ - timeouts = 0; - } - else - { - - /* Pickup saved buffer ptr, size and timeout counter. */ - buffer_ptr = ppp_ptr -> nx_ppp_receive_buffer_ptr; - buffer_size = ppp_ptr -> nx_ppp_receive_buffer_size; - - /* Pickup saved timeout count. */ - timeouts = ppp_ptr -> nx_ppp_receive_timeouts; - /* Setup the packet head pointer. */ - packet_head_ptr = ppp_ptr -> nx_ppp_head_packet; - } - - /* Loop to drain the serial buffer. */ - do - { - - /* Disable interrupts. */ - TX_DISABLE - - /* Determine if there are any characters in the serial receive buffer. */ - if (ppp_ptr -> nx_ppp_serial_buffer_byte_count) - { - - /* Yes, there are one or more characters. */ - - /* Pickup the character. */ - byte = ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_read_index]; - - /* Now determine if there is an escape sequence character and we don't have the following - character. */ - if ((byte == 0x7d) && (ppp_ptr -> nx_ppp_serial_buffer_byte_count == 1)) - { - - /* Restore interrupts. */ - TX_RESTORE - - /* We need to wait for another character. */ - break; - } - } - else - { - - /* Nothing is left in the buffer. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Determine if the timeout count has been exceeded. */ - if (timeouts > NX_PPP_RECEIVE_TIMEOUTS) - { - - /* Timeout count has been exceeded. */ - - /* Determine if the packet is non-PPP. If so, we should dispatch it to - the non-PPP packet handler. */ - if ((buffer_size) && (packet_head_ptr -> nx_packet_prepend_ptr[0] != 0x7e)) - { - - /* Determine if there is a user handler for non-PPP packets. */ - if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) - { - - /* Adjust the packet parameters. */ - packet_head_ptr -> nx_packet_length = buffer_size; - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - - /* Dispatch packet to user's handler for non-PPP packets. */ - (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); - } - else - { - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - } - } - else - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the frame timeout counter. */ - ppp_ptr -> nx_ppp_frame_timeouts++; -#endif - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - } - - /* Clear the saved receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Save the new receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup the packet head pointer. */ - packet_head_ptr = packet_ptr; - ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; - - /* Setup packet payload pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Setup packet size. */ - buffer_size = 0; - - /* Initialize the timeout counter. */ - timeouts = 0; - } - - /* We need to wait for another character. */ - break; - } - - /* At this point, we have a character. Adjust the serial buffer information. */ - ppp_ptr -> nx_ppp_serial_buffer_read_index++; - - /* Check for serial buffer wrap-around condition. */ - if (ppp_ptr -> nx_ppp_serial_buffer_read_index >= NX_PPP_SERIAL_BUFFER_SIZE) - { - - /* Reset the buffer read index. */ - ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; - } - - /* Adjust the serial buffer count. */ - ppp_ptr -> nx_ppp_serial_buffer_byte_count--; - - /* Restore interrupts. */ - TX_RESTORE - - /* Clear the timeouts counter. */ - timeouts = 0; - - /* Determine if we are at the beginning of the packet. */ - if (buffer_size == 0) - { - - /* Determine if we should add a PPP frame header. */ - if (byte == 0xFF) - { - - /* Yes, a packet is present without a leading 0x7e. Simply place it in the buffer. */ - *buffer_ptr++ = 0x7e; - - /* Increment the buffer size. */ - buffer_size++; - } - } - - /* Determine if we are at the end of the PPP frame. */ - else if (byte == 0x7e) - { - - /* Yes, we are at the end of the PPP frame. */ - - /* Determine if a non-PPP frame preceded this end of frame marker. */ - if (packet_head_ptr -> nx_packet_prepend_ptr[0] != 0x7e) - { - - /* Determine if there is a handler for non-PPP packets. */ - if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) - { - - /* Adjust the packet parameters. */ - packet_head_ptr -> nx_packet_length = buffer_size; - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - - /* Dispatch packet to user's handler for non-PPP packets. */ - (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); - } - else - { - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - } - - /* Clear the saved receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Save the current receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup the packet head pointer. */ - packet_head_ptr = packet_ptr; - ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; - - /* Setup packet payload pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Setup packet size. */ - buffer_size = 0; - - /* Initialize the timeout counter. */ - timeouts = 0; - - /* Continue to get the next byte. */ - continue; - } - - /* A PPP frame is present. Put the 0x7e into the frame. */ - - /* Yes, place the final 0x7e in the buffer. */ - *buffer_ptr++ = 0x7e; - - /* Increment the buffer size. */ - buffer_size++; - - /* Adjust the packet parameters. */ - packet_head_ptr -> nx_packet_length = buffer_size; - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - - /* Check the CRC of the packet. */ - status = _nx_ppp_check_crc(packet_head_ptr); - - /* Determine if there was an error. */ - if (status != NX_SUCCESS) - { - - /* CRC error is present, just give up on the current frame. */ - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the frame CRC error counter. */ - ppp_ptr -> nx_ppp_frame_crc_errors++; -#endif - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - - /* Clear the saved receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_WAIT_FOREVER); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Save the current receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup the packet head pointer. */ - packet_head_ptr = packet_ptr; - ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; - - /* Setup packet payload pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Setup packet size. */ - buffer_size = 0; - - /* Initialize the timeout counter. */ - timeouts = 0; - - break; - } - - /* Remove the FCS (2 bytes) and Flag (1 byte). */ - packet_head_ptr -> nx_packet_length = packet_head_ptr -> nx_packet_length - 3; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - 3; - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Check for the condition where there is essentially no data in the last packet. */ - if (packet_ptr -> nx_packet_append_ptr <= packet_ptr -> nx_packet_prepend_ptr) - { - ULONG diff = (ULONG)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_append_ptr); - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; - - if (packet_head_ptr != packet_ptr) - { - - - NX_PACKET *tmp_packet_ptr = packet_head_ptr; - NX_PACKET *prev_packet_ptr = tmp_packet_ptr; - while (tmp_packet_ptr -> nx_packet_next != 0x0) - { - prev_packet_ptr = tmp_packet_ptr; - tmp_packet_ptr = tmp_packet_ptr -> nx_packet_next; - } - - nx_packet_release(tmp_packet_ptr); - prev_packet_ptr -> nx_packet_next = NX_NULL; - prev_packet_ptr -> nx_packet_append_ptr -= diff; - } - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Remove the HDLC header. */ - packet_head_ptr -> nx_packet_prepend_ptr += 3; - packet_head_ptr -> nx_packet_length -= 3; - - /* Return the pointer. */ - *return_packet_ptr = packet_head_ptr; - - /* Set the receive packet to NULL to indicate there is no partial packet being - processed. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Return to caller. */ - return; - } - - /* Determine if an escape byte is present. */ - if (byte == 0x7d) - { - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the character - we know there is one because of earlier logic. */ - byte = ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_read_index++]; - - /* Check for serial buffer wrap-around condition. */ - if (ppp_ptr -> nx_ppp_serial_buffer_read_index >= NX_PPP_SERIAL_BUFFER_SIZE) - { - - /* Reset the buffer read index. */ - ppp_ptr -> nx_ppp_serial_buffer_read_index = 0; - } - - /* Adjust the serial buffer count. */ - ppp_ptr -> nx_ppp_serial_buffer_byte_count--; - - /* Restore interrupts. */ - TX_RESTORE - - /* Convert the escape sequence character. */ - byte = byte ^ 0x20; - } - - /* Determine if there is room in the payload. */ - if (buffer_ptr < (packet_ptr -> nx_packet_data_end - 4)) - { - - /* Put the character in the packet payload. */ - *buffer_ptr++ = byte; - - /* Increment the buffer size. */ - buffer_size++; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* We need to perform packet chaining at this point, but only for IP data frames. Non PPP data and - the other PPP protocol packets must fit within the payload of one packet. */ - else if ((packet_head_ptr -> nx_packet_prepend_ptr[0] == 0x7e) && - (packet_head_ptr -> nx_packet_prepend_ptr[1] == 0xff) && - (packet_head_ptr -> nx_packet_prepend_ptr[2] == 0x03) && - (packet_head_ptr -> nx_packet_prepend_ptr[3] == 0x00) && - (packet_head_ptr -> nx_packet_prepend_ptr[4] == 0x21)) /* 0x0021 is NX_PPP_DATA */ - { - - /* We need to move to the next packet and chain them. */ - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - - /* Allocate a new packet to for packet chaining. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &next_packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* Clear the partial receive packet pointer. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Adjust the next packet pointer. */ - packet_ptr -> nx_packet_next = next_packet_ptr; - - /* Setup the last pointer. */ - packet_head_ptr -> nx_packet_last = next_packet_ptr; - - /* Use the packet pointer. */ - packet_ptr = next_packet_ptr; - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup buffer pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Put the character in the packet payload. */ - *buffer_ptr++ = byte; - - /* Increment the buffer size. */ - buffer_size++; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - else - { - - /* At this point we know we have a buffer full of non-PPP characters, in - most cases this is simply noise. */ - - /* Determine if there is a non-PPP handler. */ - if (ppp_ptr -> nx_ppp_non_ppp_packet_handler) - { - - /* Adjust the packet parameters. */ - packet_head_ptr -> nx_packet_length = buffer_size; - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - - /* Dispatch packet to user's handler for non-PPP packets. */ - (ppp_ptr -> nx_ppp_non_ppp_packet_handler)(packet_head_ptr); - } - else - { - - /* Release the current packet. */ - nx_packet_release(packet_head_ptr); - } - - /* Clear the partial receive packet pointer. */ - ppp_ptr -> nx_ppp_receive_partial_packet = NX_NULL; - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_RECEIVE_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Save the current receive packet. */ - ppp_ptr -> nx_ppp_receive_partial_packet = packet_ptr; - - /* Setup the packet head pointer. */ - packet_head_ptr = packet_ptr; - ppp_ptr -> nx_ppp_head_packet = packet_head_ptr; - - /* Setup packet payload pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Setup packet size. */ - buffer_size = 0; - - /* Initialize the timeout counter. */ - timeouts = 0; - } - } while(ppp_ptr -> nx_ppp_serial_buffer_byte_count); - - /* Save the buffer size, buffer pointer, and timeout count. */ - ppp_ptr -> nx_ppp_receive_buffer_size = buffer_size; - ppp_ptr -> nx_ppp_receive_buffer_ptr = buffer_ptr; - ppp_ptr -> nx_ppp_receive_timeouts = timeouts; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_receive_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a received PPP request and dispatches it */ -/* to the appropriate protocol or to NetX. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to PPP packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* _nx_ppp_lcp_state_machine_update Process LCP message */ -/* _nx_ppp_pap_state_machine_update Process PAP message */ -/* _nx_ppp_chap_state_machine_update Process CHAP message */ -/* _nx_ppp_ipcp_state_machine_update Process IPCP message */ -/* _nx_ppp_netx_packet_transfer Transfer packet to NetX */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_thread_entry PPP thread entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_receive_packet_process(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UINT protocol; -UINT ppp_ipcp_state; -UINT code; - - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IP frames sent. */ - ppp_ptr -> nx_ppp_total_frames_received++; -#endif - - /* Check for valid packet length for Protocol (2 bytes). */ - if (packet_ptr -> nx_packet_length < 2) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return; - } - - /* Pickup the protocol type. */ - protocol = (((UINT) packet_ptr -> nx_packet_prepend_ptr[0]) << 8) | ((UINT) packet_ptr -> nx_packet_prepend_ptr[1]); - - /* Check protocol. */ - if (protocol != NX_PPP_DATA) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Discard the chained packets. */ - if (packet_ptr -> nx_packet_next) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return; - } -#endif - - /* Other Protocols must also have Code:1 byte, Identifier:1 bytes, Length: 2 bytes. */ - if (packet_ptr -> nx_packet_length < 6) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return; - } - } - - /* Determine if the packet is LCP. */ - if (protocol == NX_PPP_LCP_PROTOCOL) - { - - /* Pickup the type of received LCP code. */ - code = packet_ptr -> nx_packet_prepend_ptr[2]; - - /* Process the LCP message, updating the LCP state machine. */ - _nx_ppp_lcp_state_machine_update(ppp_ptr, packet_ptr); - - /* Determine if the LCP is now complete. */ - if (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_COMPLETED_STATE) - { - -#ifndef NX_PPP_DISABLE_PAP - - /* Determine if the PAP state machine should be started. */ - if ((ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_PAP_PROTOCOL) || - (ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_PAP_PROTOCOL)) - { - - /* Check if PAP already start. */ - if (ppp_ptr -> nx_ppp_pap_state == NX_PPP_PAP_INITIAL_STATE) - { - - /* Yes, change state to PAP start state and update the PAP state machine. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_START_STATE; - - /* Process the PAP message. */ - _nx_ppp_pap_state_machine_update(ppp_ptr, NX_NULL); - } - } -#endif - -#ifndef NX_PPP_DISABLE_CHAP - - /* Determine if the CHAP state machine should be started. */ - if ((ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) || - (ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_CHAP_PROTOCOL)) - { - - /* Check if CHAP already start. */ - if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_INITIAL_STATE) - { - - /* Yes, change state to CHAP start state and update the CHAP state machine. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_START_STATE; - - /* Process the CHAP message. */ - _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); - } - } -#endif - - /* Do not set the IPCP state to INIT on receipt of an LCP echo request or reply! */ - if ((code != NX_PPP_LCP_ECHO_REQUEST) && (code != NX_PPP_LCP_ECHO_REPLY)) - { - - /* Check for authentication. */ - if (ppp_ptr -> nx_ppp_authenticated) - { - - /* Check if IPCP already start. */ - if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) - { - - /* Yes, change state to IPCP start state and update the PAP state machine. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; - - /* Process the IPCP message. */ - _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); - } - } - } - - /* Check if the packet is Echo Request. */ - if (code == NX_PPP_LCP_ECHO_REQUEST) - { - - /* Clear the pointer since it was sent out as Echo Reply. */ - packet_ptr = NX_NULL; - } - } - } - - -#ifndef NX_PPP_DISABLE_PAP - - /* Determine if the packet is PAP. */ - else if (protocol == NX_PPP_PAP_PROTOCOL) - { - - /* Process the PAP message. */ - _nx_ppp_pap_state_machine_update(ppp_ptr, packet_ptr); - - /* Check for authentication. */ - if (ppp_ptr -> nx_ppp_authenticated) - { - - /* Check if IPCP already start. */ - if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) - { - - /* Yes, change state to IPCP start state and update the IPCP state machine. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; - - /* Process the IPCP message. */ - _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); - } - } - } -#endif - -#ifndef NX_PPP_DISABLE_CHAP - - /* Determine if the packet is CHAP. */ - else if (protocol == NX_PPP_CHAP_PROTOCOL) - { - - /* Process the CHAP message. */ - _nx_ppp_chap_state_machine_update(ppp_ptr, packet_ptr); - - /* Check for authentication. */ - if (ppp_ptr -> nx_ppp_authenticated) - { - - /* Check if IPCP already start. */ - if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_INITIAL_STATE) - { - - /* Yes, change state to IPCP start state and update the IPCP state machine. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_START_STATE; - - /* Process the IPCP message. */ - _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); - } - } - } -#endif - - /* Determine if packet is IPCP. */ - else if (protocol == NX_PPP_IPCP_PROTOCOL) - { - - /* Process the IPCP message. */ - ppp_ipcp_state = ppp_ptr -> nx_ppp_ipcp_state; - - _nx_ppp_ipcp_state_machine_update(ppp_ptr, packet_ptr); - - /* Check for IPCP completion... when this happens, the link is up! */ - if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_COMPLETED_STATE) - { - - /* Set the PPP state machine to indicate it is complete. */ - ppp_ptr -> nx_ppp_state = NX_PPP_ESTABLISHED; - - /* Mark the IP interface instance as link up. */ - (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_link_up = NX_TRUE; - - /* Determine if the application has registered a link up notification - callback. */ - if ((ppp_ptr -> nx_ppp_link_up_callback) && (ppp_ipcp_state!=NX_PPP_IPCP_COMPLETED_STATE)) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_up_callback)(ppp_ptr); - } - } - } - - /* Check for normal data packet. */ - else if (protocol == NX_PPP_DATA) - { - - /* Transfer the packet to NetX. */ - _nx_ppp_netx_packet_transfer(ppp_ptr, packet_ptr); - - /* Clear the pointer since it was passed to NetX. */ - packet_ptr = NX_NULL; - } -#ifndef NX_PPP_DISABLE_INFO - - else - /* Increment the number of frames dropped. */ - ppp_ptr -> nx_ppp_receive_frames_dropped++; -#endif - - /* Determine if the packet needs to be released. */ - if (packet_ptr) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes PPP time-out events, which includes */ -/* updating the responsible state machine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_lcp_state_machine_update PPP state machine update */ -/* _nx_ppp_pap_state_machine_update PPP PAP state machine update */ -/* _nx_ppp_chap_state_machine_update PPP CHAP state machine update */ -/* _nx_ppp_ipcp_state_machine_update PPP IPCP state machine update */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_timeout(NX_PPP *ppp_ptr) -{ - - /* Determine if the LCP state machine needs updating. */ - if ((ppp_ptr -> nx_ppp_lcp_state >= NX_PPP_LCP_START_STATE) && - (ppp_ptr -> nx_ppp_lcp_state < NX_PPP_LCP_COMPLETED_STATE)) - { - - /* Update the PPP state machine. */ - _nx_ppp_lcp_state_machine_update(ppp_ptr, NX_NULL); - } - -#ifndef NX_PPP_DISABLE_PAP - - /* Determine if the PAP state machine needs updating. */ - if ((ppp_ptr -> nx_ppp_pap_state >= NX_PPP_PAP_START_STATE) && - (ppp_ptr -> nx_ppp_pap_state < NX_PPP_PAP_COMPLETED_STATE)) - { - - /* Update the PAP state machine. */ - _nx_ppp_pap_state_machine_update(ppp_ptr, NX_NULL); - } -#endif - -#ifndef NX_PPP_DISABLE_CHAP - - /* Determine if the CHAP state machine needs updating. */ - if ((ppp_ptr -> nx_ppp_chap_state >= NX_PPP_CHAP_START_STATE) && - (ppp_ptr -> nx_ppp_chap_state < NX_PPP_CHAP_COMPLETED_STATE)) - { - - /* Update the CHAP state machine. */ - _nx_ppp_chap_state_machine_update(ppp_ptr, NX_NULL); - } -#endif - - /* Determine if the IPCP state machine needs updating. */ - if ((ppp_ptr -> nx_ppp_ipcp_state >= NX_PPP_IPCP_START_STATE) && - (ppp_ptr -> nx_ppp_ipcp_state < NX_PPP_IPCP_COMPLETED_STATE)) - { - - /* Update the IPCP state machine. */ - _nx_ppp_ipcp_state_machine_update(ppp_ptr, NX_NULL); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes PPP time-outs, which sets a time-out event */ -/* that wakes up the PPP processing thread. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set timeout event flag */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_timer_entry(ULONG id) -{ - -NX_PPP *ppp_ptr; - - - /* Pickup the PPP pointer. */ - ppp_ptr = (NX_PPP *) id; - - /* Make sure the PPP pointer is good. */ - if ((ppp_ptr != NX_NULL) && (ppp_ptr -> nx_ppp_id == NX_PPP_ID)) - { - - /* Set the timeout event for the PPP thread. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_TIMEOUT, TX_OR); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_netx_packet_transfer PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function removes the PPP header and passes the packet to */ -/* NetX. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ip_packet_deferred_receive Deferred IP packet receive */ -/* _nx_ip_packet_receive IP packet receive */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_process Receive packet processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_netx_packet_transfer(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -ULONG offset; - -#ifndef NX_PPP_DISABLE_INFO - /* Increment the number of IP frames received. */ - ppp_ptr -> nx_ppp_ip_frames_received++; -#endif - - /* Add the incoming interface pointer. */ - packet_ptr -> nx_packet_ip_interface = ppp_ptr -> nx_ppp_interface_ptr; - - /* Remove the PPP header [00,21] in the front of the IP packet. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - - /* Adjust the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Calculate the offset for four byte alignment. */ - offset = (((ULONG)packet_ptr -> nx_packet_prepend_ptr) & 3); - - /* Move the data to keep four byte alignment for first packet. */ - if (offset) - { - memmove(packet_ptr -> nx_packet_prepend_ptr - offset, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr)); - packet_ptr -> nx_packet_prepend_ptr -= offset; - packet_ptr -> nx_packet_append_ptr -= offset; - } - - /* Transfer the receive packet to NetX. */ -#ifdef NX_DIRECT_ISR_CALL - _nx_ip_packet_receive(ppp_ptr -> nx_ppp_ip_ptr, packet_ptr); -#else - _nx_ip_packet_deferred_receive(ppp_ptr -> nx_ppp_ip_ptr, packet_ptr); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_process_deferred_raw_string_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function takes all the raw string packets from the deferred raw*/ -/* string packet queue and then sends them out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* (nx_ppp_byte_send) User's byte output routine */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_thread_entry PPP processing thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_process_deferred_raw_string_send(NX_PPP *ppp_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_PACKET *packet_ptr; -ULONG i; -#ifdef NX_PPP_PPPOE_ENABLE -UINT release_packet; -#endif /* NX_PPP_PPPOE_ENABLE */ - - - /* Loop to process all queued packets. */ - do - { - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the number of queued packets. */ - if (ppp_ptr -> nx_ppp_raw_packet_queue_count) - { - - /* Pickup the oldest packet. */ - packet_ptr = ppp_ptr -> nx_ppp_raw_packet_queue_head; - - /* Update the head pointer to the next packet. */ - ppp_ptr -> nx_ppp_raw_packet_queue_head = packet_ptr -> nx_packet_queue_next; - - /* Decrement the number of queued packets. */ - ppp_ptr -> nx_ppp_raw_packet_queue_count--; - } - else - { - - /* No packet just set the packet pointer to NULL. */ - packet_ptr = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Is there a packet to process? */ - if (packet_ptr == NX_NULL) - { - - /* No, just get out of the loop! */ - break; - } - -#ifdef NX_PPP_PPPOE_ENABLE - release_packet = NX_TRUE; -#endif /* NX_PPP_PPPOE_ENABLE */ - - if (ppp_ptr -> nx_ppp_byte_send) - { - - /* Loop to send all the bytes of the packet out. */ - for (i = 0; i < packet_ptr -> nx_packet_length; i++) - { - - /* Send each byte out. */ - (ppp_ptr -> nx_ppp_byte_send)(packet_ptr -> nx_packet_prepend_ptr[i]); - } - } - -#ifdef NX_PPP_PPPOE_ENABLE - - /* Check the PPPoE packet send function. */ - if (ppp_ptr -> nx_ppp_packet_send) - { - - /* Send the packet out. */ - (ppp_ptr -> nx_ppp_packet_send)(packet_ptr); - - /* Update the flag since this packet should been released in PPPoE. */ - release_packet = NX_FALSE; - } - - /* Check if need to release the packet. */ - if (release_packet == NX_TRUE) -#endif /* NX_PPP_PPPOE_ENABLE */ - - nx_packet_release(packet_ptr); - - } while (1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_process_deferred_ip_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function takes all the packets from the deferred IP packet */ -/* queue, packages them in an PPP frame, and then sends them out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_packet_transmit Send AHDLC packet */ -/* nx_packet_transmit_release Release NetX packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_thread_entry PPP processing thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_process_deferred_ip_packet_send(NX_PPP *ppp_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_PACKET *packet_ptr; - - - /* Loop to process all queued packets. */ - do - { - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the number of queued packets. */ - if (ppp_ptr -> nx_ppp_ip_packet_queue_count) - { - - /* Pickup the oldest packet. */ - packet_ptr = ppp_ptr -> nx_ppp_ip_packet_queue_head; - - /* Update the head pointer to the next packet. */ - ppp_ptr -> nx_ppp_ip_packet_queue_head = packet_ptr -> nx_packet_queue_next; - - /* Decrement the number of queued packets. */ - ppp_ptr -> nx_ppp_ip_packet_queue_count--; - } - else - { - - /* No packet just set the packet pointer to NULL. */ - packet_ptr = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Is there a packet to process? */ - if (packet_ptr == NX_NULL) - { - - /* No, just get out of the loop! */ - break; - } - - /* Determine if there is room in the front of the packet for the PPP header. */ - if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < 2) - { - - /* Error, there is no room at the front of the packet to prepend the PPP header. */ - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* Release the NetX packet. */ - nx_packet_transmit_release(packet_ptr); - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Otherwise, backup the prepend pointer. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 2; - - /* Place the PPP header in the packet. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_DATA & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_DATA & 0xFF; - - /* Adjust the length of the packet. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 2; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IP frames sent. */ - ppp_ptr -> nx_ppp_ip_frames_sent++; -#endif - - /* Send the packet! */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); - } while (1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_state_machine_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes LCP messages and updates the LCP state */ -/* machine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to LCP packet. If the */ -/* packet is NULL, a timeout is*/ -/* present */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_lcp_code_reject Reject received code */ -/* _nx_ppp_lcp_configuration_retrieve Retrieve configuration info */ -/* _nx_ppp_lcp_configure_reply_send Send configure reply */ -/* _nx_ppp_lcp_configure_request_send Send configure request */ -/* _nx_ppp_lcp_nak_configure_list Get options naked */ -/* _nx_ppp_lcp_terminate_ack_send Send terminate ack */ -/* _nx_ppp_lcp_terminate_request_send Send terminate request */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_process Receive packet processing */ -/* _nx_ppp_timeout PPP timeout */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UINT configure_status; -UCHAR *lcp_message_ptr; -UCHAR code; - - /* Determine if a packet is present. If so, derive the event from the packet. */ - if (packet_ptr) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames received. */ - ppp_ptr -> nx_ppp_lcp_frames_received++; -#endif - - /* Setup a pointer to the LCP pointer. */ - lcp_message_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the type of received LCP code. */ - code = packet_ptr -> nx_packet_prepend_ptr[2]; - -#ifndef NX_PPP_DISABLE_INFO - - /* Count the number of specific LCP requests. */ - switch (code) - { - - case NX_PPP_LCP_CONFIGURE_REQUEST: - - /* Increment the number of LCP configure requests received. */ - ppp_ptr -> nx_ppp_lcp_configure_requests_received++; - break; - - case NX_PPP_LCP_CONFIGURE_ACK: - - /* Increment the number of LCP configure ACKs received. */ - ppp_ptr -> nx_ppp_lcp_configure_acks_received++; - break; - - case NX_PPP_LCP_CONFIGURE_NAK: - - /* Increment the number of LCP configure NAKs received. */ - ppp_ptr -> nx_ppp_lcp_configure_naks_received++; - break; - - case NX_PPP_LCP_CONFIGURE_REJECT: - - /* Increment the number of LCP configure rejects received. */ - ppp_ptr -> nx_ppp_lcp_configure_rejects_received++; - break; - - case NX_PPP_LCP_TERMINATE_REQUEST: - - /* Increment the number of LCP terminate requests received. */ - ppp_ptr -> nx_ppp_lcp_terminate_requests_received++; - break; - - case NX_PPP_LCP_TERMINATE_ACK: - - /* Increment the number of LCP terminate ACKs received. */ - ppp_ptr -> nx_ppp_lcp_terminate_acks_received++; - break; - - case NX_PPP_LCP_CODE_REJECT: - - /* Increment the number of LCP code rejects received. */ - ppp_ptr -> nx_ppp_lcp_code_rejects_received++; - break; - - case NX_PPP_LCP_PROTOCOL_REJECT: - - /* Increment the number of LCP protocol rejects received. */ - ppp_ptr -> nx_ppp_lcp_protocol_rejects_received++; - break; - - case NX_PPP_LCP_ECHO_REQUEST: - - /* Increment the number of LCP echo requests received. */ - ppp_ptr -> nx_ppp_lcp_echo_requests_received++; - - break; - - case NX_PPP_LCP_ECHO_REPLY: - - /* Increment the number of LCP echo replies received. */ - break; - - case NX_PPP_LCP_DISCARD_REQUEST: - - /* Increment the number of LCP discard requests received. */ - ppp_ptr -> nx_ppp_lcp_discard_requests_received++; - break; - - default: - - /* Increment the number of LCP unknown (unhandled) requests received. */ - ppp_ptr -> nx_ppp_lcp_unknown_requests_received++; - } -#endif - - /* Remember receive id. */ - ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Is the code supported by PPP? */ - if ((code < NX_PPP_LCP_CONFIGURE_REQUEST) || - (code > NX_PPP_LCP_DISCARD_REQUEST)) - { - - /* No, this code is not supported. Reject the code. */ - _nx_ppp_lcp_code_reject(ppp_ptr, lcp_message_ptr); - - /* Return. */ - return; - } - } - else - { - - /* Set the LCP pointer to NULL. */ - lcp_message_ptr = NX_NULL; - - /* Set the code to timeout to indicate a timeout has occurred. */ - code = NX_PPP_LCP_TIMEOUT; - -#ifndef NX_PPP_DISABLE_INFO - - /* Determine if we are in the initial state. If so, this really isn't a timeout. */ - if (ppp_ptr -> nx_ppp_lcp_state != NX_PPP_LCP_START_STATE) - { - - /* Increment the LCP timeout counter. */ - ppp_ptr -> nx_ppp_lcp_state_machine_timeouts++; - } -#endif - } - - /* Process relative to the current state. */ - switch (ppp_ptr -> nx_ppp_lcp_state) - { - - case NX_PPP_LCP_START_STATE: - { - - /* Initial LCP state. */ - - /* Initialize the NAK and rejected lists. */ -#ifndef NX_PPP_DNS_OPTION_DISABLE - - ppp_ptr -> nx_ppp_naked_list[0] = 0; -#else - ppp_ptr -> nx_ppp_naked_list[0] = 1; -#endif - ppp_ptr -> nx_ppp_peer_naked_list[0] = 0; - ppp_ptr -> nx_ppp_rejected_list[0] = 0; - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send configuration request to peer. */ - _nx_ppp_lcp_configure_request_send(ppp_ptr); - - /* Move to the next state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE; - break; - } - - case NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE: - { - - /* In this state, we have sent a configuration request but had not received an ACK - or a configuration request from the peer. */ - - /* Process relative to the incoming code. */ - if (code == NX_PPP_LCP_CONFIGURE_ACK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* The peer has ACKed our configuration request. Move to the - configure request ACKed state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE; - - /* Turn off the timeout for the configuration request. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - else if (code == NX_PPP_LCP_CONFIGURE_NAK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Figure out what options were naked. */ - _nx_ppp_lcp_nak_configure_list(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - - /* Send new configure request. */ - _nx_ppp_lcp_configure_request_send(ppp_ptr); - } - - else if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - - /* The peer has sent a configuration request. */ - - /* Retrieve configuration. */ - configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - - /* Determine if the configuration request is fine or needs to be negotiated further. */ - if (configure_status == 0) - { - - /* The peer's request is acceptable, move into peer configuration request ACKed state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE; - } - - /* Send configuration reply. */ - _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - } - else if (code == NX_PPP_LCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the LCP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Timeout, send configuration request again. */ - _nx_ppp_lcp_configure_request_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter LCP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE: - { - - /* In this state, we have received the ACK for our configuration request, but have not yet - received a configuration request from the peer. */ - - /* Process relative to the incoming code. */ - if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - - /* The peer has sent a configuration request. */ - - /* Retrieve configuration. */ - configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - - /* Determine if the configuration request is fine or needs to be negotiated further. */ - if (configure_status == 0) - { - - /* The peer's request is acceptable, move into the LCP done state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; - - /* Determine if we need to update the IP's MTU. */ - if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) - { - - /* Yes, the peer can accept larger messages than the default. */ - (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; - } - - /* Disable the LCP timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - /* Send configuration reply. */ - _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE: - { - - /* In this state, we have sent our configuration request, but haven't received an ACK. We have also received - a peer configuration request and have ACKed that request. */ - - /* Process relative to the incoming code. */ - if (code == NX_PPP_LCP_CONFIGURE_ACK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* The peer has ACKed our configuration request. Move to the - LCP completed state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; - - /* Determine if we need to update the IP's MTU. */ - if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) - { - - /* Yes, the peer can accept larger messages than the default. */ - (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; - } - - /* Turn off the timeout for the configuration request. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - else if (code == NX_PPP_LCP_CONFIGURE_NAK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Figure out what options were naked. */ - _nx_ppp_lcp_nak_configure_list(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - - /* Send new configure request. */ - _nx_ppp_lcp_configure_request_send(ppp_ptr); - } - - else if (code == NX_PPP_LCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the LCP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Timeout, send configuration request again. */ - _nx_ppp_lcp_configure_request_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter LCP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_LCP_COMPLETED_STATE: - { - - /* PPP is up and operational at this point. */ - - /* Process relative to incoming code. */ - if (code == NX_PPP_LCP_TERMINATE_REQUEST) - { - - /* ACK the terminate request. */ - _nx_ppp_lcp_terminate_ack_send(ppp_ptr); - - /* Move to stopped state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPED_STATE; - - /* Set the event to stop the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - else if ((code == NX_PPP_LCP_ECHO_REQUEST) && (packet_ptr)) - { - - /* Respond to the echo request. */ - _nx_ppp_lcp_ping_reply(ppp_ptr, packet_ptr); - } - - else if ((code == NX_PPP_LCP_ECHO_REPLY) && (packet_ptr)) - { - - /* Check if the PPP instance is waiting on an echo reply. */ - if (ppp_ptr -> nx_ppp_lcp_echo_reply_id) - { - - /* It is. Check if this is a valid reply. */ - _nx_ppp_lcp_ping_process_echo_reply(ppp_ptr, packet_ptr); - } - - break; - } - - /* In this state, we have received the ACK for our configuration request/completed LCP, but are expecting - a configuration request from the peer. */ - - /* Process relative to the incoming code. */ - else if ((code == NX_PPP_LCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - - /* The peer has sent a configuration request. */ - - /* Retrieve configuration. */ - configure_status = _nx_ppp_lcp_configuration_retrieve(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - - /* Determine if the configuration request is fine or needs to be negotiated further. */ - if (configure_status == 0) - { - - - /* The peer's request is acceptable, move into the LCP done state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_COMPLETED_STATE; - - /* Determine if we need to update the IP's MTU. */ - if (ppp_ptr -> nx_ppp_mru > (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size) - { - - /* Yes, the peer can accept larger messages than the default. */ - (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_mtu_size = ppp_ptr -> nx_ppp_mru; - } - - /* Disable the LCP timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - /* Send configuration reply. */ - _nx_ppp_lcp_configure_reply_send(ppp_ptr, configure_status, lcp_message_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list); - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_LCP_STOPPING_STATE: - { - - /* We received a terminate request from the other side and just need to get the ACK. */ - - /* Process relative to incoming code. */ - if (code == NX_PPP_LCP_TERMINATE_ACK) - { - - /* Move to stopped state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPED_STATE; - - /* Set the event to stop the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - else if (code == NX_PPP_LCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the LCP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_LCP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send terminate request. */ - _nx_ppp_lcp_terminate_request_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter LCP failed state. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_FAILED_STATE; - - /* Set the event to stop the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - -#ifndef NX_PPP_DISABLE_INFO - if (code == NX_PPP_LCP_ECHO_REQUEST) - { - - - ppp_ptr -> nx_ppp_lcp_echo_requests_dropped++; - } -#endif - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - default: - { - -#ifndef NX_PPP_DISABLE_INFO - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_lcp_state_machine_unhandled_requests++; - } -#endif - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_code_reject PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a code reject message and sends it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* lcp_ptr Pointer to LCP message */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send PPP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_code_reject(NX_PPP *ppp_ptr, UCHAR *lcp_ptr) -{ - -UINT i; -UINT status; -UINT length; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return. */ - return; - } - - /* Build the configuration request. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CODE_REJECT; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = lcp_ptr[4]; - packet_ptr -> nx_packet_prepend_ptr[5] = lcp_ptr[5]; - - length = (((UINT) lcp_ptr[4]) << 8) | ((UINT) lcp_ptr[5]); - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (length + 2)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Send the options that were received with RCR. */ - for(i = 0; i < (length - 4); i++) - { - - /* Copy option byte into new packet. */ - packet_ptr -> nx_packet_prepend_ptr[6+i] = lcp_ptr[6+i]; - } - - /* Setup the packet length and append pointer. */ - packet_ptr -> nx_packet_length = length + 2; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; - - /* Increment code rejects sent counter. */ - ppp_ptr -> nx_ppp_lcp_code_rejects_sent++; -#endif - - /* Send code reject message. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_configure_reply_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a configuration reply. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* configure_status Status from configure request */ -/* lcp_ptr Pointer to LCP message */ -/* naked_list List of NAKed options */ -/* rejected_list List of rejected options */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send PPP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_configure_reply_send(NX_PPP *ppp_ptr, UINT configure_status, UCHAR *lcp_ptr, UCHAR *naked_list, UCHAR *rejected_list) -{ - -UINT i; -UINT status; -UINT length; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build the configuration reply. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - - /* Process relative to the supplied status. */ - if (configure_status == 0) - { - /* Send ACK. */ - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_ACK; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP ACKs sent. */ - ppp_ptr -> nx_ppp_lcp_configure_acks_sent++; -#endif - } - else if (configure_status & 2) - { - /* Send reject. */ - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_REJECT; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP rejects sent. */ - ppp_ptr -> nx_ppp_lcp_configure_rejects_sent++; -#endif - } - else - { - /* Send NAK. */ - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_NAK; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP NAKs sent. */ - ppp_ptr -> nx_ppp_lcp_configure_naks_sent++; -#endif - } - - /* Insert the id. */ - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - - /* Process again according to the status. */ - if (configure_status == 0) - { - - /* Setup the options list. */ - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = lcp_ptr[4]; - packet_ptr -> nx_packet_prepend_ptr[5] = lcp_ptr[5]; - - length = (((UINT) lcp_ptr[4]) << 8) | ((UINT) lcp_ptr[5]); - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (length + 2)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Send the options that were received with the request. */ - for(i = 0; i < (length - 4); i++) - { - - /* Copy option byte into new packet. */ - packet_ptr -> nx_packet_prepend_ptr[6+i] = lcp_ptr[6+i]; - } - - /* Setup the packet length and append pointer. */ - packet_ptr -> nx_packet_length = length + 2; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - } - else if (configure_status & 2) - { - - /* Rejected options. */ - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(rejected_list[0] + 4); - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(rejected_list[0] + 6)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Load entire rejected list. */ - for(i = 1; i < (UCHAR)(rejected_list[0] + 1); i++) - { - /* Copy option byte into new packet. */ - packet_ptr -> nx_packet_prepend_ptr[6+i-1] = rejected_list[i]; - } - - /* Setup the packet length and append pointer. */ - packet_ptr -> nx_packet_length = (ULONG)(rejected_list[0] + 6); - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - } - else - { - - /* NAKed options. */ - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(naked_list[0] + 4); - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(naked_list[0] + 6)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Load entire naked list. */ - for(i = 1; i < (UCHAR)(naked_list[0] + 1); i++) - { - /* Copy option byte into new packet. */ - packet_ptr -> nx_packet_prepend_ptr[6+i-1] = naked_list[i]; - } - - /* Setup the packet length and append pointer. */ - packet_ptr -> nx_packet_length = (ULONG)(naked_list[0] + 6); - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; -#endif - - /* Send the reply out. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_configure_request_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a LCP configuration request. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate PPP packet */ -/* _nx_ppp_packet_transmit Send LCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_configure_request_send(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Increment the transmit ID. */ - ppp_ptr -> nx_ppp_transmit_id++; - - /* Build the configuration request. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_CONFIGURE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - - /* Load the MRU. */ - packet_ptr -> nx_packet_prepend_ptr[6] = 1; - packet_ptr -> nx_packet_prepend_ptr[7] = 4; - packet_ptr -> nx_packet_prepend_ptr[8] = (UCHAR) ((NX_PPP_MRU) >> 8); - packet_ptr -> nx_packet_prepend_ptr[9] = (UCHAR) ((NX_PPP_MRU) & 0xff); - - /* Load the authentication protocol type. */ - if ((ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_PAP_PROTOCOL) && (ppp_ptr -> nx_ppp_pap_verify_login)) - { - - /* Set the length for PAP authentication protocol. */ - packet_ptr -> nx_packet_prepend_ptr[5] = 12; - - packet_ptr -> nx_packet_prepend_ptr[10] = 3; - packet_ptr -> nx_packet_prepend_ptr[11] = 4; - packet_ptr -> nx_packet_prepend_ptr[12] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[13] = NX_PPP_PAP_PROTOCOL & 0xFF; - } - else if ((ppp_ptr -> nx_ppp_verify_authentication_protocol == NX_PPP_CHAP_PROTOCOL) && - (ppp_ptr -> nx_ppp_chap_get_challenge_values) && (ppp_ptr -> nx_ppp_chap_get_verification_values)) - { - - /* Set the length for CHAP authentication protocol. */ - packet_ptr -> nx_packet_prepend_ptr[5] = 13; - - packet_ptr -> nx_packet_prepend_ptr[10] = 3; - packet_ptr -> nx_packet_prepend_ptr[11] = 5; - packet_ptr -> nx_packet_prepend_ptr[12] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[13] = NX_PPP_CHAP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[14] = 0x05; - } - else - { - - /* Set the length for no authentication protocol. */ - packet_ptr -> nx_packet_prepend_ptr[5] = 8; - } - - /* Setup the append pointer and the packet length (LCP length + PPP header). */ - packet_ptr -> nx_packet_length = (ULONG)(packet_ptr -> nx_packet_prepend_ptr[5] + 2); - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; - - /* Increment the number of LCP configure requests sent. */ - ppp_ptr -> nx_ppp_lcp_configure_requests_sent++; -#endif - - /* Send the configure request packet. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_configuration_retrieve PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function pickup the configuration options. Unhandled options */ -/* are placed in NAKed or Rejected lists. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* naked_list List of NAKed options */ -/* rejected_list List of rejected options */ -/* */ -/* OUTPUT */ -/* */ -/* 0 -> Success */ -/* 1 -> NAKed one or more options */ -/* 2 -> Rejected on or more options */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_lcp_configuration_retrieve(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list) -{ - -UINT option_index, nak_list_index, rejected_list_index; -UINT len, status = 0; -UINT type; -UINT counter; -ULONG authentication_protocol; -UCHAR *option_data; - - - /* Clear both the NAKed and rejected list length. */ - naked_list[0] = 0; - rejected_list[0] = 0; - - /* Start indexes at 1, since byte 0 contains length. */ - nak_list_index = 1; - rejected_list_index = 1; - - /* Process the options in the LCP message. */ - for (option_index = 6; (option_index + 2) <= packet_ptr -> nx_packet_length; ) - { - - /* Pickup the option type - section 6 of RFC1661. */ - type = packet_ptr -> nx_packet_prepend_ptr[option_index++]; - - /* Get the length of the option. The length also includes the type and length fields. */ - len = packet_ptr -> nx_packet_prepend_ptr[option_index++]; - - /* Check if the length is valid. */ - if ((len < 2) || (len > (packet_ptr -> nx_packet_length - (option_index - 2)))) - return(2); - - /* Set a pointer to option data. */ - option_data = &packet_ptr -> nx_packet_prepend_ptr[option_index]; - - /* Advance the index to next option. */ - option_index += len - 2; - - /* Process relative to the option type. */ - switch (type) - { - - case 1: - - /* Maximum Receive Unit (MRU) option. */ - ppp_ptr -> nx_ppp_mru = (ULONG)((((USHORT) option_data[0]) << 8) | ((USHORT) option_data[1])); - - /* Determine if the MRU is too small. */ - if (ppp_ptr -> nx_ppp_mru < NX_PPP_MINIMUM_MRU) - { - status |= 1; - - /* Default the MRU. */ - ppp_ptr -> nx_ppp_mru = NX_PPP_MRU; - - /* Check if out of boundary. */ - if ((nak_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* Yes, enter it in the NAK list. */ - naked_list[nak_list_index++] = (UCHAR)type; - naked_list[nak_list_index++] = (UCHAR)len; - for (counter = 0; counter < (len-2); counter++) - naked_list[nak_list_index++] = option_data[counter]; - naked_list[0] = (UCHAR)(nak_list_index - 1); - } - break; - - case 3: - - /* Authentication protocol selection. */ - - /* Pickup the authentication protocol. */ - authentication_protocol = (((UINT) option_data[0]) << 8) | ((UINT) option_data[1]); - - /* Determine if the authentication protocol specified by the peer is PAP and we have a generate - routine defined. */ - if ((authentication_protocol == NX_PPP_PAP_PROTOCOL) && (ppp_ptr -> nx_ppp_pap_generate_login)) - { - - /* Yes, enable the PAP protocol. */ - ppp_ptr -> nx_ppp_generate_authentication_protocol = NX_PPP_PAP_PROTOCOL; - } - - /* Determine if the authentication protocol specified by the peer is CHAP and we have a generate - response routine defined. */ - if ((authentication_protocol == NX_PPP_CHAP_PROTOCOL) && (ppp_ptr -> nx_ppp_chap_get_responder_values)) - { - - /* Yes, enable the CHAP protocol. */ - ppp_ptr -> nx_ppp_generate_authentication_protocol = NX_PPP_CHAP_PROTOCOL; - } - - /* Determine if the required authentication at the peer is the same as what this peer can generate - login information for. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol != authentication_protocol) - { - - /* We do not support the requested authentication by the peer. */ - - /* Check to see if we don't have any authentication protocols enabled. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol == 0) - { - status |= 2; - - /* Check if out of boundary. */ - if ((rejected_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* No authentication is supported, simply include requested authentication - option in the rejected list. */ - rejected_list[rejected_list_index++] = (UCHAR)type; - rejected_list[rejected_list_index++] = (UCHAR)len; - for (counter = 0; counter < (len-2); counter++) - rejected_list[rejected_list_index++] = option_data[counter]; - rejected_list[0] = (UCHAR)(rejected_list_index - 1); - } - - /* Determine if this peer has PAP enabled. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_PAP_PROTOCOL) - { - status |= 1; - - /* Check if out of boundary. */ - if ((nak_list_index + 4) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* PAP enabled but something different is requested by the peer, build NAK entry with PAP hint. */ - naked_list[nak_list_index++] = 3; - naked_list[nak_list_index++] = NX_PPP_PAP_AUTHENTICATE_NAK; - naked_list[nak_list_index++] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; - naked_list[nak_list_index++] = NX_PPP_PAP_PROTOCOL & 0xFF; - naked_list[0] = (UCHAR)(nak_list_index - 1); - - /* Clear authentication protocol. */ - ppp_ptr -> nx_ppp_verify_authentication_protocol = 0; - } - - /* Determine if this peer has CHAP enabled. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) - { - status |= 1; - - /* Check if out of boundary. */ - if ((nak_list_index + 5) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* CHAP enabled but something different is requested by the peer, build NAK entry with CHAP hint. */ - naked_list[nak_list_index++] = 3; - naked_list[nak_list_index++] = 5; - naked_list[nak_list_index++] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - naked_list[nak_list_index++] = NX_PPP_CHAP_PROTOCOL & 0xFF; - naked_list[nak_list_index++] = 0x05; - naked_list[0] = (UCHAR)(nak_list_index - 1); - } - } - else - { - - /* Matching authentication protocol. */ - - /* Check to see if we have the CHAP authentication protocol enabled. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol == NX_PPP_CHAP_PROTOCOL) - { - - /* Now determine if something other than CHAP MD5 was requested. */ - if (option_data[2] != 0x05) - { - status |= 1; - - /* Check if out of boundary. */ - if ((nak_list_index + 5) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* CHAP enabled but something different is requested by the peer, build NAK entry with CHAP hint. */ - naked_list[nak_list_index++] = 3; - naked_list[nak_list_index++] = 5; - naked_list[nak_list_index++] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - naked_list[nak_list_index++] = NX_PPP_CHAP_PROTOCOL & 0xFF; - naked_list[nak_list_index++] = 0x05; - naked_list[0] = (UCHAR)(nak_list_index - 1); - } - else - { - - /* Clear the authenticated flag since peer requires CHAP authentication. */ - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - } - } - else - { - - /* Clear the authenticated flag since peer requires PAP authentication. */ - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - } - } - break; - - case 2: /* ACCM, Not implemented. */ - case 5: /* Magic number - just acknowledge, we do not send out magic number. */ - case 7: /* The sender can receive protocol compression. */ - case 8: /* The sender can receive address compression. */ - - /* Skip these options, since we don't care to object. */ - break; - - default: - - status |= 2; - - /* Check if out of boundary. */ - if ((rejected_list_index + len) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* All other options we must reject since we do not negotiate. */ - rejected_list[rejected_list_index++] = (UCHAR)type; - rejected_list[rejected_list_index++] = (UCHAR)len; - for (counter = 0; counter < (len-2); counter++) - rejected_list[rejected_list_index++] = option_data[counter]; - rejected_list[0] = (UCHAR)(rejected_list_index - 1); - break; - } - } - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_nak_configure_list PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the NAKed option list. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* naked_list List of NAKed options */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_nak_configure_list(NX_PPP *ppp_ptr, UCHAR *naked_list) -{ - -UINT i; - - NX_PARAMETER_NOT_USED(ppp_ptr); - - /* Currently, nothing needs to be done in this routine since the options - we are asking for are basic and must be supported. If additional options - are added, we will need to process the NAK list. */ - - /* Just clear the naked list for now. */ - for(i = 0; i < NX_PPP_OPTION_MESSAGE_LENGTH; i++) - naked_list[i] = 0; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_terminate_ack_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a terminate ACK LCP message and sends it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send AHDLC packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_terminate_ack_send(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build terminate ACK LCP message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_TERMINATE_ACK; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = 4; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 6; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; - - /* Increment the number of LCP terminate ACKs sent. */ - ppp_ptr -> nx_ppp_lcp_terminate_acks_sent++; -#endif - - /* Send the packet out. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_terminate_request_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a LCP terminate message and sends it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send PPP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update LCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_terminate_request_send(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build terminate request message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_TERMINATE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = 4; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 6; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; - - /* Increment the number of LCP terminate requests sent. */ - ppp_ptr -> nx_ppp_lcp_terminate_requests_sent++; -#endif - - /* Send terminate request. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -#ifndef NX_PPP_DISABLE_PAP -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_state_machine_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes events and state changes in the PPP PAP */ -/* state machine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to PAP packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_pap_login_valid Check for valid peer login */ -/* _nx_ppp_pap_authentication_request Send authentication request */ -/* _nx_ppp_pap_authentication_ack Send authentication ACK */ -/* _nx_ppp_pap_authentication_nak Send authentication NAK */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_process Receive PPP packet processing */ -/* _nx_ppp_timeout PPP timeout */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_pap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR code; -UINT valid; - - - /* Determine if a packet is present. If so, drive the event from the packet. */ - if (packet_ptr) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of PAP frames received. */ - ppp_ptr -> nx_ppp_pap_frames_received++; -#endif - - /* Pickup the type of received PAP code. */ - code = packet_ptr -> nx_packet_prepend_ptr[2]; - - /* Remember receive id. */ - ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Check the incoming code. */ - if ((code < NX_PPP_PAP_AUTHENTICATE_REQUEST) || (code > NX_PPP_PAP_AUTHENTICATE_NAK)) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; - - /* Increment the PAP unknown requests counter. */ - ppp_ptr -> nx_ppp_pap_unknown_requests_received++; -#endif - return; - } - } - else - { - - /* Set the code to timeout. */ - code = NX_PPP_PAP_AUTHENTICATE_TIMEOUT; - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the appropriate counter. */ - switch (code) - { - - case NX_PPP_PAP_AUTHENTICATE_REQUEST: - - /* Increment the authenticate requests counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_requests_received++; - break; - - case NX_PPP_PAP_AUTHENTICATE_ACK: - - /* Increment the authenticate acks counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_acks_received++; - break; - - case NX_PPP_PAP_AUTHENTICATE_NAK: - - /* Increment the authenticate naks counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_naks_received++; - break; - - case NX_PPP_PAP_AUTHENTICATE_TIMEOUT: - - /* Determine if we are in the initial state. If so, this really isn't a timeout. */ - if (ppp_ptr -> nx_ppp_pap_state != NX_PPP_PAP_START_STATE) - { - - /* Increment the authenticate timeout counter. */ - ppp_ptr -> nx_ppp_pap_state_machine_timeouts++; - } - break; - } -#endif - - /* Process relative to the current state. */ - switch (ppp_ptr -> nx_ppp_pap_state) - { - - /* Starting state. */ - case NX_PPP_PAP_START_STATE: - { - - /* Determine if we need to generate a login for the peer to verify. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol) - { - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Generate PAP login request and send to the peer. */ - _nx_ppp_pap_authentication_request(ppp_ptr); - - /* Move to the authenticate request sent state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE; - } - else - { - - /* Move to the authenticate wait state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE; - } - break; - } - - case NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE: - { - - /* In this state, this peer has sent an authentication request and is waiting for - an ACK or NAK from the peer. */ - if ((code == NX_PPP_PAP_AUTHENTICATE_REQUEST) && (packet_ptr)) - { - - /* Determine if the login information is valid. */ - valid = _nx_ppp_pap_login_valid(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_TRUE) - { - - /* Send an ACK message. */ - _nx_ppp_pap_authentication_ack(ppp_ptr); - - /* Now determine if we need to authenticate ourselves. */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol != NX_PPP_PAP_PROTOCOL) - { - - /* We do not need to authenticate ourselves, so we can move into PAP completed state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - } - else - { - - /* Send NAK to tell peer the authentication failed. */ - _nx_ppp_pap_authentication_nak(ppp_ptr); - - /* No state change, just stay here! */ - } - } - - /* Was a NAK received? */ - else if (code == NX_PPP_PAP_AUTHENTICATE_NAK) - { - - /* Determine if there is an application NAK callback. */ - if (ppp_ptr -> nx_ppp_nak_authentication_notify) - { - - /* Yes, call the application's authentication NAK notify callback function. */ - (ppp_ptr -> nx_ppp_nak_authentication_notify)(); - } - - /* Generate a new PAP login request and send to the peer. */ - _nx_ppp_pap_authentication_request(ppp_ptr); - } - - /* Was an ACK received? */ - else if (code == NX_PPP_PAP_AUTHENTICATE_ACK) - { - - /* Determine if this peer requires authentication. */ - if (ppp_ptr -> nx_ppp_pap_verify_login) - { - - /* Yes, we require PAP verification so move to the request wait state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE; - } - else - { - - /* Otherwise, we have completed the PAP authentication. Move to the completed - state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - } - - /* Was a timeout received? */ - else if (code == NX_PPP_PAP_AUTHENTICATE_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the PAP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_PAP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Generate a new PAP login request and send to the peer. */ - _nx_ppp_pap_authentication_request(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter PAP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; - } -#endif - - break; - } - - case NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE: - { - - /* In this state, this peer must send an authenticate request. There is no - authentication required by the peer. */ - if ((code == NX_PPP_PAP_AUTHENTICATE_REQUEST) && (packet_ptr)) - { - - /* Determine if the login information is valid. */ - valid = _nx_ppp_pap_login_valid(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_TRUE) - { - - /* Send an ACK message. */ - _nx_ppp_pap_authentication_ack(ppp_ptr); - - /* No authentication is required by peer, so we can move into PAP completed state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - else - { - - /* Send NAK to tell peer the authentication failed. */ - _nx_ppp_pap_authentication_nak(ppp_ptr); - - /* No state change, just stay here! */ - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; - } -#endif - break; - } - - default: -#ifndef NX_PPP_DISABLE_INFO - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_pap_state_machine_unhandled_requests++; - } -#endif - break; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_authentication_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends an authentication request message */ -/* the peer. The peer will then either ACK or NAK the request. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* (nx_ppp_pap_generate_login) Pickup name and password */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_pap_state_machine_update PPP state machine update */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_pap_authentication_request(NX_PPP *ppp_ptr) -{ - -UINT length, password_length, i, j; -UCHAR name[NX_PPP_NAME_SIZE + 1]; -UCHAR password[NX_PPP_PASSWORD_SIZE + 1]; -UINT status; -NX_PACKET *packet_ptr; - - - /* Initialize name and password. */ - name[0] = 0; - password[0] = 0; - - /* Determine if there is a login name/password generation routine. */ - if (ppp_ptr -> nx_ppp_pap_generate_login) - { - - /* Get the name and password */ - ppp_ptr -> nx_ppp_pap_generate_login((CHAR *) name, (CHAR *) password); - } - - /* Allocate a packet for the PPP PAP response packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Calculate the size of the name and password. */ - if (_nx_utility_string_length_check((CHAR *)name, &length, NX_PPP_NAME_SIZE) || - _nx_utility_string_length_check((CHAR *)password, &password_length, NX_PPP_PASSWORD_SIZE)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 1 + password_length + 1 + 6)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Set PAP authentication request, ID, and length. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; /* ID */ - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) (((length) + 1 + (password_length) + 1 + 4) >> 8); - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) (((length) + 1 + (password_length) + 1 + 4) & 0xFF); - - /* Store the PAP name. */ - packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR)(length & 0xFF); - for (i = 0; i < length; i++) - { - - /* Store byte of name. */ - packet_ptr -> nx_packet_prepend_ptr[i+7] = name[i]; - } - - /* Store PAP password. */ - packet_ptr -> nx_packet_prepend_ptr[i+7] = (password_length & 0xFF); - for (j = 0; j < password_length; j++) - { - - /* Store byte of name. */ - packet_ptr -> nx_packet_prepend_ptr[j+i+8] = password[j]; - } - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = (length) + 1 + (password_length) + 1 + 4 + 2; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of PAP frames sent. */ - ppp_ptr -> nx_ppp_pap_frames_sent++; - - /* Increment the authentication requests sent counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_requests_sent++; -#endif - - /* Send the PAP request. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_login_valid PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function validates the login information supplied by the */ -/* peer. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to PAP packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Valid login */ -/* NX_FALSE Invalid login */ -/* */ -/* CALLS */ -/* */ -/* (nx_ppp_pap_verify_login) Verify name and password */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_pap_state_machine_update PAP state machine update */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_pap_login_valid(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR length, password_length, i, j; -UCHAR name[NX_PPP_NAME_SIZE + 1]; -UCHAR password[NX_PPP_PASSWORD_SIZE + 1]; -UINT status; - - - /* Get the name length. */ - length = packet_ptr -> nx_packet_prepend_ptr[6]; - - /* Check for valid packet length. */ - if ((ULONG)(length + 7) > packet_ptr -> nx_packet_length) - { - return(NX_FALSE); - } - - /* Determine if the length is greater than the name size. */ - if (length > NX_PPP_NAME_SIZE) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - return(NX_FALSE); - } - - /* Get the name. */ - for(i = 0; i < length; i++) - { - - /* Get a character of the name. */ - name[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; - } - - /* Null terminate the name. */ - name[i] = 0; - - /* Get length of password. */ - password_length = packet_ptr -> nx_packet_prepend_ptr[i+7]; - - /* Check for valid packet length. */ - if ((ULONG)(password_length + i + 8) > packet_ptr -> nx_packet_length) - { - return(NX_FALSE); - } - - /* Determine if the length is greater than the password size. */ - if (password_length > NX_PPP_PASSWORD_SIZE) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - return(NX_FALSE); - } - - /* Get the password. */ - for(j = 0; j < password_length; j++) - { - - /* Get a character of the password. */ - password[j] = packet_ptr -> nx_packet_prepend_ptr[j+i+8]; - } - - /* Null terminate the password. */ - password[j] = 0; - - /* Determine if there is an authentication routine. */ - if (ppp_ptr -> nx_ppp_pap_verify_login) - { - - /* Call the user supplied PAP authentication routine. */ - status = ppp_ptr -> nx_ppp_pap_verify_login((CHAR *) name, (CHAR *) password); - - /* Check to see if it is valid. */ - if (status) - { - - /* Return NX_FALSE, which indicates the password is invalid. */ - return (NX_FALSE); - } - } - - /* Return NX_TRUE. */ - return(NX_TRUE); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_authentication_ack PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends an authentication ACK message to */ -/* the peer in response to the peer's authentication request. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_pap_state_machine_update PPP state machine update */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_pap_authentication_ack(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP PAP response packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build the PAP ACK response message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_ACK; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = 5; - packet_ptr -> nx_packet_prepend_ptr[6] = 0; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 7; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - /* Set the authenticated flag to true. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of PAP frames sent. */ - ppp_ptr -> nx_ppp_pap_frames_sent++; - - /* Increment the number of authentication ACKs sent counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_acks_sent++; -#endif - - /* Send the ACK message out. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_authentication_nak PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends an authentication NAK message to */ -/* the peer in response to the peer's authentication request. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_pap_state_machine_update PPP state machine update */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_pap_authentication_nak(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the PPP PAP response packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build the PAP ACK response message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_PAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_PAP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_PAP_AUTHENTICATE_NAK; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0; - packet_ptr -> nx_packet_prepend_ptr[5] = 5; - packet_ptr -> nx_packet_prepend_ptr[6] = 0; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 7; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of PAP frames sent. */ - ppp_ptr -> nx_ppp_pap_frames_sent++; - - /* Increment the authentication NAKs sent counter. */ - ppp_ptr -> nx_ppp_pap_authenticate_naks_sent++; -#endif - - /* Send the authentication NAK message out. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - -#endif - - -#ifndef NX_PPP_DISABLE_CHAP -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_state_machine_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes events and state changes in the PPP CHAP */ -/* state machine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr CHAP packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_chap_challenge_send Send CHAP challenge to peer */ -/* _nx_ppp_chap_challenge_respond Respond to challenge from peer*/ -/* _nx_ppp_chap_challenge_validate Validate challenge response */ -/* from peer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_process Receive PPP packet processing */ -/* _nx_ppp_timeout PPP timeout */ -/* _nx_ppp_thread_entry PPP processing thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_chap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR code; -UINT valid; - - - /* Determine if a packet is present. If so, derive the event from the packet. */ - if (packet_ptr) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of CHAP frames received. */ - ppp_ptr -> nx_ppp_chap_frames_received++; -#endif - - /* Pickup the type of received CHAP code. */ - code = packet_ptr -> nx_packet_prepend_ptr[2]; - - /* Remember receive id. */ - ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Check the incoming code. */ - if ((code < NX_PPP_CHAP_CHALLENGE_REQUEST) || (code > NX_PPP_CHAP_CHALLENGE_FAILURE)) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; - - /* Increment the number of unknown CHAP requests received. */ - ppp_ptr -> nx_ppp_chap_unknown_requests_received++; -#endif - return; - } - } - else - { - - /* Set the code to timeout. */ - code = NX_PPP_CHAP_CHALLENGE_TIMEOUT; - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Update receive counters. */ - switch (code) - { - - case NX_PPP_CHAP_CHALLENGE_REQUEST: - - /* Increment the number of CHAP challenge requests received. */ - ppp_ptr -> nx_ppp_chap_challenge_requests_received++; - break; - - case NX_PPP_CHAP_CHALLENGE_RESPONSE: - - /* Increment the number of CHAP challenge responses received. */ - ppp_ptr -> nx_ppp_chap_challenge_responses_received++; - break; - - case NX_PPP_CHAP_CHALLENGE_SUCCESS: - - /* Increment the number of CHAP challenge successful notifications received. */ - ppp_ptr -> nx_ppp_chap_challenge_successes_received++; - break; - - case NX_PPP_CHAP_CHALLENGE_FAILURE: - - /* Increment the number of CHAP challenge failures received. */ - ppp_ptr -> nx_ppp_chap_challenge_failures_received++; - break; - - case NX_PPP_CHAP_CHALLENGE_TIMEOUT: - - - /* Determine if we are in the initial state. If so, this really isn't a timeout. */ - if (ppp_ptr -> nx_ppp_chap_state != NX_PPP_CHAP_START_STATE) - { - - /* Increment the number of CHAP timeouts received. */ - ppp_ptr -> nx_ppp_chap_state_machine_timeouts++; - } - break; - } -#endif - - /* Process relative to the current state. */ - switch (ppp_ptr -> nx_ppp_chap_state) - { - /* Starting state. */ - case NX_PPP_CHAP_START_STATE: - { - - /* Determine if we need to challenge the peer. */ - if (ppp_ptr -> nx_ppp_verify_authentication_protocol) - { - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send(ppp_ptr); - - /* Move to the challenge request sent state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE; - } - else if (ppp_ptr -> nx_ppp_generate_authentication_protocol) - { - - /* Move to the challenge wait state, since the peer must challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE; - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE: - { - - /* In this state, this peer has sent a challenge request and is waiting for - response from the peer. */ - if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) - { - - /* Generate a challenge response and send it to the peer. */ - _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); - - /* Move to the sent both challenge and response sent state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE; - } - - else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) - { - - /* Determine if the challenge response is valid. Note this function all sends the Success or - Failure to the peer. */ - valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_TRUE) - { - - /* Does the peer need to perform an initial challenge? */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol) - { - - /* Move to the challenge wait state, since the peer must challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE; - } - else - { - - /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - } - else - { - - /* Determine if there is an application NAK callback. */ - if (ppp_ptr -> nx_ppp_nak_authentication_notify) - { - - /* Yes, call the application's authentication NAK notify callback function. */ - (ppp_ptr -> nx_ppp_nak_authentication_notify)(); - } - - /* Enter into a failed state since challenge failed. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } - - /* Was a timeout received? */ - else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the CHAP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter CHAP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE: - { - - /* In this state, this peer has sent a challenge request and a challenge response and is waiting for - response from the peer. */ - if (code == NX_PPP_CHAP_CHALLENGE_SUCCESS) - { - - /* Move to the challenge sent received response state, since the original challenge is still pending. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE; - } - - else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) - { - - /* Move to the failed state since our response failed to satisfy the peer's challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - - else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) - { - - /* Determine if the challenge response is valid. Note this function all sends the Success or - Failure to the peer. */ - valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_TRUE) - { - - /* Does the peer need to perform an initial challenge? */ - if (ppp_ptr -> nx_ppp_generate_authentication_protocol) - { - - /* Move to the challenge wait state, since the peer must challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE; - } - else - { - - /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - } - else - { - - /* Enter into a failed state since challenge failed. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } - - /* Was a timeout received? */ - else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the CHAP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter CHAP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE: - { - - /* In this state, we have already successfully responded to a challenge from the peer - but are still waiting for the initial reply from the peer to our challenge request. */ - if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) - { - - /* Determine if the challenge response is valid. Note this function all sends the Success or - Failure to the peer. */ - valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_TRUE) - { - - /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - else - { - - /* Enter into a failed state since challenge failed. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } - - /* Was a timeout received? */ - else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the CHAP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter CHAP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE: - { - - /* In this state we only need the challenge from peer, either this peer doesn't challenge or - the initial challenge has already successfully completed. */ - if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) - { - - /* Generate a challenge response and send it to the peer. */ - _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); - - /* Move to the wait for challenge response state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE; - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE: - { - - /* In this state, this peer has sent a challenge response and is waiting for - response from the peer. */ - if (code == NX_PPP_CHAP_CHALLENGE_SUCCESS) - { - - /* Since the peer does not need to challenge, the initial CHAP protocol is complete. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; - - /* Mark the PPP instance as authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) - { - - /* Move to the failed state since our response failed to satisfy the peer's challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_COMPLETED_STATE: - { - - /* In this state the initial challenge(s) have been processed... This state is used to field - additional challenges during the life of the link. */ - if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) - { - - /* Generate a challenge response and send it to the peer. */ - _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); - - /* Stay in this state. */ - } - else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) - { - - /* Move to the failed state since our response failed to satisfy the peer's challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_CHAP_COMPLETED_NEW_STATE: - { - - /* In this state the new challenge(s) is issued... */ - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send (ppp_ptr); - - /* Move to the new challenge request sent state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE; - break; - } - - case NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE: - { - - /* In this state the initial challenge(s) have been processed... This state is used to field - additional challenges during the life of the link. */ - if ((code == NX_PPP_CHAP_CHALLENGE_REQUEST) && (packet_ptr)) - { - - /* Generate a challenge response and send it to the peer. */ - _nx_ppp_chap_challenge_respond(ppp_ptr, packet_ptr); - - /* Stay in this state. */ - } - - else if (code == NX_PPP_CHAP_CHALLENGE_FAILURE) - { - - /* Determine if there is an application NAK callback. */ - if (ppp_ptr -> nx_ppp_nak_authentication_notify) - { - - /* Yes, call the application's authentication NAK notify callback function. */ - (ppp_ptr -> nx_ppp_nak_authentication_notify)(); - } - - /* Move to the failed state since our response failed to satisfy the peer's challenge. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Mark the PPP instance as not authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - - else if ((code == NX_PPP_CHAP_CHALLENGE_RESPONSE) && (packet_ptr)) - { - - /* Determine if the challenge response is valid. Note this function all sends the Success or - Failure to the peer. */ - valid = _nx_ppp_chap_challenge_validate(ppp_ptr, packet_ptr); - - /* Is the login valid? */ - if (valid == NX_FALSE) - { - - /* No: Determine if there is an application NAK callback. */ - if (ppp_ptr -> nx_ppp_nak_authentication_notify) - { - - /* Yes, call the application's authentication NAK notify callback function. */ - (ppp_ptr -> nx_ppp_nak_authentication_notify)(); - } - - /* Enter into a failed state since challenge failed. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Mark the PPP instance as not authenticated. */ - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - else - { - - /* Simply move back to the completed state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_COMPLETED_STATE; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - } - /* Was a timeout received? */ - else if (code == NX_PPP_CHAP_CHALLENGE_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the CHAP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_CHAP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send challenge request to peer. */ - _nx_ppp_chap_challenge_send (ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter CHAP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_CHALLENGE_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_chap_state_machine_unhandled_requests++; - } -#endif - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_challenge_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a CHAP challenge to the peer. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* (nx_ppp_chap_get_challenge_values) Get values for challenge */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_chap_challenge_send(NX_PPP *ppp_ptr) -{ - -UCHAR id; -UINT length, length1, i, j; -NX_PACKET *packet_ptr; -UINT status; - - - /* Determine if there is a challenge generation routine. */ - if (ppp_ptr -> nx_ppp_chap_get_challenge_values) - { - - /* Yes, get the challenge values. */ - ppp_ptr -> nx_ppp_chap_get_challenge_values(ppp_ptr -> nx_ppp_chap_random_value, - (CHAR *) &id, ppp_ptr -> nx_ppp_chap_challenger_name); - } - else - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* An error was detected, simply return. */ - return; - } - - /* Allocate a packet for the PPP CHAP challenge packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Calculate the lengths of the challenger name and random value. */ - if (_nx_utility_string_length_check(ppp_ptr -> nx_ppp_chap_challenger_name, &length1, NX_PPP_NAME_SIZE) || - _nx_utility_string_length_check(ppp_ptr -> nx_ppp_chap_random_value, &length, NX_PPP_VALUE_SIZE)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 1 + length1 + 6)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Build CHAP challenge message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ - - /* Setup the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) ((((UINT) length) + 1 + ((UINT) length1) + 4) >> 8); - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) ((((UINT) length) + 1 + ((UINT) length1) + 4) & 0xFF); - - /* Store the CHAP random value. */ - packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR)length; - for (i = 0; i < length; i++) - { - - /* Store byte of name. */ - packet_ptr -> nx_packet_prepend_ptr[i+7] = (UCHAR)(ppp_ptr -> nx_ppp_chap_random_value[i]); - } - - /* Store CHAP challenge name. */ - for (j = 0; j < length1; j++) - { - - /* Store byte of name. */ - packet_ptr -> nx_packet_prepend_ptr[j+i+7] = (UCHAR)(ppp_ptr -> nx_ppp_chap_challenger_name[j]); - } - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = ((UINT) length) + 1 + ((UINT) length1) + 4 + 2; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of CHAP frames sent. */ - ppp_ptr -> nx_ppp_chap_frames_sent++; - - /* Increment the number of CHAP challenge requests. */ - ppp_ptr -> nx_ppp_chap_challenge_requests_sent++; -#endif - - /* Send challenge message. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_challenge_respond PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the CHAP challenge request from the peer. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to CHAP challenge */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* (nx_ppp_chap_get_responder_values) Get responder values for reply*/ -/* _nx_ppp_hash_generator Generate MD5 hash */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_chap_challenge_respond(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR name[NX_PPP_NAME_SIZE + 1], secret[NX_PPP_NAME_SIZE + 1]; -UCHAR value[NX_PPP_VALUE_SIZE + 1], hvalue[NX_PPP_HASHED_VALUE_SIZE + 1]; -UCHAR id; -UINT length, length1, i, j; -NX_PACKET *response_packet_ptr; -UINT status; -UINT name_length; - - - /* Pickup the id and length. */ - id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Pickup the length. */ - length = (UINT) packet_ptr -> nx_packet_prepend_ptr[4]; - length1 = (UINT) packet_ptr -> nx_packet_prepend_ptr[5]; - length1 = (length << 8) | (length1) ; - - /* Check for valid packet length. */ - if ((length1 + 2) > packet_ptr -> nx_packet_length) - { - return; - } - - /* Pickup the length of the random value. */ - length = (UINT) packet_ptr -> nx_packet_prepend_ptr[6]; - - /* Check for valid packet length. */ - if ((length == 0) || ((ULONG)(length + 7) > packet_ptr -> nx_packet_length)) - { - return; - } - - /* Determine if the length is greater than the destination. */ - name_length = length1 - length - 5; - if ((length > NX_PPP_VALUE_SIZE) || - (name_length > NX_PPP_NAME_SIZE)) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - return; - } - - /* Pickup the random value. */ - for(i = 0; i < length; i++) - { - - /* Pickup a byte of the random value. */ - value[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; - } - - /* Now pickup the challenge name. */ - for(j = 0; j < name_length; j++) - { - - /* Pickup a byte of the challenger name. */ - name[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+7]; - } - - /* Null terminate it. */ - name[j] = 0; - - /* Determine if there is a challenge get responder values routine. */ - if (ppp_ptr -> nx_ppp_chap_get_responder_values) - { - - /* Get name and password for this server */ - ppp_ptr -> nx_ppp_chap_get_responder_values((CHAR*) name, (CHAR *) name, (CHAR *) secret); - } - else - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Generate hash value. */ - _nx_ppp_hash_generator(hvalue, id, secret, value, length); - - /* Allocate a packet for the PPP CHAP response packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &response_packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Calculate length of the name */ - for(length = 0; name[length]; length++); - - /* Check if out of boundary. */ - if ((UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + NX_PPP_HASHED_VALUE_SIZE + 7)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Build CHAP challenge response message. */ - response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; - response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_RESPONSE; - response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ - - /* Setup the length. */ - response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) ((((UINT) length) + NX_PPP_HASHED_VALUE_SIZE + 5) >> 8); - response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) ((((UINT) length) + NX_PPP_HASHED_VALUE_SIZE + 5) & 0xFF); - - /* Set the length of the hashed response value. */ - response_packet_ptr -> nx_packet_prepend_ptr[6] = (UCHAR) NX_PPP_HASHED_VALUE_SIZE; - - /* Loop to insert the hashed value. */ - for(i = 0; i < NX_PPP_HASHED_VALUE_SIZE; i++) - { - - /* Copy one byte of the hashed value. */ - response_packet_ptr -> nx_packet_prepend_ptr[i+7] = hvalue[i]; - } - - /* Loop to insert the name. */ - for(j = 0; j < length; j++) - { - - /* Copy one byte of the name. */ - response_packet_ptr -> nx_packet_prepend_ptr[i+j+7] = name[j]; - } - - /* Setup the append pointer and the packet length. */ - response_packet_ptr -> nx_packet_length = length + NX_PPP_HASHED_VALUE_SIZE + 5 + 2; - response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of CHAP frames sent. */ - ppp_ptr -> nx_ppp_chap_frames_sent++; - - /* Increment the number of CHAP responses sent. */ - ppp_ptr -> nx_ppp_chap_challenge_responses_sent++; -#endif - - /* Transmit response message. */ - _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_challenge_validate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function validates the CHAP response from the peer. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to CHAP challenge */ -/* */ -/* OUTPUT */ -/* */ -/* status NX_TRUE - valid login */ -/* NX_FALSE - invalid login */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* (nx_ppp_chap_get_verification_values) Get verification values */ -/* _nx_ppp_hash_generator Generate MD5 hash */ -/* _nx_ppp_packet_transmit Send PAP response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_chap_state_machine_update Update CHAP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_chap_challenge_validate(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR name[NX_PPP_NAME_SIZE + 1], secret[NX_PPP_NAME_SIZE + 1]; -UCHAR hvalue[NX_PPP_HASHED_VALUE_SIZE + 1]; -UCHAR hvalue1[NX_PPP_HASHED_VALUE_SIZE + 1]; -UCHAR id; -UINT length, length1, i, j; -NX_PACKET *response_packet_ptr; -UINT status; -UINT name_length; - - - /* Pickup the id and length. */ - id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Pickup the length. */ - length = (UINT) packet_ptr -> nx_packet_prepend_ptr[4]; - length1 = (UINT) packet_ptr -> nx_packet_prepend_ptr[5]; - length1 = (length << 8) | (length1) ; - - /* Check for valid packet length. */ - if ((length1 + 2) > packet_ptr -> nx_packet_length) - { - return(NX_FALSE); - } - - /* Pickup the length of the hashed value. */ - length = (UINT) packet_ptr -> nx_packet_prepend_ptr[6]; - - /* Check for valid packet length. */ - if ((length == 0) || ((ULONG)(length + 7) > packet_ptr -> nx_packet_length)) - { - return(NX_FALSE); - } - - /* Determine if the length is greater than the destination. */ - name_length = length1 - length - 5; - if ((length > NX_PPP_HASHED_VALUE_SIZE) || - (name_length > NX_PPP_NAME_SIZE)) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* Return false in case of internal error. */ - return(NX_FALSE); - } - - /* Pickup the hashed value. */ - for(i = 0; i < length; i++) - { - - /* Pickup one byte of the hashed value. */ - hvalue[i] = packet_ptr -> nx_packet_prepend_ptr[i+7]; - } - - /* Pickup the name. */ - for(j = 0; j < name_length; j++) - { - - /* Pickup one byte of the hashed value. */ - name[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+7]; - } - - /* Null terminate the name. */ - name[j] = 0; - - /* Determine if there is a challenge get verification values routine. */ - if (ppp_ptr -> nx_ppp_chap_get_verification_values) - { - - /* Get name and password for this server */ - ppp_ptr -> nx_ppp_chap_get_verification_values(ppp_ptr -> nx_ppp_chap_challenger_name, (CHAR *) name, (CHAR *) secret); - } - else - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* Return false in case of internal error. */ - return(NX_FALSE); - } - - /* Generate hash value. */ - _nx_ppp_hash_generator(hvalue1, id, secret, (UCHAR *) ppp_ptr -> nx_ppp_chap_random_value, 0); - - /* Compare the computed hash value with the hash value received. */ - for(i = 0; i < NX_PPP_HASHED_VALUE_SIZE; i++) - { - - /* Are the hash values equal? */ - if (hvalue[i] != hvalue1[i]) - { - /* No, get out of the loop. */ - break; - } - } - - - /* Allocate a packet for the PPP CHAP response packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &response_packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* Return false in case of internal error. */ - return(NX_FALSE); - } - - /* Determine if challenge was successful. */ - if (i == NX_PPP_HASHED_VALUE_SIZE) - { - - /* Build CHAP ACK message. */ - response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; - response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_SUCCESS; - response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ - - /* Setup the length. */ - response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) 0; - response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) 4; - - /* Setup the append pointer and the packet length. */ - response_packet_ptr -> nx_packet_length = 6; - response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of CHAP frames sent. */ - ppp_ptr -> nx_ppp_chap_frames_sent++; - - /* Increment the number of CHAP success notifications sent. */ - ppp_ptr -> nx_ppp_chap_challenge_successes_sent++; -#endif - - /* Transmit the message. */ - _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); - - /* Return true to indicate the response was valid. */ - return(NX_TRUE); - } - else - { - - /* Build CHAP NAK message. */ - response_packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_CHAP_PROTOCOL & 0xFF00) >> 8; - response_packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_CHAP_PROTOCOL & 0xFF; - response_packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_CHAP_CHALLENGE_FAILURE; - response_packet_ptr -> nx_packet_prepend_ptr[3] = id; /* ID */ - - /* Setup the length. */ - response_packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR) 0; - response_packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR) 4; - - /* Setup the append pointer and the packet length. */ - response_packet_ptr -> nx_packet_length = 6; - response_packet_ptr -> nx_packet_append_ptr = response_packet_ptr -> nx_packet_prepend_ptr + response_packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of CHAP frames sent. */ - ppp_ptr -> nx_ppp_chap_frames_sent++; - - /* Increment the number of CHAP failure notifications sent. */ - ppp_ptr -> nx_ppp_chap_challenge_failures_sent++; -#endif - - /* Transmit the message. */ - _nx_ppp_packet_transmit(ppp_ptr, response_packet_ptr); - - /* Return false to indicate the response was invalid. */ - return(NX_FALSE); - } -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_state_machine_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes events and state changes in the PPP IPCP */ -/* state machine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_ipcp_configure_check Check configuration info */ -/* _nx_ppp_ipcp_configure_request_send Send configuration request */ -/* _nx_ppp_ipcp_response_extract Extract info from response */ -/* _nx_ppp_ipcp_response_send Send response */ -/* _nx_ppp_ipcp_terminate_send Send terminate */ -/* _nx_ppp_ipcp_terminate_ack_send Send terminate ack */ -/* nx_ip_interface_address_set Set interface IP address */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_process Receive PPP packet processing */ -/* _nx_ppp_timeout PPP timeout */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UINT acceptable_configuration; -UCHAR good_data[NX_PPP_OPTION_MESSAGE_LENGTH]; -UCHAR code; - - - /* Determine if a packet is present. If so, derive the event from the packet. */ - if (packet_ptr) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IPCP frames received. */ - ppp_ptr -> nx_ppp_ipcp_frames_received++; -#endif - - /* Pickup the type of received IPCP code. */ - code = packet_ptr -> nx_packet_prepend_ptr[2]; - - /* Remember receive id. */ - ppp_ptr -> nx_ppp_receive_id = packet_ptr -> nx_packet_prepend_ptr[3]; - - /* Is the code supported by PPP? */ - if ((code < NX_PPP_IPCP_CONFIGURE_REQUEST) || - (code > NX_PPP_IPCP_TERMINATE_ACK)) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of internal errors. */ - ppp_ptr -> nx_ppp_internal_errors++; - - /* Increment the number of unhandled requests. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; -#endif - return; - } - } - else - { - - /* Set the code to timeout to indicate a timeout has occurred. */ - code = NX_PPP_IPCP_TIMEOUT; - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the corresponding request counter. */ - switch (code) - { - - case NX_PPP_IPCP_CONFIGURE_REQUEST: - - /* Increment the number of IPCP configure requests received. */ - ppp_ptr -> nx_ppp_ipcp_configure_requests_received++; - break; - - case NX_PPP_IPCP_CONFIGURE_ACK: - - /* Increment the number of IPCP configure ACKs received. */ - ppp_ptr -> nx_ppp_ipcp_configure_acks_received++; - break; - - case NX_PPP_IPCP_CONFIGURE_NAK: - - /* Increment the number of IPCP configure NAKs received. */ - ppp_ptr -> nx_ppp_ipcp_configure_naks_received++; - break; - - case NX_PPP_IPCP_CONFIGURE_REJECT: - - /* Increment the number of IPCP configure rejects received. */ - ppp_ptr -> nx_ppp_ipcp_configure_rejects_received++; - break; - - case NX_PPP_IPCP_TERMINATE_REQUEST: - - /* Increment the number of IPCP terminate requests received. */ - ppp_ptr -> nx_ppp_ipcp_terminate_requests_received++; - break; - - case NX_PPP_IPCP_TERMINATE_ACK: - - /* Increment the number of IPCP terminate ACKs received. */ - ppp_ptr -> nx_ppp_ipcp_terminate_acks_received++; - break; - - case NX_PPP_IPCP_TIMEOUT: - - /* Determine if we are in the initial state. If so, this really isn't a timeout. */ - if (ppp_ptr -> nx_ppp_ipcp_state != NX_PPP_IPCP_START_STATE) - { - - /* Increment the number of IPCP state machine timeouts. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_timeouts++; - } - break; - } -#endif - - /* Process relative to the current state. */ - switch (ppp_ptr -> nx_ppp_ipcp_state) - { - - case NX_PPP_IPCP_START_STATE: - { - - /* Initial IPCP state. */ - - /* Initialize the NAK and rejected list. */ -#ifndef NX_PPP_DNS_OPTION_DISABLE - ppp_ptr -> nx_ppp_naked_list[0] = 0; - ppp_ptr -> nx_ppp_naked_list[1] = 0; -#else - ppp_ptr -> nx_ppp_naked_list[0] = 1; - ppp_ptr -> nx_ppp_naked_list[1] = 1; -#endif - - ppp_ptr -> nx_ppp_peer_naked_list[0] = 0; - ppp_ptr -> nx_ppp_rejected_list[0] = 0; - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - - /* Move into the request sent state. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE; - break; - } - - case NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE: - { - - /* In this state, we have sent a configuration request but had not received an ACK - or a configuration request from the peer. */ - - /* Process relative to the incoming code. */ - if (code == NX_PPP_IPCP_CONFIGURE_ACK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* The peer has ACKed our configuration request. Move to the - configure request ACKed state. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE; - - /* Turn off the timeout for the configuration request. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - else if (code == NX_PPP_IPCP_CONFIGURE_REJECT) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Set the NAK option list, just to indicate to the configure request that - the IPCP request without DNS option is what we want. */ - ppp_ptr -> nx_ppp_naked_list[0] = 1; - - /* Send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - - else if ((code == NX_PPP_IPCP_CONFIGURE_NAK) && (packet_ptr)) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Extract the information from response... looking for IP address and possibly DNS server IP address. */ - _nx_ppp_ipcp_response_extract(ppp_ptr, packet_ptr); - - /* Send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - - else if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - - /* The peer has sent a configuration request. */ - - /* Check configuration information. */ - acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, - ppp_ptr -> nx_ppp_rejected_list, - good_data); - - /* Check for acceptable configuration. */ - if (acceptable_configuration == NX_TRUE) - { - - /* Yes, send an ack. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); - - /* Move to the state where the peer's configuration has been ACKed. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE; - } - else - { - - /* Otherwise, configuration is unacceptable, send a nak. */ - - /* Check rejected list. */ - if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) - { - - /* Yes, there are rejected options so send a configure reject. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, - &ppp_ptr -> nx_ppp_rejected_list[1], - ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); - - } - else if (ppp_ptr -> nx_ppp_peer_naked_list[0] != 0) - { - - /* Yes, there are naked options so send a new request. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, - &ppp_ptr -> nx_ppp_peer_naked_list[1], - ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); - - } - } - } - else if (code == NX_PPP_IPCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the IPCP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_IPCP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Timeout, send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter IPCP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE: - { - - /* In this state, we have received the ACK for our configuration request, but have not yet - received a configuration request from the peer. */ - - /* Process relative to the incoming code. */ - if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - - /* The peer has sent a configuration request. */ - - /* Check configuration information. */ - acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list, good_data); - - /* Check for acceptable configuration. */ - if (acceptable_configuration == NX_TRUE) - { - - /* Yes, send an ack. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); - - /* Move to the state where the peer's configuration has been ACKed. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_COMPLETED_STATE; - - /* Set the IP address for the specific interface from the configuration. */ - nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, - IP_ADDRESS(ppp_ptr -> nx_ppp_ipcp_local_ip[0], - ppp_ptr -> nx_ppp_ipcp_local_ip[1], - ppp_ptr -> nx_ppp_ipcp_local_ip[2], - ppp_ptr -> nx_ppp_ipcp_local_ip[3]), - 0xffffffff); - - /* Set gateway address. */ - (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_address = (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_address; - (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_interface = ppp_ptr -> nx_ppp_interface_ptr; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - else - { - - /* Otherwise, configuration is unacceptable, send a NAK. */ - - /* Check rejected list. */ - if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) - { - - /* Yes, there are rejected options so send a new request. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, &ppp_ptr -> nx_ppp_rejected_list[1], ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); - } - else if (ppp_ptr -> nx_ppp_naked_list[0] != 0) - { - - /* Yes, there are naked options so send a new request. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, &ppp_ptr -> nx_ppp_peer_naked_list[1], ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE: - { - - /* In this state, we have sent our configuration request, but haven't received an ACK. We have also received - a peer configuration request and have ACKed that request. */ - - /* Process relative to the incoming code. */ - if (code == NX_PPP_IPCP_CONFIGURE_ACK) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* The peer has ACKed our configuration request. Move to the - IPCP completed state. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_COMPLETED_STATE; - - /* Turn off the timeout for the configuration request. */ - ppp_ptr -> nx_ppp_timeout = 0; - - /* Set the IP address for the specific interface from the configuration. */ - nx_ip_interface_address_set(ppp_ptr -> nx_ppp_ip_ptr, ppp_ptr -> nx_ppp_interface_index, - IP_ADDRESS(ppp_ptr -> nx_ppp_ipcp_local_ip[0], ppp_ptr -> nx_ppp_ipcp_local_ip[1], - ppp_ptr -> nx_ppp_ipcp_local_ip[2], ppp_ptr -> nx_ppp_ipcp_local_ip[3]), - 0xffffffff); - - /* Set gateway address. */ - (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_address = (ppp_ptr -> nx_ppp_interface_ptr) -> nx_interface_ip_address; - (ppp_ptr -> nx_ppp_ip_ptr) -> nx_ip_gateway_interface = ppp_ptr -> nx_ppp_interface_ptr; - - /* Turn off the timeout. */ - ppp_ptr -> nx_ppp_timeout = 0; - } - - else if (code == NX_PPP_IPCP_CONFIGURE_REJECT) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Set the NAK option list, just to indicate to the configure request that - the IPCP request without DNS option is what we want. */ - ppp_ptr -> nx_ppp_naked_list[0] = 1; - - /* Send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - - else if ((code == NX_PPP_IPCP_CONFIGURE_NAK) && (packet_ptr)) - { - - /* Determine if the ID matches our last transmit ID. If not, just discard it. */ - if (ppp_ptr -> nx_ppp_transmit_id != ppp_ptr -> nx_ppp_receive_id) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the invalid frame ID counter. */ - ppp_ptr -> nx_ppp_invalid_frame_id++; -#endif - - /* Discard this request by simply returning! */ - return; - } - - /* Extract the information from response... looking for IP address and possibly DNS server IP address. */ - _nx_ppp_ipcp_response_extract(ppp_ptr, packet_ptr); - - /* Send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - - else if (code == NX_PPP_IPCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Timeout, send the configuration request. */ - _nx_ppp_ipcp_configure_request_send(ppp_ptr, ppp_ptr -> nx_ppp_naked_list); - } - -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_IPCP_COMPLETED_STATE: - { - - /* IPCP is up and operational at this point. */ - - /* Process relative to incoming code. */ - if (code == NX_PPP_IPCP_TERMINATE_REQUEST) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* ACK the terminate request. */ - _nx_ppp_ipcp_terminate_ack_send(ppp_ptr); - - /* Send terminate request. */ - _nx_ppp_ipcp_terminate_send(ppp_ptr); - - /* Move into the IPCP stopping state. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_STOPPING_STATE; - } - else if ((code == NX_PPP_IPCP_CONFIGURE_REQUEST) && (packet_ptr)) - { - /* The peer has sent a configuration request. */ - - /* Check configuration information. */ - acceptable_configuration = _nx_ppp_ipcp_configure_check(ppp_ptr, packet_ptr, ppp_ptr -> nx_ppp_peer_naked_list, ppp_ptr -> nx_ppp_rejected_list, good_data); - - /* Check for acceptable configuration. */ - if (acceptable_configuration == NX_TRUE) - { - - /* Yes, send an ack. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_ACK, good_data, good_data[1], packet_ptr); - } - else - { - /* Otherwise, configuration is unacceptable, send a nak. */ - - /* Check rejected list. */ - if (ppp_ptr -> nx_ppp_rejected_list[0] != 0) - { - - /* Yes, there are rejected options so send a new request. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_REJECT, &ppp_ptr -> nx_ppp_rejected_list[1], ppp_ptr -> nx_ppp_rejected_list[0], NX_NULL); - } - else if (ppp_ptr -> nx_ppp_peer_naked_list[0] != 0) - { - - /* Yes, there are naked options so send a new request. */ - _nx_ppp_ipcp_response_send(ppp_ptr, NX_PPP_IPCP_CONFIGURE_NAK, &ppp_ptr -> nx_ppp_peer_naked_list[1], ppp_ptr -> nx_ppp_peer_naked_list[0], NX_NULL); - } - } - } - -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - case NX_PPP_LCP_STOPPING_STATE: - { - - /* We received a terminate request from the other side and just need to get the ACK. */ - - /* Process relative to incoming code. */ - if (code == NX_PPP_IPCP_TERMINATE_ACK) - { - - /* Move the the stopped state. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_STOPPED_STATE; - } - else if (code == NX_PPP_IPCP_TIMEOUT) - { - - /* Increment the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter++; - - /* Determine if the IPCP retry counter has been exceeded. */ - if (ppp_ptr -> nx_ppp_protocol_retry_counter < NX_PPP_MAX_IPCP_PROTOCOL_RETRIES) - { - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Send terminate request. */ - _nx_ppp_ipcp_terminate_send(ppp_ptr); - } - else - { - - /* Retry counter exceeded. */ - - /* Enter IPCP failed state. PPP must be stopped and started to try again. */ - ppp_ptr -> nx_ppp_ipcp_state = NX_PPP_IPCP_FAILED_STATE; - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } -#ifndef NX_PPP_DISABLE_INFO - else - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - - default: - { - -#ifndef NX_PPP_DISABLE_INFO - { - - /* Increment the number of unhandled state machine events. */ - ppp_ptr -> nx_ppp_ipcp_state_machine_unhandled_requests++; - } -#endif - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_configure_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the IPCP message options. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr IPCP packet pointer */ -/* naked_list NAKed option list */ -/* rejected_list Rejected option list */ -/* good_data Good options */ -/* */ -/* OUTPUT */ -/* */ -/* status */ -/* NX_TRUE 1 indicates no errors, address obtained */ -/* NX_FALSE 0 indicates an error or unknown option or address */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_ipcp_configure_check(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list, UCHAR *good_data) -{ - -UINT length, ip_stat, status; -UINT i, w, m; -UINT nak_length = 0; -UINT rej_length = 0; -UINT good_index = 0; -UINT nak_index = 0; -UINT rej_index = 0; -UCHAR option; - - - /* Extract the length. */ - length = ((UINT)(packet_ptr -> nx_packet_prepend_ptr[4] << 8) | (UINT)packet_ptr -> nx_packet_prepend_ptr[5]); - - /* Subtract 4 to remove the code, id, and length bytes from the length. */ - length = length - 4; - - /* Check for valid packet length. */ - if ((length + 6) > packet_ptr -> nx_packet_length) - { - return(NX_FALSE); - } - - /* Initialize the rejected and naked lists. */ - rejected_list[0] = naked_list[0] = good_data[0] = 0; - - /* Loop to process the IPCP configuration options. */ - for(w = 0, rej_index = 1, status = 1, nak_index = 1; (w + 2) <= length;) - { - - UINT opt_length; - - /* Pickup the IPCP option. */ - option = packet_ptr -> nx_packet_prepend_ptr[w + 6]; - - /* Pickup the IPCP option length. */ - opt_length = (UINT) packet_ptr -> nx_packet_prepend_ptr[w + 7]; - - /* Determine if the length is valid. */ - if ((opt_length < 2) || (opt_length > (length - w))) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal overflow counter. */ - ppp_ptr -> nx_ppp_packet_overflow++; -#endif - - /* Something is wrong, just get out of the loop! */ - return(status); - } - - /* Adjust the option length. */ - opt_length -= 2; - - /* Process relative to the option. */ - switch (option) - { - - case NX_PPP_IP_ADDRESS_OPTION: - { - - /* Check if out of boundary. */ - if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) - return(NX_FALSE); - - /* IP address option. */ - good_data[good_index++] = NX_PPP_IP_ADDRESS_OPTION; - good_data[good_index++] = 6; - - ip_stat = 0; - for(i = 0; i < 4; i++) - { - - /* Pick up each byte of the IP address. */ - good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; - - /* OR in the IP address bytes to make it easy to see if we got something. */ - ip_stat |= good_data[i + good_index]; - } - - /* Adjust the main index. */ - w += (opt_length + good_index); - - /* Check if we really have an IP address. */ - if (!ip_stat) - { - - /* Copy default IP address. */ - for(i = 0; i < 4; i++) - { - good_data[i + good_index] = ppp_ptr -> nx_ppp_ipcp_peer_ip[i]; - } - - /* Setup NAK list so we can get the IP address hint. */ - for(i = 0; i < 6; i++) - { - naked_list[nak_index++] = good_data[i]; - } - - nak_length = nak_index - 1; - - /* Clear status. */ - status = 0; - } - else - { - - /* We did get an IP address for the peer. Remember it! */ - for (i = 0; i < 4; i++) - { - - /* Remember each byte of peer's IP address. */ - ppp_ptr -> nx_ppp_ipcp_peer_ip[i] = good_data[i + good_index]; - } - } - - good_index += opt_length; - - break; - } - - case NX_PPP_IP_COMPRESSION_OPTION: - { - - /* IP Compression Option. Since this is the receiver telling us what they - support it is not important to us since we don't support compression. */ - - /* Simply adjust the main index into the option list. */ - w += (opt_length + 2); /* skip */ - break; - } - - case NX_PPP_DNS_SERVER_OPTION: - { - - /* Check if out of boundary. */ - if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* Only request a hint if we don't have already have a dns address . */ - good_data[good_index++] = NX_PPP_DNS_SERVER_OPTION; - good_data[good_index++] = 6; - ip_stat = 0; - for(i = 0; i < 4; i++) - { - - /* Pick up each byte of the primary DNS address. */ - good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; - - /* Or in the IP address bytes to make it easy to see if we got something. */ - ip_stat |= good_data[i + good_index]; - } - - /* Adjust the main index. */ - w += (opt_length + 2); - - /* Check if we really have an primary DNS address. */ - if (!ip_stat) - { - - - /* Update the number of retries on secondary address requests. */ - ppp_ptr -> nx_ppp_dns_address_retries++; - - /* Check if we have reached the limit on retries. */ - if (ppp_ptr -> nx_ppp_dns_address_retries >= NX_PPP_DNS_ADDRESS_MAX_RETRIES) - { - /* We have. Return successful result and let IPCP complete. */ - break; - } - - /* Copy default DNS IP address. */ - good_data[good_index] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address >> 24); - good_data[good_index + 1] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 16) & 0xff); - good_data[good_index + 2] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 8) & 0xff); - good_data[good_index + 3]= (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address & 0xff); - - /* Setup NAK list so we can get the DNS IP address hint. */ - for(i = 0; i < 6; i++) - { - naked_list[nak_index++] = good_data[good_index + i - 2]; - } - - /* Clear status. */ - status = 0; - - /* Update the size of the nak and reject data. */ - nak_length = nak_index - 1; - } - else - { - - /* Copy good IP address. */ - ppp_ptr -> nx_ppp_primary_dns_address = ((ULONG)good_data[good_index] << 24) & 0xFF000000; - ppp_ptr -> nx_ppp_primary_dns_address |= (good_data[good_index + 1] << 16) & 0x00FF0000; - ppp_ptr -> nx_ppp_primary_dns_address |= (good_data[good_index + 2] << 8) & 0x0000FF00; - ppp_ptr -> nx_ppp_primary_dns_address |= good_data[good_index + 3] & 0x000000FF; - } - - good_index += opt_length; - - break; - } - - case NX_PPP_DNS_SECONDARY_SERVER_OPTION: - { - - /* Check if out of boundary. */ - if ((good_index + 6) > NX_PPP_OPTION_MESSAGE_LENGTH) - break; - - /* Only request a hint if we don't have already have a dns address . */ - good_data[good_index++] = NX_PPP_DNS_SECONDARY_SERVER_OPTION; - good_data[good_index++] = 6; - ip_stat = 0; - for(i = 0; i < 4; i++) - { - - /* Pick up each byte of the secondary DNS address. */ - good_data[i + good_index] = packet_ptr -> nx_packet_prepend_ptr[w + i + 8]; - - /* Or in the IP address bytes to make it easy to see if we got something. */ - ip_stat |= good_data[i + good_index]; - } - - /* Adjust the main index. */ - w += (opt_length + 2); - - /* Check if we really have an primary DNS address. */ - if (!ip_stat) - { - - /* Update the number of retries on primary address requests. */ - ppp_ptr -> nx_ppp_secondary_dns_address_retries++; - - /* Check if we have reached the limit on retries. */ - if (ppp_ptr -> nx_ppp_secondary_dns_address_retries >= NX_PPP_DNS_ADDRESS_MAX_RETRIES) - { - /* We have. Return successful result and let IPCP complete. */ - break; - } - - /* Copy the primary DNS IP address from the packet data. */ - good_data[good_index] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address >> 24); - good_data[good_index + 1] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 16) & 0xff); - good_data[good_index + 2] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 8) & 0xff); - good_data[good_index + 3]= (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address & 0xff); - - /* Setup NAK list so we can get the DNS IP address hint. */ - for(i = 0; i < 6; i++) - { - naked_list[nak_index++] = good_data[good_index + i - 2]; - } - - /* Clear status. */ - status = 0; - - /* Update the size of the nak and reject data. */ - nak_length = nak_index - 1; - } - - else - { - - /* Copy good IP address. */ - ppp_ptr -> nx_ppp_secondary_dns_address = ((ULONG)good_data[good_index] << 24) & 0xFF000000; - ppp_ptr -> nx_ppp_secondary_dns_address |= (good_data[good_index + 1] << 16) & 0x00FF0000; - ppp_ptr -> nx_ppp_secondary_dns_address |= (good_data[good_index + 2] << 8) & 0x0000FF00; - ppp_ptr -> nx_ppp_secondary_dns_address |= good_data[good_index + 3] & 0x000000FF; - } - - good_index += opt_length; - - break; - } - - default: - { - - /* All other options get NAKed. */ - status = 0; - - /* Determine if the option will fit. */ - if ((rej_index + opt_length + 2) >= NX_PPP_OPTION_MESSAGE_LENGTH) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal overflow counter. */ - ppp_ptr -> nx_ppp_packet_overflow++; -#endif - - /* Return status. */ - return(status); - } - - /* Place the option in the rejected list. */ - rejected_list[rej_index++] = option; - rejected_list[rej_index++] = (UCHAR)(opt_length + 2); - - /* Loop to copy the rest of the options into the rejected list. */ - for (m = 0; m < opt_length; m++) - { - - /* Copy option byte into the rejected option list. */ - rejected_list[rej_index] = packet_ptr -> nx_packet_prepend_ptr[w + m + 8]; - rej_index++; - } - - rej_length = rej_index - 1; - - /* Adjust the main index into the option list. */ - w += (opt_length + 2); /* skip */ - break; - } - } - } - - /* Setup the length in the naked and rejected lists. */ - naked_list[0] = (UCHAR)nak_length; - rejected_list[0] = (UCHAR)rej_length; - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_configure_request_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a configure request message and sends it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* negotiate_list List of options to negotiate */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send IPCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_configure_request_send(NX_PPP *ppp_ptr, UCHAR *negotiate_list) -{ - -UINT status, i; -NX_PACKET *packet_ptr; -UINT index; - - - /* Allocate a packet for the IPCP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Clear the packet memory.*/ - memset(packet_ptr -> nx_packet_prepend_ptr, 0, (UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr)); - - /* Adjust the transmit ID. */ - ppp_ptr -> nx_ppp_transmit_id++; - - /* Build IPCP request message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_CONFIGURE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; - packet_ptr -> nx_packet_prepend_ptr[5] = 0x0A; /* Size of the IPCP data */ - packet_ptr -> nx_packet_prepend_ptr[6] = 0x03; - packet_ptr -> nx_packet_prepend_ptr[7] = 0x06; - - /* Load up the default IP address. */ - for(i = 0; i < 4; i++) - { - - /* Copy byte of IP address. */ - packet_ptr -> nx_packet_prepend_ptr[i+8] = ppp_ptr -> nx_ppp_ipcp_local_ip[i]; - } - - index = i + 8; - - /* Determine if we want the DNS option ... */ - if (negotiate_list[0] == 0) - { - - /* Yes (because it is not obvious from the code style), let's try to get the DNS server. */ - - /* Update the IPCP length for DNS address. */ - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(packet_ptr -> nx_packet_prepend_ptr[5] + 6); - - /* Add the option for retrieving the DNS server as well. */ - packet_ptr -> nx_packet_prepend_ptr[index] = NX_PPP_DNS_SERVER_OPTION; - packet_ptr -> nx_packet_prepend_ptr[index+1] = 0x06; - packet_ptr -> nx_packet_prepend_ptr[index+2] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address >> 24); - packet_ptr -> nx_packet_prepend_ptr[index+3] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 16) & 0xff); - packet_ptr -> nx_packet_prepend_ptr[index+4] = (UCHAR) ((ppp_ptr -> nx_ppp_primary_dns_address >> 8) & 0xff); - packet_ptr -> nx_packet_prepend_ptr[index+5] = (UCHAR) (ppp_ptr -> nx_ppp_primary_dns_address & 0xff); - index += 6; - - /* Also check for a secondary DNS address request. */ - if (negotiate_list[1] == 0) - { - - /* Update the IPCP length for secondary DNS address. */ - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(packet_ptr -> nx_packet_prepend_ptr[5] + 6); - - /* Add the option for retrieving the DNS server as well. */ - packet_ptr -> nx_packet_prepend_ptr[index] = NX_PPP_DNS_SECONDARY_SERVER_OPTION; - packet_ptr -> nx_packet_prepend_ptr[index+1] = 0x06; - packet_ptr -> nx_packet_prepend_ptr[index+2] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address >> 24); - packet_ptr -> nx_packet_prepend_ptr[index+3] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 16) & 0xff); - packet_ptr -> nx_packet_prepend_ptr[index+4] = (UCHAR) ((ppp_ptr -> nx_ppp_secondary_dns_address >> 8) & 0xff); - packet_ptr -> nx_packet_prepend_ptr[index+5] = (UCHAR) (ppp_ptr -> nx_ppp_secondary_dns_address & 0xff); - index += 6; - } - } - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = index; - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IPCP frames sent. */ - ppp_ptr -> nx_ppp_ipcp_frames_sent++; - - /* Increment the number of IPCP configure requests sent. */ - ppp_ptr -> nx_ppp_ipcp_configure_requests_sent++; -#endif - - /* Send IPCP configure request packet. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_response_extract PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts information from the IPCP response */ -/* message. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* packet_ptr Pointer to IPCP packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_response_extract(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UINT i, j; -ULONG length; - - - - /* Search for IP address and DNS address in response. */ - - /* Setup the packet length. */ - length = (((ULONG) packet_ptr -> nx_packet_prepend_ptr[4]) << 8) | ((ULONG) packet_ptr -> nx_packet_prepend_ptr[5]); - - /* Subtract the request type, id, and length. */ - if (length >= 4) - length = length - 4; - else - length = 0; - - /* Check for valid packet length. */ - if ((length + 6) > packet_ptr -> nx_packet_length) - { - return; - } - - /* Loop to parse the options to look for primary DNS address. */ - i = 6; - while (length) - { - - /* Subtract the length. */ - if (length >= ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1])) - length = length - ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1]); - else - length = 0; - - /* Check for the IP address. */ - if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_IP_ADDRESS_OPTION) - { - - - /* Copy the IP address bytes into the PPP storage. */ - for(j = 0; j < 4; j++) - { - - /* Copy a byte of the IP address. */ - ppp_ptr -> nx_ppp_ipcp_local_ip[j] = packet_ptr -> nx_packet_prepend_ptr[i+j+2]; - } - } - - /* Check for the primary DNS option. */ - else if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_DNS_SERVER_OPTION) - { - - /* Yes, we have a primary DNS address. */ - - /* Let's copy it into the PPP structure in case we need it later. */ - ppp_ptr -> nx_ppp_primary_dns_address = ((((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+2]) << 24) | - (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+3]) << 16) | - (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+4]) << 8) | - ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+5])); - - } - - /* Check for the primary DNS option. */ - else if (packet_ptr -> nx_packet_prepend_ptr[i] == NX_PPP_DNS_SECONDARY_SERVER_OPTION) - { - - /* Yes, we have a secondary DNS address. */ - - /* Let's copy it into the PPP structure in case we need it later. */ - ppp_ptr -> nx_ppp_secondary_dns_address = ((((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+2]) << 24) | - (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+3]) << 16) | - (((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+4]) << 8) | - ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+5])); - - - /* Break out of the loop. */ - break; - } - - /* Otherwise move to the next option. */ - if (length >= ((ULONG) packet_ptr -> nx_packet_prepend_ptr[i+1])) - { - - /* Yes, there is another option. */ - - /* Position to the next option. */ - i = i + (((UINT) packet_ptr -> nx_packet_prepend_ptr[i+1])); - } - else - { - - /* Make sure the length is 0. */ - length = 0; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends an IPCP response message. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* type ACK or NAK selection */ -/* data Previous IPCP message */ -/* length Length of previous IPCP msg */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send frame */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_response_send(NX_PPP *ppp_ptr, UCHAR type, UCHAR *data, UCHAR length, NX_PACKET *cfg_packet_ptr) -{ - -UINT status, i; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the IPCP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Determine if an ACK is requested. */ - if (type == NX_PPP_IPCP_CONFIGURE_ACK) - { - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(cfg_packet_ptr -> nx_packet_length)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Yes, an ACK is requested. Simply copy the config packet into the new packet and change - the type. */ - for (i = 0; i < cfg_packet_ptr -> nx_packet_length; i++) - { - - /* Determine if the copy exceeds the payload. */ - if (&packet_ptr -> nx_packet_prepend_ptr[i] >= packet_ptr -> nx_packet_data_end) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Simply return. */ - return; - } - - /* Copy one byte. */ - packet_ptr -> nx_packet_prepend_ptr[i] = cfg_packet_ptr -> nx_packet_prepend_ptr[i]; - } - - /* Adjust the type of the new packet to represent an ACK. */ - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_CONFIGURE_ACK; - - /* Adjust the length and append pointers of the packet. */ - packet_ptr -> nx_packet_length = cfg_packet_ptr -> nx_packet_length; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - } - else - { - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(length + 6)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Build IPCP response message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = type; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(length + 4); - - /* Load up the default IP address. */ - for(i = 0; i < length; i++) - { - - /* Copy byte of IP address. */ - packet_ptr -> nx_packet_prepend_ptr[i+6] = data[i]; - } - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = (UCHAR)(length + 4 + 2); - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IPCP frames sent. */ - ppp_ptr -> nx_ppp_ipcp_frames_sent++; - - /* Increment counters based on type of response. */ - if (type == NX_PPP_IPCP_CONFIGURE_ACK) - { - - /* Increment the number of IPCP configure ACKs sent. */ - ppp_ptr -> nx_ppp_ipcp_configure_acks_sent++; - } - else if (type == NX_PPP_IPCP_CONFIGURE_NAK) - { - - /* Increment the number of IPCP configure NAKs sent. */ - ppp_ptr -> nx_ppp_ipcp_configure_naks_sent++; - } - else if (type == NX_PPP_IPCP_CONFIGURE_REJECT) - { - - /* Increment the number of IPCP configure rejects sent. */ - ppp_ptr -> nx_ppp_ipcp_configure_rejects_sent++; - } -#endif - - /* Send IPCP response. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_terminate_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a terminate request message and sends */ -/* it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send AHDLC packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_terminate_send(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the IPCP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build IPCP terminate message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_TERMINATE_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; - packet_ptr -> nx_packet_prepend_ptr[5] = 0x04; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 6; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IPCP frames sent. */ - ppp_ptr -> nx_ppp_ipcp_frames_sent++; - - /* Increment the number of IPCP terminate sent. */ - ppp_ptr -> nx_ppp_ipcp_terminate_requests_sent++; -#endif - - /* Send IPCP terminate packet. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ipcp_terminate_ack_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds a terminate ACK request message and sends */ -/* it out. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send AHDLC packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_ipcp_state_machine_update IPCP state machine processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_ipcp_terminate_ack_send(NX_PPP *ppp_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Allocate a packet for the IPCP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* An error was detected, simply return a NULL pointer. */ - return; - } - - /* Build IPCP terminate ACK message. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_IPCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_IPCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_IPCP_TERMINATE_ACK; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_receive_id; - packet_ptr -> nx_packet_prepend_ptr[4] = 0x00; - packet_ptr -> nx_packet_prepend_ptr[5] = 0x04; - - /* Setup the append pointer and the packet length. */ - packet_ptr -> nx_packet_length = 6; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of IPCP frames sent. */ - ppp_ptr -> nx_ppp_ipcp_frames_sent++; - - /* Increment the number of IPCP terminate ACKs sent. */ - ppp_ptr -> nx_ppp_ipcp_terminate_acks_sent++; -#endif - - /* Send IPCP terminate ACK packet. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_packet_transmit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a CRC to the current transmit buffer and then */ -/* sends the buffer via the user supplied byte output routine. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* packet_ptr Pointer to PPP packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* [_nx_ppp_debug_log_capture] Put send frame in debug log */ -/* _nx_ppp_crc_append Add PPP CRC */ -/* (nx_ppp_byte_send) User supplied byte send */ -/* nx_packet_transmit_release Release the transmit packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_process_deferred_ip_packet_send Process deferred IP packet */ -/* _nx_ppp_lcp_code_reject Send LCP code reject message */ -/* _nx_ppp_lcp_configure_reply_send Send LCP configure reply */ -/* _nx_ppp_lcp_configure_request_send Send LCP configure request */ -/* _nx_ppp_lcp_terminate_ack_send Send LCP terminate ACK */ -/* _nx_ppp_lcp_terminate_request_send Send LCP terminate request */ -/* _nx_ppp_pap_authentication_request PAP authentication request */ -/* _nx_ppp_pap_authentication_ack PAP authentication ACK */ -/* _nx_ppp_pap_authentication_nak PAP authentication NAK */ -/* _nx_ppp_chap_challenge_send CHAP challenge send */ -/* _nx_ppp_chap_challenge_respond CHAP challenge respond */ -/* _nx_ppp_chap_challenge_validate CHAP challenge validate */ -/* _nx_ppp_ipcp_configure_request_send Send IPCP configure request */ -/* _nx_ppp_ipcp_response_send Send IPCP response */ -/* _nx_ppp_ipcp_terminate_send Send IPCP terminate */ -/* _nx_ppp_ipcp_terminate_ack_send Send IPCP terminate ACK */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_packet_transmit(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -NX_PACKET *current_packet_ptr; -UINT i; -UCHAR byte; -UCHAR *buffer_ptr; -UCHAR hdlc[3] = {0x7e, 0xff, 0x03}; -UCHAR crc[2]; -#ifdef NX_PPP_PPPOE_ENABLE -UINT release_packet = NX_TRUE; -#endif /* NX_PPP_PPPOE_ENABLE */ - - -#ifdef NX_PPP_DEBUG_LOG_ENABLE - - /* Place the outgoing frame into the optional PPP debug log. */ - _nx_ppp_debug_log_capture(ppp_ptr, 'S', packet_ptr); -#endif - - /* Check for send function. */ - if (ppp_ptr -> nx_ppp_byte_send) - { - - /* Step1. Send the HDLC bytes. */ - for (i = 0; i < 3; i++) - { - - /* Pickup the byte. */ - byte = hdlc[i]; - - /* Determine if it needs an escape sequence. */ - if ((byte < ((UCHAR) 0x20)) || ((byte == ((UCHAR) 0x7e)) && (i != 0)) || (byte == ((UCHAR) 0x7d))) - { - - /* Yes, this byte needs an escape sequence. */ - - /* Change the byte. */ - byte = byte ^ 0x20; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Send the escape sequence byte via the user supplied output routine. */ - ppp_ptr -> nx_ppp_byte_send(0x7d); - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Call user supplied byte output routine. */ - ppp_ptr -> nx_ppp_byte_send(byte); - } - - /* Step2. Send the data. */ - /* Initialize the current packet pointer to the packet pointer. */ - current_packet_ptr = packet_ptr; - - /* Setup the initial buffer pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Loop through the buffer to send each byte out. */ - for(i = 0; i < packet_ptr -> nx_packet_length; i++) - { - - /* Determine if we need to move to any additional packets. */ - if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Yes, we need to move to the next packet. */ - current_packet_ptr = current_packet_ptr -> nx_packet_next; - - /* Determine if there is a next packet. */ - if (current_packet_ptr == NX_NULL) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the internal error counter. */ - ppp_ptr -> nx_ppp_internal_errors++; -#endif - - /* Get out of the loop. */ - break; - } - - /* Otherwise setup new buffer pointer. */ - buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; -#else - break; - -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } - - /* Pickup the next byte to be sent. */ - byte = *buffer_ptr++; - - /* Determine if this byte needs an escape sequence. */ - if ((byte < ((UCHAR) 0x20)) || (byte == 0x7e) || (byte == 0x7d)) - { - - /* Yes, this byte needs an escape sequence. */ - - /* Change the byte. */ - byte = byte ^ 0x20; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Send the escape sequence byte via the user supplied output routine. */ - ppp_ptr -> nx_ppp_byte_send(0x7d); - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Call user supplied byte output routine. */ - ppp_ptr -> nx_ppp_byte_send(byte); - } - - /* Step3. Send CRC. */ - /* Place a CRC at the end of the transmit buffer. */ - _nx_ppp_crc_append(packet_ptr, crc); - - /* Now send the CRC and end-of-frame bytes. */ - for (i = 0; i < 2; i++) - { - - /* Pickup the byte. */ - byte = crc[i]; - - /* Determine if it needs an escape sequence. */ - if ((byte < ((UCHAR) 0x20)) || (byte == ((UCHAR) 0x7e)) || (byte == ((UCHAR) 0x7d))) - { - - /* Yes, this byte needs an escape sequence. */ - - /* Change the byte. */ - byte = byte ^ 0x20; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Send the escape sequence byte via the user supplied output routine. */ - ppp_ptr -> nx_ppp_byte_send(0x7d); - } - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of bytes sent. */ - ppp_ptr -> nx_ppp_bytes_sent++; -#endif - - /* Call user supplied byte output routine. */ - ppp_ptr -> nx_ppp_byte_send(byte); - } - - /* Step4. Finally, send an end-of-frame character. */ - ppp_ptr -> nx_ppp_byte_send((UCHAR) 0x7e); - } - -#ifdef NX_PPP_PPPOE_ENABLE - - /* Check the PPPoE packet send function. */ - if (ppp_ptr -> nx_ppp_packet_send) - { - - /* Send the packet out. */ - (ppp_ptr -> nx_ppp_packet_send)(packet_ptr); - - /* Update the flag since this packet should been released in PPPoE. */ - release_packet = NX_FALSE; - - } - - /* Check if need to release the packet. */ - if (release_packet == NX_TRUE) - { -#endif /* NX_PPP_PPPOE_ENABLE */ - - /* Remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - -#ifdef NX_PPP_PPPOE_ENABLE - } -#endif /* NX_PPP_PPPOE_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_check_crc PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the CRC of the AHDLC packet in the packet */ -/* payload. If the CRC is correct, the CRC is removed from the receive */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Address of PPP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_receive_packet_get Receive PPP packet processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_check_crc(NX_PACKET *packet_ptr) -{ - -NX_PACKET *current_packet_ptr; -UCHAR byte; -UCHAR *buffer_ptr; -USHORT i; -USHORT crc_value; - - - /* Set initial CRC value. */ - crc_value = 0xffff; - - /* Setup buffer pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 1; - - /* Setup the current packet pointer. */ - current_packet_ptr = packet_ptr; - - /* Loop to process the CRC for the receive buffer. */ - for(i = 1; i < (packet_ptr -> nx_packet_length - 1); i++) - { - - /* Determine if the buffer pointer is inside the current packet. */ - if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* We have exhausted this packet and must move to the next. */ - current_packet_ptr = current_packet_ptr -> nx_packet_next; - - /* Determine if there is a next packet. */ - if (current_packet_ptr == NX_NULL) - break; - - /* Otherwise, we have a valid next packet. Setup the buffer pointer - to the first byte in the next packet. */ - buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; -#else - break; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } - - /* Pickup character from buffer. */ - byte = *buffer_ptr++; - - /* Update the CRC. */ - crc_value = (( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ byte ]); - } - - /* At this point, the CRC should be 0xf0b8. */ - if (crc_value != 0xf0b8) - { - - /* CRC failed, not a valid PPP packet. */ - return(NX_PPP_BAD_PACKET); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_crc_append PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates and appends the two byte CRC to the */ -/* frame. It also adds the end of frame marker after the CRC. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to PPP packet */ -/* crc Destination for CRC */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_packet_transmit PPP packet transmit routine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_crc_append(NX_PACKET *packet_ptr, UCHAR crc[2]) -{ - -NX_PACKET *current_packet_ptr; -UCHAR *buffer_ptr; -UINT i; -USHORT crc_value; -UCHAR byte; -UCHAR address = 0xff; -UCHAR control = 0x03; - - - /* The FCS field is calculated over all bits of the Address, Control, - Protocol, Information and Padding fields, not including any start - and stop bits (asynchronous) nor any bits (synchronous) or octets - (asynchronous or synchronous) inserted for transparency. This - also does not include the Flag Sequences nor the FCS field itself. - RFC1662, Section3.1, Page6. */ - - /* Initialize CRC value. */ - crc_value = 0xffff; - - /* Step1. Calculate address and control. */ - crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ address ]; - crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ control ]; - - /* Step2. Calculate protocol, information and padding fiedls. */ - - /* Initialize the current packet pointer to the packet pointer. */ - current_packet_ptr = packet_ptr; - - /* Setup the initial buffer pointer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Loop to calculate CRC. */ - for(i = 0; i < packet_ptr -> nx_packet_length; i++) - { - - /* Determine if we need to move to any additional packets. */ - if (buffer_ptr >= current_packet_ptr -> nx_packet_append_ptr) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Yes, we need to move to the next packet. */ - current_packet_ptr = current_packet_ptr -> nx_packet_next; - - /* Determine if there is a next packet. */ - if (current_packet_ptr == NX_NULL) - { - - /* Get out of the loop. */ - break; - } - - /* Otherwise setup new buffer pointer. */ - buffer_ptr = current_packet_ptr -> nx_packet_prepend_ptr; -#else - break; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } - - /* Pickup the next byte to be sent. */ - byte = *buffer_ptr++; - - /* Update the CRC. */ - crc_value = ( crc_value >> 8 ) ^ _nx_ppp_crc_table[ ( crc_value & 0xFF ) ^ byte ]; - } - - /* Now complement the CRC value. */ - crc_value = crc_value ^ 0xffff; - - /* Store first byte of the CRC. */ - crc[0] = (UCHAR) (crc_value & 0xff); - - /* Store second byte of the CRC. */ - crc[1] = (UCHAR) ((crc_value >> 8) & 0xff); - - /* Return a successful completion. */ - return(NX_SUCCESS); -} - - -#ifdef NX_PPP_DEBUG_LOG_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_debug_log_capture PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the current frame into the circular debug */ -/* log. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP structure */ -/* packet_type Either a send or receive */ -/* packet_ptr Pointer to PPP packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_time_get Get time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_packet_transmit Transmit packet processing */ -/* _nx_ppp_thread_entry Receive thread processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_debug_log_capture(NX_PPP *ppp_ptr, UCHAR packet_type, NX_PACKET *packet_ptr) -{ - -UINT i; -ULONG time; -NX_PPP_DEBUG_ENTRY *entry_ptr; - - /* Check for a NULL pointer. */ - if (packet_ptr == NX_NULL) - return; - - /* Pickup current time. */ - time = tx_time_get(); - -#ifdef NX_PPP_DEBUG_LOG_PRINT_ENABLE - /* Print out the current time stamp. */ - printf("Time: %lu, ", time); - - /* Print out the PPP name. */ - printf("PPP Name: %s, ", ppp_ptr -> nx_ppp_name); - - /* Print out the current PPP state. */ - printf("PPP State: %u, ", ppp_ptr -> nx_ppp_state); - - /* Print out the current PPP LCP state. */ - printf("PPP LCP State: %u, ", ppp_ptr -> nx_ppp_lcp_state); - - /* Print out the current PPP PAP state. */ - printf("PPP PAP State: %u, ", ppp_ptr -> nx_ppp_pap_state); - - /* Print out the current PPP CHAP state. */ - printf("PPP CHAP State: %u, ", ppp_ptr -> nx_ppp_chap_state); - - /* Print out the current IPCP state. */ - printf("PPP IPCP State: %u, ", ppp_ptr -> nx_ppp_ipcp_state); - - /* Print out the authentication flag. */ - if (ppp_ptr -> nx_ppp_authenticated) - printf("Authenticated, "); - else - printf("Not Authenticated, "); - - /* Determine if the packet is a receive packet or a send packet. */ - if (packet_type == 'R') - printf("Received Packet Length: %lu, Packet: ", packet_ptr -> nx_packet_length); - else - printf("Send Packet Length: %lu, Packet: ", packet_ptr -> nx_packet_length); - - /* Dump out at least part of the packet payload. */ - for (i = 0; i < packet_ptr -> nx_packet_length; i++) - { - - /* Check for packet spanning multiple packets. */ - if ((packet_ptr -> nx_packet_prepend_ptr+i) >= packet_ptr -> nx_packet_append_ptr) - break; - - /* Check for maximum dump size. */ - if (i >= NX_PPP_DEBUG_FRAME_SIZE) - break; - - /* Print one character. */ - printf("%02x ", packet_ptr -> nx_packet_prepend_ptr[i]); - } - - printf("\n"); -#endif /* NX_PPP_DEBUG_LOG_PRINT_ENABLE */ - - /* Now load the internal PPP log. */ - - /* Setup the debug log entry pointer. */ - entry_ptr = &(ppp_ptr -> nx_ppp_debug_log[ppp_ptr -> nx_ppp_debug_log_oldest_index++]); - - /* Check for wrap-around of the index. */ - if (ppp_ptr -> nx_ppp_debug_log_oldest_index >= NX_PPP_DEBUG_LOG_SIZE) - ppp_ptr -> nx_ppp_debug_log_oldest_index = 0; - - /* Setup the debug log entries. */ - entry_ptr -> nx_ppp_debug_entry_time_stamp = time; - entry_ptr -> nx_ppp_debug_ppp_state = (UCHAR) ppp_ptr -> nx_ppp_state; - entry_ptr -> nx_ppp_debug_lcp_state = (UCHAR) ppp_ptr -> nx_ppp_lcp_state; - entry_ptr -> nx_ppp_debug_pap_state = (UCHAR) ppp_ptr -> nx_ppp_pap_state; - entry_ptr -> nx_ppp_debug_chap_state = (UCHAR) ppp_ptr -> nx_ppp_chap_state; - entry_ptr -> nx_ppp_debug_ipcp_state = (UCHAR) ppp_ptr -> nx_ppp_ipcp_state; - entry_ptr -> nx_ppp_debug_authenticated = ppp_ptr -> nx_ppp_authenticated; - entry_ptr -> nx_ppp_debug_frame_type = packet_type; - entry_ptr -> nx_ppp_debug_packet_length = packet_ptr -> nx_packet_length; - - /* Store at least part of the packet payload. */ - for (i = 0; i < packet_ptr -> nx_packet_length; i++) - { - - /* Check for packet spanning multiple packets. */ - if ((packet_ptr -> nx_packet_prepend_ptr+i) >= packet_ptr -> nx_packet_append_ptr) - break; - - /* Check for maximum dump size. */ - if (i >= NX_PPP_DEBUG_FRAME_SIZE) - break; - - /* Store one character. */ - entry_ptr -> nx_ppp_debug_frame[i] = packet_ptr -> nx_packet_prepend_ptr[i]; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_debug_log_capture_protocol PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function outputs the status of various protocols and timeouts */ -/* of the specified PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP structure */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_thread_entry PPP event processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_debug_log_capture_protocol(NX_PPP *ppp_ptr) -{ - - - /* Print out the PPP name. */ - printf("%s: ", ppp_ptr -> nx_ppp_name); - - /* Print out the current PPP state. */ - printf("State: %u, ", ppp_ptr -> nx_ppp_state); - - /* Print out the current PPP LCP state. */ - printf("LCP State: %u, ", ppp_ptr -> nx_ppp_lcp_state); - - /* Print out the current IPCP state. */ - printf("IPCP State: %u, ", ppp_ptr -> nx_ppp_ipcp_state); - - if ((ppp_ptr -> nx_ppp_chap_enabled) || (ppp_ptr -> nx_ppp_pap_enabled)) - { - - /* Print out the authentication flag. */ - if (ppp_ptr -> nx_ppp_authenticated) - printf("Authenticated, "); - else - { - - printf("Not Authenticated, "); - - /* Print out the current PPP PAP state. */ - printf("PAP State: %u, ", ppp_ptr -> nx_ppp_pap_state); - - /* Print out the current PPP CHAP state. */ - printf("CHAP State: %u, ", ppp_ptr -> nx_ppp_chap_state); - } - } - - /* Print out the current PPP LCP state. */ - printf("Time remaining: %lu, ", ppp_ptr -> nx_ppp_timeout); - printf("Timeouts: %lu, ", ppp_ptr -> nx_ppp_receive_timeouts); - printf("Protocol retries: %lu, ", ppp_ptr -> nx_ppp_protocol_retry_counter); - - printf("\n"); -} -#endif /* NX_PPP_DEBUG_LOG_ENABLE */ - - -#ifndef NX_PPP_DISABLE_CHAP -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_hash_generator PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the MD5 hash value for CHAP authentication */ -/* processing. The input challenge "rand_value" is a stream of octets,*/ -/* including 0x0, so the length option ensures the rand_value length is*/ -/* set correctly. */ -/* */ -/* If the caller is certain there is no 0x0 within the rand_value it */ -/* can send a zero length arguement and this function will compute the */ -/* rand_value length. */ -/* */ -/* INPUT */ -/* */ -/* hvalue Hash value return string */ -/* id PPP message ID */ -/* secret Secret input string */ -/* rand_value Random value input string */ -/* length Length of random string, */ -/* if zero, assume null */ -/* terminated */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_chap_challenge_respond CHAP challenge response */ -/* _nx_ppp_chap_challenge_validate CHAP validate response */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_hash_generator(unsigned char *hvalue, unsigned char id, - unsigned char *secret, unsigned char *rand_value, UINT length) -{ - -UINT slen, rlen; -NX_MD5 context; - - - /* Compute the length of the secret. */ - for(slen = 0; secret[slen]; slen++); - - /* Compute the length of the rand_value if no length is specified. */ - if(length==0) - { - for(rlen = 0; rand_value[rlen]; rlen++); - } - else - { - rlen = length; - } - - /* Initialize the MD5 digest calculation. */ - _nx_md5_initialize(&context); - - /* Update the digest. */ - _nx_md5_update(&context, &id, 1); - _nx_md5_update(&context, secret, slen); - _nx_md5_update(&context, rand_value, rlen); - - /* Finally, calculate the digest. */ - _nx_md5_digest_calculate(&context, hvalue); -} -#endif /* NX_PPP_DISABLE_CHAP */ - - -/* Define externally available API functions. */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_byte_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP byte receive */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* byte Newly received byte */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_byte_receive Actual PPP byte receive */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Call actual byte receive function. */ - status = _nx_ppp_byte_receive(ppp_ptr, byte); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_byte_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives a byte from the application (usually an */ -/* application ISR), buffers it, and notifies the PPP receive thread. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* byte Newly received byte */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Notify PPP receiving thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code (Including ISRs) */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Disable interrupts. */ - TX_DISABLE - - /* Check for no longer active PPP instance. */ - if (ppp_ptr -> nx_ppp_id != NX_PPP_ID) - { - - /* PPP is no longer active. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Return an error. */ - return(NX_PTR_ERROR); - } - - /* Check for a stopped PPP instance. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) - { - - /* Silently discard byte. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Return success. */ - return(NX_SUCCESS); - } - - /* Determine if there is enough room in the serial buffer. */ - if (ppp_ptr -> nx_ppp_serial_buffer_byte_count >= NX_PPP_SERIAL_BUFFER_SIZE) - { - -#ifndef NX_PPP_DISABLE_INFO - /* Increment the number of bytes dropped. */ - ppp_ptr -> nx_ppp_bytes_dropped++; -#endif - - /* Restore interrupts. */ - TX_RESTORE - - /* No, return an error. */ - return(NX_PPP_BUFFER_FULL); - } - - /* Otherwise, PPP is active and there is room in the buffer! */ - - /* Place the byte in the buffer. */ - ppp_ptr -> nx_ppp_serial_buffer[ppp_ptr -> nx_ppp_serial_buffer_write_index++] = byte; - - /* Check for a wrap-around of the serial buffer. */ - if (ppp_ptr -> nx_ppp_serial_buffer_write_index >= NX_PPP_SERIAL_BUFFER_SIZE) - { - - /* Yes, buffer wrap-around is present. Reset the write pointer to the beginning of the - buffer. */ - ppp_ptr -> nx_ppp_serial_buffer_write_index = 0; - } - - /* Increment the byte count. */ - ppp_ptr -> nx_ppp_serial_buffer_byte_count++; - -#ifndef NX_PPP_DISABLE_INFO - /* Increment the number of bytes received. */ - ppp_ptr -> nx_ppp_bytes_received++; -#endif - - /* Restore interrupts. */ - TX_RESTORE - - /* Determine if the PPP receive thread needs to be alerted. */ - if ((ppp_ptr -> nx_ppp_serial_buffer_byte_count >= NX_PPP_SERIAL_BUFFER_ALERT_THRESHOLD) || - (byte == 0x7e)) - { - - /* Yes, alert the receiving thread that a byte is available for processing. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_PACKET_RECEIVE, TX_OR); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP create instance */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* name Pointer to instance name */ -/* ip_ptr Pointer to IP instance */ -/* stack_memory_ptr Pointer to thread stack */ -/* stack_size Pointer to thread stack size */ -/* thread_priority Priority of thread(s) created */ -/* for PPP */ -/* pool_ptr Default packet pool pointer */ -/* ppp_non_ppp_packet_handler Non PPP packet handler */ -/* provided by the application */ -/* ppp_byte_send Byte output function provided */ -/* by the application */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_create Actual PPP create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, - VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, - NX_PACKET_POOL *pool_ptr, - void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), - void (*ppp_byte_send)(UCHAR byte)) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id == NX_PPP_ID) || - (ip_ptr == NX_NULL) || (stack_memory_ptr == NX_NULL) || (pool_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP create function. */ - status = _nx_ppp_create(ppp_ptr, name, ip_ptr, stack_memory_ptr, stack_size, thread_priority, - pool_ptr, ppp_non_ppp_packet_handler, ppp_byte_send); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a PPP instance for the specified IP. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* name Pointer to instance name */ -/* ip_ptr Pointer to IP instance */ -/* stack_memory_ptr Pointer to thread stack */ -/* stack_size Pointer to thread stack size */ -/* thread_priority Priority of thread(s) created */ -/* for PPP */ -/* pool_ptr Default packet pool pointer */ -/* ppp_non_ppp_packet_handler Non PPP packet handler */ -/* provided by the application */ -/* ppp_byte_send Byte output function provided */ -/* by the application */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_create Create PPP event flags group */ -/* tx_thread_create Create PPP helper thread */ -/* tx_time_get Get time for IDs */ -/* tx_timer_create Create PPP timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, - VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, - NX_PACKET_POOL *pool_ptr, - void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), - void (*ppp_byte_send)(UCHAR byte)) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_PPP *tail_ptr; - - - /* Check the supplied packet pool for minimum required payload length. */ - if (pool_ptr -> nx_packet_pool_payload_size < NX_PPP_MIN_PACKET_PAYLOAD) - { - return(NX_PPP_BAD_PACKET); - } - - /* Initialize the PPP control block to zero. */ - memset((void *) ppp_ptr, 0, sizeof(NX_PPP)); - - /* Save the PPP name. */ - ppp_ptr -> nx_ppp_name = name; - - /* Save the IP pointer. */ - ppp_ptr -> nx_ppp_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - ppp_ptr -> nx_ppp_packet_pool_ptr = pool_ptr; - - /* Save the byte output routine specified by the user. */ - ppp_ptr -> nx_ppp_byte_send = ppp_byte_send; - ppp_ptr -> nx_ppp_non_ppp_packet_handler = ppp_non_ppp_packet_handler; - - /* Setup the initial state. */ - ppp_ptr -> nx_ppp_state = NX_PPP_STOPPED; - - /* Setup the Maximum Receive Unit (MRU). */ - ppp_ptr -> nx_ppp_mru = NX_PPP_MRU; - - /* Setup receive and transmit IDs. */ - ppp_ptr -> nx_ppp_transmit_id = (UCHAR) tx_time_get(); - - /* Default the authenticated field to true. */ - ppp_ptr -> nx_ppp_authenticated = NX_TRUE; - - /* Create event flag group to control the PPP processing thread. */ - tx_event_flags_create(&(ppp_ptr -> nx_ppp_event), "PPP EVENTS") ; - - /* Create the PPP processing thread. Note that this thread does not run until the PPP driver is - initialized during the IP create. */ - tx_thread_create(&(ppp_ptr -> nx_ppp_thread), "PPP THREAD", _nx_ppp_thread_entry, (ULONG) ppp_ptr, - stack_memory_ptr, stack_size, thread_priority, thread_priority, NX_PPP_THREAD_TIME_SLICE, TX_DONT_START); - - /* Create the PPP timeout timer. */ - tx_timer_create(&(ppp_ptr -> nx_ppp_timer), "PPP TIMER", _nx_ppp_timer_entry, (ULONG) ppp_ptr, NX_PPP_BASE_TIMEOUT, NX_PPP_BASE_TIMEOUT, TX_NO_ACTIVATE); - - /* Otherwise, the PPP initialization was successful. Place the - PPP control block on the list of created PPP instances. */ - TX_DISABLE - - /* Load the PPP ID field in the PPP control block. */ - ppp_ptr -> nx_ppp_id = NX_PPP_ID; - - /* Place the new PPP control block on the list of created IPs. First, - check for an empty list. */ - if (_nx_ppp_created_ptr) - { - - /* Pickup tail pointer. */ - tail_ptr = _nx_ppp_created_ptr -> nx_ppp_created_previous; - - /* Place the new PPP control block in the list. */ - _nx_ppp_created_ptr -> nx_ppp_created_previous = ppp_ptr; - tail_ptr -> nx_ppp_created_next = ppp_ptr; - - /* Setup this PPP's created links. */ - ppp_ptr -> nx_ppp_created_previous = tail_ptr; - ppp_ptr -> nx_ppp_created_next = _nx_ppp_created_ptr; - } - else - { - - /* The created PPP list is empty. Add PPP control block to empty list. */ - _nx_ppp_created_ptr = ppp_ptr; - ppp_ptr -> nx_ppp_created_next = ppp_ptr; - ppp_ptr -> nx_ppp_created_previous = ppp_ptr; - } - - /* Increment the created PPP counter. */ - _nx_ppp_created_count++; - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP delete instance */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_delete Actual PPP delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_delete(NX_PPP *ppp_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP delete function. */ - status = _nx_ppp_delete(ppp_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a PPP instance for the specified IP. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_delete Delete PPP event flags group */ -/* tx_event_flags_set Set PPP event flag to stop PPP*/ -/* tx_thread_delete Create PPP helper threads */ -/* tx_thread_identify Identify current thread */ -/* tx_thread_sleep Sleep for a small time */ -/* tx_timer_deactivate Timer deactivate */ -/* tx_timer_delete Delete timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_delete(NX_PPP *ppp_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Determine if the caller is the PPP thread itself. This is not allowed since - a thread cannot delete itself in ThreadX. */ - if (&ppp_ptr -> nx_ppp_thread == tx_thread_identify()) - { - - /* Invalid caller of this routine, return an error! */ - return(NX_CALLER_ERROR); - } - - /* Set the event to close the PPP thread. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Now wait until the PPP thread goes to a closed state before proceeding with the delete. - This will give PPP the opportunity to properly release all packets being worked on. */ - while (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) - { - - /* Sleep for a tick. */ - tx_thread_sleep(1); - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Clear the PPP ID to show that it is no longer valid. */ - ppp_ptr -> nx_ppp_id = 0; - - /* Decrement the number of PPP instances created. */ - _nx_ppp_created_count--; - - /* See if the PPP instance is the only one on the list. */ - if (ppp_ptr == ppp_ptr -> nx_ppp_created_next) - { - - /* Only created PPP instance, just set the created list to NULL. */ - _nx_ppp_created_ptr = TX_NULL; - } - else - { - - /* Link-up the neighbors. */ - (ppp_ptr -> nx_ppp_created_next) -> nx_ppp_created_previous = - ppp_ptr -> nx_ppp_created_previous; - (ppp_ptr -> nx_ppp_created_previous) -> nx_ppp_created_next = - ppp_ptr -> nx_ppp_created_next; - - /* See if we have to update the created list head pointer. */ - if (_nx_ppp_created_ptr == ppp_ptr) - - /* Yes, move the head pointer to the next link. */ - _nx_ppp_created_ptr = ppp_ptr -> nx_ppp_created_next; - } - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Terminate the thread. */ - tx_thread_terminate(&(ppp_ptr -> nx_ppp_thread)); - - /* Delete the PPP thread. */ - tx_thread_delete(&(ppp_ptr -> nx_ppp_thread)); - - /* Deactivate the PPP timer. */ - tx_timer_deactivate(&(ppp_ptr -> nx_ppp_timer)); - - /* Delete the PPP timer. */ - tx_timer_delete(&(ppp_ptr -> nx_ppp_timer)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(ppp_ptr -> nx_ppp_event)); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_link_up_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP link up notify callback */ -/* notify set function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* ppp_link_up_callback Pointer to application */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_link_up_notify Actual PPP link up notify set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP link up notify set function. */ - status = _nx_ppp_link_up_notify(ppp_ptr, ppp_link_up_callback); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_link_up_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function registers an application callback for the link up */ -/* event. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* ppp_link_up_callback Pointer to application */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)) -{ - - /* Valid PPP pointer, now setup the notification callback. Note that supplying - a NULL for the callback will disable notification. */ - ppp_ptr -> nx_ppp_link_up_callback = ppp_link_up_callback; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_link_down_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP link down notify callback*/ -/* notify set function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* ppp_link_down_callback Pointer to application */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_link_down_notify Actual PPP link down notify */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP link down notify set function. */ - status = _nx_ppp_link_down_notify(ppp_ptr, ppp_link_down_callback); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_link_down_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function registers an application callback for the link down */ -/* event. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* ppp_link_down_callback Pointer to application */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)) -{ - - /* Valid PPP pointer, now setup the notification callback. Note that supplying - a NULL for the callback will disable notification. */ - ppp_ptr -> nx_ppp_link_down_callback = ppp_link_down_callback; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_pap_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP PAP enable */ -/* function call. */ -/* */ -/* Note: The first string lengths of name and password are limited by */ -/* internal buffer size. The second string of name and password are */ -/* NULL terminated. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* generate_login Pointer to login function */ -/* verify_login Pointer to verify function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_pap_enable Actual PPP PAP enable function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), - UINT (*verify_login)(CHAR *name, CHAR *password)) -{ - -UINT status; - - - /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) || - ((generate_login == NX_NULL) && (verify_login == NX_NULL))) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP PAP enable function. */ - status = _nx_ppp_pap_enable(ppp_ptr, generate_login, verify_login); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_pap_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables PAP for the specified PPP instance. */ -/* */ -/* Note: The first string lengths of name and password are limited by */ -/* internal buffer size. The second string of name and password are */ -/* NULL terminated. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* generate_login Pointer to application */ -/* function that generates */ -/* name and password for login */ -/* verify_login Pointer to application */ -/* function that verifies the */ -/* supplied name and password */ -/* are valid */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), - UINT (*verify_login)(CHAR *name, CHAR *password)) -{ - -#ifdef NX_PPP_DISABLE_PAP - - /* Return the non implemented error. */ - return(NX_NOT_IMPLEMENTED); - -#else - - /* Setup the PAP information. */ - if (generate_login) - { - - /* Setup login generation information. */ - ppp_ptr -> nx_ppp_pap_generate_login = generate_login; - - /* The authenticated flag is not cleared for the generate login, since the - peer may choose not to require PAP. */ - } - - /* Determine if the generate login is provided. */ - if (verify_login) - { - /* Setup login verification information. */ - ppp_ptr -> nx_ppp_pap_verify_login = verify_login; - ppp_ptr -> nx_ppp_verify_authentication_protocol = NX_PPP_PAP_PROTOCOL; - - /* Authentication is needed, clear the flag. */ - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - } - - /* Show that the PAP is enabled. */ - ppp_ptr -> nx_ppp_pap_enabled = NX_TRUE; - - /* Set the initial PAP state. */ - ppp_ptr -> nx_ppp_pap_state = NX_PPP_PAP_INITIAL_STATE; - - /* Return success. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_chap_challenge PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP CHAP challenge */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_chap_challenge Actual PPP CHAP challenge */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_chap_challenge(NX_PPP *ppp_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP CHAP challenge function. */ - status = _nx_ppp_chap_challenge(ppp_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_challenge PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function generates a CHAP challenge for the specified PPP */ -/* instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Notify PPP receiving thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_chap_challenge(NX_PPP *ppp_ptr) -{ - -#ifdef NX_PPP_DISABLE_CHAP - - /* Return the non implemented error. */ - return(NX_NOT_IMPLEMENTED); - -#else - - /* Determine if the CHAP of the PPP instance is enabled and able to challenge. */ - if ((ppp_ptr -> nx_ppp_chap_enabled) && - (ppp_ptr -> nx_ppp_chap_get_challenge_values) && - (ppp_ptr -> nx_ppp_chap_get_verification_values)) - { - - /* Check for the appropriate CHAP state. If the initial CHAP has not yet - completed, simply discard this request. */ - if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_COMPLETED_STATE) - { - - /* Yes, the CHAP protocol is in an open state so another challenge is legal. */ - - /* Initiate CHAP challenge by setting the appropriate event flag to wakeup the PPP thread. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_CHAP_CHALLENGE, TX_OR); - } - - /* Return successful completion. */ - return(NX_SUCCESS); - } - else - { - - /* CHAP is either not enabled or is setup only for CHAP response - not a challenge. Return an error! */ - return(NX_PPP_FAILURE); - } -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_chap_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP CHAP enable */ -/* function call. */ -/* */ -/* Note: The string lengths of rand_value, name, system and secret are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* get_challenge_values Pointer to application */ -/* function that retrieves */ -/* values required to make */ -/* a challenge */ -/* get_responder_values Pointer to application */ -/* function that retrieves */ -/* values required to respond */ -/* to a challenge */ -/* get_verification_values Pointer to application */ -/* function that retrieves */ -/* values required to verify */ -/* a challenge */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_chap_enable Actual PPP CHAP enable */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_chap_enable(NX_PPP *ppp_ptr, - UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), - UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), - UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)) -{ - -UINT status; - - - /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) || - ((get_challenge_values == NX_NULL) && (get_responder_values == NX_NULL) && (get_verification_values == NX_NULL))) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP CHAP enable function. */ - status = _nx_ppp_chap_enable(ppp_ptr, get_challenge_values, get_responder_values, get_verification_values); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_chap_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables CHAP for the specified PPP instance. */ -/* */ -/* Note: The string lengths of rand_value, name, system and secret are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* get_challenge_values Pointer to application */ -/* function that retrieves */ -/* values required to make */ -/* a challenge */ -/* get_responder_values Pointer to application */ -/* function that retrieves */ -/* values required to respond */ -/* to a challenge */ -/* get_verification_values Pointer to application */ -/* function that retrieves */ -/* values required to verify */ -/* a challenge response */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_chap_enable(NX_PPP *ppp_ptr, - UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), - UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), - UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)) -{ - -#ifdef NX_PPP_DISABLE_CHAP - - /* Return the non implemented error. */ - return(NX_NOT_IMPLEMENTED); - -#else - - /* Setup CHAP information. */ - if (get_responder_values) - { - - /* Setup challenge response callback. */ - ppp_ptr -> nx_ppp_chap_get_responder_values = get_responder_values; - - /* The authenticated flag is not cleared for the generate login, since the - peer may choose not to require CHAP. */ - } - - /* Determine if we are going to challenge the peer. */ - if ((get_challenge_values) && (get_verification_values)) - { - - /* Setup the CHAP information. */ - ppp_ptr -> nx_ppp_chap_get_challenge_values = get_challenge_values; - ppp_ptr -> nx_ppp_chap_get_verification_values = get_verification_values; - - /* Yes, we must generate a challenge. */ - ppp_ptr -> nx_ppp_verify_authentication_protocol = NX_PPP_CHAP_PROTOCOL; - ppp_ptr -> nx_ppp_authenticated = NX_FALSE; - } - - /* Show that the CHAP is enabled. */ - ppp_ptr -> nx_ppp_chap_enabled = NX_TRUE; - - /* Set the initial CHAP state. */ - ppp_ptr -> nx_ppp_chap_state = NX_PPP_CHAP_INITIAL_STATE; - - /* Return success. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_dns_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS address of the PPP */ -/* instance get function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* dns_address_ptr Destination for DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_dns_address_get Actual PPP DNS address get */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer... */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || - (dns_address_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP DNS address get function. */ - status = _nx_ppp_dns_address_get(ppp_ptr, dns_address_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_dns_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the DNS address of the PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* dns_address_ptr Destination for DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr) -{ - - /* Determine if the PPP instance is in an established state. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) - { - - if (ppp_ptr -> nx_ppp_primary_dns_address == 0x0) - { - return NX_PPP_ADDRESS_NOT_ESTABLISHED; - } - - /* Return the DNS address ptr. */ - *dns_address_ptr = ppp_ptr -> nx_ppp_primary_dns_address; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Set the DNS address to 0. */ - *dns_address_ptr = 0; - - /* The PPP connection has not yet been established. */ - return(NX_PPP_NOT_ESTABLISHED); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_dns_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the DNS address of the PPP */ -/* instance set function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* dns_address Primary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_dns_address_set Actual PPP DNS address set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address) -{ - -UINT status; - - /* Check for an invalid input pointer... */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for invalid address. */ - if (dns_address == 0x0) - return(NX_PPP_INVALID_PARAMETER); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP DNS address set function. */ - status = _nx_ppp_dns_address_set(ppp_ptr, dns_address); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_dns_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the primary DNS address for the PPP device to */ -/* supply if it receives a DNS option request (129) in the configure */ -/* request NAKed list. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* dns_address Primary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address) -{ - - /* Set the primary DNS address. */ - ppp_ptr -> nx_ppp_primary_dns_address = dns_address; - - /* Return success. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_secondary_dns_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the secondary DNS address of the */ -/* PPP instance get function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* secondary_dns_address_ptr Secondary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_secondary_dns_address_get Actual PPP secondary DNS */ -/* address get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer... */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || - (secondary_dns_address_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP secondary DNS address get function. */ - status = _nx_ppp_secondary_dns_address_get(ppp_ptr, secondary_dns_address_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_secondary_dns_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the secondary DNS address of the PPP */ -/* instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* secondary_dns_address_ptr Secondary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr) -{ - - /* Determine if the PPP instance is in an established state. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) - { - - if (ppp_ptr -> nx_ppp_secondary_dns_address == 0x0) - { - return(NX_PPP_ADDRESS_NOT_ESTABLISHED); - } - - /* Return the DNS address ptr. */ - *secondary_dns_address_ptr = ppp_ptr -> nx_ppp_secondary_dns_address; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Set the DNS address to 0. */ - *secondary_dns_address_ptr = 0; - - /* The PPP connection has not yet been established. */ - return(NX_PPP_NOT_ESTABLISHED); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_secondary_dns_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the secondary DNS address of the */ -/* PPP instance set function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* secondary_dns_address_ptr Secondary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_secondary_dns_address_set Actual PPP secondary DNS */ -/* address set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address) -{ - -UINT status; - - /* Check for an invalid input pointer... */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for invalid address. */ - if (secondary_dns_address == 0x0) - return(NX_PPP_INVALID_PARAMETER); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP secondary DNS address set function. */ - status = _nx_ppp_secondary_dns_address_set(ppp_ptr, secondary_dns_address); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_secondary_dns_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the secondary DNS address for the PPP device to */ -/* supply if it receives a DNS option request (131) in the configure */ -/* request NAKed list. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* secondary_dns_address_ptr Secondary DNS address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address) -{ - - /* Set the secondary DNS address. */ - ppp_ptr -> nx_ppp_secondary_dns_address = secondary_dns_address; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_interface_index_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP interface index get */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* index_ptr Index of associated interface */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_ppp_interface_index_get Actual PPP interface index get */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP interface idnex get function. */ - status = _nx_ppp_interface_index_get(ppp_ptr, index_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_interface_index_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the interface index with a particular PPP */ -/* instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* index_ptr Index of associated interface */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr) -{ - - /* Return the interface index. */ - *index_ptr = ppp_ptr -> nx_ppp_interface_index; - - /* Determine if the interface is actually setup. */ - if (ppp_ptr -> nx_ppp_interface_ptr) - { - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - /* Return an error. The IP thread has not executed yet which means the - interface has not be setup. */ - return(NX_IN_PROGRESS); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_ip_address_assign PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP IP address assign */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* local_ip_address Local IP address */ -/* peer_ip_address Peer IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_ip_address_assign Actual PPP IP address assign */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address) -{ - -UINT status; - - - /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP IP address assign function. */ - status = _nx_ppp_ip_address_assign(ppp_ptr, local_ip_address, peer_ip_address); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ip_address_assign PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function assigns a local and peer IP address for the */ -/* specified PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* local_ip_address Local IP address */ -/* peer_ip_address Peer IP address */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address) -{ - -UINT i; - - - /* Check if set the local IP address. */ - if (local_ip_address != 0) - { - - /* If true, this PPP instance is a Server. Update the flag. */ - ppp_ptr -> nx_ppp_server = NX_TRUE; - } - - /* Load the IP addresses into the PPP IPCP arrays. */ - i = 4; - do - { - - /* Load the IP values into the array. */ - ppp_ptr -> nx_ppp_ipcp_local_ip[i-1] = (UCHAR) (local_ip_address & 0xFF); - ppp_ptr -> nx_ppp_ipcp_peer_ip[i-1] = (UCHAR) (peer_ip_address & 0xFF); - - /* Shift the IP address down. */ - local_ip_address = local_ip_address >> 8; - peer_ip_address = peer_ip_address >> 8; - - /* Decrement the index. */ - i--; - - } while (i); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_nak_authentication_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PP NAK authentication notify */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* nak_authentication_notify Authentication NAK callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_nak_authentication_notify Actual PPP NAK authentication */ -/* notify set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)) -{ - -UINT status; - - /* Check for an invalid input pointer... including not being in the closed state for this configuration API. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_INIT_AND_THREADS_CALLER_CHECKING - - /* Call actual PPP NAK authentication notify set function. */ - status = _nx_ppp_nak_authentication_notify(ppp_ptr, nak_authentication_notify); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_nak_authentication_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function assigns an application callback function to be */ -/* called if an authentication NAK is received from the peer. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* nak_authentication_notify Authentication NAK callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)) -{ - - /* Store the callback function pointer in the PPP structure. */ - ppp_ptr -> nx_ppp_nak_authentication_notify = nak_authentication_notify; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_raw_string_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP raw string send */ -/* function call. */ -/* */ -/* Note: The string length of string_ptr is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* string_ptr Pointer to ASCII string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_raw_string_send Actual PPP raw string send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (string_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP raw string send function. */ - status = _nx_ppp_raw_string_send(ppp_ptr, string_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_raw_string_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a raw ASCII string to through PPP without any */ -/* PPP framing. This is useful to respond to modem commands in some */ -/* applications. */ -/* */ -/* Note: The string length of string_ptr is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* string_ptr Pointer to ASCII string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet */ -/* tx_event_flags_set Alert PPP thread to process */ -/* raw packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - -UINT i, j; -UINT status; -NX_PACKET *packet_ptr; - - - /* Initialize the string index. */ - i = 0; - - /* Loop to process the raw string send request. */ - while (string_ptr[i]) - { - - /* Allocate a packet to defer the raw string send to the PPP thread. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, NX_PPP_TIMEOUT); - - /* Determine if there was an error allocating a packet. */ - if (status != NX_SUCCESS) - { - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of packet allocation timeouts. */ - ppp_ptr -> nx_ppp_packet_allocate_timeouts++; -#endif - - /* Just return an error. */ - return(NX_NO_PACKET); - } - - /* Initialize the packet index. */ - j = 0; - - /* Loop through the string copying the characters into the packet. */ - do - { - - /* Copy character into the packet. */ - packet_ptr -> nx_packet_prepend_ptr[j++] = (UCHAR)(string_ptr[i++]); - - } while ((string_ptr[i]) && (&(packet_ptr -> nx_packet_prepend_ptr[j]) < packet_ptr -> nx_packet_data_end)); - - /* Update the append pointer. */ - packet_ptr -> nx_packet_append_ptr = &(packet_ptr -> nx_packet_prepend_ptr[j]); - - /* Setup the packet length. */ - packet_ptr -> nx_packet_length = j; - - /* Now place the packet on the raw packet queue. */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Determine if the raw transmit queue is empty. */ - if (ppp_ptr -> nx_ppp_raw_packet_queue_count++) - { - - /* Not empty, simply link the new packet to the tail and update the tail. */ - (ppp_ptr -> nx_ppp_raw_packet_queue_tail) -> nx_packet_queue_next = packet_ptr; - ppp_ptr -> nx_ppp_raw_packet_queue_tail = packet_ptr; - } - else - { - - /* List is empty, set the head and tail to this packet. */ - ppp_ptr -> nx_ppp_raw_packet_queue_head = packet_ptr; - ppp_ptr -> nx_ppp_raw_packet_queue_tail = packet_ptr; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Set event flag to wake up PPP thread for processing. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_RAW_STRING_SEND, TX_OR); - } - - /* Return success. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP start function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_start Actual PPP start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_start(NX_PPP *ppp_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP start function. */ - status = _nx_ppp_start(ppp_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set PPP event flag to */ -/* start PPP */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_start(NX_PPP *ppp_ptr) -{ - - /* Determine the current state. */ - if (ppp_ptr -> nx_ppp_state != NX_PPP_STOPPED) - { - - /* Already started. */ - return(NX_PPP_ALREADY_STARTED); - } - else - { - - /* Now restart the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); - } - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP stop function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_stop Actual PPP stop function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_stop(NX_PPP *ppp_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP stop function. */ - status = _nx_ppp_stop(ppp_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops the PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set PPP event flag to stop PPP*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_stop(NX_PPP *ppp_ptr) -{ - - - /* Determine the current state. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) - { - - /* Already stopped. */ - return(NX_PPP_ALREADY_STOPPED); - } - else - { - - /* Check if LCP connection is already established or in negotiation. */ - if ((ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_COMPLETED_STATE) || - (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE) || - (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE) || - (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE)) - { - - /* Setup the retry counter. */ - ppp_ptr -> nx_ppp_protocol_retry_counter = 0; - - /* Setup the timeout. */ - ppp_ptr -> nx_ppp_timeout = NX_PPP_PROTOCOL_TIMEOUT; - - /* Move into the stopping to wait for terminate ack. */ - ppp_ptr -> nx_ppp_lcp_state = NX_PPP_LCP_STOPPING_STATE; - - /* Send terminate request. */ - _nx_ppp_lcp_terminate_request_send(ppp_ptr); - } - else - { - - /* Set the event to stop the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Determine if the application has registered a link down notification - callback. */ - if (ppp_ptr -> nx_ppp_link_down_callback) - { - - /* Yes, call the application's callback function. */ - (ppp_ptr -> nx_ppp_link_down_callback)(ppp_ptr); - } - } - } - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_restart PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP restart function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_restart Actual PPP restart function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_restart(NX_PPP *ppp_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP restart function. */ - status = _nx_ppp_restart(ppp_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_restart PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function restarts the PPP instance. This is typically done */ -/* after a link down situation. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to instance */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set PPP event flag to stop PPP*/ -/* tx_thread_sleep Sleep for a small time */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_restart(NX_PPP *ppp_ptr) -{ - - /* Set the event to stop the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_STOP, TX_OR); - - /* Now restart the PPP instance. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_START, TX_OR); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_status_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP status get function call.*/ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* status_ptr Pointer to destination for */ -/* PPP status */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_status_get Actual PPP status get function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr) -{ - -UINT status; - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID) || (status_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PPP status get function. */ - status = _nx_ppp_status_get(ppp_ptr, status_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_status_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the current status of the PPP instance. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* status_ptr Pointer to destination for */ -/* PPP status */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr) -{ - - /* Now determine the current state. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_ESTABLISHED) - { - - /* PPP is up, return established state. */ - *status_ptr = NX_PPP_STATUS_ESTABLISHED; - - /* Return success! */ - return(NX_SUCCESS); - } - else if ((ppp_ptr -> nx_ppp_lcp_state > NX_PPP_LCP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_lcp_state < NX_PPP_LCP_COMPLETED_STATE)) - { - - /* Is LCP in a failed state? */ - if (ppp_ptr -> nx_ppp_lcp_state == NX_PPP_LCP_FAILED_STATE) - { - - /* Return LCP failed state. */ - *status_ptr = NX_PPP_STATUS_LCP_FAILED; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Return LCP in-progress state. */ - *status_ptr = NX_PPP_STATUS_LCP_IN_PROGRESS; - - /* Return success. */ - return(NX_SUCCESS); - } - } - else if ((ppp_ptr -> nx_ppp_pap_state > NX_PPP_PAP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_pap_state < NX_PPP_PAP_COMPLETED_STATE)) - { - - /* Is PAP in a failed state? */ - if (ppp_ptr -> nx_ppp_pap_state == NX_PPP_PAP_FAILED_STATE) - { - - /* Return PAP failed state. */ - *status_ptr = NX_PPP_STATUS_PAP_FAILED; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Return PAP in-progress state. */ - *status_ptr = NX_PPP_STATUS_PAP_IN_PROGRESS; - - /* Return success. */ - return(NX_SUCCESS); - } - } - else if ((ppp_ptr -> nx_ppp_chap_state > NX_PPP_CHAP_INITIAL_STATE) && (ppp_ptr -> nx_ppp_chap_state < NX_PPP_CHAP_COMPLETED_STATE)) - { - - /* Is CHAP in a failed state? */ - if (ppp_ptr -> nx_ppp_chap_state == NX_PPP_CHAP_CHALLENGE_FAILED_STATE) - { - - /* Return CHAP failed state. */ - *status_ptr = NX_PPP_STATUS_CHAP_FAILED; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Return CHAP in-progress state. */ - *status_ptr = NX_PPP_STATUS_CHAP_IN_PROGRESS; - - /* Return success. */ - return(NX_SUCCESS); - } - } - else - { - - /* Is IPCP in a failed state? */ - if (ppp_ptr -> nx_ppp_ipcp_state == NX_PPP_IPCP_FAILED_STATE) - { - - /* Return IPCP failed state. */ - *status_ptr = NX_PPP_STATUS_IPCP_FAILED; - - /* Return success. */ - return(NX_SUCCESS); - } - else - { - - /* Return IPCP in-progress state. */ - *status_ptr = NX_PPP_STATUS_IPCP_IN_PROGRESS; - - /* Return success. */ - return(NX_SUCCESS); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_ping_reply PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the PPP instance detects an LCP echo */ -/* request is received, and retransmits a response. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* packet_ptr Pointer to echo request packet*/ -/* received */ -/* */ -/* OUTPUT */ -/* */ -/* None Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_packet_transmit Transmit the PPP data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update Processes events and updates */ -/* the PPP in the LCP state */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_ping_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - - - /* Change the coding to indicate an Echo reply. */ - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_ECHO_REPLY; - - /* Set the Magic number as zero. */ - packet_ptr -> nx_packet_prepend_ptr[6] = 0; - packet_ptr -> nx_packet_prepend_ptr[7] = 0; - packet_ptr -> nx_packet_prepend_ptr[8] = 0; - packet_ptr -> nx_packet_prepend_ptr[9] = 0; - -#ifndef NX_PPP_DISABLE_INFO - - ppp_ptr -> nx_ppp_lcp_echo_replies_sent++; - - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; -#endif - - /* Send the reply out. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_lcp_ping_process_echo_reply PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the PPP instance detects an LCP echo */ -/* reply is received. It checks if the reply has a matching ID with the */ -/* previous echo request sent out and if so clears the */ -/* nx_ppp_lcp_echo_reply_id to indicate the device received a valid */ -/* reply. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* packet_ptr Pointer to echo request packet*/ -/* received */ -/* */ -/* OUTPUT */ -/* */ -/* None Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_ppp_lcp_state_machine_update Processes events and updates */ -/* the PPP in the LCP state */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_ppp_lcp_ping_process_echo_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - - /* Verify the PPP ID matches. */ - if (packet_ptr -> nx_packet_prepend_ptr[3] == ppp_ptr -> nx_ppp_lcp_echo_reply_id) - { - - /* Successful ping received. */ -#ifndef NX_PPP_DISABLE_INFO - /* Increment the number of LCP echo replies received. */ - ppp_ptr -> nx_ppp_lcp_echo_replies_received++; -#endif - - /* Clear the echo ID to indicate we received an LCP echo reply - matching the one we just sent out. */ - ppp_ptr -> nx_ppp_lcp_echo_reply_id = 0; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_ping_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the nx_ppp_ping_request */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* data_ptr Pointer to data in LCP echo */ -/* data_size Size of data in LCP echo */ -/* wait_option Wait option to transmit echo */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_PPP_INVALID_PARAMETER Invalid non pointer input */ -/* NX_SUCCESS Successful echo request sent */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_ping_request Actual LCP echo service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option) -{ - -UINT status; - - if ((ppp_ptr == NX_NULL) || (data_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - if (data_size == 0) - { - return NX_PPP_INVALID_PARAMETER; - } - - status = _nx_ppp_ping_request(ppp_ptr, data_ptr, data_size, wait_option); - - return status; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_ping_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends an LCP echo request, and sets the */ -/* echo ID to the PPP nx_ppp_transmit_id. The caller waits for the echo*/ -/* ID (nx_ppp_lcp_echo_reply_id) to be reset to zero to indicate a */ -/* matching echo reply was received. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr PPP instance pointer */ -/* data_ptr Pointer to data in LCP echo */ -/* data_size Size of data in LCP echo */ -/* wait_option Wait option to transmit echo */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Echo request successfully sent*/ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for sending */ -/* _nx_ppp_packet_transmit Send PPP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option) -{ - -UINT status; -UINT i; -CHAR *work_ptr; -NX_PACKET *packet_ptr; - - - /* Echo request may only be sent in the LCP completed state.. */ - if (ppp_ptr -> nx_ppp_lcp_state != NX_PPP_LCP_COMPLETED_STATE) - { - - return NX_PPP_NOT_ESTABLISHED; - } - - /* Allocate a packet for the PPP packet. */ - status = nx_packet_allocate(ppp_ptr -> nx_ppp_packet_pool_ptr, &packet_ptr, NX_PPP_PACKET, wait_option); - - /* Determine if the packet was allocated successfully. */ - if (status != NX_SUCCESS) - { - - /* An error was detected, simply return a NULL pointer. */ - return status; - } - - /* Check if out of boundary. */ - if ((UINT)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_prepend_ptr) < (UINT)(data_size + 10)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return(NX_PPP_BAD_PACKET); - } - - /* Increment the transmit ID. */ - ppp_ptr -> nx_ppp_transmit_id++; - - /* Build the configuration request. */ - packet_ptr -> nx_packet_prepend_ptr[0] = (NX_PPP_LCP_PROTOCOL & 0xFF00) >> 8; - packet_ptr -> nx_packet_prepend_ptr[1] = NX_PPP_LCP_PROTOCOL & 0xFF; - packet_ptr -> nx_packet_prepend_ptr[2] = NX_PPP_LCP_ECHO_REQUEST; - packet_ptr -> nx_packet_prepend_ptr[3] = ppp_ptr -> nx_ppp_transmit_id; - - /* Indicate the PPP instance is waiting on an ECHO reply with this id: */ - ppp_ptr -> nx_ppp_lcp_echo_reply_id = ppp_ptr -> nx_ppp_transmit_id; - - /* Set up the length. */ - packet_ptr -> nx_packet_prepend_ptr[4] = (UCHAR)(((UINT)(data_size + 8)) >> 8); - packet_ptr -> nx_packet_prepend_ptr[5] = (UCHAR)(((UINT)(data_size + 8)) & 0xFF); - - /* Magic number will be all zeroes. */ - packet_ptr -> nx_packet_prepend_ptr[6] = 0; - packet_ptr -> nx_packet_prepend_ptr[7] = 0; - packet_ptr -> nx_packet_prepend_ptr[8] = 0; - packet_ptr -> nx_packet_prepend_ptr[9] = 0; - - /* Load the data */ - work_ptr = data_ptr; - - /* Loop through the input buffer. */ - for(i = 1; i <= data_size; i++) - { - - /* Copy byte of IP address. */ - packet_ptr -> nx_packet_prepend_ptr[i+9] = (UCHAR)(*work_ptr); - work_ptr++ ; - } - - packet_ptr -> nx_packet_length = i + 9; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + packet_ptr -> nx_packet_length; - -#ifndef NX_PPP_DISABLE_INFO - - /* Increment the number of LCP echo requests sent. */ - ppp_ptr -> nx_ppp_lcp_echo_requests_sent++; - - /* Increment the number of LCP frames sent. */ - ppp_ptr -> nx_ppp_lcp_frames_sent++; -#endif - - /* Send the configure request packet. */ - _nx_ppp_packet_transmit(ppp_ptr, packet_ptr); - - return NX_SUCCESS; -} - - - -#ifdef NX_PPP_PPPOE_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP packet receive */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_ppp_packet_receive Actual PPP packet receive */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for packet pointer. */ - if (packet_ptr == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual packet receive function. */ - status = _nx_ppp_packet_receive(ppp_ptr, packet_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives packet from the application (usually an */ -/* application ISR), buffers it, and notifies the PPP receive thread. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Notify PPP receiving thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code (Including ISRs) */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Disable interrupts. */ - TX_DISABLE - - /* Check for no longer active PPP instance. */ - if (ppp_ptr -> nx_ppp_id != NX_PPP_ID) - { - - /* PPP is no longer active. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Return an error. */ - return(NX_PTR_ERROR); - } - - /* Check for a stopped PPP instance. */ - if (ppp_ptr -> nx_ppp_state == NX_PPP_STOPPED) - { - - /* Silently discard byte. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Return success. */ - return(NX_SUCCESS); - } - - /* Check to see if the deferred processing queue is empty. */ - if (ppp_ptr -> nx_ppp_deferred_received_packet_head) - { - - /* Not empty, just place the packet at the end of the queue. */ - (ppp_ptr -> nx_ppp_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - ppp_ptr -> nx_ppp_deferred_received_packet_tail = packet_ptr; - - /* Restore interrupts. */ - TX_RESTORE - } - else - { - - /* Empty deferred receive processing queue. Just setup the head pointers and - set the event flags to ensure the PPP helper thread looks at the deferred processing - queue. */ - ppp_ptr -> nx_ppp_deferred_received_packet_head = packet_ptr; - ppp_ptr -> nx_ppp_deferred_received_packet_tail = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Restore interrupts. */ - TX_RESTORE - - /* Wakeup PPP helper thread to process the PPP deferred receive. */ - tx_event_flags_set(&(ppp_ptr -> nx_ppp_event), NX_PPP_EVENT_PPPOE_PACKET_RECEIVE, TX_OR); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_ppp_packet_send_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPP set packet send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* nx_ppp_packet_send Routine to send PPP packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_ppp_packet_send_set Actual PPP packet send set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)) -{ - -UINT status; - - - /* Check for an invalid input pointer. */ - if ((ppp_ptr == NX_NULL) || (ppp_ptr -> nx_ppp_id != NX_PPP_ID)) - return(NX_PTR_ERROR); - - /* Check for packet pointer. */ - if (nx_ppp_packet_send == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual packet send set function. */ - status = _nx_ppp_packet_send_set(ppp_ptr, nx_ppp_packet_send); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_ppp_packet_send_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function set the PPP packet send function. */ -/* */ -/* INPUT */ -/* */ -/* ppp_ptr Pointer to PPP instance */ -/* nx_ppp_packet_send Routine to send PPP packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* none */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)) -{ - - - /* Set the PPP packet send function. */ - ppp_ptr -> nx_ppp_packet_send = nx_ppp_packet_send; - - /* Return successful completion. */ - return(NX_SUCCESS); -} -#endif /* NX_PPP_PPPOE_ENABLE */ -#endif /* NX_DISABLE_IPV4 */ diff --git a/protocol_handlers/ppp/nx_ppp.h b/protocol_handlers/ppp/nx_ppp.h deleted file mode 100644 index d757c9d8..00000000 --- a/protocol_handlers/ppp/nx_ppp.h +++ /dev/null @@ -1,824 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Point-to-Point Protocol (PPP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_ppp.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Point-to-Point Protocol (PPP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_PPP_H -#define NX_PPP_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the PPP ID. */ - -#define NX_PPP_ID 0x50505020UL - -#define NX_PPP_SERIAL_BUFFER_ALERT_THRESHOLD NX_PPP_SERIAL_BUFFER_SIZE/4 - -/* Defined, support for transmitting PPP over Ethernet. */ -/* -#define NX_PPP_PPPOE_ENABLE -*/ - -/* If defined, this removes logic for compiling PPP transmit and receive statistics. -#define NX_PPP_DISABLE_INFO -*/ - -/* If defined, this enables PPP event logging. -#define NX_PPP_DEBUG_LOG_ENABLE -*/ - -/* If defined, this enables data saved to the PPP log to be printed out (printf). -#define NX_PPP_DEBUG_LOG_PRINT_ENABLE -*/ - -/* If defined, this disables CHAP authentication. -#define NX_PPP_DISABLE_CHAP -*/ - -/* If defined, this disables PAP authentication. -#define NX_PPP_DISABLE_PAP -*/ - -/* If defined, the primary DNS address request option is not set in NAKed list. -#define NX_PPP_DNS_OPTION_DISABLE -*/ - -/* Define how many times the PPP should try to request DNS address from the Peer. This - will have no effect if NX_PPP_DNS_OPTION_DISABLE is defined. */ -#ifndef NX_PPP_DNS_ADDRESS_MAX_RETRIES -#define NX_PPP_DNS_ADDRESS_MAX_RETRIES 2 -#endif - -/* Define the thread time slice. */ -#ifndef NX_PPP_THREAD_TIME_SLICE -#define NX_PPP_THREAD_TIME_SLICE TX_NO_TIME_SLICE -#endif - -/* Set the link transfer size. */ -#ifndef NX_PPP_MRU -#ifdef NX_PPP_PPPOE_ENABLE -#define NX_PPP_MRU 1480 /* Minimum value! */ -#else /* !NX_PPP_PPPOE_ENABLE */ -#define NX_PPP_MRU 1500 /* Minimum value! */ -#endif /* NX_PPP_PPPOE_ENABLE */ -#endif /* NX_PPP_MRU */ - -/* Minimum MRU to accept in MRU parsed from received LCP configuration request. */ -#ifndef NX_PPP_MINIMUM_MRU -#ifdef NX_PPP_PPPOE_ENABLE -#define NX_PPP_MINIMUM_MRU 1480 -#else /* !NX_PPP_PPPOE_ENABLE */ -#define NX_PPP_MINIMUM_MRU 1500 -#endif /* NX_PPP_PPPOE_ENABLE */ -#endif /* NX_PPP_MINIMUM_MRU */ - -/* Size of the receive character buffer. */ -#ifndef NX_PPP_SERIAL_BUFFER_SIZE -#define NX_PPP_SERIAL_BUFFER_SIZE NX_PPP_MRU*2 -#endif - - -/* User name buffer size for PAP login. */ -#ifndef NX_PPP_NAME_SIZE -#define NX_PPP_NAME_SIZE 32 -#endif - -/* Password buffer size for PAP login. */ -#ifndef NX_PPP_PASSWORD_SIZE -#define NX_PPP_PASSWORD_SIZE 32 -#endif - -/* Buffer size of the random value to process the CHAP challenge name */ -#ifndef NX_PPP_VALUE_SIZE -#define NX_PPP_VALUE_SIZE 32 -#endif - -/* Buffer size of the hash value to process the CHAP challenge name */ -#ifndef NX_PPP_HASHED_VALUE_SIZE -#define NX_PPP_HASHED_VALUE_SIZE 16 -#endif - - -/* The time period in timer ticks at which the PPP timer function executes and wakes up the PPP processing thread - to check for PPP events. */ -#ifndef NX_PPP_BASE_TIMEOUT -#define NX_PPP_BASE_TIMEOUT (NX_IP_PERIODIC_RATE * 1) /* 1 second */ -#endif - -/* The time out in timer ticks on allocating packets for processing PPP data into IP packets either receiving or sending. */ -#ifndef NX_PPP_TIMEOUT -#define NX_PPP_TIMEOUT (NX_IP_PERIODIC_RATE * 4) /* 4 seconds */ -#endif - -/* Number of times the PPP task times out waiting for another byte in the serial buffer. On reaching - this value, the PPP instance releases the packet and allocates a fresh packet for a new message. */ -#ifndef NX_PPP_RECEIVE_TIMEOUTS -#define NX_PPP_RECEIVE_TIMEOUTS 4 -#endif - -/* Timeout in seconds on the PPP task to receive a response to PPP protocol request. */ -#ifndef NX_PPP_PROTOCOL_TIMEOUT -#define NX_PPP_PROTOCOL_TIMEOUT 4 /* 4 seconds. */ -#endif - -/* Size of debug entry, this is also the wrap around index for debug output to overwrite oldest data. */ -#ifndef NX_PPP_DEBUG_LOG_SIZE -#define NX_PPP_DEBUG_LOG_SIZE 50 -#endif - -/* Maximum amount of data to add to debug output from received packet. */ -#ifndef NX_PPP_DEBUG_FRAME_SIZE -#define NX_PPP_DEBUG_FRAME_SIZE 50 -#endif - -/* Size of the NAK list. Not in use. */ -#ifndef NX_PPP_OPTION_MESSAGE_LENGTH -#define NX_PPP_OPTION_MESSAGE_LENGTH 64 -#endif - -/* Number of instances the PPP instance resends another LCP configure request message without a response. - When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ -#ifndef NX_PPP_MAX_LCP_PROTOCOL_RETRIES -#define NX_PPP_MAX_LCP_PROTOCOL_RETRIES 20 -#endif - -/* Number of instances the PPP instance resends another PAP authentication request message without a response. - When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ -#ifndef NX_PPP_MAX_PAP_PROTOCOL_RETRIES -#define NX_PPP_MAX_PAP_PROTOCOL_RETRIES 20 -#endif - -/* Number of instances the PPP instance resends another CHAP challenge message without a response. - When this number is reached, the PPP instance aborts the PPP handshake, and the link status is down. */ -#ifndef NX_PPP_MAX_CHAP_PROTOCOL_RETRIES -#define NX_PPP_MAX_CHAP_PROTOCOL_RETRIES 20 -#endif - -/* Number of instances the PPP instance times out before the IPCP part of the PPP handshake. - When this number is reached, the PPP instance aborts and the link is down. */ -#ifndef NX_PPP_MAX_IPCP_PROTOCOL_RETRIES -#define NX_PPP_MAX_IPCP_PROTOCOL_RETRIES 20 -#endif - -/* Define the packet header. */ -#ifdef NX_PPP_PPPOE_ENABLE -#ifndef NX_PPP_PACKET -#define NX_PPP_PACKET 22 /* Ethernet Header(14) + (PPPoE Header(6) + 2), keep four-byte alignment for Ethernet. */ -#endif /* NX_PPP_PACKET */ -#else /* !NX_PPP_PPPOE_ENABLE */ -#define NX_PPP_PACKET 0 -#endif /* NX_PPP_PPPOE_ENABLE */ - -/* Define the minimum PPP packet payload, the PPP commands (LCP, PAP, CHAP, IPCP) should be in one packet. */ - -#ifndef NX_PPP_MIN_PACKET_PAYLOAD -#define NX_PPP_MIN_PACKET_PAYLOAD (NX_PPP_PACKET + 128) -#endif - -/* Define PPP protocol types. */ - -#define NX_PPP_LCP_PROTOCOL 0xC021 -#define NX_PPP_IPCP_PROTOCOL 0x8021 -#define NX_PPP_PAP_PROTOCOL 0xC023 -#define NX_PPP_CHAP_PROTOCOL 0xC223 -#define NX_PPP_DATA 0x0021 - - -/* Define PPP LCP codes and action. */ - -#define NX_PPP_LCP_CONFIGURE_REQUEST 1 -#define NX_PPP_LCP_CONFIGURE_ACK 2 -#define NX_PPP_LCP_CONFIGURE_NAK 3 -#define NX_PPP_LCP_CONFIGURE_REJECT 4 -#define NX_PPP_LCP_TERMINATE_REQUEST 5 -#define NX_PPP_LCP_TERMINATE_ACK 6 -#define NX_PPP_LCP_CODE_REJECT 7 -#define NX_PPP_LCP_PROTOCOL_REJECT 8 -#define NX_PPP_LCP_ECHO_REQUEST 9 -#define NX_PPP_LCP_ECHO_REPLY 10 -#define NX_PPP_LCP_DISCARD_REQUEST 11 -#define NX_PPP_LCP_TIMEOUT 99 - - -/* Define PPP PAP codes and action. */ - -#define NX_PPP_PAP_AUTHENTICATE_REQUEST 1 -#define NX_PPP_PAP_AUTHENTICATE_ACK 2 -#define NX_PPP_PAP_AUTHENTICATE_NAK 3 -#define NX_PPP_PAP_AUTHENTICATE_TIMEOUT 99 - - -/* Define PPP CHAP codes and action. */ - -#define NX_PPP_CHAP_CHALLENGE_REQUEST 1 -#define NX_PPP_CHAP_CHALLENGE_RESPONSE 2 -#define NX_PPP_CHAP_CHALLENGE_SUCCESS 3 -#define NX_PPP_CHAP_CHALLENGE_FAILURE 4 -#define NX_PPP_CHAP_CHALLENGE_TIMEOUT 99 - - -/* Define PPP IPCP codes and action. */ - -#define NX_PPP_IPCP_CONFIGURE_REQUEST 1 -#define NX_PPP_IPCP_CONFIGURE_ACK 2 -#define NX_PPP_IPCP_CONFIGURE_NAK 3 -#define NX_PPP_IPCP_CONFIGURE_REJECT 4 -#define NX_PPP_IPCP_TERMINATE_REQUEST 5 -#define NX_PPP_IPCP_TERMINATE_ACK 6 -#define NX_PPP_IPCP_TIMEOUT 99 - - -/* Define API return codes. */ - -#define NX_PPP_FAILURE 0xb0 -#define NX_PPP_BUFFER_FULL 0xb1 -#define NX_PPP_BAD_PACKET 0xb3 -#define NX_PPP_ERROR 0xb4 -#define NX_PPP_NOT_ESTABLISHED 0xb5 -#define NX_PPP_INVALID_PARAMETER 0xb6 -#define NX_PPP_ADDRESS_NOT_ESTABLISHED 0xb7 -#define NX_PPP_ALREADY_STOPPED 0xb8 -#define NX_PPP_ALREADY_STARTED 0xb9 - -/* Define PPP state machine states. */ - -#define NX_PPP_STOPPED 0 -#define NX_PPP_STARTED 1 -#define NX_PPP_ESTABLISHED 2 - - -/* Define LCP state machine states. */ - -#define NX_PPP_LCP_INITIAL_STATE 0 -#define NX_PPP_LCP_START_STATE 1 -#define NX_PPP_LCP_CONFIGURE_REQUEST_SENT_STATE 2 -#define NX_PPP_LCP_CONFIGURE_REQUEST_ACKED_STATE 3 -#define NX_PPP_LCP_PEER_CONFIGURE_REQUEST_ACKED_STATE 4 -#define NX_PPP_LCP_STOPPING_STATE 5 -#define NX_PPP_LCP_STOPPED_STATE 6 -#define NX_PPP_LCP_FAILED_STATE 7 -#define NX_PPP_LCP_COMPLETED_STATE 8 - - -/* Define PAP state machine states. */ - -#define NX_PPP_PAP_INITIAL_STATE 0 -#define NX_PPP_PAP_START_STATE 1 -#define NX_PPP_PAP_AUTHENTICATE_REQUEST_SENT_STATE 2 -#define NX_PPP_PAP_AUTHENTICATE_REQUEST_WAIT_STATE 3 -#define NX_PPP_PAP_FAILED_STATE 4 -#define NX_PPP_PAP_COMPLETED_STATE 5 - - -/* Define CHAP state machine states. */ - -#define NX_PPP_CHAP_INITIAL_STATE 0 -#define NX_PPP_CHAP_START_STATE 1 -#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_STATE 2 -#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_BOTH_STATE 3 -#define NX_PPP_CHAP_CHALLENGE_REQUEST_WAIT_STATE 4 -#define NX_PPP_CHAP_CHALLENGE_REQUEST_SENT_RESPONDED_STATE 5 -#define NX_PPP_CHAP_CHALLENGE_RESPONSE_WAIT_STATE 6 -#define NX_PPP_CHAP_COMPLETED_NEW_STATE 8 -#define NX_PPP_CHAP_COMPLETED_NEW_SENT_STATE 9 -#define NX_PPP_CHAP_CHALLENGE_FAILED_STATE 10 -#define NX_PPP_CHAP_COMPLETED_STATE 11 - - -/* Define IPCP state machine states. */ - -#define NX_PPP_IPCP_INITIAL_STATE 0 -#define NX_PPP_IPCP_START_STATE 1 -#define NX_PPP_IPCP_CONFIGURE_REQUEST_SENT_STATE 2 -#define NX_PPP_IPCP_CONFIGURE_REQUEST_ACKED_STATE 3 -#define NX_PPP_IPCP_PEER_CONFIGURE_REQUEST_ACKED_STATE 4 -#define NX_PPP_IPCP_STOPPING_STATE 5 -#define NX_PPP_IPCP_STOPPED_STATE 6 -#define NX_PPP_IPCP_FAILED_STATE 7 -#define NX_PPP_IPCP_COMPLETED_STATE 8 - - -/* Define event flags for PPP thread control. */ - -#define NX_PPP_EVENT_START 0x01 -#define NX_PPP_EVENT_STOP 0x02 -#define NX_PPP_EVENT_PACKET_RECEIVE 0x04 -#define NX_PPP_EVENT_RAW_STRING_SEND 0x08 -#define NX_PPP_EVENT_IP_PACKET_SEND 0x10 -#define NX_PPP_EVENT_CHAP_CHALLENGE 0x20 -#define NX_PPP_EVENT_TIMEOUT 0x40 -#define NX_PPP_EVENT_PPPOE_PACKET_RECEIVE 0x80 - - -/* Define PPP status return values. */ - -#define NX_PPP_STATUS_LCP_IN_PROGRESS 0 -#define NX_PPP_STATUS_LCP_FAILED 1 -#define NX_PPP_STATUS_PAP_IN_PROGRESS 2 -#define NX_PPP_STATUS_PAP_FAILED 3 -#define NX_PPP_STATUS_CHAP_IN_PROGRESS 4 -#define NX_PPP_STATUS_CHAP_FAILED 5 -#define NX_PPP_STATUS_IPCP_IN_PROGRESS 6 -#define NX_PPP_STATUS_IPCP_FAILED 7 -#define NX_PPP_STATUS_ESTABLISHED 8 - -/* Define NAKed list options */ -#define NX_PPP_IP_COMPRESSION_OPTION 0x02 -#define NX_PPP_IP_ADDRESS_OPTION 0x03 -#define NX_PPP_DNS_SERVER_OPTION 0x81 -#define NX_PPP_DNS_SECONDARY_SERVER_OPTION 0x83 - - - -/* Define optional debug log. This is used to capture the PPP traffic for debug - purposes. */ - -typedef struct NX_PPP_DEBUG_ENTRY_STRUCT -{ - - ULONG nx_ppp_debug_entry_time_stamp; - UCHAR nx_ppp_debug_ppp_state; - UCHAR nx_ppp_debug_lcp_state; - UCHAR nx_ppp_debug_pap_state; - UCHAR nx_ppp_debug_chap_state; - UCHAR nx_ppp_debug_ipcp_state; - UCHAR nx_ppp_debug_authenticated; - UCHAR nx_ppp_debug_frame_type; - ULONG nx_ppp_debug_packet_length; - UCHAR nx_ppp_debug_frame[NX_PPP_DEBUG_FRAME_SIZE]; -} NX_PPP_DEBUG_ENTRY; - - - -/* Define the main PPP data structure. */ - -typedef struct NX_PPP_STRUCT -{ - - ULONG nx_ppp_id; - CHAR *nx_ppp_name; - NX_IP *nx_ppp_ip_ptr; - NX_INTERFACE *nx_ppp_interface_ptr; - UINT nx_ppp_interface_index; - NX_PACKET_POOL *nx_ppp_packet_pool_ptr; - UCHAR nx_ppp_transmit_id; - UCHAR nx_ppp_receive_id; - UCHAR nx_ppp_lcp_echo_reply_id; - UCHAR nx_ppp_reserved; - ULONG nx_ppp_mru; - UINT nx_ppp_server; - UINT nx_ppp_state; - UINT nx_ppp_lcp_state; - UINT nx_ppp_pap_state; - UINT nx_ppp_chap_state; - UINT nx_ppp_ipcp_state; - UINT nx_ppp_authenticated; - UINT nx_ppp_generate_authentication_protocol; - UINT nx_ppp_verify_authentication_protocol; - USHORT nx_ppp_pap_enabled; - USHORT nx_ppp_chap_enabled; - CHAR nx_ppp_chap_challenger_name[NX_PPP_NAME_SIZE + 1]; - CHAR nx_ppp_chap_random_value[NX_PPP_VALUE_SIZE + 1]; - UCHAR nx_ppp_ipcp_local_ip[4]; - UCHAR nx_ppp_ipcp_peer_ip[4]; - ULONG nx_ppp_primary_dns_address; - ULONG nx_ppp_secondary_dns_address; - UINT nx_ppp_dns_address_retries; - UINT nx_ppp_secondary_dns_address_retries; - ULONG nx_ppp_timeout; - ULONG nx_ppp_receive_timeouts; - ULONG nx_ppp_protocol_retry_counter; -#ifndef NX_PPP_DISABLE_INFO - ULONG nx_ppp_packet_allocate_timeouts; - ULONG nx_ppp_frame_timeouts; - ULONG nx_ppp_internal_errors; - ULONG nx_ppp_frame_crc_errors; - ULONG nx_ppp_packet_overflow; - ULONG nx_ppp_bytes_received; - ULONG nx_ppp_bytes_sent; - ULONG nx_ppp_bytes_dropped; - ULONG nx_ppp_bytes_invalid; - ULONG nx_ppp_total_frames_received; - ULONG nx_ppp_lcp_frames_received; - ULONG nx_ppp_lcp_frames_sent; - ULONG nx_ppp_lcp_configure_requests_sent; - ULONG nx_ppp_lcp_configure_requests_received; - ULONG nx_ppp_lcp_configure_acks_sent; - ULONG nx_ppp_lcp_configure_acks_received; - ULONG nx_ppp_lcp_configure_naks_sent; - ULONG nx_ppp_lcp_configure_naks_received; - ULONG nx_ppp_lcp_configure_rejects_sent; - ULONG nx_ppp_lcp_configure_rejects_received; - ULONG nx_ppp_lcp_terminate_requests_sent; - ULONG nx_ppp_lcp_terminate_requests_received; - ULONG nx_ppp_lcp_terminate_acks_sent; - ULONG nx_ppp_lcp_terminate_acks_received; - ULONG nx_ppp_lcp_code_rejects_sent; - ULONG nx_ppp_lcp_code_rejects_received; - ULONG nx_ppp_lcp_protocol_rejects_sent; - ULONG nx_ppp_lcp_protocol_rejects_received; - ULONG nx_ppp_lcp_echo_requests_sent; - ULONG nx_ppp_lcp_echo_replies_received; - ULONG nx_ppp_lcp_echo_requests_received; - ULONG nx_ppp_lcp_echo_requests_dropped; - ULONG nx_ppp_lcp_echo_replies_sent; - ULONG nx_ppp_lcp_discard_requests_sent; - ULONG nx_ppp_lcp_discard_requests_received; - ULONG nx_ppp_lcp_unknown_requests_received; - ULONG nx_ppp_lcp_state_machine_unhandled_requests; - ULONG nx_ppp_lcp_state_machine_timeouts; -#ifndef NX_PPP_DISABLE_PAP - ULONG nx_ppp_pap_frames_received; - ULONG nx_ppp_pap_frames_sent; - ULONG nx_ppp_pap_authenticate_requests_sent; - ULONG nx_ppp_pap_authenticate_requests_received; - ULONG nx_ppp_pap_authenticate_acks_sent; - ULONG nx_ppp_pap_authenticate_acks_received; - ULONG nx_ppp_pap_authenticate_naks_sent; - ULONG nx_ppp_pap_authenticate_naks_received; - ULONG nx_ppp_pap_unknown_requests_received; - ULONG nx_ppp_pap_state_machine_unhandled_requests; - ULONG nx_ppp_pap_state_machine_timeouts; -#endif -#ifndef NX_PPP_DISABLE_CHAP - ULONG nx_ppp_chap_frames_received; - ULONG nx_ppp_chap_frames_sent; - ULONG nx_ppp_chap_challenge_requests_sent; - ULONG nx_ppp_chap_challenge_requests_received; - ULONG nx_ppp_chap_challenge_responses_sent; - ULONG nx_ppp_chap_challenge_responses_received; - ULONG nx_ppp_chap_challenge_successes_sent; - ULONG nx_ppp_chap_challenge_successes_received; - ULONG nx_ppp_chap_challenge_failures_sent; - ULONG nx_ppp_chap_challenge_failures_received; - ULONG nx_ppp_chap_unknown_requests_received; - ULONG nx_ppp_chap_state_machine_unhandled_requests; - ULONG nx_ppp_chap_state_machine_timeouts; -#endif - ULONG nx_ppp_ipcp_frames_received; - ULONG nx_ppp_ipcp_frames_sent; - ULONG nx_ppp_ipcp_configure_requests_sent; - ULONG nx_ppp_ipcp_configure_requests_received; - ULONG nx_ppp_ipcp_configure_acks_sent; - ULONG nx_ppp_ipcp_configure_acks_received; - ULONG nx_ppp_ipcp_configure_naks_sent; - ULONG nx_ppp_ipcp_configure_naks_received; - ULONG nx_ppp_ipcp_configure_rejects_sent; - ULONG nx_ppp_ipcp_configure_rejects_received; - ULONG nx_ppp_ipcp_terminate_requests_sent; - ULONG nx_ppp_ipcp_terminate_requests_received; - ULONG nx_ppp_ipcp_terminate_acks_sent; - ULONG nx_ppp_ipcp_terminate_acks_received; - ULONG nx_ppp_ipcp_unknown_requests_received; - ULONG nx_ppp_ipcp_state_machine_unhandled_requests; - ULONG nx_ppp_ipcp_state_machine_timeouts; - ULONG nx_ppp_ip_frames_received; - ULONG nx_ppp_ip_frames_sent; - ULONG nx_ppp_receive_frames_dropped; - ULONG nx_ppp_transmit_frames_dropped; - ULONG nx_ppp_invalid_frame_id; -#endif - - void (*nx_ppp_byte_send)(UCHAR byte); - -#ifdef NX_PPP_PPPOE_ENABLE - void (*nx_ppp_packet_send)(NX_PACKET *packet_ptr); -#endif /* NX_PPP_PPPOE_ENABLE */ - - void (*nx_ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr); - void (*nx_ppp_nak_authentication_notify)(void); - - void (*nx_ppp_link_up_callback)(struct NX_PPP_STRUCT *ppp_ptr); - void (*nx_ppp_link_down_callback)(struct NX_PPP_STRUCT *ppp_ptr); - - UINT (*nx_ppp_pap_verify_login)(CHAR *name, CHAR *password); - UINT (*nx_ppp_pap_generate_login)(CHAR *name, CHAR *password); - - UINT (*nx_ppp_chap_get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name); - UINT (*nx_ppp_chap_get_responder_values)(CHAR *sys, CHAR *name, CHAR *secret); - UINT (*nx_ppp_chap_get_verification_values)(CHAR *sys, CHAR *name, CHAR *secret); - TX_EVENT_FLAGS_GROUP - nx_ppp_event; - TX_TIMER nx_ppp_timer; - - UCHAR nx_ppp_serial_buffer[NX_PPP_SERIAL_BUFFER_SIZE]; - USHORT nx_ppp_serial_buffer_write_index; - USHORT nx_ppp_serial_buffer_read_index; - USHORT nx_ppp_serial_buffer_byte_count; - - NX_PACKET *nx_ppp_receive_partial_packet; - ULONG nx_ppp_receive_buffer_size; - UCHAR *nx_ppp_receive_buffer_ptr; - - NX_PACKET *nx_ppp_head_packet; - -#ifdef NX_PPP_PPPOE_ENABLE - - /* Define the deferred packet processing queue for driver packet. */ - NX_PACKET *nx_ppp_deferred_received_packet_head, - *nx_ppp_deferred_received_packet_tail; -#endif /* NX_PPP_PPPOE_ENABLE */ - - NX_PACKET *nx_ppp_raw_packet_queue_head; - NX_PACKET *nx_ppp_raw_packet_queue_tail; - ULONG nx_ppp_raw_packet_queue_count; - - NX_PACKET *nx_ppp_ip_packet_queue_head; - NX_PACKET *nx_ppp_ip_packet_queue_tail; - ULONG nx_ppp_ip_packet_queue_count; - - TX_THREAD nx_ppp_thread; - struct NX_PPP_STRUCT - *nx_ppp_created_next, - *nx_ppp_created_previous; - - UCHAR nx_ppp_naked_list[NX_PPP_OPTION_MESSAGE_LENGTH]; - UCHAR nx_ppp_peer_naked_list[NX_PPP_OPTION_MESSAGE_LENGTH]; - UCHAR nx_ppp_rejected_list[NX_PPP_OPTION_MESSAGE_LENGTH]; - -#ifdef NX_PPP_DEBUG_LOG_ENABLE - NX_PPP_DEBUG_ENTRY - nx_ppp_debug_log[NX_PPP_DEBUG_LOG_SIZE]; - UINT nx_ppp_debug_log_oldest_index; -#endif - -} NX_PPP; - - -#ifndef NX_PPP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_ppp_byte_receive _nx_ppp_byte_receive -#define nx_ppp_chap_challenge _nx_ppp_chap_challenge -#define nx_ppp_chap_enable _nx_ppp_chap_enable -#define nx_ppp_create _nx_ppp_create -#define nx_ppp_delete _nx_ppp_delete -#define nx_ppp_dns_address_get _nx_ppp_dns_address_get -#define nx_ppp_dns_address_set _nx_ppp_dns_address_set -#define nx_ppp_secondary_dns_address_get _nx_ppp_secondary_dns_address_get -#define nx_ppp_secondary_dns_address_set _nx_ppp_secondary_dns_address_set -#define nx_ppp_driver _nx_ppp_driver -#define nx_ppp_interface_index_get _nx_ppp_interface_index_get -#define nx_ppp_ip_address_assign _nx_ppp_ip_address_assign -#define nx_ppp_link_down_notify _nx_ppp_link_down_notify -#define nx_ppp_link_up_notify _nx_ppp_link_up_notify -#define nx_ppp_nak_authentication_notify _nx_ppp_nak_authentication_notify -#define nx_ppp_pap_enable _nx_ppp_pap_enable -#define nx_ppp_raw_string_send _nx_ppp_raw_string_send -#define nx_ppp_start _nx_ppp_start -#define nx_ppp_stop _nx_ppp_stop -#define nx_ppp_restart _nx_ppp_restart -#define nx_ppp_status_get _nx_ppp_status_get -#define nx_ppp_ping_request _nx_ppp_ping_request -#ifdef NX_PPP_PPPOE_ENABLE -#define nx_ppp_packet_receive _nx_ppp_packet_receive -#define nx_ppp_packet_send_set _nx_ppp_packet_send_set -#endif /* NX_PPP_PPPOE_ENABLE */ - -#else - -/* Services with error checking. */ - -#define nx_ppp_byte_receive _nxe_ppp_byte_receive -#define nx_ppp_chap_challenge _nxe_ppp_chap_challenge -#define nx_ppp_chap_enable _nxe_ppp_chap_enable -#define nx_ppp_create _nxe_ppp_create -#define nx_ppp_delete _nxe_ppp_delete -#define nx_ppp_dns_address_get _nxe_ppp_dns_address_get -#define nx_ppp_dns_address_set _nxe_ppp_dns_address_set -#define nx_ppp_secondary_dns_address_get _nxe_ppp_secondary_dns_address_get -#define nx_ppp_secondary_dns_address_set _nxe_ppp_secondary_dns_address_set -#define nx_ppp_driver _nx_ppp_driver -#define nx_ppp_interface_index_get _nxe_ppp_interface_index_get -#define nx_ppp_ip_address_assign _nxe_ppp_ip_address_assign -#define nx_ppp_link_down_notify _nxe_ppp_link_down_notify -#define nx_ppp_link_up_notify _nxe_ppp_link_up_notify -#define nx_ppp_nak_authentication_notify _nxe_ppp_nak_authentication_notify -#define nx_ppp_pap_enable _nxe_ppp_pap_enable -#define nx_ppp_raw_string_send _nxe_ppp_raw_string_send -#define nx_ppp_start _nxe_ppp_start -#define nx_ppp_stop _nxe_ppp_stop -#define nx_ppp_restart _nxe_ppp_restart -#define nx_ppp_status_get _nxe_ppp_status_get -#define nx_ppp_ping_request _nxe_ppp_ping_request -#ifdef NX_PPP_PPPOE_ENABLE -#define nx_ppp_packet_receive _nxe_ppp_packet_receive -#define nx_ppp_packet_send_set _nxe_ppp_packet_send_set -#endif /* NX_PPP_PPPOE_ENABLE */ - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); -UINT nx_ppp_chap_challenge(NX_PPP *ppp_ptr); -UINT nx_ppp_chap_enable(NX_PPP *ppp_ptr, - UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), - UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), - UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); -UINT nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, - VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, - NX_PACKET_POOL *pool_ptr, - void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), - void (*ppp_byte_send)(UCHAR byte)); -UINT nx_ppp_delete(NX_PPP *ppp_ptr); -UINT nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); -UINT nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); -UINT nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); -UINT nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); -void nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); -UINT nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); -UINT nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); -UINT nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); -UINT nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); -UINT nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); -UINT nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); -UINT nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); -UINT nx_ppp_start(NX_PPP *ppp_ptr); -UINT nx_ppp_stop(NX_PPP *ppp_ptr); -UINT nx_ppp_restart(NX_PPP *ppp_ptr); -UINT nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); -UINT nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); -#ifdef NX_PPP_PPPOE_ENABLE -UINT nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT nx_ppp_packet_send_set(NX_PPP *ppp_ptr, void (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); -#endif /* NX_PPP_PPPOE_ENABLE */ - -#else /* NX_PPP_SOURCE_CODE */ - -UINT _nxe_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); -UINT _nx_ppp_byte_receive(NX_PPP *ppp_ptr, UCHAR byte); -UINT _nxe_ppp_chap_challenge(NX_PPP *ppp_ptr); -UINT _nx_ppp_chap_challenge(NX_PPP *ppp_ptr); -UINT _nxe_ppp_chap_enable(NX_PPP *ppp_ptr, - UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), - UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), - UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); -UINT _nx_ppp_chap_enable(NX_PPP *ppp_ptr, - UINT (*get_challenge_values)(CHAR *rand_value, CHAR *id, CHAR *name), - UINT (*get_responder_values)(CHAR *system, CHAR *name, CHAR *secret), - UINT (*get_verification_values)(CHAR *system, CHAR *name, CHAR *secret)); -UINT _nxe_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, - VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, - NX_PACKET_POOL *pool_ptr, - void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), - void (*ppp_byte_send)(UCHAR byte)); -UINT _nx_ppp_create(NX_PPP *ppp_ptr, CHAR *name, NX_IP *ip_ptr, - VOID *stack_memory_ptr, ULONG stack_size, UINT thread_priority, - NX_PACKET_POOL *pool_ptr, - void (*ppp_non_ppp_packet_handler)(NX_PACKET *packet_ptr), - void (*ppp_byte_send)(UCHAR byte)); -UINT _nxe_ppp_delete(NX_PPP *ppp_ptr); -UINT _nx_ppp_delete(NX_PPP *ppp_ptr); -UINT _nxe_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); -UINT _nx_ppp_dns_address_get(NX_PPP *ppp_ptr, ULONG *dns_address_ptr); -UINT _nxe_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); -UINT _nx_ppp_dns_address_set(NX_PPP *ppp_ptr, ULONG dns_address); -UINT _nxe_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); -UINT _nx_ppp_secondary_dns_address_get(NX_PPP *ppp_ptr, ULONG *secondary_dns_address_ptr); -UINT _nxe_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); -UINT _nx_ppp_secondary_dns_address_set(NX_PPP *ppp_ptr, ULONG secondary_dns_address); -UINT _nxe_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); -UINT _nx_ppp_interface_index_get(NX_PPP *ppp_ptr, UINT *index_ptr); -UINT _nxe_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); -UINT _nx_ppp_ip_address_assign(NX_PPP *ppp_ptr, ULONG local_ip_address, ULONG peer_ip_address); -UINT _nxe_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); -UINT _nx_ppp_link_down_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_down_callback)(NX_PPP *ppp_ptr)); -UINT _nxe_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); -UINT _nx_ppp_link_up_notify(NX_PPP *ppp_ptr, VOID (*ppp_link_up_callback)(NX_PPP *ppp_ptr)); -UINT _nxe_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); -UINT _nx_ppp_nak_authentication_notify(NX_PPP *ppp_ptr, void (*nak_authentication_notify)(void)); -UINT _nxe_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); -UINT _nx_ppp_pap_enable(NX_PPP *ppp_ptr, UINT (*generate_login)(CHAR *name, CHAR *password), UINT (*verify_login)(CHAR *name, CHAR *password)); -UINT _nxe_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); -UINT _nx_ppp_raw_string_send(NX_PPP *ppp_ptr, CHAR *string_ptr); -UINT _nxe_ppp_start(NX_PPP *ppp_ptr); -UINT _nx_ppp_start(NX_PPP *ppp_ptr); -UINT _nxe_ppp_stop(NX_PPP *ppp_ptr); -UINT _nx_ppp_stop(NX_PPP *ppp_ptr); -UINT _nxe_ppp_restart(NX_PPP *ppp_ptr); -UINT _nx_ppp_restart(NX_PPP *ppp_ptr); -UINT _nxe_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); -UINT _nx_ppp_status_get(NX_PPP *ppp_ptr, UINT *status_ptr); -UINT _nxe_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); -UINT _nx_ppp_ping_request(NX_PPP *ppp_ptr, CHAR *data_ptr, ULONG data_size, ULONG wait_option); -#ifdef NX_PPP_PPPOE_ENABLE -UINT _nxe_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT _nx_ppp_packet_receive(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT _nxe_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); -UINT _nx_ppp_packet_send_set(NX_PPP *ppp_ptr, VOID (*nx_ppp_packet_send)(NX_PACKET *packet_ptr)); -#endif /* NX_PPP_PPPOE_ENABLE */ - -/* Define internal PPP services. */ -void _nx_ppp_thread_entry(ULONG ppp_addr); -void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); -void _nx_ppp_receive_packet_get(NX_PPP *ppp_ptr, NX_PACKET **return_packet_ptr); -void _nx_ppp_receive_packet_process(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_timeout(NX_PPP *ppp_ptr); -void _nx_ppp_timer_entry(ULONG id); -void _nx_ppp_netx_packet_transfer(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_process_deferred_raw_string_send(NX_PPP *ppp_ptr); -void _nx_ppp_process_deferred_ip_packet_send(NX_PPP *ppp_ptr); -void _nx_ppp_lcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_lcp_code_reject(NX_PPP *ppp_ptr, UCHAR *lcp_ptr); -void _nx_ppp_lcp_configure_reply_send(NX_PPP *ppp_ptr, UINT configure_status, UCHAR *lcp_ptr, UCHAR *naked_list, UCHAR *rejected_list); -void _nx_ppp_lcp_configure_request_send(NX_PPP *ppp_ptr); -UINT _nx_ppp_lcp_configuration_retrieve(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list); -void _nx_ppp_lcp_nak_configure_list(NX_PPP *ppp_ptr, UCHAR *naked_list); -void _nx_ppp_lcp_terminate_ack_send(NX_PPP *ppp_ptr); -void _nx_ppp_lcp_terminate_request_send(NX_PPP *ppp_ptr); -void _nx_ppp_pap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_pap_authentication_request(NX_PPP *ppp_ptr); -UINT _nx_ppp_pap_login_valid(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_pap_authentication_ack(NX_PPP *ppp_ptr); -void _nx_ppp_pap_authentication_nak(NX_PPP *ppp_ptr); -void _nx_ppp_chap_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_chap_challenge_send(NX_PPP *ppp_ptr); -void _nx_ppp_chap_challenge_respond(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT _nx_ppp_chap_challenge_validate(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_ipcp_state_machine_update(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT _nx_ppp_ipcp_configure_check(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr, UCHAR *naked_list, UCHAR *rejected_list, UCHAR *good_data); -void _nx_ppp_ipcp_configure_request_send(NX_PPP *ppp_ptr, UCHAR *negotiate_list); -void _nx_ppp_ipcp_response_extract(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_ipcp_response_send(NX_PPP *ppp_ptr, UCHAR type, UCHAR *data, UCHAR length, NX_PACKET *cfg_packet_ptr); -void _nx_ppp_ipcp_terminate_send(NX_PPP *ppp_ptr); -void _nx_ppp_ipcp_terminate_ack_send(NX_PPP *ppp_ptr); -void _nx_ppp_packet_transmit(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -UINT _nx_ppp_check_crc(NX_PACKET *packet_ptr); -UINT _nx_ppp_crc_append(NX_PACKET *packet_ptr, UCHAR crc[2]); -void _nx_ppp_debug_log_capture(NX_PPP *ppp_ptr, UCHAR packet_type, NX_PACKET *packet_ptr); -void _nx_ppp_debug_log_capture_protocol(NX_PPP *ppp_ptr); -void _nx_ppp_hash_generator(unsigned char *hvalue, unsigned char id, unsigned char *secret, unsigned char *rand_value, UINT length); -void _nx_ppp_lcp_ping_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); -void _nx_ppp_lcp_ping_process_echo_reply(NX_PPP *ppp_ptr, NX_PACKET *packet_ptr); - -#endif /* NX_PPP_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_PPP_H */ diff --git a/protocol_handlers/pppoe/nx_pppoe_client.c b/protocol_handlers/pppoe/nx_pppoe_client.c deleted file mode 100644 index bca12f0f..00000000 --- a/protocol_handlers/pppoe/nx_pppoe_client.c +++ /dev/null @@ -1,3734 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** PPP Over Ethernet (PPPoE) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_PPPOE_CLIENT_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -#ifndef TX_DISABLE_ERROR_CHECKING -#define TX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_ip.h" -#include "nx_packet.h" -#include "nx_pppoe_client.h" -#include "tx_thread.h" -#include "tx_timer.h" - -/* Define the PPPoE created list head pointer and count. */ -NX_PPPOE_CLIENT *_nx_pppoe_client_created_ptr = NX_NULL; - - -/* Define internal PPPoE services. */ - -static VOID _nx_pppoe_client_thread_entry(ULONG pppoe_client_ptr_value); -static VOID _nx_pppoe_client_timer_entry(ULONG pppoe_client_address); -static VOID _nx_pppoe_client_packet_receive(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); -static VOID _nx_pppoe_client_discovery_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw); -static VOID _nx_pppoe_client_session_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw); -static UINT _nx_pppoe_client_discovery_send(NX_PPPOE_CLIENT *pppoe_client_ptr, UINT code); -static VOID _nx_pppoe_client_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, UINT command); -static ULONG _nx_pppoe_client_data_get(UCHAR *data, UINT size); -static VOID _nx_pppoe_client_data_add(UCHAR *data, UINT size, ULONG value); -static VOID _nx_pppoe_client_string_add(UCHAR *dest, UCHAR *source, UINT size); -static UINT _nx_pppoe_client_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index); -static UINT _nx_pppoe_client_session_cleanup(NX_PPPOE_CLIENT *pppoe_client_ptr); -static VOID _nx_pppoe_client_session_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); -static VOID _nx_pppoe_client_session_thread_resume(TX_THREAD **suspension_list_head, UINT status); -static VOID _nx_pppoe_client_session_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), - NX_PPPOE_CLIENT *pppoe_client_ptr, TX_MUTEX *mutex_ptr, ULONG wait_option); - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Client instance create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* name Name of this PPPoE instance */ -/* ip_ptr Pointer to IP control block */ -/* interface_index IP Interface Index */ -/* pool_ptr packet pool */ -/* stack_ptr Pointer stack area for PPPoE */ -/* stack_size Size of PPPoE stack area */ -/* priority Priority of PPPoE thread */ -/* pppoe_link_driver User supplied link driver */ -/* pppoe_packet_receive User supplied function to */ -/* receive PPPoE packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_create Actual PPPoE instance create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), - VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id == NX_PPPOE_CLIENT_ID) || - (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || - (stack_ptr == NX_NULL) || (pppoe_link_driver == NX_NULL) || (pppoe_packet_receive == NX_NULL)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Check for invalid interface ID */ - if(interface_index >= NX_MAX_PHYSICAL_INTERFACES) - return(NX_PPPOE_CLIENT_INVALID_INTERFACE); - - /* Check for interface being valid. */ - if(!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) - return(NX_PPPOE_CLIENT_INVALID_INTERFACE); - - /* Check for payload size of packet pool. */ - if (pool_ptr -> nx_packet_pool_payload_size < NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE) - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - - /* Check for a memory size error. */ - if (stack_size < TX_MINIMUM_STACK) - return(NX_PPPOE_CLIENT_MEMORY_SIZE_ERROR); - - /* Check the priority specified. */ - if (priority >= TX_MAX_PRIORITIES) - return(NX_PPPOE_CLIENT_PRIORITY_ERROR); - - /* Call actual PPPoE client instance create function. */ - status = _nx_pppoe_client_create(pppoe_client_ptr, name, ip_ptr, interface_index, - pool_ptr, stack_ptr, stack_size, priority, - pppoe_link_driver, pppoe_packet_receive); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an PPPoE Client instance, including setting */ -/* up all appropriate data structures, creating PPPoE event flag */ -/* object and PPPoE thread. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* name Name of this PPPoE instance */ -/* ip_ptr Pointer to IP control block */ -/* interface_index Interface Index */ -/* pool_ptr packet pool */ -/* stack_ptr Pointer stack area for PPPoE */ -/* stack_size Size of PPPoE stack area */ -/* priority Priority of PPPoE thread */ -/* pppoe_link_driver User supplied link driver */ -/* pppoe_packet_receive User supplied function to */ -/* receive PPPoE packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_create Create IP event flags */ -/* tx_thread_create Create IP helper thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), - VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Initialize the PPPoE Server control block to zero. */ - memset((void *) pppoe_client_ptr, 0, sizeof(NX_PPPOE_CLIENT)); - - /* Save the PPPoE name. */ - pppoe_client_ptr -> nx_pppoe_name = name; - - /* Save the IP pointer. */ - pppoe_client_ptr -> nx_pppoe_ip_ptr = ip_ptr; - - /* Setup the interface index and interface pointer. */ - pppoe_client_ptr -> nx_pppoe_interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]); - - /* Save the packet pool pointer. */ - pppoe_client_ptr -> nx_pppoe_packet_pool_ptr = pool_ptr; - - /* Setup the link driver address. */ - pppoe_client_ptr -> nx_pppoe_link_driver_entry = pppoe_link_driver; - - /* Setup the function to receive PPPoE packet. */ - pppoe_client_ptr ->nx_pppoe_packet_receive = pppoe_packet_receive; - - /* Create event flag group to control the PPPoE processing thread. */ - tx_event_flags_create(&(pppoe_client_ptr -> nx_pppoe_events), "PPPoE Client EVENTS") ; - - /* Create the PPPoE processing thread. */ - tx_thread_create(&(pppoe_client_ptr -> nx_pppoe_thread), "PPPoE Client THREAD", _nx_pppoe_client_thread_entry, (ULONG) pppoe_client_ptr, - stack_ptr, stack_size, priority, priority, NX_PPPOE_CLIENT_THREAD_TIME_SLICE, TX_AUTO_START); - - /* Create the PPPoE timer. */ - tx_timer_create(&(pppoe_client_ptr -> nx_pppoe_timer), "PPPoE Client timer", - (VOID (*)(ULONG))_nx_pppoe_client_timer_entry, (ULONG)pppoe_client_ptr, - NX_IP_PERIODIC_RATE, NX_IP_PERIODIC_RATE, TX_NO_ACTIVATE); - - /* Otherwise, the PPPoE initialization was successful. Place the - PPPoE control block on created PPPoE instance. */ - TX_DISABLE - - /* Load the PPPoE Client ID field in the PPPoE Client control block. */ - pppoe_client_ptr -> nx_pppoe_id = NX_PPPOE_CLIENT_ID; - - /* Set the pointer of global variable PPPoE. */ - _nx_pppoe_client_created_ptr = pppoe_client_ptr; - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Client instance delete */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_delete Actual PPPoE instance delete */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE client instance delete function. */ - status = _nx_pppoe_client_delete(pppoe_client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes an PPPoE Client instance. including deleting */ -/* PPPoE event flag object and PPPoE thread. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_terminate Terminate PPPoE helper thread */ -/* tx_thread_delete Delete PPPoE helper thread */ -/* tx_event_flags_delete Delete PPPoE event flags */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Determine if the caller is the PPPoE thread itself. This is not allowed since - a thread cannot delete itself in ThreadX. */ - if (&pppoe_client_ptr -> nx_pppoe_thread == tx_thread_identify()) - { - - /* Invalid caller of this routine, return an error! */ - return(NX_CALLER_ERROR); - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Clear the PPPOE ID to show that it is no longer valid. */ - pppoe_client_ptr -> nx_pppoe_id = 0; - - /* Clear the created pointer. */ - _nx_pppoe_client_created_ptr = NX_NULL; - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Terminate the thread. */ - tx_thread_terminate(&(pppoe_client_ptr -> nx_pppoe_thread)); - - /* Delete the PPPoE thread. */ - tx_thread_delete(&(pppoe_client_ptr -> nx_pppoe_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(pppoe_client_ptr -> nx_pppoe_events)); - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_service_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE service name set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an service name. */ -/* Service name must be */ -/* Null-terminated string. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_service_name_set Actual PPPoE service name set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE service name set function. */ - status = _nx_pppoe_client_service_name_set(pppoe_client_ptr, service_name); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_service_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the service name for PPPoE Client. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an service name. */ -/* Service name must be */ -/* Null-terminated string. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* _nx_pppoe_client_service_name_set Actual PPPoE service name set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name) -{ -UINT status; -UINT service_name_length = 0; - - - /* Calculate the service_name length. */ - if (_nx_utility_string_length_check((CHAR *)service_name, &service_name_length, NX_MAX_STRING_LENGTH)) - { - return(NX_SIZE_ERROR); - } - - /* Call actual PPPoE service name set function. */ - status = _nx_pppoe_client_service_name_set_extended(pppoe_client_ptr, service_name, service_name_length); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_service_name_set_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE service name set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an service name. */ -/* Service name must be */ -/* Null-terminated string. */ -/* service_name_length Length of service_name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_service_name_set_extended */ -/* Actual PPPoE service name set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE service name set function. */ - status = _nx_pppoe_client_service_name_set_extended(pppoe_client_ptr, service_name, service_name_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_service_name_set_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the service name for PPPoE Client. */ -/* */ -/* Note: The string of service_name must be NULL-terminated and length */ -/* of service_name matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an service name. */ -/* Service name must be */ -/* Null-terminated string. */ -/* service_name_length Length of service_name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length) -{ - -UINT temp_service_name_length = 0; - - /* Get the length of service_name string. */ - if (_nx_utility_string_length_check((CHAR*)service_name, &temp_service_name_length, service_name_length)) - return(NX_SIZE_ERROR); - - /* Check the service_name length. */ - if (service_name_length != temp_service_name_length) - return(NX_SIZE_ERROR); - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Setup service name pointer. */ - pppoe_client_ptr -> nx_pppoe_service_name = service_name; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_host_uniq_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE host uniq set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* host_uniq Pointer to an host unique. */ -/* Host unique must be */ -/* Null-terminated string. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_host_uniq_set Actual PPPoE host uniq set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE host uniq set function. */ - status = _nx_pppoe_client_host_uniq_set(pppoe_client_ptr, host_uniq); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_host_uniq_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the host unique for PPPoE Client. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* host_uniq Pointer to an host unique. */ -/* Host unique must be */ -/* Null-terminated string. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* _nx_pppoe_client_host_uniq_set_extended */ -/* Actual PPPoE host uniq set */ -/* function */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq) -{ -UINT status; -UINT host_uniq_length = 0; - - /* Calculate the host_uniq length. */ - if (_nx_utility_string_length_check((CHAR *)host_uniq, &host_uniq_length, NX_MAX_STRING_LENGTH)) - { - return(NX_SIZE_ERROR); - } - - status = _nx_pppoe_client_host_uniq_set_extended(pppoe_client_ptr, host_uniq, host_uniq_length); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_host_uniq_set_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE host uniq set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* host_uniq Pointer to an host unique. */ -/* Host unique must be */ -/* Null-terminated string. */ -/* host_uniq_length Length of host_uniq */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_host_uniq_set_extended */ -/* Actual PPPoE host uniq set */ -/* function */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE host uniq set function. */ - status = _nx_pppoe_client_host_uniq_set_extended(pppoe_client_ptr, host_uniq, host_uniq_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_host_uniq_set_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the host unique for PPPoE Client. */ -/* */ -/* Note: The string of host_uniq must be NULL-terminated and length */ -/* of host_uniq matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* host_uniq Pointer to an host unique. */ -/* Host unique must be */ -/* Null-terminated string. */ -/* host_uniq_length Length of host_uniq */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length) -{ -UINT temp_host_uniq_length = 0; - - /* Get the length of host_uniq string. */ - if (_nx_utility_string_length_check((CHAR*)host_uniq, &temp_host_uniq_length, host_uniq_length)) - return(NX_SIZE_ERROR); - - /* Check the host_uniq length. */ - if (host_uniq_length != temp_host_uniq_length) - return(NX_SIZE_ERROR); - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Setup service name pointer. */ - pppoe_client_ptr -> nx_pppoe_host_uniq = host_uniq; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_session_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Client session connect */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_session_connect Actual PPPoE connect function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE client instance enable function. */ - status = _nx_pppoe_client_session_connect(pppoe_client_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects the PPPoE session. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_session_connect Actual PPPoE connect function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option) -{ - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check to PPPoE state. */ - if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_INITIAL) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return(NX_PPPOE_CLIENT_INVALID_SESSION); - } - - /* Activate the PPPoE client timer. */ - tx_timer_activate(&pppoe_client_ptr -> nx_pppoe_timer); - - /* Update the state. */ - pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_PADI_SENT; - - /* Set the retransmit timeout and count for PADI. */ - pppoe_client_ptr -> nx_pppoe_rtr_timeout = NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT; - pppoe_client_ptr -> nx_pppoe_rtr_count = NX_PPPOE_CLIENT_PADI_COUNT - 1; - - /* Start to establish the PPPoE session connection. */ - _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADI); - - /* Optionally suspend the thread. If timeout occurs, return a connection timeout status. If - immediate response is selected, return a connection in progress status. Only on a real - connection should success be returned. */ - if ((wait_option) && (_tx_thread_current_ptr != &(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_thread))) - { - - /* Suspend the thread on this socket's connection attempt. */ - /* Note: the IP protection mutex is released inside _nx_pppoe_client_session_thread_suspend(). */ - - _nx_pppoe_client_session_thread_suspend(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), _nx_pppoe_client_session_connect_cleanup, - pppoe_client_ptr, &(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), wait_option); - - /* Just return the completion code. */ - return(_tx_thread_current_ptr -> tx_thread_suspend_status); - } - else - { - - /* No suspension is request, just release protection and return to the caller. */ - - /* Release the IP protection. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return in-progress completion status. */ - return(NX_IN_PROGRESS); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_session_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session packet send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* packet_ptr Pointer to packet to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_session_packet_send Actual PPPoE Session data send*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; - - /* Check for invalid packet. */ - if (packet_ptr == NX_NULL) - { - return(NX_PPPOE_CLIENT_PTR_ERROR); - } - - /* Check for minimum packet length (PPP DATA Header). */ - if (packet_ptr -> nx_packet_length < 2) - { - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_CLIENT_PTR_ERROR); - } - - /* Call actual PPPoE session packet_send function. */ - status = _nx_pppoe_client_session_packet_send(pppoe_client_ptr, packet_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE Session packet and calls the */ -/* associated driver to send it out on the network. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* data_ptr Session Data pointer */ -/* data_length Length of Session Data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* nx_packet_release Release packet to packet pool */ -/* nx_packet_data_append Copies the specified data */ -/* _nx_pppoe_client_data_add Add PPPoE data */ -/* _nx_pppoe_client_packet_send Send out PPPoE packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) -{ - -NX_PPPOE_SERVER_SESSION *server_session_ptr; -UCHAR *work_ptr; - - - /* Obtain the IP internal mutex. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check to see if PPPoE session is established. */ - if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); - } - - /* Check for an invalid packet prepend pointer. */ - if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_PPPOE_CLIENT_OFFSET_PAYLOAD) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return error code. */ - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - - /* Set the server session pointer. */ - server_session_ptr = &(pppoe_client_ptr -> nx_pppoe_server_session); - - /* Set the work pointer. */ - packet_ptr -> nx_packet_prepend_ptr -= NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - work_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Added the PPPoE header. */ - /* - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | VER | TYPE | CODE | SESSION_ID | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | LENGTH | payload - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add version and type. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1, NX_PPPOE_CLIENT_VERSION_TYPE); - - /* Add code. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1, NX_PPPOE_CLIENT_CODE_ZERO); - - /* Add session id. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, server_session_ptr -> nx_pppoe_session_id); - - /* Add length. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2, packet_ptr -> nx_packet_length); - - /* Update the packet length. */ - packet_ptr -> nx_packet_length += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - - /* Send PPPoE session packet. */ - _nx_pppoe_client_packet_send(pppoe_client_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_session_terminate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session terminate */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_session_terminate Actual PPPoE Session terminate*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE session terminate function. */ - status = _nx_pppoe_client_session_terminate(pppoe_client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_terminate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE packet to terminate the session. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_client_discovery_send Send out PPPoE packet */ -/* _nx_pppoe_client_session_cleanup Cleanup PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr) -{ - -UINT status; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check to see if PPPoE is established. */ - if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); - } - - /* Terminate the PPPoE session. */ - status = _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADT); - - /* Check the status. */ - if (status == NX_PPPOE_CLIENT_SUCCESS) - { - - /* Cleanup the session. */ - _nx_pppoe_client_session_cleanup(pppoe_client_ptr); - } - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_client_session_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session get function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index The index of Client Session */ -/* server_mac_msw Server physical address MSW */ -/* server_mac_lsw Server physical address LSW */ -/* session_id Session ID */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_session_get Actual PPPoE Session get */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_client_ptr == NX_NULL) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - return(NX_PPPOE_CLIENT_PTR_ERROR); - - /* Call actual PPPoE session get function. */ - status = _nx_pppoe_client_session_get(pppoe_client_ptr, client_mac_msw, client_mac_lsw, session_id); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE packet to get the session physical */ -/* address and session id. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* session_index The index of Client Session */ -/* server_mac_msw Server physical address MSW */ -/* server_mac_lsw Server physical address LSW */ -/* session_id Session ID */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id) -{ - - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check to see if PPPoE session is established. */ - if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return(NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); - } - - /* Yes, get the Server physical address MSW. */ - if (server_mac_msw) - *server_mac_msw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw; - - /* Yes, get the Server physical address LSW. */ - if (server_mac_lsw) - *server_mac_lsw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw; - - /* Yes, get the Session ID. */ - if (session_id) - *session_id = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_client_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return status. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_packet_deferred_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives a packet from the link driver (usually the */ -/* link driver's input ISR) and places it in the deferred receive */ -/* packet queue. This moves the minimal receive packet processing */ -/* from the ISR to the PPPoE helper thread. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for PPPoE thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Check to see if PPPoE instance is created. */ - if (_nx_pppoe_client_created_ptr == NX_NULL) - { - - /* Release the packet. */; - nx_packet_release(packet_ptr); - - return; - } - - /* Check to see if PPPoE is ready to receive packet. */ - if (_nx_pppoe_client_created_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_INITIAL) - { - - /* Release the packet. */; - nx_packet_release(packet_ptr); - - return; - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Check to see if the deferred processing queue is empty. */ - if (_nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_head) - { - - /* Not empty, just place the packet at the end of the queue. */ - (_nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - - /* Restore interrupts. */ - TX_RESTORE - } - else - { - - /* Empty deferred receive processing queue. Just setup the head pointers and - set the event flags to ensure the PPPoE helper thread looks at the deferred processing - queue. */ - _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; - _nx_pppoe_client_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Restore interrupts. */ - TX_RESTORE - - /* Wakeup PPPoE helper thread to process the PPPoE deferred receive. */ - tx_event_flags_set(&(_nx_pppoe_client_created_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT, TX_OR); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry point for each PPPoE's helper thread. */ -/* The PPPoE helper thread is responsible for processing PPPoE packet. */ -/* */ -/* Note that the priority of this function is determined by the PPPoE */ -/* create service. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr_value Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Suspend on event flags that */ -/* are used to signal this */ -/* thread what to do */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_client_packet_receive PPPoE receive packet */ -/* processing */ -/* nx_packet_release Release packet to packet pool */ -/* (pppoe_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX Scheduler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_thread_entry(ULONG pppoe_client_ptr_value) -{ - - -TX_INTERRUPT_SAVE_AREA - -#ifdef NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE -NX_IP_DRIVER driver_request; -#endif -NX_PPPOE_CLIENT *pppoe_client_ptr; -NX_IP *ip_ptr; -NX_PACKET *packet_ptr; -ULONG pppoe_events; -ULONG timeout = 0; - - - /* Setup the PPPoE pointer. */ - pppoe_client_ptr = (NX_PPPOE_CLIENT *) pppoe_client_ptr_value; - - /* Setup the IP pointer. */ - ip_ptr = pppoe_client_ptr -> nx_pppoe_ip_ptr; - - /* Obtain the IP internal mutex before calling the driver. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - -#ifdef NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE - - /* Initialize and enable the hardware for physical interface. */ - - /* Is this a valid interface with a link driver associated with it? */ - if((pppoe_client_ptr -> nx_pppoe_interface_ptr -> nx_interface_valid) && (pppoe_client_ptr -> nx_pppoe_link_driver_entry)) - { - - /* Yes; attach the interface to the device. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_ATTACH; - driver_request.nx_ip_driver_interface = pppoe_client_ptr -> nx_pppoe_interface_ptr; - (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Call the link driver to initialize the hardware. Among other - responsibilities, the driver is required to provide the - Maximum Transfer Unit (MTU) for the physical layer. The MTU - should represent the actual physical layer transfer size - less the physical layer headers and trailers. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_INITIALIZE; - (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Call the link driver again to enable the interface. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_ENABLE; - (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Indicate to the IP software that IP to physical mapping - is not required. */ - pppoe_client_ptr -> nx_pppoe_interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; - } -#endif - - /* Loop to continue processing incoming bytes. */ - while(NX_FOREVER) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Pickup IP event flags. */ - tx_event_flags_get(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_ALL_EVENTS, TX_OR_CLEAR, &pppoe_events, NX_WAIT_FOREVER); - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check for PPPoE packet receive event. */ - if (pppoe_events & NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT) - { - - /* Loop to process all deferred packet requests. */ - while (pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head) - { - - /* Remove the first packet and process it! */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the first packet. */ - packet_ptr = pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head; - - /* Move the head pointer to the next packet. */ - pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; - - /* Check for end of deferred processing queue. */ - if (pppoe_client_ptr -> nx_pppoe_deferred_received_packet_head == NX_NULL) - { - - /* Yes, the queue is empty. Set the tail pointer to NULL. */ - pppoe_client_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Discard the chained packets. */ - if (packet_ptr -> nx_packet_next) - { - nx_packet_release(packet_ptr); - continue; - } -#endif - - /* Check for valid packet length. */ - if (packet_ptr -> nx_packet_length < NX_PPPOE_CLIENT_OFFSET_PAYLOAD) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check the packet interface. */ - if ((packet_ptr -> nx_packet_ip_interface != NX_NULL) && - (packet_ptr -> nx_packet_ip_interface != pppoe_client_ptr -> nx_pppoe_interface_ptr)) - { - nx_packet_release(packet_ptr); - continue; - } - - /* Call the actual PPPoE Client packet receive function. */ - _nx_pppoe_client_packet_receive(pppoe_client_ptr, packet_ptr); - } - } - - /* Check for PPPoE periodic timer event. */ - if (pppoe_events & NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT) - { - - /* Check if max number of PADI/PADR messages have been sent. */ - if (pppoe_client_ptr -> nx_pppoe_rtr_timeout != 0) - { - - /* Check on count down timer for sending out next PADI/PADR message. */ - pppoe_client_ptr -> nx_pppoe_rtr_timeout--; - - /* Check the timer. */ - if(pppoe_client_ptr -> nx_pppoe_rtr_timeout == 0) - { - - /* It has expired. Send out a PADI/PADR message. */ - - /* Check if max number of PADI/PADR messages have been sent. */ - if (pppoe_client_ptr -> nx_pppoe_rtr_count) - { - - /* Retransmit PADI/PADR message. */ - - /* When a host does not receive a PADO/PADS packet with in a specified amount of time, - it should resend it's PADI/PADR packet and double the waiting period. RFC2516, Section8, Page8. */ - - /* Check PPPoE state. */ - if (pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADI_SENT) - { - - /* Calculate timeout. */ - timeout = ((ULONG)NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT) << (ULONG)(NX_PPPOE_CLIENT_PADI_COUNT - pppoe_client_ptr -> nx_pppoe_rtr_count); - - /* Send PADI. */ - _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADI); - } - - /* Check PPPoE state. */ - if (pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADR_SENT) - { - - /* Calculate timeout. */ - timeout = ((ULONG)NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT) << (ULONG)(NX_PPPOE_CLIENT_PADR_COUNT - pppoe_client_ptr -> nx_pppoe_rtr_count); - - /* Send PADR. */ - _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADR); - } - - /* Update the retransmit count. */ - pppoe_client_ptr -> nx_pppoe_rtr_count --; - - /* Set the retransmit timeout. */ - pppoe_client_ptr -> nx_pppoe_rtr_timeout = timeout; - } - else - { - - /* Reach the max number of PADI/PADR have been sent. */ - - /* Deactivate the PPPoE client timer. */ - tx_timer_deactivate(&(pppoe_client_ptr -> nx_pppoe_timer)); - - /* Cleanup the PPPoE session. */ - _nx_pppoe_client_session_cleanup(pppoe_client_ptr); - - /* Determine if we need to wake a thread suspended on the connection. */ - if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) - { - - /* Resume the suspended thread. */ - _nx_pppoe_client_session_thread_resume(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED); - } - } - } - } - } - - /* Check for PPPoE event. */ - if (pppoe_events & NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT) - { - - if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) - { - _nx_pppoe_client_session_connect_cleanup(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread NX_CLEANUP_ARGUMENT); - } - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles waking up the PPPoE Client helper thread on a */ -/* periodic basis. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_address PPPoE address in a ULONG */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_timer_entry(ULONG pppoe_client_address) -{ - -NX_PPPOE_CLIENT *pppoe_client_ptr; - - - /* Convert input parameter to an PPPoE Client pointer. */ - pppoe_client_ptr = (NX_PPPOE_CLIENT *)pppoe_client_address; - - /* Wakeup this PPPoE Client's helper thread. */ - tx_event_flags_set(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives a PPPoE packet from the PPPoE deferred */ -/* processing queue. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_client_data_get Get the PPPoE data */ -/* _nx_pppoe_client_discovery_packet_process */ -/* Process discovery packet */ -/* _nx_pppoe_client_session_packet_process */ -/* Process session packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_client_packet_receive(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR *ethernet_header_ptr; -ULONG dest_mac_msw; -ULONG dest_mac_lsw; -ULONG src_mac_msw; -ULONG src_mac_lsw; -UINT ethernet_type; - - - /* Set up UCHAR pointer to ethernet header to extract client hardware address - which we will use as the client's unique identifier. */ - ethernet_header_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_PPPOE_CLIENT_ETHER_HEADER_SIZE; - - /* Pickup the MSW and LSW of the destination MAC address. */ - dest_mac_msw = (((ULONG) ethernet_header_ptr[0]) << 8) | ((ULONG) ethernet_header_ptr[1]); - dest_mac_lsw = (((ULONG) ethernet_header_ptr[2]) << 24) | (((ULONG) ethernet_header_ptr[3]) << 16) | - (((ULONG) ethernet_header_ptr[4]) << 8) | ((ULONG) ethernet_header_ptr[5]); - - /* Check the destination hardware (mac address) field is filled in. */ - if ((dest_mac_msw == 0) && (dest_mac_lsw == 0)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check if it is a broadcast message. - Only PADI packet with the destination address set to the broadcast address, and PADI only can be sent from PPPoE Client. */ - if ((dest_mac_msw == 0xFFFF) && (dest_mac_lsw == 0xFFFFFFFF)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the MSW and LSW of the source MAC address. */ - src_mac_msw = (((ULONG) ethernet_header_ptr[6]) << 8) | ((ULONG) ethernet_header_ptr[7]); - src_mac_lsw = (((ULONG) ethernet_header_ptr[8]) << 24) | (((ULONG) ethernet_header_ptr[9]) << 16) | - (((ULONG) ethernet_header_ptr[10]) << 8) | ((ULONG) ethernet_header_ptr[11]); - - /* Check the source hardware (mac address) field is filled in. */ - if ((src_mac_msw == 0) && (src_mac_lsw == 0)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Get the ethernet type. */ - ethernet_type = _nx_pppoe_client_data_get(ethernet_header_ptr + 12, 2); - - /* Process the packet according to packet type. */ - if(ethernet_type == NX_PPPOE_CLIENT_ETHER_TYPE_DISCOVERY) - { - - /* Process the discovery packet. */ - _nx_pppoe_client_discovery_packet_process(pppoe_client_ptr, packet_ptr, src_mac_msw, src_mac_lsw); - } - else if(ethernet_type == NX_PPPOE_CLIENT_ETHER_TYPE_SESSION) - { - - /* Process the session packet. */ - _nx_pppoe_client_session_packet_process(pppoe_client_ptr, packet_ptr, src_mac_msw, src_mac_lsw); - } - else - { - - /* Relase the packet. */ - nx_packet_release(packet_ptr); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_discovery_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an incoming discovery packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* is_broadcast Broadcast flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_client_data_get Get the PPPoE data */ -/* _nx_pppoe_client_tag_process Process PPPoE tags */ -/* _nx_pppoe_client_discovery_send Send discovery packet */ -/* _nx_pppoe_client_session_find Find the PPPoE session */ -/* _nx_pppoe_client_session_cleanup Cleanup the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_client_discovery_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw) -{ - - -UCHAR *pppoe_header_ptr; -UINT is_accepted = NX_FALSE; -ULONG ver_type; -ULONG code; -ULONG session_id; -ULONG length; -UCHAR *tag_ptr; -ULONG tag_type; -ULONG tag_length; -UINT tag_index = 0; -UINT tag_ac_name_count = 0; -UINT tag_service_name_count = 0; -UINT tag_service_name_valid = NX_FALSE; -UINT tag_host_uniq_count = 0; -UINT tag_host_uniq_valid = NX_FALSE; - - - /* Setup the PPPoE header. */ - pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the version and type. */ - ver_type = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1); - - /* Check the version and type. */ - if (ver_type != NX_PPPOE_CLIENT_VERSION_TYPE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the code. */ - code = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1); - - /* Check the session state and the code of incoming packet. */ - if (((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADI_SENT) && (code == NX_PPPOE_CLIENT_CODE_PADO)) || - ((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_PADR_SENT) && (code == NX_PPPOE_CLIENT_CODE_PADS)) || - ((pppoe_client_ptr -> nx_pppoe_state == NX_PPPOE_CLIENT_STATE_ESTABLISHED) && (code == NX_PPPOE_CLIENT_CODE_PADT))) - { - - /* Packet can be accepted. */ - is_accepted = NX_TRUE; - } - - /* Ignore the packet that is not accepted. */ - if (is_accepted != NX_TRUE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the session id. */ - session_id = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2); - - /* Check the session id. - Session ID must be zero for PADO, - Session ID must be not zero for PADS and PADT. - Session ID must be same value for PADT. */ - if (((code == NX_PPPOE_CLIENT_CODE_PADO) && (session_id != 0)) || - ((code != NX_PPPOE_CLIENT_CODE_PADO) && (session_id == 0)) || - ((code == NX_PPPOE_CLIENT_CODE_PADT) && (session_id != pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id))) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check the MAC address for PADS and PADT before process tags. */ - if (code != NX_PPPOE_CLIENT_CODE_PADO) - { - - if ((pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw != server_mac_msw) || - (pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw != server_mac_lsw)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - } - - /* Initialize the value. */ - pppoe_client_ptr -> nx_pppoe_ac_name_size = 0; - pppoe_client_ptr -> nx_pppoe_ac_cookie_size = 0; - pppoe_client_ptr -> nx_pppoe_relay_session_id_size = 0; - pppoe_client_ptr -> nx_pppoe_error_flag = 0; - - /* Pickup the length of tags. */ - length = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2); - - /* Check for valid payload. */ - if (length > packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Set the tag pointer. */ - tag_ptr = pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - - /* Loop to process the tag. */ - while (tag_index < length) - { - - /* Pickup the tag type. */ - tag_type = _nx_pppoe_client_data_get(tag_ptr + tag_index, 2); - - /* Update the index. */ - tag_index += 2; - - /* Pickup the tag length. */ - tag_length = _nx_pppoe_client_data_get(tag_ptr + tag_index, 2); - - /* Update the index. */ - tag_index += 2; - - /* Check for valid tag length. */ - if ((tag_index + tag_length) > length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Process the option type. */ - switch (tag_type) - { - - case NX_PPPOE_CLIENT_TAG_TYPE_END_OF_LIST: - { - - /* End tag. */ - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME: - { - - /* Update the Service-Name count. */ - tag_service_name_count ++; - - /* Check the tag length. */ - if (tag_length == 0) - { - - /* When the tag length is zero this tag is used to indicate that any service is acceptable. */ - tag_service_name_valid = NX_TRUE; - } - else - { - - /* Compare the service name with PPPoE Service name that Client is requesting. */ - if (!memcmp(tag_ptr + tag_index, pppoe_client_ptr -> nx_pppoe_service_name, tag_length)) - { - - /* Update the information. */ - tag_service_name_valid = NX_TRUE; - } - } - - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_AC_NAME: - { - - /* Check the cache for AC-Name. */ - if (tag_length > NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Update the AC-Name count. */ - tag_ac_name_count ++; - - /* Save the AC-Name. */ - memcpy(pppoe_client_ptr -> nx_pppoe_ac_name, tag_ptr + tag_index, tag_length); - - /* Set the AC-Name size. */ - pppoe_client_ptr -> nx_pppoe_ac_name_size = tag_length; - - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ: - { - - /* Update the Host-Uniq count. */ - tag_host_uniq_count ++; - - /* Check the Host-Uniq. */ - if (!memcmp(tag_ptr + tag_index, pppoe_client_ptr -> nx_pppoe_host_uniq, tag_length)) - { - - /* Update the information. */ - tag_host_uniq_valid = NX_TRUE; - } - - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE: - { - - /* Check the cache for AC-Cookie. */ - if (tag_length > NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Save the AC-Cookie. */ - memcpy(pppoe_client_ptr -> nx_pppoe_ac_cookie, tag_ptr + tag_index, tag_length); - - /* Set the AC-Cookie size. */ - pppoe_client_ptr -> nx_pppoe_ac_cookie_size = tag_length; - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_RELAY_SESSION_ID: - { - - /* Check the cache for Relay-Session_Id. */ - if (tag_length > NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Save the Relay-Session_Id. */ - memcpy(pppoe_client_ptr -> nx_pppoe_relay_session_id, tag_ptr + tag_index, tag_length); - - /* Set the Relay-Session_Id size. */ - pppoe_client_ptr -> nx_pppoe_relay_session_id_size = tag_length; - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME_ERROR: - { - - /* Set the service name error flag. */ - pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_SERVICE_NAME; - - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_AC_SYSTEM_ERROR: - { - - /* Set the AC system error flag. */ - pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_AC_SYSTEM; - - break; - } - case NX_PPPOE_CLIENT_TAG_TYPE_GENERIC_ERROR: - { - - /* Set the generic error flag. */ - pppoe_client_ptr -> nx_pppoe_error_flag |= NX_PPPOE_CLIENT_ERROR_GENERIC; - - break; - } - default: - break; - } - - /* Move to the next tag. */ - tag_index += tag_length; - } - - /* Now we can release the packet. */ - nx_packet_release(packet_ptr); - - /* Check the code value. */ - if (code == NX_PPPOE_CLIENT_CODE_PADO) - { - - /* PADO packet MUST contain one AC-Name TAG containing the Access Concentrator's name, - a Service-Name TAG indentical to the one in the PADI. RFC2516, Section5.2, Page6. */ - - /* Check AC-Name. */ - if (tag_ac_name_count != 1) - return; - - /* The Host MAY include a Host-Uniq TAG in a PADI or - PADR. If the Access Concentrator receives this TAG, it MUST - include the TAG unmodified in the associated PADO or PADS - response. RFC2516, Appendix A, Page10. */ - if (pppoe_client_ptr -> nx_pppoe_host_uniq) - { - - /* Check if include valid Host-Uniq. */ - if ((tag_host_uniq_count != 1) || (tag_host_uniq_valid != NX_TRUE)) - return; - } - else - { - - /* Check if include the Host-Uniq. */ - if (tag_host_uniq_count) - return; - } - - /* Check Service-Name. */ - if (tag_service_name_valid != NX_TRUE) - return; - - /* Check for error. */ - if (pppoe_client_ptr -> nx_pppoe_error_flag) - return; - - /* Choose one PPPoE Server. - Since the PADI was broadcast, the Host may receive more than one - PADO. The Host looks through the PADO packets it receives and - chooses one. The choice can be based on the AC-Name or the Services - offered. The Host then sends one PADR packet to the Access - Concentrator that it has chosen. RFC2516, Section5.3, Page6. */ - - /* Simplify the logic, we choose the first PPPoE Server sent out PADO. */ - - /* Record server information. */ - pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw = server_mac_msw; - pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw = server_mac_lsw; - - /* Send PPPoE Active Discovery Offer packet. */ - _nx_pppoe_client_discovery_send(pppoe_client_ptr, NX_PPPOE_CLIENT_CODE_PADR); - - /* Update the state. */ - pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_PADR_SENT; - - /* Set the retransmit timeout and count for PADR. */ - pppoe_client_ptr -> nx_pppoe_rtr_timeout = NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT; - pppoe_client_ptr -> nx_pppoe_rtr_count = NX_PPPOE_CLIENT_PADR_COUNT - 1; - } - else if (code == NX_PPPOE_CLIENT_CODE_PADS) - { - - /* The PADS packet contains exactly one TAG of TAG_TYPE Service-Name. RFC2516, Section5.4, Page6. */ - - /* Check Service-Name. */ - if ((tag_service_name_count != 1) || (tag_service_name_valid != NX_TRUE)) - return; - - /* Check for error. */ - if (pppoe_client_ptr -> nx_pppoe_error_flag) - return; - - /* Record the session id. */ - pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id = (USHORT)session_id; - - /* Update the state. */ - pppoe_client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_ESTABLISHED; - - /* Deactivate the PPPoE client timer. */ - tx_timer_deactivate(&(pppoe_client_ptr -> nx_pppoe_timer)); - - /* Determine if we need to wake a thread suspended on the connection. */ - if (pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread) - { - - /* Resume the suspended thread. */ - _nx_pppoe_client_session_thread_resume(&(pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread), NX_PPPOE_CLIENT_SUCCESS); - } - } - else if (code == NX_PPPOE_CLIENT_CODE_PADT) - { - - /* Cleanup the PPPoE session. */ - _nx_pppoe_client_session_cleanup(pppoe_client_ptr); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an incoming session packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_client_data_get Get the PPPoE data */ -/* _nx_pppoe_client_session_find Find the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_session_packet_process(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, ULONG server_mac_msw, ULONG server_mac_lsw) -{ - - -UCHAR *pppoe_header_ptr; -ULONG ver_type; -ULONG code; -ULONG session_id; -ULONG length; -NX_PPPOE_SERVER_SESSION *server_session_ptr; - - - /* Setup the PPPoE header. */ - pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the version and type. */ - ver_type = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1); - - /* Check the version and type. */ - if (ver_type != NX_PPPOE_CLIENT_VERSION_TYPE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the code. */ - code = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1); - - /* Check the code. */ - if (code != NX_PPPOE_CLIENT_CODE_ZERO) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the session id. */ - session_id = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2); - - /* Check the session id. */ - if (session_id == 0) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check the session state. */ - if (pppoe_client_ptr -> nx_pppoe_state != NX_PPPOE_CLIENT_STATE_ESTABLISHED) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Set the server session pointer. */ - server_session_ptr = &(pppoe_client_ptr -> nx_pppoe_server_session); - - /* Check the session id and server MAC address. */ - if ((session_id != server_session_ptr -> nx_pppoe_session_id) || - (server_mac_msw != server_session_ptr -> nx_pppoe_physical_address_msw) || - (server_mac_lsw != server_session_ptr -> nx_pppoe_physical_address_lsw)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Setup the prepend pointer to point the payload of PPPoE. */ - packet_ptr -> nx_packet_prepend_ptr += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - packet_ptr -> nx_packet_length -= NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - - /* Pickup the length of payload. */ - length = _nx_pppoe_client_data_get(pppoe_header_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2); - - /* Check for valid payload. */ - if (length > packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Remove the Ethernet padding. */ - if (length < packet_ptr -> nx_packet_length) - { - packet_ptr -> nx_packet_append_ptr -= (packet_ptr -> nx_packet_length - length); - packet_ptr -> nx_packet_length -= (packet_ptr -> nx_packet_length - length); - } - - /* Check the PPPoE receive function. */ - if (pppoe_client_ptr -> nx_pppoe_packet_receive) - { - - /* Call the function to receive the data frame. - Notice: the receive function must release this packet. */ - pppoe_client_ptr -> nx_pppoe_packet_receive(packet_ptr); - } - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_discovery_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a PPPoE discovery packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* client_session_ptr Pointer to Client Session */ -/* code PPPoE code */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate a packet for the */ -/* PPPoE Discovery */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_client_data_add Add PPPoE data */ -/* _nx_pppoe_client_tag_string_add Add PPPoE tag */ -/* _nx_pppoe_client_packet_send Send out PPPoE packet */ -/* _nx_pppoe_client_session_find Find the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_session_terminate Terminate the PPPoE session */ -/* _nx_pppoe_client_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_client_discovery_send(NX_PPPOE_CLIENT *pppoe_client_ptr, UINT code) -{ - - -NX_PACKET *packet_ptr; -UCHAR *work_ptr; -UINT status; -UINT index = 0; -UINT tag_length; - - - /* Allocate a PPPoE packet. */ - status = nx_packet_allocate(pppoe_client_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_NO_WAIT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Set the work pointer. */ - work_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First skip the PPPoE header. */ - index += NX_PPPOE_CLIENT_OFFSET_PAYLOAD; - - /* The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type-length-value) construct and is defined as follows. */ - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | TAG_TYPE | TAG_LENGTH | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | TAG_VALUE ... - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add the PPPoE tags. */ - if (code == NX_PPPOE_CLIENT_CODE_PADI) - { - - /* The PADI packet MUST contain exactly one TAG of TAG_TYPE Service-Name, indicating the service the host is requesting, - and any number of other TAG types. RFC2516, Section5.1, Page5. */ - if (pppoe_client_ptr -> nx_pppoe_service_name) - { - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_SERVICE_NAME_ERROR); - } - - if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= - (4 + tag_length)) - { - - /* Added the Service-Name tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, tag_length, pppoe_client_ptr -> nx_pppoe_service_name, &index); - } - else - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - } - else - { - - /* Added the Service-Name tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); - } - - /* The Host MAY include a Host-Uniq TAG in a PADI or PADR. */ - if (pppoe_client_ptr -> nx_pppoe_host_uniq) - { - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_host_uniq), &tag_length, NX_MAX_STRING_LENGTH)) - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - - if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= - (4 + tag_length)) - { - - /* Added the Host-Uniq tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, tag_length, pppoe_client_ptr -> nx_pppoe_host_uniq, &index); - } - else - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - } - } - else if (code == NX_PPPOE_CLIENT_CODE_PADR) - { - - /* The PADR packet MUST contain exactly one TAG of TAG_TYPE Service-Name, indicating the service the host is requesting, - and any number of other TAG types. RFC2516, Section5.3, Page6. */ - if (pppoe_client_ptr -> nx_pppoe_service_name) - { - - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_SERVICE_NAME_ERROR); - } - - if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= - (4 + tag_length)) - { - - /* Added the Service-Name tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, tag_length, pppoe_client_ptr -> nx_pppoe_service_name, &index); - } - else - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - } - else - { - - /* Added the Service-Name tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); - } - - /* The Host MAY include a Host-Uniq TAG in a PADI or PADR. */ - if (pppoe_client_ptr -> nx_pppoe_host_uniq) - { - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(pppoe_client_ptr -> nx_pppoe_host_uniq), &tag_length, NX_MAX_STRING_LENGTH)) - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - - if (((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(&work_ptr[index])) >= - (4 + tag_length)) - { - - /* Added the Host-Uniq tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, tag_length, pppoe_client_ptr -> nx_pppoe_host_uniq, &index); - } - else - { - - /* Packet too small. */ - nx_packet_release(packet_ptr); - return(NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR); - } - } - - /* If a Host receives AC-Cookie tag, it MUST return the TAG unmodified in the following PADR. */ - if (pppoe_client_ptr -> nx_pppoe_ac_cookie_size) - { - - /* Added the AC-Cookie tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE, pppoe_client_ptr -> nx_pppoe_ac_cookie_size, pppoe_client_ptr -> nx_pppoe_ac_cookie, &index); - } - - /* If either the Host or Access Concentrator receives Relay-Session-Id TAG they MUST include it unmodified in any discovery packet they send as a response. */ - if (pppoe_client_ptr -> nx_pppoe_relay_session_id_size) - { - - /* Added the Host-Uniq tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, pppoe_client_ptr -> nx_pppoe_relay_session_id_size, pppoe_client_ptr -> nx_pppoe_relay_session_id, &index); - } - } - else if (code == NX_PPPOE_CLIENT_CODE_PADT) - { - - /* If either the Host or Access Concentrator receives Relay-Session-Id TAG they MUST include it unmodified in any discovery packet they send as a response. */ - if (pppoe_client_ptr -> nx_pppoe_relay_session_id_size) - { - - /* Added the Host-Uniq tag. */ - _nx_pppoe_client_tag_string_add(work_ptr, NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ, pppoe_client_ptr -> nx_pppoe_relay_session_id_size, pppoe_client_ptr -> nx_pppoe_relay_session_id, &index); - } - } - - /* Add the PPPoE header. */ - /* - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | VER | TYPE | CODE | SESSION_ID | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | LENGTH | payload - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add version and type. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_VER_TYPE, 1, NX_PPPOE_CLIENT_VERSION_TYPE); - - /* Add code. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_CODE, 1, code); - - /* Add the Session id. */ - if (code == NX_PPPOE_CLIENT_CODE_PADT) - { - - /* Add session id. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id); - } - else - { - - /* Add session id. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_SESSION_ID, 2, 0); - } - - /* Add length. */ - _nx_pppoe_client_data_add(work_ptr + NX_PPPOE_CLIENT_OFFSET_LENGTH, 2, (index - NX_PPPOE_CLIENT_OFFSET_PAYLOAD)); - - /* Update the append pointer and length. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; - packet_ptr -> nx_packet_length = index; - - /* Send PPPoE session packet. */ - _nx_pppoe_client_packet_send(pppoe_client_ptr, packet_ptr, NX_LINK_PPPOE_DISCOVERY_SEND); - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a PPPoE packet to the appropriate link driver. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_client_ptr Pointer to PPPoE control block*/ -/* client_session_ptr Pointer to Client Session */ -/* packet_ptr Pointer to packet to send */ -/* command Driver command */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* (ip_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ -/* _nx_pppoe_client_session_send Send PPPoE Session packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr, UINT command) -{ - -NX_IP_DRIVER driver_request; - - - /* Initialize the driver request. */ - driver_request.nx_ip_driver_command = command; - driver_request.nx_ip_driver_ptr = pppoe_client_ptr -> nx_pppoe_ip_ptr; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = pppoe_client_ptr -> nx_pppoe_interface_ptr; - - /* Check if have the server address. */ - if ((pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw) || - (pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw)) - { - - /* Set the destination address as server address. */ - driver_request.nx_ip_driver_physical_address_msw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw; - driver_request.nx_ip_driver_physical_address_lsw = pppoe_client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw; - } - else - { - - /* Set the destination address as boradcast address. */ - driver_request.nx_ip_driver_physical_address_msw = 0x0000FFFF; - driver_request.nx_ip_driver_physical_address_lsw = 0xFFFFFFFF; - } - - /* Sendout the PPPoE packet. */ - (pppoe_client_ptr -> nx_pppoe_link_driver_entry) (&driver_request); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_data_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the datas of PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_packet_receive Receive the PPPoE packet */ -/* _nx_pppoe_client_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* _nx_pppoe_client_session_packet_process */ -/* Process PPPoE Session packet */ -/* _nx_pppoe_client_tag_process Process PPPoE TAGs */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_pppoe_client_data_get(UCHAR *data, UINT size) -{ - -ULONG value = 0; - - - /* Process the data retrieval request. */ - while (size-- > 0) - { - - /* Build return value. */ - value = (value << 8) | *data++; - } - - /* Return value. */ - return(value); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_data_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the datas into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* value Value to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ -/* _nx_pppoe_client_session_send Send PPPoE Session packet */ -/* _nx_pppoe_client_tag_string_add Add PPPoE string TAG */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_data_add(UCHAR *data, UINT size, ULONG value) -{ - - /* Make sure that data is left justified. */ - switch (size) - { - - case 1: - - value <<= 24; - break; - - case 2: - - value <<= 16; - break; - - case 3: - - value <<= 8; - break; - - default: - break; - } - - /* Store the value. */ - while (size-- > 0) - { - - *data = (UCHAR) ((value >> 24) & 0xff); - data++; - value <<= 8; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_string_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the string into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* dest Pointer to destination buffer */ -/* source Pointer to source buffer */ -/* size Number of bytes to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_tag_string_add Add PPPoE string TAG */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_string_add(UCHAR *dest, UCHAR *source, UINT size) -{ - - /* Loop to copy all bytes. */ - while (size-- > 0) - { - - /* Copy a byte. */ - *dest++ = *source++; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_tag_string_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the TAG with string into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data_ptr Pointer to data buffer */ -/* tag_type Type of TAG */ -/* tag_length Length of TAG */ -/* tag_value_string String value of TAG to add */ -/* index Location into data buffer */ -/* to write data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_client_data_add Add PPPoE data */ -/* _nx_pppoe_client_string_add Add PPPoE string data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_discovery_send Send PPPoE Discovery packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_client_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index) -{ - - /* Add the tag type. */ - _nx_pppoe_client_data_add(data_ptr + (*index), 2, tag_type); - (*index) += 2; - - /* Add the tag length. */ - _nx_pppoe_client_data_add(data_ptr + (*index), 2, tag_length); - (*index) += 2; - - /* Add the tag value string. */ - _nx_pppoe_client_string_add(data_ptr + (*index), tag_value_string, tag_length); - (*index) += tag_length; - - /* Return a successful completion. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function cleans up the PPPoE session. */ -/* */ -/* INPUT */ -/* */ -/* client_session_ptr Pointer to Client Session */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_client_session_terminate Terminate the PPPoE session */ -/* _nx_pppoe_client_session_packet_process */ -/* Process PPPoE Session packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_client_session_cleanup(NX_PPPOE_CLIENT *client_ptr) -{ - - /* Cleanup the state. */ - client_ptr -> nx_pppoe_state = NX_PPPOE_CLIENT_STATE_INITIAL; - - /* Ceanup the tags. */ - client_ptr -> nx_pppoe_ac_name_size = 0; - client_ptr -> nx_pppoe_ac_cookie_size = 0; - client_ptr -> nx_pppoe_relay_session_id_size = 0; - - /* Cleanup the server information. */ - client_ptr -> nx_pppoe_server_session.nx_pppoe_session_id = NX_NULL; - client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_msw = NX_NULL; - client_ptr -> nx_pppoe_server_session.nx_pppoe_physical_address_lsw = NX_NULL; - - /* Return success. */ - return(NX_PPPOE_CLIENT_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_thread_suspend PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function suspends a thread on a PPPoE Session connect service */ -/* */ -/* INPUT */ -/* */ -/* suspension_list_head Pointer to the suspension list*/ -/* mutex_ptr Pointer to mutex to release */ -/* suspend_cleanup Suspension cleanup routine */ -/* wait_option Optional timeout value */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_put Release protection */ -/* _tx_thread_system_suspend Suspend thread */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_session_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD * NX_CLEANUP_PARAMETER), - NX_PPPOE_CLIENT *pppoe_client_ptr, TX_MUTEX *mutex_ptr, ULONG wait_option) -{ - -TX_INTERRUPT_SAVE_AREA - -TX_THREAD *thread_ptr; - - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup thread pointer. */ - thread_ptr = _tx_thread_current_ptr; - - /* Setup suspension list. */ - if (*suspension_list_head) - { - - /* This list is not NULL, add current thread to the end. */ - thread_ptr -> tx_thread_suspended_next = *suspension_list_head; - thread_ptr -> tx_thread_suspended_previous = (*suspension_list_head) -> tx_thread_suspended_previous; - ((*suspension_list_head) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = thread_ptr; - (*suspension_list_head) -> tx_thread_suspended_previous = thread_ptr; - } - else - { - - /* No other threads are suspended. Setup the head pointer and - just setup this threads pointers to itself. */ - *suspension_list_head = thread_ptr; - thread_ptr -> tx_thread_suspended_next = thread_ptr; - thread_ptr -> tx_thread_suspended_previous = thread_ptr; - } - - /* Setup cleanup routine pointer. */ - thread_ptr -> tx_thread_suspend_cleanup = suspend_cleanup; - - /* Setup cleanup information, i.e. this pool control - block. */ - thread_ptr -> tx_thread_suspend_control_block = (void *)pppoe_client_ptr; - - /* Set the state to suspended. */ - thread_ptr -> tx_thread_state = TX_TCP_IP; - - /* Set the suspending flag. */ - thread_ptr -> tx_thread_suspending = TX_TRUE; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Save the timeout value. */ - thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; - - /* Restore interrupts. */ - TX_RESTORE - - /* Release protection. */ - tx_mutex_put(mutex_ptr); - - /* Call actual thread suspension routine. */ - _tx_thread_system_suspend(thread_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_thread_resume PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function resumes a thread suspended on a PPPoE Client session */ -/* connect service. */ -/* */ -/* INPUT */ -/* */ -/* thread_ptr Pointer to thread to resume */ -/* status Return status */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _tx_thread_system_resume Resume suspended thread */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_client_session_thread_resume(TX_THREAD **suspension_list_head, UINT status) -{ - -TX_INTERRUPT_SAVE_AREA - -TX_THREAD *thread_ptr; - - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the thread pointer. */ - thread_ptr = *suspension_list_head; - - /* Determine if there still is a thread suspended. */ - if (thread_ptr) - { - - /* Determine if there are anymore threads on the suspension list. */ - if (thread_ptr == thread_ptr -> tx_thread_suspended_next) - { - - /* Only this thread is on the suspension list. Simply set the - list head to NULL to reflect an empty suspension list. */ - *suspension_list_head = TX_NULL; - } - else - { - - /* More than one thread is on the suspension list, we need to - adjust the link pointers and move the next entry to the - front of the list. */ - *suspension_list_head = thread_ptr -> tx_thread_suspended_next; - - /* Update the links of the adjacent threads. */ - (thread_ptr -> tx_thread_suspended_next) -> tx_thread_suspended_previous = - thread_ptr -> tx_thread_suspended_previous; - (thread_ptr -> tx_thread_suspended_previous) -> tx_thread_suspended_next = - thread_ptr -> tx_thread_suspended_next; - } - - /* Prepare for resumption of the thread. */ - - /* Clear cleanup routine to avoid timeout. */ - thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Restore interrupts. */ - TX_RESTORE - - /* Put return status into the thread control block. */ - thread_ptr -> tx_thread_suspend_status = status; - - /* Resume thread. */ - _tx_thread_system_resume(thread_ptr); - } - else - { - - /* Nothing was suspended. Simply restore interrupts. */ - TX_RESTORE - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_client_session_connect_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes PPPoE connect timeout and thread terminate */ -/* actions that require the PPPoE Client data structures to be cleaned */ -/* up. */ -/* */ -/* INPUT */ -/* */ -/* thread_ptr Pointer to suspended thread's */ -/* control block */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set event flag */ -/* _tx_thread_system_resume Resume thread service */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_client_session_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) -{ - -TX_INTERRUPT_SAVE_AREA - -NX_PPPOE_CLIENT *pppoe_client_ptr; /* Working PPPoE Client pointer */ - - NX_CLEANUP_EXTENSION - - /* Disable interrupts. */ - TX_DISABLE - - /* Setup pointer to PPPoE Client control block. */ - pppoe_client_ptr = (NX_PPPOE_CLIENT *)thread_ptr -> tx_thread_suspend_control_block; - - /* Determine if the PPPoE Client pointer is valid. */ - if ((!pppoe_client_ptr) || (pppoe_client_ptr -> nx_pppoe_id != NX_PPPOE_CLIENT_ID)) - { - - /* Restore interrupts. */ - TX_RESTORE - - return; - } - - /* Determine if the cleanup is still required. */ - if (!(thread_ptr -> tx_thread_suspend_cleanup)) - { - - /* Restore interrupts. */ - TX_RESTORE - - return; - } - - /* Determine if the caller is an ISR or the system timer thread. */ -#ifndef TX_TIMER_PROCESS_IN_ISR - if ((TX_THREAD_GET_SYSTEM_STATE()) || (_tx_thread_current_ptr == &_tx_timer_thread)) -#else - if (TX_THREAD_GET_SYSTEM_STATE()) -#endif - { - - /* Yes, defer the processing to the PPPoE Client thread. */ - - /* Restore interrupts. */ - TX_RESTORE - - /* Set the deferred cleanup flag for the IP thread. */ - tx_event_flags_set(&(pppoe_client_ptr -> nx_pppoe_events), NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT, TX_OR); - - /* Return to caller. */ - return; - } - else - { - - /* Yes, we still have thread suspension! */ - - /* Clear the suspension cleanup flag. */ - thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; - - /* Clear the suspension pointer. */ - pppoe_client_ptr -> nx_pppoe_session_connect_suspended_thread = NX_NULL; - - /* Cleanup the PPPoE session. */ - _nx_pppoe_client_session_cleanup(pppoe_client_ptr); - - /* Now we need to determine if this cleanup is from a terminate, timeout, - or from a wait abort. */ - if (thread_ptr -> tx_thread_state == TX_TCP_IP) - { - - /* Thread still suspended on the PPPoE Client. Setup return error status and - resume the thread. */ - - /* Setup return status. */ - thread_ptr -> tx_thread_suspend_status = NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED; - - /* Temporarily disable preemption. */ - _tx_thread_preempt_disable++; - - /* Restore interrupts. */ - TX_RESTORE - - /* Resume the thread! Check for preemption even though we are executing - from the system timer thread right now which normally executes at the - highest priority. */ - _tx_thread_system_resume(thread_ptr); - - /* Finished, just return. */ - return; - } - } - - /* Restore interrupts. */ - TX_RESTORE -} -#endif /* NX_DISABLE_IPV4 */ - diff --git a/protocol_handlers/pppoe/nx_pppoe_client.h b/protocol_handlers/pppoe/nx_pppoe_client.h deleted file mode 100644 index 170e69a4..00000000 --- a/protocol_handlers/pppoe/nx_pppoe_client.h +++ /dev/null @@ -1,352 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** PPP Over Ethernet (PPPoE) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_pppoe_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX PPP Over Ethernet (PPPoE) Client */ -/* componet, including all data types and external references. It is */ -/* assumed that nx_api.h and nx_port.h have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_PPPOE_CLIENT_H -#define NX_PPPOE_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Note: Prerequisite for using PPPoE. - Redefine NX_PHYSICAL_HEADER to 24 to ensure enough space for filling in physical header. - Physical header:14(Ethernet header) + 6(PPPoE header) + 2(PPP header) + 2(four-byte aligment). */ - -/* Define the Driver command for PPPoE packet. */ -#ifndef NX_LINK_PPPOE_DISCOVERY_SEND -#define NX_LINK_PPPOE_DISCOVERY_SEND 51 -#endif -#ifndef NX_LINK_PPPOE_SESSION_SEND -#define NX_LINK_PPPOE_SESSION_SEND 52 -#endif - -/* Define the PPPoE Client ID. */ -#define NX_PPPOE_CLIENT_ID 0x504F4543UL - -/* If the driver is not initialized in other module, enable the feature to initialize the driver in PPPoE module . */ -/* -#define NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE -*/ - -/* Define the PPPoE Thread time slice. */ -#ifndef NX_PPPOE_CLIENT_THREAD_TIME_SLICE -#define NX_PPPOE_CLIENT_THREAD_TIME_SLICE TX_NO_TIME_SLICE -#endif - -/* Define the init timeout for PADI. */ -#ifndef NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT -#define NX_PPPOE_CLIENT_PADI_INIT_TIMEOUT 1 -#endif - -/* Define the maximum number for PADI. */ -#ifndef NX_PPPOE_CLIENT_PADI_COUNT -#define NX_PPPOE_CLIENT_PADI_COUNT 4 -#endif - -/* Define the init timeout for PADR. */ -#ifndef NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT -#define NX_PPPOE_CLIENT_PADR_INIT_TIMEOUT 1 -#endif - -/* Define the maximum number for PADR. */ -#ifndef NX_PPPOE_CLIENT_PADR_COUNT -#define NX_PPPOE_CLIENT_PADR_COUNT 4 -#endif - -/* Define the size of pppoe AC-Name. */ -#ifndef NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE -#define NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE 32 -#endif - -/* Define the size of pppoe AC-Cookie. */ -#ifndef NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE -#define NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE 32 -#endif - -/* Define the size of pppoe Relay-Session-Id. */ -#ifndef NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE -#define NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE 12 -#endif - -/* Define the minimum size of packet payload to avoid packet chained. Maximum Payload Size of Ethernet(1500) + Ethernet Header + CRC + Four-byte alignment. */ - -#ifndef NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE -#define NX_PPPOE_CLIENT_MIN_PACKET_PAYLOAD_SIZE 1520 -#endif - -/* Define PPPoE ethernet header size. */ -#define NX_PPPOE_CLIENT_ETHER_HEADER_SIZE 14 - -/* Define PPPoE ethernet types. */ -#define NX_PPPOE_CLIENT_ETHER_TYPE_DISCOVERY 0x8863 -#define NX_PPPOE_CLIENT_ETHER_TYPE_SESSION 0x8864 - -/* Define PPPoE version and type. */ -#define NX_PPPOE_CLIENT_VERSION_TYPE 0x11 /* Version 1, Type 1. */ - -/* Define PPPoE codes. */ -#define NX_PPPOE_CLIENT_CODE_ZERO 0x00 -#define NX_PPPOE_CLIENT_CODE_PADI 0x09 -#define NX_PPPOE_CLIENT_CODE_PADO 0x07 -#define NX_PPPOE_CLIENT_CODE_PADR 0x19 -#define NX_PPPOE_CLIENT_CODE_PADS 0x65 -#define NX_PPPOE_CLIENT_CODE_PADT 0xa7 - -/* Define the PPPoE Area Offsets. */ -#define NX_PPPOE_CLIENT_OFFSET_VER_TYPE 0 /* 1 byte, version + type: 0x11 */ -#define NX_PPPOE_CLIENT_OFFSET_CODE 1 /* 1 byte, code: Discovery or Session */ -#define NX_PPPOE_CLIENT_OFFSET_SESSION_ID 2 /* 2 bytes, session id: unique session identifieer */ -#define NX_PPPOE_CLIENT_OFFSET_LENGTH 4 /* 2 bytes, length: the length of PPPoE payload */ -#define NX_PPPOE_CLIENT_OFFSET_PAYLOAD 6 /* variable, payload */ - -/* Define the PPPoE Tag Types. */ -#define NX_PPPOE_CLIENT_TAG_TYPE_END_OF_LIST 0x0000 -#define NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME 0x0101 -#define NX_PPPOE_CLIENT_TAG_TYPE_AC_NAME 0x0102 -#define NX_PPPOE_CLIENT_TAG_TYPE_HOST_UNIQ 0x0103 -#define NX_PPPOE_CLIENT_TAG_TYPE_AC_COOKIE 0x0104 -#define NX_PPPOE_CLIENT_TAG_TYPE_VENDOR_SPECIFIC 0x0105 -#define NX_PPPOE_CLIENT_TAG_TYPE_RELAY_SESSION_ID 0x0110 -#define NX_PPPOE_CLIENT_TAG_TYPE_SERVICE_NAME_ERROR 0x0201 -#define NX_PPPOE_CLIENT_TAG_TYPE_AC_SYSTEM_ERROR 0x0202 -#define NX_PPPOE_CLIENT_TAG_TYPE_GENERIC_ERROR 0x0203 - -/* Define the PPPoE Error flags. */ -#define NX_PPPOE_CLIENT_ERROR_SERVICE_NAME ((ULONG) 0x00000001) /* Service Name Error. */ -#define NX_PPPOE_CLIENT_ERROR_AC_SYSTEM ((ULONG) 0x00000002) /* AC-System Error */ -#define NX_PPPOE_CLIENT_ERROR_GENERIC ((ULONG) 0x00000004) /* Generic Error */ - -/* Define event flags for PPPoE thread control. */ -#define NX_PPPOE_CLIENT_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags */ -#define NX_PPPOE_CLIENT_PACKET_RECEIVE_EVENT ((ULONG) 0x00000001) /* PPPoE Client receive packet event */ -#define NX_PPPOE_CLIENT_TIMER_PERIODIC_EVENT ((ULONG) 0x00000002) /* PPPoE CLient timer Periodic event */ -#define NX_PPPOE_CLIENT_SESSION_CONNECT_CLEANUP_EVENT ((ULONG) 0x00000004) /* PPPoE Client Session cleanup event */ - -/* Define PPPoE Client state. */ -#define NX_PPPOE_CLIENT_STATE_INITIAL 0 -#define NX_PPPOE_CLIENT_STATE_PADI_SENT 1 -#define NX_PPPOE_CLIENT_STATE_PADR_SENT 2 -#define NX_PPPOE_CLIENT_STATE_ESTABLISHED 3 - -/* Define error codes from PPPoE Server operation. */ -#define NX_PPPOE_CLIENT_SUCCESS 0x00 /* Success */ -#define NX_PPPOE_CLIENT_PTR_ERROR 0xD1 /* Invalid input pointers */ -#define NX_PPPOE_CLIENT_INVALID_INTERFACE 0xD2 /* Invalid interface */ -#define NX_PPPOE_CLIENT_PACKET_PAYLOAD_ERROR 0xD3 /* Invalid payload size of packet */ -#define NX_PPPOE_CLIENT_MEMORY_SIZE_ERROR 0xD4 /* Invalid memory size */ -#define NX_PPPOE_CLIENT_PRIORITY_ERROR 0xD5 /* Invalid priority */ -#define NX_PPPOE_CLIENT_NOT_ENABLED 0xD6 /* PPPoE is not enabled */ -#define NX_PPPOE_CLIENT_INVALID_SESSION 0xD7 /* Invalid Session */ -#define NX_PPPOE_CLIENT_SESSION_NOT_ESTABLISHED 0xD8 /* PPPoE Session is not established */ -#define NX_PPPOE_CLIENT_SERVICE_NAME_ERROR 0xD9 /* Service name error */ -#define NX_PPPOE_CLIENT_AC_NAME_ERROR 0xDA /* AC Name error */ -#define NX_PPPOE_CLIENT_CLIENT_SESSION_FULL 0xDB /* Client Session full */ -#define NX_PPPOE_CLIENT_CLIENT_SESSION_NOT_FOUND 0xDC /* Not found the client session */ -#define NX_PPPOE_CLIENT_HOST_UNIQ_CACHE_ERROR 0xDD /* The cache is not enough to record the Host Uniq */ -#define NX_PPPOE_CLIENT_RELAY_SESSION_ID_CACHE_ERROR 0xDF /* The cache is not enough to record Relay Session ID*/ - - -/* Define the PPPoE Server Session structure containing the session id and physical address. */ - -typedef struct NX_PPPOE_SERVER_SESSION_STRUCT -{ - - USHORT nx_pppoe_session_id; - USHORT reserved; - ULONG nx_pppoe_physical_address_msw; - ULONG nx_pppoe_physical_address_lsw; -} NX_PPPOE_SERVER_SESSION; - - -/* Define the main PPPoE Server data structure. */ - -typedef struct NX_PPPOE_CLIENT_STRUCT -{ - - ULONG nx_pppoe_id; - UCHAR *nx_pppoe_name; - NX_IP *nx_pppoe_ip_ptr; - NX_INTERFACE *nx_pppoe_interface_ptr; - NX_PACKET_POOL *nx_pppoe_packet_pool_ptr; - TX_EVENT_FLAGS_GROUP nx_pppoe_events; - TX_THREAD nx_pppoe_thread; - TX_TIMER nx_pppoe_timer; - NX_PACKET *nx_pppoe_deferred_received_packet_head, - *nx_pppoe_deferred_received_packet_tail; - UINT nx_pppoe_state; - NX_PPPOE_SERVER_SESSION nx_pppoe_server_session; - UCHAR *nx_pppoe_service_name; - UCHAR *nx_pppoe_host_uniq; - UCHAR nx_pppoe_ac_name[NX_PPPOE_CLIENT_MAX_AC_NAME_SIZE]; - UINT nx_pppoe_ac_name_size; - UCHAR nx_pppoe_ac_cookie[NX_PPPOE_CLIENT_MAX_AC_COOKIE_SIZE]; - UINT nx_pppoe_ac_cookie_size; - UCHAR nx_pppoe_relay_session_id[NX_PPPOE_CLIENT_MAX_RELAY_SESSION_ID_SIZE]; - UINT nx_pppoe_relay_session_id_size; - UINT nx_pppoe_error_flag; - - /* Define the retransmit timeout and count for PADI and PADR. */ - UINT nx_pppoe_rtr_timeout; - UINT nx_pppoe_rtr_count; - - /* Define the Link Driver entry point. */ - VOID (*nx_pppoe_link_driver_entry)(struct NX_IP_DRIVER_STRUCT *); - - /* Define the function to receive PPPoE packet. */ - VOID (*nx_pppoe_packet_receive)(NX_PACKET *packet_ptr); - - /* Define the PPPoE session connect suspension pointer that contains the pointer to the - thread suspended attempting to establish a PPPoE session connection. */ - TX_THREAD *nx_pppoe_session_connect_suspended_thread; - -} NX_PPPOE_CLIENT; - - -#ifndef NX_PPPOE_CLIENT_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_pppoe_client_create _nx_pppoe_client_create -#define nx_pppoe_client_delete _nx_pppoe_client_delete -#define nx_pppoe_client_host_uniq_set _nx_pppoe_client_host_uniq_set -#define nx_pppoe_client_host_uniq_set_extended _nx_pppoe_client_host_uniq_set_extended -#define nx_pppoe_client_service_name_set _nx_pppoe_client_service_name_set -#define nx_pppoe_client_service_name_set_extended _nx_pppoe_client_service_name_set_extended -#define nx_pppoe_client_session_connect _nx_pppoe_client_session_connect -#define nx_pppoe_client_session_packet_send _nx_pppoe_client_session_packet_send -#define nx_pppoe_client_session_terminate _nx_pppoe_client_session_terminate -#define nx_pppoe_client_session_get _nx_pppoe_client_session_get - -#else - -/* Services with error checking. */ - -#define nx_pppoe_client_create _nxe_pppoe_client_create -#define nx_pppoe_client_delete _nxe_pppoe_client_delete -#define nx_pppoe_client_host_uniq_set _nxe_pppoe_client_host_uniq_set -#define nx_pppoe_client_host_uniq_set_extended _nxe_pppoe_client_host_uniq_set_extended -#define nx_pppoe_client_service_name_set _nxe_pppoe_client_service_name_set -#define nx_pppoe_client_service_name_set_extended _nxe_pppoe_client_service_name_set_extended -#define nx_pppoe_client_session_connect _nxe_pppoe_client_session_connect -#define nx_pppoe_client_session_packet_send _nxe_pppoe_client_session_packet_send -#define nx_pppoe_client_session_terminate _nxe_pppoe_client_session_terminate -#define nx_pppoe_client_session_get _nxe_pppoe_client_session_get - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), - VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); -UINT nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); -UINT nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); -UINT nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); -UINT nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); -UINT nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); -UINT nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); -UINT nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); -VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr); - -#else - -UINT _nxe_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), - VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); -UINT _nx_pppoe_client_create(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - NX_PACKET_POOL *pool_ptr, VOID *stack_ptr, ULONG stack_size, UINT priority, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), - VOID (*pppoe_packet_receive)(NX_PACKET *packet_ptr)); -UINT _nxe_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT _nx_pppoe_client_delete(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT _nxe_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); -UINT _nx_pppoe_client_host_uniq_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq); -UINT _nxe_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); -UINT _nx_pppoe_client_host_uniq_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *host_uniq, UINT host_uniq_length); -UINT _nxe_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); -UINT _nx_pppoe_client_service_name_set(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name); -UINT _nxe_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); -UINT _nx_pppoe_client_service_name_set_extended(NX_PPPOE_CLIENT *pppoe_client_ptr, UCHAR *service_name, UINT service_name_length); -UINT _nxe_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); -UINT _nx_pppoe_client_session_connect(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG wait_option); -UINT _nxe_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); -UINT _nx_pppoe_client_session_packet_send(NX_PPPOE_CLIENT *pppoe_client_ptr, NX_PACKET *packet_ptr); -UINT _nxe_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT _nx_pppoe_client_session_terminate(NX_PPPOE_CLIENT *pppoe_client_ptr); -UINT _nxe_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_client_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); -UINT _nx_pppoe_client_session_get(NX_PPPOE_CLIENT *pppoe_server_ptr, ULONG *server_mac_msw, ULONG *server_mac_lsw, ULONG *session_id); -VOID _nx_pppoe_client_packet_deferred_receive(NX_PACKET *packet_ptr); - -#endif /* NX_PPPOE_CLIENT_SOURCE_CODE */ - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_PPP_CLIENT_H */ diff --git a/protocol_handlers/pppoe/nx_pppoe_server.c b/protocol_handlers/pppoe/nx_pppoe_server.c deleted file mode 100644 index 918f1986..00000000 --- a/protocol_handlers/pppoe/nx_pppoe_server.c +++ /dev/null @@ -1,4408 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** PPP Over Ethernet (PPPoE) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_PPPOE_SERVER_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -#ifndef TX_DISABLE_ERROR_CHECKING -#define TX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "nx_api.h" -#ifndef NX_DISABLE_IPV4 -#include "nx_ip.h" -#include "nx_pppoe_server.h" -#include "nx_packet.h" - -/* Define the PPPoE created list head pointer and count. */ -NX_PPPOE_SERVER *_nx_pppoe_server_created_ptr = NX_NULL; - - -/* Define internal PPPoE services. */ - -static VOID _nx_pppoe_server_thread_entry(ULONG pppoe_server_ptr_value); -static VOID _nx_pppoe_server_packet_receive(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr); -static VOID _nx_pppoe_server_discovery_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, UINT is_broadcast); -static VOID _nx_pppoe_server_session_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw); -static UINT _nx_pppoe_server_discovery_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code); -static VOID _nx_pppoe_server_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, NX_PACKET *packet_ptr, UINT command); -static UINT _nx_pppoe_server_tag_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code, UCHAR *tag_ptr, ULONG length); -static ULONG _nx_pppoe_server_data_get(UCHAR *data, UINT size); -static VOID _nx_pppoe_server_data_add(UCHAR *data, UINT size, ULONG value); -static VOID _nx_pppoe_server_string_add(UCHAR *dest, UCHAR *source, UINT size); -static UINT _nx_pppoe_server_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index); -static UINT _nx_pppoe_server_session_find(NX_PPPOE_SERVER *pppoe_server_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, - ULONG session_id, UINT *session_index, NX_PPPOE_CLIENT_SESSION **client_session_ptr); -static UINT _nx_pppoe_server_session_cleanup(NX_PPPOE_CLIENT_SESSION *client_session_ptr); - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -static UCHAR *nx_pppoe_service_name[1]; -#endif - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server instance create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* name Name of this PPPoE instance */ -/* ip_ptr Pointer to IP control block */ -/* interface_index IP Interface Index */ -/* pppoe_link_driver User supplied link driver */ -/* pool_ptr packet pool */ -/* stack_ptr Pointer stack area for PPPoE */ -/* stack_size Size of PPPoE stack area */ -/* priority Priority of PPPoE thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_create Actual PPPoE instance create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT priority) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id == NX_PPPOE_SERVER_ID) || - (ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (pppoe_link_driver == NX_NULL) || (pool_ptr == NX_NULL) || - (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || - (stack_ptr == NX_NULL)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check for invalid interface ID */ - if(interface_index >= NX_MAX_PHYSICAL_INTERFACES) - return(NX_PPPOE_SERVER_INVALID_INTERFACE); - - /* Check for interface being valid. */ - if(!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) - return(NX_PPPOE_SERVER_INVALID_INTERFACE); - - /* Check for payload size of packet pool. */ - if (pool_ptr -> nx_packet_pool_payload_size < NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE) - return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); - - /* Check for a memory size error. */ - if (stack_size < TX_MINIMUM_STACK) - return(NX_PPPOE_SERVER_MEMORY_SIZE_ERROR); - - /* Check the priority specified. */ - if (priority >= TX_MAX_PRIORITIES) - return(NX_PPPOE_SERVER_PRIORITY_ERROR); - - /* Call actual PPPoE server instance create function. */ - status = _nx_pppoe_server_create(pppoe_server_ptr, name, ip_ptr, interface_index, - pppoe_link_driver, pool_ptr, stack_ptr, stack_size, priority); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an PPPoE Server instance, including setting */ -/* up all appropriate data structures, creating PPPoE event flag */ -/* object and PPPoE thread. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* name Name of this PPPoE instance */ -/* ip_ptr Pointer to IP control block */ -/* interface_index Interface Index */ -/* pppoe_link_driver User supplied link driver */ -/* pool_ptr packet pool */ -/* stack_ptr Pointer stack area for PPPoE */ -/* stack_size Size of PPPoE stack area */ -/* priority Priority of PPPoE thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_create Create IP event flags */ -/* tx_thread_create Create IP helper thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT priority) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Initialize the PPPoE Server control block to zero. */ - memset((void *) pppoe_server_ptr, 0, sizeof(NX_PPPOE_SERVER)); - - /* Save the PPPoE name. */ - pppoe_server_ptr -> nx_pppoe_name = name; - - /* Save the length of PPPoE name to avoid compute strlen repeatedly in _nx_pppoe_server_discovery_send. */ - if (_nx_utility_string_length_check((char *)pppoe_server_ptr -> nx_pppoe_name, - &(pppoe_server_ptr -> nx_pppoe_name_length), - NX_MAX_STRING_LENGTH)) - { - return(NX_PPPOE_SERVER_PTR_ERROR); - } - - /* Save the IP pointer. */ - pppoe_server_ptr -> nx_pppoe_ip_ptr = ip_ptr; - - /* Setup the interface index and interface pointer. */ - pppoe_server_ptr -> nx_pppoe_interface_ptr = &(ip_ptr -> nx_ip_interface[interface_index]); - - /* Save the packet pool pointer. */ - pppoe_server_ptr -> nx_pppoe_packet_pool_ptr = pool_ptr; - - /* Setup the enabled flag. */ - pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; - - /* Save the starting Session ID. */ - pppoe_server_ptr -> nx_pppoe_session_id = NX_PPPOE_SERVER_START_SESSION_ID; - - /* Initialize PPPoE notify function pointer */ - pppoe_server_ptr -> nx_pppoe_discover_initiation_notify = NX_NULL; - pppoe_server_ptr -> nx_pppoe_discover_request_notify = NX_NULL; - pppoe_server_ptr -> nx_pppoe_discover_terminate_notify = NX_NULL; - pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm = NX_NULL; - pppoe_server_ptr -> nx_pppoe_data_receive_notify = NX_NULL; - pppoe_server_ptr -> nx_pppoe_data_send_notify = NX_NULL; - - /* Setup the link driver address. */ - pppoe_server_ptr -> nx_pppoe_link_driver_entry = pppoe_link_driver; - - /* Create event flag group to control the PPPoE processing thread. */ - tx_event_flags_create(&(pppoe_server_ptr -> nx_pppoe_events), "PPPoE Server EVENTS") ; - - /* Create the PPPoE processing thread. */ - tx_thread_create(&(pppoe_server_ptr -> nx_pppoe_thread), "PPPoE Server THREAD", _nx_pppoe_server_thread_entry, (ULONG) pppoe_server_ptr, - stack_ptr, stack_size, priority, priority, NX_PPPOE_SERVER_THREAD_TIME_SLICE, TX_DONT_START); - - /* Otherwise, the PPPoE initialization was successful. Place the - PPPoE control block on created PPPoE instance. */ - TX_DISABLE - - /* Load the PPPoE Server ID field in the PPPoE Server control block. */ - pppoe_server_ptr -> nx_pppoe_id = NX_PPPOE_SERVER_ID; - - /* Set the pointer of global variable PPPoE. */ - _nx_pppoe_server_created_ptr = pppoe_server_ptr; - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_ac_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server set Access */ -/* Concentrator name function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* ac_name Access Concentrator name */ -/* ac_name_length Length of Name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_ac_name_set Set Access Concentrator */ -/* name function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call Access Concentrator name set function. */ - status = _nx_pppoe_server_ac_name_set(pppoe_server_ptr, ac_name, ac_name_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_ac_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets Access Concentrator name function call. */ -/* */ -/* Note: The string of ac_name must be NULL-terminated and length */ -/* of ac_name matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* ac_name Access Concentrator name */ -/* ac_name_length Length of Name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length) -{ -UINT temp_name_length = 0; - - /* Get the length of ac_name string. */ - if (_nx_utility_string_length_check((CHAR*)ac_name, &temp_name_length, ac_name_length)) - return(NX_SIZE_ERROR); - - /* Check the name length. */ - if (ac_name_length != temp_name_length) - return(NX_SIZE_ERROR); - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Save the nx_pppoe_ac_name. */ - pppoe_server_ptr -> nx_pppoe_ac_name = ac_name; - - /* Save the nx_pppoe_ac_name length. */ - pppoe_server_ptr -> nx_pppoe_ac_name_length = ac_name_length; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server instance delete */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_delete Actual PPPoE instance delete */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call actual PPPoE server instance delete function. */ - status = _nx_pppoe_server_delete(pppoe_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes an PPPoE Server instance. including deleting */ -/* PPPoE event flag object and PPPoE thread. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_terminate Terminate PPPoE helper thread */ -/* tx_thread_delete Delete PPPoE helper thread */ -/* tx_event_flags_delete Delete PPPoE event flags */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Determine if the caller is the PPPoE thread itself. This is not allowed since - a thread cannot delete itself in ThreadX. */ - if (&pppoe_server_ptr -> nx_pppoe_thread == tx_thread_identify()) - { - - /* Invalid caller of this routine, return an error! */ - return(NX_CALLER_ERROR); - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Clear the PPPOE ID to show that it is no longer valid. */ - pppoe_server_ptr -> nx_pppoe_id = 0; - pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; - - /* Clear the created pointer. */ - _nx_pppoe_server_created_ptr = NX_NULL; - - /* Restore previous interrupt posture. */ - TX_RESTORE - - /* Terminate the thread. */ - tx_thread_terminate(&(pppoe_server_ptr -> nx_pppoe_thread)); - - /* Delete the PPPoE thread. */ - tx_thread_delete(&(pppoe_server_ptr -> nx_pppoe_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(pppoe_server_ptr -> nx_pppoe_events)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server enable function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_enable Actual PPPoE enable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Make sure the data receive callback function is set before enable. - Setting this function by nx_pppoe_server_callback_notify_set() API. */ - if (pppoe_server_ptr -> nx_pppoe_data_receive_notify == NX_NULL) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call actual PPPoE server instance enable function. */ - status = _nx_pppoe_server_enable(pppoe_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_enable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function enables the PPPoE Server feature. */ -/* */ -/* INPUT */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* tx_thread_resume Resume PPPoE helper thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_enable Actual PPPoE enable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the enabled flag. */ - pppoe_server_ptr -> nx_pppoe_enabled = NX_TRUE; - - /* Resume the PPPoE server thread. */ - tx_thread_resume(&(pppoe_server_ptr -> nx_pppoe_thread)); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server disable function*/ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_disable Actual PPPoE disable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call actual PPPoE server instance disable function. */ - status = _nx_pppoe_server_disable(pppoe_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_disable PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disables the PPPoE Server feature. */ -/* */ -/* INPUT */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* tx_thread_suspend Suspend PPPoE helper thread */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_enable Actual PPPoE enable function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr) -{ - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the enabled flag. */ - pppoe_server_ptr -> nx_pppoe_enabled = NX_FALSE; - - /* Suspend the PPPoE server thread. */ - tx_thread_suspend(&(pppoe_server_ptr -> nx_pppoe_thread)); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_callback_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE Server disable function*/ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* pppoe_discover_initiation_notify Routine to call when discovery*/ -/* initiation data is received */ -/* pppoe_discover_request_notify Routine to call when discovery*/ -/* reques data is received */ -/* pppoe_discover_terminate_notify Routine to call when discovery*/ -/* terminate data is received */ -/* pppoe_discover_terminate_confirm Routine to call when discovery*/ -/* terminate data is sent */ -/* pppoe_data_receive_notify Routine to call when session */ -/* data is received */ -/* pppoe_data_send_notify Routine to call when session */ -/* data is sent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_callback_notify_set Actual PPPoE callback set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, - VOID (* pppoe_discover_initiation_notify)(UINT session_index), - VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), - VOID (* pppoe_discover_terminate_notify)(UINT session_index), - VOID (* pppoe_discover_terminate_confirm)(UINT session_index), - VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), - VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check to see if pppoe_data_receive_notify is set. */ - if (pppoe_data_receive_notify == NX_NULL) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call actual PPPoE service callback notify set function. */ - status = _nx_pppoe_server_callback_notify_set(pppoe_server_ptr, pppoe_discover_initiation_notify, pppoe_discover_request_notify, - pppoe_discover_terminate_notify, pppoe_discover_terminate_confirm, - pppoe_data_receive_notify, pppoe_data_send_notify); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_callback_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the callback notify functions. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* pppoe_discover_initiation_notify Routine to call when discovery*/ -/* initiation data is received */ -/* pppoe_discover_request_notify Routine to call when discovery*/ -/* reques data is received */ -/* pppoe_discover_terminate_notify Routine to call when discovery*/ -/* terminate data is received */ -/* pppoe_discover_terminate_confirm Routine to call when discovery*/ -/* terminate data is sent */ -/* pppoe_data_receive_notify Routine to call when session */ -/* data is received */ -/* pppoe_data_send_notify Routine to call when session */ -/* data is sent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, - VOID (* pppoe_discover_initiation_notify)(UINT session_index), - VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), - VOID (* pppoe_discover_terminate_notify)(UINT session_index), - VOID (* pppoe_discover_terminate_confirm)(UINT session_index), - VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), - VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)) -{ - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Install PPPoE notify function pointer */ - pppoe_server_ptr -> nx_pppoe_discover_initiation_notify = pppoe_discover_initiation_notify; - pppoe_server_ptr -> nx_pppoe_discover_request_notify = pppoe_discover_request_notify; - pppoe_server_ptr -> nx_pppoe_discover_terminate_notify = pppoe_discover_terminate_notify; - pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm = pppoe_discover_terminate_confirm; - pppoe_server_ptr -> nx_pppoe_data_receive_notify = pppoe_data_receive_notify; - pppoe_server_ptr -> nx_pppoe_data_send_notify = pppoe_data_send_notify; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_service_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE service name set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an array service */ -/* names. Each service name */ -/* must be Null-terminated */ -/* string. */ -/* service_name_count The counter of service names */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_service_name_set Actual PPPoE service name set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Call actual PPPoE service name set function. */ - status = _nx_pppoe_server_service_name_set(pppoe_server_ptr, service_name, service_name_count); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_service_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the the PPPoE service name. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* service_name Pointer to an array service */ -/* names. Each service name */ -/* must be Null-terminated */ -/* string. */ -/* service_name_count The counter of service names */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count) -{ - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Setup service name pointer. */ - pppoe_server_ptr -> nx_pppoe_service_name = service_name; - - /* Setup service name count. */ - pppoe_server_ptr -> nx_pppoe_service_name_count = service_name_count; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_session_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session data send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* data_ptr Session Data pointer */ -/* data_length Length of Session Data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_session_send Actual PPPoE Session data send*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID) || (data_ptr == NX_NULL)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check the service_name_count. */ - if (data_length == 0) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check to see if PPPoE is enabled. */ - if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) - return(NX_PPPOE_SERVER_NOT_ENABLED); - - /* Check for invalid session index. */ - if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return(NX_PPPOE_SERVER_INVALID_SESSION); - - /* Check to see if PPPoE session is established. */ - if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || - (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) - return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); - - /* Call actual PPPoE session send function. */ - status = _nx_pppoe_server_session_send(pppoe_server_ptr, session_index, data_ptr, data_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE Session packet and calls the */ -/* associated driver to send it out on the network. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* data_ptr Session Data pointer */ -/* data_length Length of Session Data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* nx_packet_allocate Allocate a packet for the */ -/* PPPoE Session */ -/* nx_packet_release Release packet to packet pool */ -/* nx_packet_data_append Copies the specified data */ -/* _nx_pppoe_server_data_add Add PPPoE data */ -/* _nx_pppoe_server_packet_send Send out PPPoE packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length) -{ - -NX_PPPOE_CLIENT_SESSION *client_session_ptr; -NX_PACKET *packet_ptr; -UCHAR *work_ptr; -UINT status; - - - /* Allocate a PPPoE packet. */ - status = nx_packet_allocate(pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_PPPOE_SERVER_PACKET_TIMEOUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Obtain the IP internal mutex. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the client session pointer. */ - client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); - - /* Set the work pointer. */ - work_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Added the PPPoE header. */ - /* - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | VER | TYPE | CODE | SESSION_ID | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | LENGTH | payload - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add version and type. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); - - /* Add code. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, NX_PPPOE_SERVER_CODE_ZERO); - - /* Add session id. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); - - /* Add length. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, data_length); - - /* Update the pointer to add the payload of PPPoE. */ - packet_ptr -> nx_packet_append_ptr += NX_PPPOE_SERVER_OFFSET_PAYLOAD; - packet_ptr -> nx_packet_length += NX_PPPOE_SERVER_OFFSET_PAYLOAD; - - /* Release the mutex before a blocking call. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Append the data into PPPoE packet. */ - status = nx_packet_data_append(packet_ptr, data_ptr, data_length, pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, NX_PPPOE_SERVER_PACKET_TIMEOUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Relase the packet. */ - nx_packet_release(packet_ptr); - - /* Return status. */ - return(status); - } - - /* Regain obtain the IP internal mutex. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Send PPPoE session packet. */ - _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); - - /* Check the PPPoE send function. */ - if (pppoe_server_ptr -> nx_pppoe_data_send_notify) - { - - /* Call the function to send the data frame. */ - pppoe_server_ptr -> nx_pppoe_data_send_notify(session_index, data_ptr); - } - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_session_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session packet send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* packet_ptr Pointer to packet to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_session_packet_send Actual PPPoE Session data send*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr) -{ - -UINT status; - - /* Check for invalid packet. */ - if (packet_ptr == NX_NULL) - { - return(NX_PPPOE_SERVER_PTR_ERROR); - } - - /* Check for minimum packet length (PPP DATA Header). */ - if (packet_ptr -> nx_packet_length < 2) - { - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); - } - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_SERVER_PTR_ERROR); - } - - /* Check to see if PPPoE is enabled. */ - if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_SERVER_NOT_ENABLED); - } - - /* Check for invalid session index. */ - if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_SERVER_INVALID_SESSION); - } - - /* Check to see if PPPoE session is established. */ - if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || - (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); - } - - /* Call actual PPPoE session packet_send function. */ - status = _nx_pppoe_server_session_packet_send(pppoe_server_ptr, session_index, packet_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE Session packet and calls the */ -/* associated driver to send it out on the network. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* data_ptr Session Data pointer */ -/* data_length Length of Session Data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* nx_packet_release Release packet to packet pool */ -/* nx_packet_data_append Copies the specified data */ -/* _nx_pppoe_server_data_add Add PPPoE data */ -/* _nx_pppoe_server_packet_send Send out PPPoE packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr) -{ - -NX_PPPOE_CLIENT_SESSION *client_session_ptr; -UCHAR *work_ptr; - - - /* Obtain the IP internal mutex. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check for an invalid packet prepend pointer. */ - if ((packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < NX_PPPOE_SERVER_OFFSET_PAYLOAD) - { - - /* Adjust the packet prepend to remove the PPP header. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - 2; - - /* Release the packet. */ - nx_packet_transmit_release(packet_ptr); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return error code. */ - return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); - } - - /* Set the client session pointer. */ - client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); - - /* Set the work pointer. */ - packet_ptr -> nx_packet_prepend_ptr -= NX_PPPOE_SERVER_OFFSET_PAYLOAD; - work_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Added the PPPoE header. */ - /* - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | VER | TYPE | CODE | SESSION_ID | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | LENGTH | payload - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add version and type. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); - - /* Add code. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, NX_PPPOE_SERVER_CODE_ZERO); - - /* Add session id. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); - - /* Add length. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, packet_ptr -> nx_packet_length); - - /* Update the packet length. */ - packet_ptr -> nx_packet_length += NX_PPPOE_SERVER_OFFSET_PAYLOAD; - - /* Send PPPoE session packet. */ - _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_SESSION_SEND); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_session_terminate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session terminate */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_session_terminate Actual PPPoE Session terminate*/ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check to see if PPPoE is enabled. */ - if (pppoe_server_ptr -> nx_pppoe_enabled != NX_TRUE) - return(NX_PPPOE_SERVER_NOT_ENABLED); - - /* Check for invalid session index. */ - if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return(NX_PPPOE_SERVER_INVALID_SESSION); - - /* Check to see if PPPoE session is established. */ - if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || - (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) - return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); - - /* Call actual PPPoE session terminate function. */ - status = _nx_pppoe_server_session_terminate(pppoe_server_ptr, session_index); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_terminate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE packet to terminate the session. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index Session index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_server_discovery_send Send out PPPoE packet */ -/* _nx_pppoe_server_session_cleanup Cleanup PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index) -{ - -NX_PPPOE_CLIENT_SESSION *client_session_ptr; -UINT status; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the client session pointer. */ - client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[session_index]); - - /* Terminate the PPPoE session. */ - status = _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADT); - - /* Check the status. */ - if (status == NX_PPPOE_SERVER_SUCCESS) - { - - /* Cleanup the session. */ - _nx_pppoe_server_session_cleanup(client_session_ptr); - - /* Check the PPPoE terminate confirm function. */ - if (pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm) - { - - /* Call terminate confirm function. */ - pppoe_server_ptr -> nx_pppoe_discover_terminate_confirm(session_index); - } - } - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_pppoe_server_session_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the PPPoE session get function */ -/* call. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index The index of Client Session */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* session_id Session ID */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_session_get Actual PPPoE Session get */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((pppoe_server_ptr == NX_NULL) || (pppoe_server_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return(NX_PPPOE_SERVER_PTR_ERROR); - - /* Check for invalid session index. */ - if(session_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return(NX_PPPOE_SERVER_INVALID_SESSION); - - /* Call actual PPPoE session get function. */ - status = _nx_pppoe_server_session_get(pppoe_server_ptr, session_index, client_mac_msw, client_mac_lsw, session_id); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds an PPPoE packet to get the session physical */ -/* address and session id. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* session_index The index of Client Session */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* session_id Session ID */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id) -{ - - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check to see if PPPoE session is established. */ - if ((pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_valid != NX_TRUE) || - (pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id == 0)) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return(NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED); - } - - /* Yes, get the Client physical address MSW. */ - if (client_mac_msw) - *client_mac_msw = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_physical_address_msw; - - /* Yes, get the Client physical address LSW. */ - if (client_mac_lsw) - *client_mac_lsw = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_physical_address_lsw; - - /* Yes, get the Session ID. */ - if (session_id) - *session_id = pppoe_server_ptr -> nx_pppoe_client_session[session_index].nx_pppoe_session_id; - - /* Release the IP internal mutex. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Return status. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - - /**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_packet_deferred_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives a packet from the link driver (usually the */ -/* link driver's input ISR) and places it in the deferred receive */ -/* packet queue. This moves the minimal receive packet processing */ -/* from the ISR to the PPPoE helper thread. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for PPPoE thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr) -{ - -TX_INTERRUPT_SAVE_AREA - - - /* Check to see if PPPoE instance is created. */ - if (_nx_pppoe_server_created_ptr == NX_NULL) - { - - /* Release the packet. */; - nx_packet_release(packet_ptr); - - return; - } - - /* Check to see if PPPoE is enabled. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) - { - - /* Release the packet. */; - nx_packet_release(packet_ptr); - - return; - } - - /* Disable interrupts. */ - TX_DISABLE - - /* Check to see if the deferred processing queue is empty. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_head) - { - - /* Not empty, just place the packet at the end of the queue. */ - (_nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - - /* Restore interrupts. */ - TX_RESTORE - } - else - { - - /* Empty deferred receive processing queue. Just setup the head pointers and - set the event flags to ensure the PPPoE helper thread looks at the deferred processing - queue. */ - _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; - _nx_pppoe_server_created_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Restore interrupts. */ - TX_RESTORE - - /* Wakeup PPPoE helper thread to process the PPPoE deferred receive. */ - tx_event_flags_set(&(_nx_pppoe_server_created_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT, TX_OR); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry point for each PPPoE's helper thread. */ -/* The PPPoE helper thread is responsible for processing PPPoE packet. */ -/* */ -/* Note that the priority of this function is determined by the PPPoE */ -/* create service. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr_value Pointer to PPPoE control block*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Suspend on event flags that */ -/* are used to signal this */ -/* thread what to do */ -/* tx_mutex_get Obtain protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_server_packet_receive PPPoE receive packet */ -/* processing */ -/* nx_packet_release Release packet to packet pool */ -/* (pppoe_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX Scheduler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_server_thread_entry(ULONG pppoe_server_ptr_value) -{ - -TX_INTERRUPT_SAVE_AREA - -#ifdef NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE -NX_IP_DRIVER driver_request; -#endif -NX_PPPOE_SERVER *pppoe_server_ptr; -NX_IP *ip_ptr; -NX_PACKET *packet_ptr; -ULONG pppoe_events; -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -UINT i; -#endif - - - /* Setup the PPPoE pointer. */ - pppoe_server_ptr = (NX_PPPOE_SERVER *) pppoe_server_ptr_value; - - /* Setup the IP pointer. */ - ip_ptr = pppoe_server_ptr -> nx_pppoe_ip_ptr; - - /* Obtain the IP internal mutex before calling the driver. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - -#ifdef NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE - - /* Initialize and enable the hardware for physical interface. */ - - /* Is this a valid interface with a link driver associated with it? */ - if((pppoe_server_ptr -> nx_pppoe_interface_ptr -> nx_interface_valid) && (pppoe_server_ptr -> nx_pppoe_link_driver_entry)) - { - - /* Yes; attach the interface to the device. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_INTERFACE_ATTACH; - driver_request.nx_ip_driver_interface = pppoe_server_ptr -> nx_pppoe_interface_ptr; - (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Call the link driver to initialize the hardware. Among other - responsibilities, the driver is required to provide the - Maximum Transfer Unit (MTU) for the physical layer. The MTU - should represent the actual physical layer transfer size - less the physical layer headers and trailers. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_INITIALIZE; - (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Call the link driver again to enable the interface. */ - driver_request.nx_ip_driver_ptr = ip_ptr; - driver_request.nx_ip_driver_command = NX_LINK_ENABLE; - (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); - - /* Indicate to the IP software that IP to physical mapping - is not required. */ - pppoe_server_ptr -> nx_pppoe_interface_ptr -> nx_interface_address_mapping_needed = NX_FALSE; - } -#endif - - /* Loop to continue processing incoming bytes. */ - while(NX_FOREVER) - { - - - /* Release the IP internal mutex. */ - tx_mutex_put(&(ip_ptr -> nx_ip_protection)); - - /* Pickup IP event flags. */ - tx_event_flags_get(&(pppoe_server_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_ALL_EVENTS, TX_OR_CLEAR, &pppoe_events, NX_WAIT_FOREVER); - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Check for PPPoE event. */ - if (pppoe_events & NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT) - { - - /* Loop to process all deferred packet requests. */ - while (pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head) - { - - /* Remove the first packet and process it! */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the first packet. */ - packet_ptr = pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head; - - /* Move the head pointer to the next packet. */ - pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; - - /* Check for end of deferred processing queue. */ - if (pppoe_server_ptr -> nx_pppoe_deferred_received_packet_head == NX_NULL) - { - - /* Yes, the queue is empty. Set the tail pointer to NULL. */ - pppoe_server_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Discard the chained packets. */ - if (packet_ptr -> nx_packet_next) - { - nx_packet_release(packet_ptr); - continue; - } -#endif - - /* Check for valid packet length. */ - if (packet_ptr -> nx_packet_length < NX_PPPOE_SERVER_OFFSET_PAYLOAD) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check the packet interface. */ - if ((packet_ptr -> nx_packet_ip_interface != NX_NULL) && - (packet_ptr -> nx_packet_ip_interface != pppoe_server_ptr -> nx_pppoe_interface_ptr)) - { - nx_packet_release(packet_ptr); - continue; - } - - /* Call the actual PPPoE Server packet receive function. */ - _nx_pppoe_server_packet_receive(pppoe_server_ptr, packet_ptr); - } - } - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Check for PPPoE Session Receive event. */ - if (pppoe_events & NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT) - { - - for(i = 0; i < NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; i ++) - { - - /* Check if this session is valid. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_valid != NX_TRUE) - continue; - - /* Check if this session is ready to receive the packet. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_packet_receive_stopped == NX_TRUE) - continue; - - /* Check if this session queued the packets. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head) - { - - /* Remove the first packet and process it! */ - - /* Disable interrupts. */ - TX_DISABLE - - /* Pickup the first packet. */ - packet_ptr = pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head; - - /* Move the head pointer to the next packet. */ - pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; - - /* Check for end of deferred processing queue. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_head == NX_NULL) - { - - /* Yes, the queue is empty. Set the tail pointer to NULL. */ - pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_deferred_received_packet_tail = NX_NULL; - } - - /* Restore interrupts. */ - TX_RESTORE - - /* Set the flag to stop receive the next packet. */ - pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_packet_receive_stopped = NX_TRUE; - - /* Check the PPPoE receive function. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_data_receive_notify) - { - - /* Call the function to receive the data frame. */ - _nx_pppoe_server_created_ptr -> nx_pppoe_data_receive_notify(i, packet_ptr -> nx_packet_length, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr)); - } - } - } - } -#endif - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives a PPPoE packet from the PPPoE deferred */ -/* processing queue. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_server_data_get Get the PPPoE data */ -/* _nx_pppoe_server_discovery_packet_process */ -/* Process discovery packet */ -/* _nx_pppoe_server_session_packet_process */ -/* Process session packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_server_packet_receive(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr) -{ - -UCHAR *ethernet_header_ptr; -ULONG server_mac_msw; -ULONG server_mac_lsw; -ULONG client_mac_msw; -ULONG client_mac_lsw; -UINT ethernet_type; -UINT is_broadcast = NX_FALSE; - - /* Set up UCHAR pointer to ethernet header to extract client hardware address - which we will use as the client's unique identifier. */ - ethernet_header_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_PPPOE_SERVER_ETHER_HEADER_SIZE; - - /* Pickup the MSW and LSW of the destination MAC address. */ - server_mac_msw = (((ULONG) ethernet_header_ptr[0]) << 8) | ((ULONG) ethernet_header_ptr[1]); - server_mac_lsw = (((ULONG) ethernet_header_ptr[2]) << 24) | (((ULONG) ethernet_header_ptr[3]) << 16) | - (((ULONG) ethernet_header_ptr[4]) << 8) | ((ULONG) ethernet_header_ptr[5]); - - /* Check the server hardware (mac address) field is filled in. */ - if ((server_mac_msw == 0) && (server_mac_lsw == 0)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Check if it is a broadcast message. */ - if ((server_mac_msw == 0xFFFF) && (server_mac_lsw == 0xFFFFFFFF)) - is_broadcast = NX_TRUE; - - /* Pickup the MSW and LSW of the source MAC address. */ - client_mac_msw = (((ULONG) ethernet_header_ptr[6]) << 8) | ((ULONG) ethernet_header_ptr[7]); - client_mac_lsw = (((ULONG) ethernet_header_ptr[8]) << 24) | (((ULONG) ethernet_header_ptr[9]) << 16) | - (((ULONG) ethernet_header_ptr[10]) << 8) | ((ULONG) ethernet_header_ptr[11]); - - /* Check the client hardware (mac address) field is filled in. */ - if ((client_mac_msw == 0) && (client_mac_lsw == 0)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Get the ethernet type. */ - ethernet_type = _nx_pppoe_server_data_get(ethernet_header_ptr + 12, 2); - - /* Process the packet according to packet type. */ - if(ethernet_type == NX_PPPOE_SERVER_ETHER_TYPE_DISCOVERY) - { - - /* Process the discovery packet. */ - _nx_pppoe_server_discovery_packet_process(pppoe_server_ptr, packet_ptr, client_mac_msw, client_mac_lsw, is_broadcast); - } - else if(ethernet_type == NX_PPPOE_SERVER_ETHER_TYPE_SESSION) - { - - /* Session Stage, all Ethernet packets are unicast. */ - if (is_broadcast == NX_TRUE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Process the session packet. */ - _nx_pppoe_server_session_packet_process(pppoe_server_ptr, packet_ptr, client_mac_msw, client_mac_lsw); - } - else - { - - /* Relase the packet. */ - nx_packet_release(packet_ptr); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_discovery_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an incoming discovery packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* is_broadcast Broadcast flag */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_server_data_get Get the PPPoE data */ -/* _nx_pppoe_server_tag_process Process PPPoE tags */ -/* _nx_pppoe_server_discovery_send Send discovery packet */ -/* _nx_pppoe_server_session_find Find the PPPoE session */ -/* _nx_pppoe_server_session_cleanup Cleanup the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_pppoe_server_discovery_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, UINT is_broadcast) -{ - -UCHAR *pppoe_header_ptr; -ULONG ver_type; -ULONG code; -ULONG session_id; -ULONG length; -UINT status; -UCHAR *tag_ptr; -UINT session_index = 0; -NX_PPPOE_CLIENT_SESSION *client_session_ptr = NX_NULL; - - - /* Setup the PPPoE header. */ - pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the version and type. */ - ver_type = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1); - - /* Check the version and type. */ - if (ver_type != NX_PPPOE_SERVER_VERSION_TYPE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the code. */ - code = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1); - - /* Check the code. */ - if ((code != NX_PPPOE_SERVER_CODE_PADI) && - (code != NX_PPPOE_SERVER_CODE_PADR) && - (code != NX_PPPOE_SERVER_CODE_PADT)) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* For PADI, the destination address should be broadcast. - For PADR and PART, the destination address should be unicast. */ - if (((code == NX_PPPOE_SERVER_CODE_PADI) && (is_broadcast != NX_TRUE)) || - ((code != NX_PPPOE_SERVER_CODE_PADI) && (is_broadcast == NX_TRUE))) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the session id. */ - session_id = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2); - - /* Check the session id. - Session ID must be zero for PADI and PADR, - Session ID must be not zero for PADT. */ - if (((code != NX_PPPOE_SERVER_CODE_PADT) && (session_id != 0)) || - ((code == NX_PPPOE_SERVER_CODE_PADT) && (session_id == 0))) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Find the PPPoE Session. */ - status = _nx_pppoe_server_session_find(pppoe_server_ptr, client_mac_msw, client_mac_lsw, session_id, &session_index, &client_session_ptr); - - /* Check the status. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the length of tags. */ - length = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2); - - /* Check for valid payload. */ - if (length > packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Set the tag pointer. */ - tag_ptr = pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_PAYLOAD; - - /* Process the tag. */ - status = _nx_pppoe_server_tag_process(pppoe_server_ptr, client_session_ptr, code, tag_ptr, length); - - /* Now we can release the packet. */ - nx_packet_release(packet_ptr); - - /* Check the status. */ - if (status) - { - - /* If the Access Concentrator does not like the Service-Name in the PADR, - then it MUST reply with a PADS containing a TAG of TAG_TYPE Service-Name-Error (and any number of other TAG types). - In this case the SESSION_ID MUST be set to 0x0000. RFC2516, Section5.4, Page6. */ - if ((status == NX_PPPOE_SERVER_SERVICE_NAME_ERROR) && (code == NX_PPPOE_SERVER_CODE_PADR)) - { - - /* Clear the session id. */ - client_session_ptr -> nx_pppoe_session_id = 0; - - /* Send PADS. */ - _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); - } - - /* Cleanup the PPPoE session. */ - _nx_pppoe_server_session_cleanup(client_session_ptr); - - return; - } - - /* Check the code value. */ - if (code == NX_PPPOE_SERVER_CODE_PADI) - { - - /* It is PPPoE Active Discovery Initiation packet. */ - if (pppoe_server_ptr -> nx_pppoe_discover_initiation_notify) - { - - /* Call discover initiation notify function. */ - pppoe_server_ptr -> nx_pppoe_discover_initiation_notify(session_index); - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Send PPPoE Active Discover Offer packet in PppDiscoverCnf(). */ - return; -#endif - } - - /* Send PPPoE Active Discovery Offer packet. */ - _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADO); - } - else if (code == NX_PPPOE_SERVER_CODE_PADR) - { - - /* Generate the unique session id. */ - if (client_session_ptr -> nx_pppoe_session_id == 0) - { - - /* The Session ID should not be zero and 0xFFFF. - RFC2516, Section4, Page4. */ - if ((pppoe_server_ptr -> nx_pppoe_session_id == 0) || - (pppoe_server_ptr -> nx_pppoe_session_id == 0xFFFF)) - pppoe_server_ptr -> nx_pppoe_session_id = 1; - - /* Setup the session id. */ - client_session_ptr -> nx_pppoe_session_id = pppoe_server_ptr -> nx_pppoe_session_id; - - /* Update the session id for next client session. */ - pppoe_server_ptr -> nx_pppoe_session_id++; - } - - /* It is PPPoE Active Discovery Request packet. */ - if (pppoe_server_ptr -> nx_pppoe_discover_request_notify) - { - - /* Call discover reqest notify function. */ - if (client_session_ptr -> nx_pppoe_service_name == NX_NULL) - { - pppoe_server_ptr -> nx_pppoe_discover_request_notify(session_index, 0, NX_NULL); - } - else - { - /* Check service name length. */ - _nx_utility_string_length_check((char*)client_session_ptr -> nx_pppoe_service_name, (UINT *)&length, NX_MAX_STRING_LENGTH); - - pppoe_server_ptr -> nx_pppoe_discover_request_notify(session_index, length, client_session_ptr -> nx_pppoe_service_name); - } - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Send PPPoE Active Discover Session-confirmation packet in PppOpenCnf(). */ - return; -#endif - } - - /* Send PPPoE Active Discovery Session-confirmation packet. */ - _nx_pppoe_server_discovery_send(pppoe_server_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); - } - else if (code == NX_PPPOE_SERVER_CODE_PADT) - { - -#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Cleanup the PPPoE session. */ - _nx_pppoe_server_session_cleanup(client_session_ptr); -#endif - - /* It is PPPoE Active Discovery Terminate packet. */ - if (pppoe_server_ptr -> nx_pppoe_discover_terminate_notify) - { - - /* Call discover terminate notify function. */ - pppoe_server_ptr -> nx_pppoe_discover_terminate_notify(session_index); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_packet_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an incoming session packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* packet_ptr Pointer to packet to receive */ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_server_data_get Get the PPPoE data */ -/* _nx_pppoe_server_session_find Find the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_server_session_packet_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PACKET *packet_ptr, ULONG client_mac_msw, ULONG client_mac_lsw) -{ - -UCHAR *pppoe_header_ptr; -ULONG ver_type; -ULONG code; -ULONG session_id; -ULONG length; -UINT status; -UINT session_index = 0; -NX_PPPOE_CLIENT_SESSION *client_session_ptr = NX_NULL; - - - /* Setup the PPPoE header. */ - pppoe_header_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the version and type. */ - ver_type = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1); - - /* Check the version and type. */ - if (ver_type != NX_PPPOE_SERVER_VERSION_TYPE) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the code. */ - code = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1); - - /* Check the code. */ - if (code != NX_PPPOE_SERVER_CODE_ZERO) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the session id. */ - session_id = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2); - - /* Check the session id. */ - if (session_id == 0) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Setup the prepend pointer to point the payload of PPPoE. */ - packet_ptr -> nx_packet_prepend_ptr += NX_PPPOE_SERVER_OFFSET_PAYLOAD; - packet_ptr -> nx_packet_length -= NX_PPPOE_SERVER_OFFSET_PAYLOAD; - - /* Look up the PPPoE session by physical address and interface index in Client Records table. */ - status = _nx_pppoe_server_session_find(pppoe_server_ptr, client_mac_msw, client_mac_lsw, session_id, &session_index, &client_session_ptr); - - /* Check the status. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the length of payload. */ - length = _nx_pppoe_server_data_get(pppoe_header_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2); - - /* Check for valid payload. */ - if (length > packet_ptr -> nx_packet_length) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Remove the Ethernet padding. */ - if (length < packet_ptr -> nx_packet_length) - { - packet_ptr -> nx_packet_append_ptr -= (packet_ptr -> nx_packet_length - length); - packet_ptr -> nx_packet_length -= (packet_ptr -> nx_packet_length - length); - } - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - - /* Check to see if the deferred processing queue is empty. */ - if (client_session_ptr -> nx_pppoe_deferred_received_packet_head) - { - - /* Not empty, just place the packet at the end of the queue. */ - (client_session_ptr -> nx_pppoe_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - client_session_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - - /* Return. */ - return; - } - else - { - - /* Check the packet receive flag. */ - if (client_session_ptr -> nx_pppoe_packet_receive_stopped == NX_TRUE) - { - - /* Empty deferred receive processing queue. Just setup the head pointers and - set the event flags to ensure the PPPoE helper thread looks at the deferred processing queue. */ - client_session_ptr -> nx_pppoe_deferred_received_packet_head = packet_ptr; - client_session_ptr -> nx_pppoe_deferred_received_packet_tail = packet_ptr; - packet_ptr -> nx_packet_queue_next = NX_NULL; - - /* Return. */ - return; - } - } - - /* Set the flag to stop receive the next packet. */ - client_session_ptr -> nx_pppoe_packet_receive_stopped = NX_TRUE; -#endif - - /* Check the PPPoE receive function. */ - if (pppoe_server_ptr -> nx_pppoe_data_receive_notify) - { - - /* Call the function to receive the data frame. - Notice: the receive function must release this packet. */ - pppoe_server_ptr -> nx_pppoe_data_receive_notify(session_index, length, packet_ptr -> nx_packet_prepend_ptr, (UINT)(packet_ptr)); - } - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_discovery_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a PPPoE discovery packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* client_session_ptr Pointer to Client Session */ -/* code PPPoE code */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* nx_packet_allocate Allocate a packet for the */ -/* PPPoE Discovery */ -/* nx_packet_release Release packet to packet pool */ -/* _nx_pppoe_server_data_add Add PPPoE data */ -/* _nx_pppoe_server_tag_string_add Add PPPoE tag */ -/* _nx_pppoe_server_packet_send Send out PPPoE packet */ -/* _nx_pppoe_server_session_find Find the PPPoE session */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_session_terminate Terminate the PPPoE session */ -/* _nx_pppoe_server_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_server_discovery_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code) -{ - -NX_PACKET *packet_ptr; -UCHAR *work_ptr; -UINT status; -UINT index = 0; -UINT tag_length; -UINT service_name_index = 0; -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -UCHAR *service_name_ptr; -#endif - - - /* Release the mutex before a blocking call. */ - tx_mutex_put(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - /* Allocate a PPPoE packet. */ - status = nx_packet_allocate(pppoe_server_ptr -> nx_pppoe_packet_pool_ptr, &packet_ptr, NX_PHYSICAL_HEADER, NX_PPPOE_SERVER_PACKET_TIMEOUT); - - /* Was the packet allocation successful? */ - if (status != NX_SUCCESS) - { - - /* Return status. */ - return(status); - } - - /* Obtain the IP internal mutex. */ - tx_mutex_get(&(pppoe_server_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the work pointer. */ - work_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* First skip the PPPoE header. */ - index += NX_PPPOE_SERVER_OFFSET_PAYLOAD; - - /* The PPPoE payload contains zero or more TAGs. A TAG is a TLV (type-length-value) construct and is defined as follows. */ - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | TAG_TYPE | TAG_LENGTH | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | TAG_VALUE ... - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add the PPPoE tags. */ - if (code == NX_PPPOE_SERVER_CODE_PADO) - { - - /* The PADO packet MUST contain one AC-Name TAG containing the Access Concentrator's name. RFC2516, Section 5.2, Page6. */ - - /* Added the AC-Name tag. */ - if (pppoe_server_ptr -> nx_pppoe_ac_name) - { - - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_AC_NAME, pppoe_server_ptr -> nx_pppoe_ac_name_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_ac_name), &index); - } - else - { - - /* If user does not separately set Access Concentrator name, will use PPPoE server name as Access Concentrator name.*/ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_AC_NAME, pppoe_server_ptr -> nx_pppoe_name_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_name), &index); - } - - /* The PADO packet MUST contain a Service-Name TAG identical to the one in the PADI, - and any number of other Service-Name TAGs indicating other services. RFC2516, Section 5.2, Page6. */ - - /* Added a Service-Name TAG identical to the one in the PADI. */ - if (client_session_ptr -> nx_pppoe_service_name) - { - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Set the service name pointer. */ - service_name_ptr = client_session_ptr -> nx_pppoe_service_name; - - /* Loop to add service name that user configured. */ - while(service_name_index < client_session_ptr -> nx_pppoe_service_name_length) - { - - /* Get the service name. */ - if (_nx_utility_string_length_check((const char *)(service_name_ptr), &tag_length, NX_MAX_STRING_LENGTH)) - { - nx_packet_release(packet_ptr); - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, service_name_ptr, &index); - - /* Update the service name pointer, length + null-terminated. */ - service_name_ptr += (tag_length + 1); - service_name_index += (tag_length + 1); - } -#else - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(client_session_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) - { - nx_packet_release(packet_ptr); - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, client_session_ptr -> nx_pppoe_service_name, &index); -#endif - } - else - { - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); - } - -#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Add any number of other Service-Name TAGs indicating other services. */ - if (pppoe_server_ptr -> nx_pppoe_service_name_count) - { - - /* The PADO packet can contain any number of Service-Name TAGs. */ - for (service_name_index = 0; service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count; service_name_index ++) - { - - /* Check if this Service-Name has been added. */ - if (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index] == client_session_ptr -> nx_pppoe_service_name) - continue; - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), &tag_length, NX_MAX_STRING_LENGTH)) - { - nx_packet_release(packet_ptr); - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, (UCHAR *)(pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), &index); - } - } -#endif - - /* If the Access Concentrator receives this Host-Uniq TAG, it MUST include the TAG unmodified in associated PADO or PADS response. - RFC2516, Appendix A, Host-Uniq. */ - if (client_session_ptr -> nx_pppoe_host_uniq_size) - { - - /* Added the Host-Uniq. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ, client_session_ptr -> nx_pppoe_host_uniq_size, client_session_ptr -> nx_pppoe_host_uniq, &index); - } - - /* If either the Host or Access Concentrator receives this Relay-Session-Id TAG, they MUST include it unmodified in any discovery packet they send as a response. - RFC2516, Appendix A, Relay-Session-Id. */ - if (client_session_ptr -> nx_pppoe_relay_session_id_size) - { - - /* Added the Host-Uniq. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID, client_session_ptr -> nx_pppoe_relay_session_id_size, client_session_ptr -> nx_pppoe_relay_session_id, &index); - } - } - else if (code == NX_PPPOE_SERVER_CODE_PADS) - { - - /* Check the error. */ - if (client_session_ptr -> nx_pppoe_error_flag & NX_PPPOE_SERVER_ERROR_SERVICE_NAME) - { - - /* Added Service-Name-Error tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME_ERROR, 0, NX_NULL, &index); - } - - /* The PADS packet MUST contain one exactly one TAG of TAG_TYPE Service-Name. RFC2516, Section 5.4, Page6 */ - - /* Check the service name. */ - if (client_session_ptr -> nx_pppoe_service_name) - { - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((char *)(client_session_ptr -> nx_pppoe_service_name), &tag_length, NX_MAX_STRING_LENGTH)) - { - nx_packet_release(packet_ptr); - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, tag_length, client_session_ptr -> nx_pppoe_service_name, &index); - } - else - { - - /* Added the Service-Name tag. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME, 0, NX_NULL, &index); - } - - /* If the Access Concentrator receives this Host-Uniq TAG, it MUST include the TAG unmodified in associated PADO or PADS response. - RFC2516, Appendix A, Host-Uniq. */ - if (client_session_ptr -> nx_pppoe_host_uniq_size) - { - - /* Added the Host-Uniq. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ, client_session_ptr -> nx_pppoe_host_uniq_size, client_session_ptr -> nx_pppoe_host_uniq, &index); - } - - /* If either the Host or Access Concentrator receives this Relay-Session-Id TAG, they MUST include it unmodified in any discovery packet they send as a response. - RFC2516, Appendix A, Relay-Session-Id. */ - if (client_session_ptr -> nx_pppoe_relay_session_id_size) - { - - /* Added the Host-Uniq. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID, client_session_ptr -> nx_pppoe_relay_session_id_size, client_session_ptr -> nx_pppoe_relay_session_id, &index); - } - } - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - else if (code == NX_PPPOE_SERVER_CODE_PADT) - { - - /* Check the Generic-Error. */ - if (client_session_ptr -> nx_pppoe_generic_error) - { - - /* Calculate the Generic-Error string length. */ - if (_nx_utility_string_length_check((const char *)(client_session_ptr -> nx_pppoe_generic_error), &tag_length, NX_MAX_STRING_LENGTH)) - { - nx_packet_release(packet_ptr); - return(NX_SIZE_ERROR); - } - - /* Added the Generic-Error. */ - _nx_pppoe_server_tag_string_add(work_ptr, NX_PPPOE_SERVER_TAG_TYPE_GENERIC_ERROR, tag_length, client_session_ptr -> nx_pppoe_generic_error, &index); - } - } -#endif - - /* Add the PPPoE header. */ - /* - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | VER | TYPE | CODE | SESSION_ID | - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * | LENGTH | payload - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - */ - - /* Add version and type. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_VER_TYPE, 1, NX_PPPOE_SERVER_VERSION_TYPE); - - /* Add code. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_CODE, 1, code); - - /* Add the Session id. */ - if (code == NX_PPPOE_SERVER_CODE_PADO) - { - - /* Add session id. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, 0); - } - else - { - - /* Add session id. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_SESSION_ID, 2, client_session_ptr -> nx_pppoe_session_id); - } - - /* Add length. */ - _nx_pppoe_server_data_add(work_ptr + NX_PPPOE_SERVER_OFFSET_LENGTH, 2, (index - NX_PPPOE_SERVER_OFFSET_PAYLOAD)); - - /* Update the append pointer and length. */ - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + index; - packet_ptr -> nx_packet_length = index; - - /* Send PPPoE session packet. */ - _nx_pppoe_server_packet_send(pppoe_server_ptr, client_session_ptr, packet_ptr, NX_LINK_PPPOE_DISCOVERY_SEND); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a PPPoE packet to the appropriate link driver. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* client_session_ptr Pointer to Client Session */ -/* packet_ptr Pointer to packet to send */ -/* command Driver command */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* (ip_link_driver) User supplied link driver */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ -/* _nx_pppoe_server_session_send Send PPPoE Session packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_server_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, NX_PACKET *packet_ptr, UINT command) -{ - -NX_IP_DRIVER driver_request; - - - /* Initialize the driver request. */ - driver_request.nx_ip_driver_ptr = pppoe_server_ptr -> nx_pppoe_ip_ptr; - driver_request.nx_ip_driver_packet = packet_ptr; - driver_request.nx_ip_driver_interface = pppoe_server_ptr -> nx_pppoe_interface_ptr; - driver_request.nx_ip_driver_physical_address_msw = client_session_ptr -> nx_pppoe_physical_address_msw; - driver_request.nx_ip_driver_physical_address_lsw = client_session_ptr -> nx_pppoe_physical_address_lsw; - driver_request.nx_ip_driver_command = command; - - /* Sendout the PPPoE packet. */ - (pppoe_server_ptr -> nx_pppoe_link_driver_entry) (&driver_request); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_tag_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes tags of PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* client_session_ptr Pointer to Client Session */ -/* code PPPoE code */ -/* tag_ptr Pointer to PPPoE tag */ -/* length Length of PPPoe tags */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_data_get Get the PPPoE data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_server_tag_process(NX_PPPOE_SERVER *pppoe_server_ptr, NX_PPPOE_CLIENT_SESSION *client_session_ptr, UINT code, UCHAR *tag_ptr, ULONG length) -{ - -ULONG tag_type; -ULONG tag_length; -UINT tag_index = 0; -UINT tag_service_name_count = 0; -UINT tag_service_name_valid = NX_FALSE; -UINT service_name_index = 0; -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -UCHAR *service_name_ptr; -UINT service_name_length; -#endif - - /* Initialize the value. */ - client_session_ptr -> nx_pppoe_host_uniq_size = 0; - client_session_ptr -> nx_pppoe_relay_session_id_size = 0; - client_session_ptr -> nx_pppoe_error_flag = 0; -#ifndef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - client_session_ptr -> nx_pppoe_service_name = NX_NULL; -#endif - - - /* Loop to process the tag. */ - while (tag_index < length) - { - - /* Pickup the tag type. */ - tag_type = _nx_pppoe_server_data_get(tag_ptr + tag_index, 2); - - /* Update the index. */ - tag_index += 2; - - /* Pickup the tag length. */ - tag_length = _nx_pppoe_server_data_get(tag_ptr + tag_index, 2); - - /* Update the index. */ - tag_index += 2; - - /* Check for valid tag length. */ - if ((tag_index + tag_length) > length) - { - return(NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR); - } - - /* Process the option type. */ - switch (tag_type) - { - - case NX_PPPOE_SERVER_TAG_TYPE_END_OF_LIST: - { - - /* End tag. */ - break; - } - case NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME: - { - - /* Service name tag. */ - tag_service_name_count ++; - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - if (code == NX_PPPOE_SERVER_CODE_PADI) - { - - /* The service name of incoming PADI must match the default service name of PPPoE. */ - /* Check the tag length. */ - if (tag_length == 0) - { - - /* Check the default service name. */ - if (pppoe_server_ptr -> nx_pppoe_service_name_count == 0) - tag_service_name_valid = NX_TRUE; - } - else - { - - /* Loop to find the service name. */ - while (service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count) - { - - /* Compare the same service name with PPPoE Service Name. */ - if (!memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), tag_length)) - { - tag_service_name_valid = NX_TRUE; - client_session_ptr -> nx_pppoe_service_name = pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]; - break; - } - service_name_index ++; - } - } - } - else if (code == NX_PPPOE_SERVER_CODE_PADR) - { - - /* Compare the service name with session service name. */ - /* Check the tag length. */ - if ((tag_length == 0) && (client_session_ptr -> nx_pppoe_service_name_length == 0)) - { - - /* Update the information. */ - tag_service_name_valid = NX_TRUE; - client_session_ptr -> nx_pppoe_service_name = NX_NULL; - client_session_ptr -> nx_pppoe_service_name_length = 0; - break; - } - - /* Set the service name pointer. */ - service_name_ptr = client_session_ptr -> nx_pppoe_service_name; - - /* Loop to compare the service name with session service name. */ - while(service_name_index < client_session_ptr -> nx_pppoe_service_name_length) - { - - /* Get the service name. */ - if (_nx_utility_string_length_check((const char *)(service_name_ptr), &service_name_length, NX_MAX_STRING_LENGTH)) - { - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - - /* Check the tag length. */ - if ((tag_length == 0) && (service_name_length == 0)) - { - tag_service_name_valid = NX_TRUE; - } - else if ((tag_length != 0) && (service_name_length != 0)) - { - - /* Compare the service name. */ - if (!memcmp(tag_ptr + tag_index, service_name_ptr, tag_length)) - tag_service_name_valid = NX_TRUE; - } - - /* Update the service name information for PADS. */ - if (tag_service_name_valid == NX_TRUE) - { - client_session_ptr -> nx_pppoe_service_name = service_name_ptr; - client_session_ptr -> nx_pppoe_service_name_length = service_name_length; - break; - } - - /* Update the service name pointer, length + null-terminated. */ - service_name_ptr += (service_name_length + 1); - service_name_index += (service_name_length + 1); - } - } -#else - - /* Check the tag length. */ - if (tag_length == 0) - { - - /* When the tag length is zero this tag is used to indicate that any service is acceptable. */ - tag_service_name_valid = NX_TRUE; - break; - } - - /* Compare the service name with PPPoE Service name. */ - while (service_name_index < pppoe_server_ptr -> nx_pppoe_service_name_count) - { - - /* Find the same service name. */ - if (!memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]), tag_length)) - { - - /* Update the information. */ - tag_service_name_valid = NX_TRUE; - client_session_ptr -> nx_pppoe_service_name = pppoe_server_ptr -> nx_pppoe_service_name[service_name_index]; - break; - } - service_name_index ++; - } -#endif - break; - } - case NX_PPPOE_SERVER_TAG_TYPE_AC_NAME: - { - - if (pppoe_server_ptr -> nx_pppoe_ac_name) - { - /* Check the access concentrator name. */ - if (memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_ac_name), tag_length)) - { - - return(NX_PPPOE_SERVER_AC_NAME_ERROR); - } - } - else - { - /* If user does not separately set Access Concentrator name, will use PPPoE server name as Access Concentrator name.*/ - if (memcmp(tag_ptr + tag_index, (pppoe_server_ptr -> nx_pppoe_name), tag_length)) - { - - return(NX_PPPOE_SERVER_AC_NAME_ERROR); - } - } - break; - } - case NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ: - { - - /* Check the cache for Host-Uniq. */ - if (tag_length> NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE) - return (NX_PPPOE_SERVER_HOST_UNIQ_CACHE_ERROR); - - /* Save the Host-Uniq. */ - memcpy(client_session_ptr -> nx_pppoe_host_uniq, tag_ptr + tag_index, tag_length); - - /* Set the Host-Uniq size. */ - client_session_ptr -> nx_pppoe_host_uniq_size = tag_length; - break; - } - case NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID: - { - - /* Check the cache for Relay-Session_Id. */ - if (tag_length> NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE) - return (NX_PPPOE_SERVER_RELAY_SESSION_ID_CACHE_ERROR); - - /* Save the Relay-Session_Id. */ - memcpy(client_session_ptr -> nx_pppoe_relay_session_id, tag_ptr + tag_index, tag_length); - - /* Set the Relay-Session_Id size. */ - client_session_ptr -> nx_pppoe_relay_session_id_size = tag_length; - break; - } - default: - break; - } - - /* Move to the next tag. */ - tag_index += tag_length; - } - - /* Check the code. */ - if ((code == NX_PPPOE_SERVER_CODE_PADI) || (code == NX_PPPOE_SERVER_CODE_PADR)) - { - - /* The PADI and PADR packet MUST contains exactly one TAG of TAG_TYPE Service- Name, RFC2516 */ - if ((tag_service_name_count != 1) || (tag_service_name_valid != NX_TRUE)) - { - - /* Set the service name error flag. */ - client_session_ptr -> nx_pppoe_error_flag |= NX_PPPOE_SERVER_ERROR_SERVICE_NAME; - - /* Service-Name tag error. */ - return(NX_PPPOE_SERVER_SERVICE_NAME_ERROR); - } - } - - /* TAGs processed. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_data_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the datas of PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_packet_receive Receive the PPPoE packet */ -/* _nx_pppoe_server_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* _nx_pppoe_server_session_packet_process */ -/* Process PPPoE Session packet */ -/* _nx_pppoe_server_tag_process Process PPPoE TAGs */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static ULONG _nx_pppoe_server_data_get(UCHAR *data, UINT size) -{ - -ULONG value = 0; - - - /* Process the data retrieval request. */ - while (size-- > 0) - { - - /* Build return value. */ - value = (value << 8) | *data++; - } - - /* Return value. */ - return(value); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_data_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the datas into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to buffer data */ -/* size Size of data value */ -/* value Value to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ -/* _nx_pppoe_server_session_send Send PPPoE Session packet */ -/* _nx_pppoe_server_tag_string_add Add PPPoE string TAG */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_server_data_add(UCHAR *data, UINT size, ULONG value) -{ - - /* Make sure that data is left justified. */ - switch (size) - { - - case 1: - - value <<= 24; - break; - - case 2: - - value <<= 16; - break; - - case 3: - - value <<= 8; - break; - - default: - break; - } - - /* Store the value. */ - while (size-- > 0) - { - - *data = (UCHAR) ((value >> 24) & 0xff); - data++; - value <<= 8; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_string_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the string into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* dest Pointer to destination buffer */ -/* source Pointer to source buffer */ -/* size Number of bytes to add */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_tag_string_add Add PPPoE string TAG */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_pppoe_server_string_add(UCHAR *dest, UCHAR *source, UINT size) -{ - - /* Loop to copy all bytes. */ - while (size-- > 0) - { - - /* Copy a byte. */ - *dest++ = *source++; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_tag_string_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds the TAG with string into PPPoE packet. */ -/* */ -/* INPUT */ -/* */ -/* data_ptr Pointer to data buffer */ -/* tag_type Type of TAG */ -/* tag_length Length of TAG */ -/* tag_value_string String value of TAG to add */ -/* index Location into data buffer */ -/* to write data */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_pppoe_server_data_add Add PPPoE data */ -/* _nx_pppoe_server_string_add Add PPPoE string data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_discovery_send Send PPPoE Discovery packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_server_tag_string_add(UCHAR *data_ptr, UINT tag_type, UINT tag_length, UCHAR *tag_value_string, UINT *index) -{ - - /* Add the tag type. */ - _nx_pppoe_server_data_add(data_ptr + (*index), 2, tag_type); - (*index) += 2; - - /* Add the tag length. */ - _nx_pppoe_server_data_add(data_ptr + (*index), 2, tag_length); - (*index) += 2; - - /* Add the tag value string. */ - _nx_pppoe_server_string_add(data_ptr + (*index), tag_value_string, tag_length); - (*index) += tag_length; - - /* Return a successful completion. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds a PPPoE session by the client hardware mac */ -/* address and session id. In Discovery Stage, match the client harware*/ -/* address, if not match, mark one available session. In Session Stage,*/ -/* match the client harware address and session id, if not match, */ -/* return NX_PPPOE_CLIENT_SESSION_NOT_FOUND. */ -/* */ -/* INPUT */ -/* */ -/* pppoe_server_ptr Pointer to PPPoE control block*/ -/* client_mac_msw Client physical address MSW */ -/* client_mac_lsw Client physical address LSW */ -/* session_id Session ID */ -/* session_index Session Index */ -/* client_session_ptr Pointer to Client Session */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_discovery_packet_process */ -/* Process PPPoE Discovery packet*/ -/* _nx_pppoe_server_session_packet_process */ -/* Process PPPoE Session packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_server_session_find(NX_PPPOE_SERVER *pppoe_server_ptr, ULONG client_mac_msw, ULONG client_mac_lsw, - ULONG session_id, UINT *session_index, NX_PPPOE_CLIENT_SESSION **client_session_ptr) -{ - -UINT i; -UINT available_index; - - - /* Initialize the value. */ - i = 0; - available_index = NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; - - for(i = 0; i < NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER; i ++) - { - - /* Check if this session is valid. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_valid == NX_TRUE) - { - - /* Compare the physical address. */ - if ((pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_physical_address_msw != client_mac_msw) || - (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_physical_address_lsw != client_mac_lsw)) - continue; - - /* If the session id is not zero, means the session has been established. */ - if (session_id != 0) - { - - /* Compare the session id. */ - if (pppoe_server_ptr -> nx_pppoe_client_session[i].nx_pppoe_session_id != session_id) - continue; - } - - /* Yes, find the matched session. */ - *session_index = i; - *client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[i]); - - return(NX_PPPOE_SERVER_SUCCESS); - } - else - { - - /* Set the first available index. */ - if (i < available_index) - available_index = i; - } - } - - /* If the session id is not zero, means the session has been established. */ - if (session_id != 0) - { - return(NX_PPPOE_SERVER_CLIENT_SESSION_NOT_FOUND); - } - - /* Check if there is available room in the table for a new client session. */ - if (available_index >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - { - - /* No, we cannot add this client session into the server's table. */ - return(NX_PPPOE_SERVER_CLIENT_SESSION_FULL); - } - - /* Set the session. */ - pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_physical_address_msw = client_mac_msw; - pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_physical_address_lsw = client_mac_lsw; - - /* Mark this session is valid. */ - pppoe_server_ptr -> nx_pppoe_client_session[available_index].nx_pppoe_valid = NX_TRUE; - - /* Set local pointer to an available slot. */ - *session_index = available_index; - *client_session_ptr = &(pppoe_server_ptr -> nx_pppoe_client_session[available_index]); - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_pppoe_server_session_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function cleans up the PPPoE session. */ -/* */ -/* INPUT */ -/* */ -/* client_session_ptr Pointer to Client Session */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_pppoe_server_session_terminate Terminate the PPPoE session */ -/* _nx_pppoe_server_session_packet_process */ -/* Process PPPoE Session packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_pppoe_server_session_cleanup(NX_PPPOE_CLIENT_SESSION *client_session_ptr) -{ - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -NX_PACKET *next_packet; -NX_PACKET *current_packet; -#endif - - /* Cleanup the client session. */ - client_session_ptr -> nx_pppoe_valid = NX_FALSE; - client_session_ptr -> nx_pppoe_session_id = NX_NULL; - client_session_ptr -> nx_pppoe_physical_address_msw = NX_NULL; - client_session_ptr -> nx_pppoe_physical_address_lsw = NX_NULL; - client_session_ptr -> nx_pppoe_service_name = NX_NULL; - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - /* Loop to release the queued packet. */ - next_packet = client_session_ptr -> nx_pppoe_deferred_received_packet_head; - - /* Release any packets queued up. */ - while (next_packet) - { - - /* Setup the current packet pointer. */ - current_packet = next_packet; - - /* Move to the next packet. */ - next_packet = next_packet -> nx_packet_queue_next; - - /* Release the current packet. */ - nx_packet_release(current_packet); - } - - /* Cleanup the parameters. */ - client_session_ptr -> nx_pppoe_deferred_received_packet_head = NX_NULL; - client_session_ptr -> nx_pppoe_deferred_received_packet_tail = NX_NULL; - client_session_ptr -> nx_pppoe_packet_receive_stopped = NX_FALSE; -#endif - - /* Return success. */ - return(NX_PPPOE_SERVER_SUCCESS); -} - - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppInitInd PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function configures the default Service Namet that the PPPoE */ -/* should use to filter incoming PADI requests. */ -/* */ -/* INPUT */ -/* */ -/* length The number of bytes in aData */ -/* aData Contains PPPoE Service Name */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_pppoe_server_service_name_set Set the service name */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppInitInd(UINT length, UCHAR *aData) -{ - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check the length. */ - if (length == 0) - { - - /* Clean the default service name. */ - nx_pppoe_server_service_name_set(_nx_pppoe_server_created_ptr, NX_NULL, 0); - } - else - { - - /* Transmit the Service. */ - nx_pppoe_service_name[0] = aData; - - /* Set the default service name. */ - nx_pppoe_server_service_name_set(_nx_pppoe_server_created_ptr, nx_pppoe_service_name, 1); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppDiscoverCnf PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function defines the Service Name field of the PADO packet. */ -/* */ -/* INPUT */ -/* */ -/* interfaceHandle The handle of session */ -/* length The number of bytes in aData */ -/* aData Contains PPPoE Service Name */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_server_discovery_send Send PPPoE Discovery */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppDiscoverCnf(UINT length, UCHAR *aData, UINT interfaceHandle) -{ - -NX_PPPOE_CLIENT_SESSION *client_session_ptr; - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check to see if PPPoE is enabled. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) - return; - - /* Check for invalid session index. */ - if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Check to see if PPPoE session is valid. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) - return; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Get the Session pointer. */ - client_session_ptr = &(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle]); - - /* Check if this session is valid. */ - if (client_session_ptr -> nx_pppoe_valid != NX_TRUE) - { - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return; - } - - /* Set the Service Name field. */ - client_session_ptr -> nx_pppoe_service_name = aData; - client_session_ptr -> nx_pppoe_service_name_length = length; - - /* Send PADO packet. */ - _nx_pppoe_server_discovery_send(_nx_pppoe_server_created_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADO); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppOpenCnf PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows PPPoE to accept or reject the PPPoE Session. */ -/* */ -/* INPUT */ -/* */ -/* accept The flag to accept or reject */ -/* interfaceHandle The handle of session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* _nx_pppoe_server_discovery_send Send PPPoE Discovery */ -/* _nx_pppoe_server_session_cleanup Cleanup the PPPoE Session */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppOpenCnf(UCHAR accept, UINT interfaceHandle) -{ - -NX_PPPOE_CLIENT_SESSION *client_session_ptr; - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check to see if PPPoE is enabled. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) - return; - - /* Check for invalid session index. */ - if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Check to see if PPPoE session is valid. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) - return; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Get the Session pointer. */ - client_session_ptr = &(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle]); - - /* Check the accept flag. */ - if (accept == NX_TRUE) - { - - /* Send PADS to accept the PPPoE Session. */ - _nx_pppoe_server_discovery_send(_nx_pppoe_server_created_ptr, client_session_ptr, NX_PPPOE_SERVER_CODE_PADS); - } - else - { - - /* Reject the PPPoE Session. */ - _nx_pppoe_server_session_cleanup(client_session_ptr); - } - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppCloseInd PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows PPPoE to terminate PPPoE Session. */ -/* */ -/* INPUT */ -/* */ -/* interfaceHandle The handle of session */ -/* causeCode The reason for terminating */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_pppoe_server_session_terminate Terminate the PPPoE Session */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppCloseInd(UINT interfaceHandle, UCHAR *causeCode) -{ - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check to see if PPPoE is enabled. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) - return; - - /* Check for invalid session index. */ - if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Check to see if PPPoE session is established. */ - if ((_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_session_id == 0)) - return; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Set the reason for terminating the session. */ - _nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_generic_error = causeCode; - - /* Send PADT to terminate the session. */ - nx_pppoe_server_session_terminate(_nx_pppoe_server_created_ptr, interfaceHandle); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppCloseCnf PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function confirm that the session has been freed. */ -/* */ -/* INPUT */ -/* */ -/* interfaceHandle The handle of session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppCloseCnf(UINT interfaceHandle) -{ - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check for invalid session index. */ - if (interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Cleanup the PPPoE session. */ - _nx_pppoe_server_session_cleanup(&(_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle])); - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppTransmitDataCnf PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allows TTP's software to receive new data frame. */ -/* */ -/* INPUT */ -/* */ -/* interfaceHandle The handle of session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Obtain a protection mutex */ -/* tx_mutex_put Release protection mutex */ -/* tx_event_flags_set Set events for PPPoE thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppTransmitDataCnf(UINT interfaceHandle, UCHAR *data_ptr, UINT packet_id) -{ - -NX_PACKET *packet_ptr; - - /* Check to see if PPPoE instance is created. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check for invalid session index. */ - if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Obtain the IP internal mutex before processing the IP event. */ - tx_mutex_get(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); - - /* Release the packet. */ - if (packet_id) - { - packet_ptr = (NX_PACKET *)(packet_id); - nx_packet_release(packet_ptr); - } - - /* Clean the flag to receive the next packet. */ - _nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_packet_receive_stopped = NX_FALSE; - - /* Check if this session queued the packets. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_deferred_received_packet_head) - { - - /* Wakeup PPPoE helper thread to process the PPPoE Session receive. */ - tx_event_flags_set(&(_nx_pppoe_server_created_ptr -> nx_pppoe_events), NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT, TX_OR); - } - - /* Release the IP internal mutex. */ - tx_mutex_put(&(_nx_pppoe_server_created_ptr -> nx_pppoe_ip_ptr -> nx_ip_protection)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* PppReceiveDataInd PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends data fram over Ethernet. */ -/* */ -/* INPUT */ -/* */ -/* interfaceHandle The handle of session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_pppoe_server_session_send Send PPPoE session data */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID PppReceiveDataInd(UINT interfaceHandle, UINT data_length, UCHAR *data_ptr) -{ - - /* Check for invalid input pointers. */ - if ((_nx_pppoe_server_created_ptr == NX_NULL) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_id != NX_PPPOE_SERVER_ID)) - return; - - /* Check to see if PPPoE is enabled. */ - if (_nx_pppoe_server_created_ptr -> nx_pppoe_enabled != NX_TRUE) - return; - - /* Check for invalid session index. */ - if(interfaceHandle >= NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER) - return; - - /* Check to see if PPPoE session is established. */ - if ((_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_valid != NX_TRUE) || - (_nx_pppoe_server_created_ptr -> nx_pppoe_client_session[interfaceHandle].nx_pppoe_session_id == 0)) - return; - - /* Send data. */ - nx_pppoe_server_session_send(_nx_pppoe_server_created_ptr, interfaceHandle, data_ptr, data_length); -} -#endif -#endif /* NX_DISABLE_IPV4 */ diff --git a/protocol_handlers/pppoe/nx_pppoe_server.h b/protocol_handlers/pppoe/nx_pppoe_server.h deleted file mode 100644 index acc8db97..00000000 --- a/protocol_handlers/pppoe/nx_pppoe_server.h +++ /dev/null @@ -1,376 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** PPP Over Ethernet (PPPoE) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_pppoe_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX PPP Over Ethernet (PPPoE) Server */ -/* componet, including all data types and external references. It is */ -/* assumed that nx_api.h and nx_port.h have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_PPPOE_SERVER_H -#define NX_PPPOE_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Note: Prerequisite for using PPPoE. - Redefine NX_PHYSICAL_HEADER to 24 to ensure enough space for filling in physical header. - Physical header:14(Ethernet header) + 6(PPPoE header) + 2(PPP header) + 2(four-byte aligment). */ - -/* Define the Driver command for PPPoE packet. */ -#ifndef NX_LINK_PPPOE_DISCOVERY_SEND -#define NX_LINK_PPPOE_DISCOVERY_SEND 51 -#endif -#ifndef NX_LINK_PPPOE_SESSION_SEND -#define NX_LINK_PPPOE_SESSION_SEND 52 -#endif - -/* Define the PPPoE Server ID. */ -#define NX_PPPOE_SERVER_ID 0x50505045UL - -/* Enable the feature to control the session established. */ -/* -#define NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -*/ - -/* If the driver is not initialized in other module, enable the feature to initialize the driver in PPPoE module . */ -/* -#define NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE -*/ - -/* Define the PPPoE Thread time slice. */ -#ifndef NX_PPPOE_SERVER_THREAD_TIME_SLICE -#define NX_PPPOE_SERVER_THREAD_TIME_SLICE TX_NO_TIME_SLICE -#endif - -/* Define the number of pppoe clients. */ -#ifndef NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER -#define NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER 10 -#endif - -/* Define the size of pppoe Host-Uniq. */ -#ifndef NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE -#define NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE 32 -#endif - -/* Define the size of pppoe Relay-Session-Id. */ -#ifndef NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE -#define NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE 12 -#endif - -/* Define the minimum size of packet payload to avoid packet chained. Maximum Payload Size of Ethernet(1500) + Ethernet Header + CRC + Four-byte alignment. */ - -#ifndef NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE -#define NX_PPPOE_SERVER_MIN_PACKET_PAYLOAD_SIZE 1520 -#endif - -/* The time out in timer ticks on allocating packets or appending data into packets. */ -#ifndef NX_PPPOE_SERVER_PACKET_TIMEOUT -#define NX_PPPOE_SERVER_PACKET_TIMEOUT (NX_IP_PERIODIC_RATE) /* 1 second */ -#endif - -/* Set the start Session ID for assigning to the PPPoE session. */ -#ifndef NX_PPPOE_SERVER_START_SESSION_ID -#define NX_PPPOE_SERVER_START_SESSION_ID 0x4944 -#endif - -/* Define PPPoE ethernet header size. */ -#define NX_PPPOE_SERVER_ETHER_HEADER_SIZE 14 - -/* Define PPPoE ethernet types. */ -#define NX_PPPOE_SERVER_ETHER_TYPE_DISCOVERY 0x8863 -#define NX_PPPOE_SERVER_ETHER_TYPE_SESSION 0x8864 - -/* Define PPPoE version and type. */ -#define NX_PPPOE_SERVER_VERSION_TYPE 0x11 /* Version 1, Type 1. */ - -/* Define PPPoE codes. */ -#define NX_PPPOE_SERVER_CODE_ZERO 0x00 -#define NX_PPPOE_SERVER_CODE_PADI 0x09 -#define NX_PPPOE_SERVER_CODE_PADO 0x07 -#define NX_PPPOE_SERVER_CODE_PADR 0x19 -#define NX_PPPOE_SERVER_CODE_PADS 0x65 -#define NX_PPPOE_SERVER_CODE_PADT 0xa7 - -/* Define the PPPoE Area Offsets. */ -#define NX_PPPOE_SERVER_OFFSET_VER_TYPE 0 /* 1 byte, version + type: 0x11 */ -#define NX_PPPOE_SERVER_OFFSET_CODE 1 /* 1 byte, code: Discovery or Session */ -#define NX_PPPOE_SERVER_OFFSET_SESSION_ID 2 /* 2 bytes, session id: unique session identifieer */ -#define NX_PPPOE_SERVER_OFFSET_LENGTH 4 /* 2 bytes, length: the length of PPPoE payload */ -#define NX_PPPOE_SERVER_OFFSET_PAYLOAD 6 /* variable, payload */ - -/* Define the PPPoE Tag Types. */ -#define NX_PPPOE_SERVER_TAG_TYPE_END_OF_LIST 0x0000 -#define NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME 0x0101 -#define NX_PPPOE_SERVER_TAG_TYPE_AC_NAME 0x0102 -#define NX_PPPOE_SERVER_TAG_TYPE_HOST_UNIQ 0x0103 -#define NX_PPPOE_SERVER_TAG_TYPE_AC_COOKIE 0x0104 -#define NX_PPPOE_SERVER_TAG_TYPE_VENDOR_SPECIFIC 0x0105 -#define NX_PPPOE_SERVER_TAG_TYPE_RELAY_SESSION_ID 0x0110 -#define NX_PPPOE_SERVER_TAG_TYPE_SERVICE_NAME_ERROR 0x0201 -#define NX_PPPOE_SERVER_TAG_TYPE_AC_SYSTEM_ERROR 0x0202 -#define NX_PPPOE_SERVER_TAG_TYPE_GENERIC_ERROR 0x0203 - -/* Define the PPPoE Error flags. */ -#define NX_PPPOE_SERVER_ERROR_SERVICE_NAME ((ULONG) 0x00000001) /* Service Name Error. */ -#define NX_PPPOE_SERVER_ERROR_AC_SYSTEM ((ULONG) 0x00000002) /* AC-System Error */ -#define NX_PPPOE_SERVER_ERROR_GENERIC ((ULONG) 0x00000004) /* Generic Error */ - -/* Define event flags for PPPoE thread control. */ -#define NX_PPPOE_SERVER_ALL_EVENTS ((ULONG) 0xFFFFFFFF) /* All event flags */ -#define NX_PPPOE_SERVER_PACKET_RECEIVE_EVENT ((ULONG) 0x00000001) /* PPPoE Server receive packet event */ -#define NX_PPPOE_SERVER_SESSION_RECEIVE_EVENT ((ULONG) 0x00000002) /* PPPoE Session receive packet event */ - -/* Define error codes from PPPoE Server operation. */ -#define NX_PPPOE_SERVER_SUCCESS 0x00 /* Success */ -#define NX_PPPOE_SERVER_PTR_ERROR 0xC1 /* Invalid input pointers */ -#define NX_PPPOE_SERVER_INVALID_INTERFACE 0xC2 /* Invalid interface */ -#define NX_PPPOE_SERVER_PACKET_PAYLOAD_ERROR 0xC3 /* Invalid payload size of packet */ -#define NX_PPPOE_SERVER_MEMORY_SIZE_ERROR 0xC4 /* Invalid memory size */ -#define NX_PPPOE_SERVER_PRIORITY_ERROR 0xC5 /* Invalid priority */ -#define NX_PPPOE_SERVER_NOT_ENABLED 0xC6 /* PPPoE is not enabled */ -#define NX_PPPOE_SERVER_INVALID_SESSION 0xC7 /* Invalid Session */ -#define NX_PPPOE_SERVER_SESSION_NOT_ESTABLISHED 0xC8 /* PPPoE Session is not established */ -#define NX_PPPOE_SERVER_SERVICE_NAME_ERROR 0xC9 /* Service name error */ -#define NX_PPPOE_SERVER_AC_NAME_ERROR 0xCA /* AC Name error */ -#define NX_PPPOE_SERVER_CLIENT_SESSION_FULL 0xCB /* Client Session full */ -#define NX_PPPOE_SERVER_CLIENT_SESSION_NOT_FOUND 0xCC /* Not found the client session */ -#define NX_PPPOE_SERVER_HOST_UNIQ_CACHE_ERROR 0xCD /* The cache is not enough to record the Host Uniq */ -#define NX_PPPOE_SERVER_RELAY_SESSION_ID_CACHE_ERROR 0xCF /* The cache is not enough to record Relay Session ID*/ - -/* Define the PPPoE Client Session structure containing the session id and physical address. */ - -typedef struct NX_PPPOE_CLIENT_SESSION_STRUCT -{ - - USHORT nx_pppoe_valid; - USHORT nx_pppoe_session_id; - ULONG nx_pppoe_physical_address_msw; - ULONG nx_pppoe_physical_address_lsw; - UCHAR *nx_pppoe_service_name; -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE - UINT nx_pppoe_service_name_length; - UINT nx_pppoe_packet_receive_stopped; - NX_PACKET *nx_pppoe_deferred_received_packet_head, - *nx_pppoe_deferred_received_packet_tail; - UCHAR *nx_pppoe_generic_error; -#endif - UCHAR nx_pppoe_host_uniq[NX_PPPOE_SERVER_MAX_HOST_UNIQ_SIZE]; - UINT nx_pppoe_host_uniq_size; - UCHAR nx_pppoe_relay_session_id[NX_PPPOE_SERVER_MAX_RELAY_SESSION_ID_SIZE]; - UINT nx_pppoe_relay_session_id_size; - UINT nx_pppoe_error_flag; -} NX_PPPOE_CLIENT_SESSION; - - - -/* Define the main PPPoE Server data structure. */ - -typedef struct NX_PPPOE_SERVER_STRUCT -{ - - ULONG nx_pppoe_id; - UINT nx_pppoe_enabled; - UCHAR *nx_pppoe_name; - UINT nx_pppoe_name_length; - UCHAR *nx_pppoe_ac_name; - UINT nx_pppoe_ac_name_length; - NX_IP *nx_pppoe_ip_ptr; - NX_INTERFACE *nx_pppoe_interface_ptr; - NX_PACKET_POOL *nx_pppoe_packet_pool_ptr; - TX_EVENT_FLAGS_GROUP nx_pppoe_events; - TX_THREAD nx_pppoe_thread; - NX_PACKET *nx_pppoe_deferred_received_packet_head, - *nx_pppoe_deferred_received_packet_tail; - UCHAR **nx_pppoe_service_name; - UINT nx_pppoe_service_name_count; - USHORT nx_pppoe_session_id; - USHORT nx_pppoe_reserved[2]; - NX_PPPOE_CLIENT_SESSION nx_pppoe_client_session[NX_PPPOE_SERVER_MAX_CLIENT_SESSION_NUMBER]; - - /* Define the callback nofiy function. */ - VOID (*nx_pppoe_discover_initiation_notify)(UINT session_index); - VOID (*nx_pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data); - VOID (*nx_pppoe_discover_terminate_notify)(UINT session_index); - VOID (*nx_pppoe_discover_terminate_confirm)(UINT session_index); - VOID (*nx_pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id); - VOID (*nx_pppoe_data_send_notify)(UINT session_index, UCHAR *data); - - /* Define the Link Driver entry point. */ - VOID (*nx_pppoe_link_driver_entry)(struct NX_IP_DRIVER_STRUCT *); - -} NX_PPPOE_SERVER; - - -#ifndef NX_PPPOE_SERVER_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_pppoe_server_create _nx_pppoe_server_create -#define nx_pppoe_server_delete _nx_pppoe_server_delete -#define nx_pppoe_server_enable _nx_pppoe_server_enable -#define nx_pppoe_server_disable _nx_pppoe_server_disable -#define nx_pppoe_server_callback_notify_set _nx_pppoe_server_callback_notify_set -#define nx_pppoe_server_ac_name_set _nx_pppoe_server_ac_name_set -#define nx_pppoe_server_service_name_set _nx_pppoe_server_service_name_set -#define nx_pppoe_server_session_send _nx_pppoe_server_session_send -#define nx_pppoe_server_session_packet_send _nx_pppoe_server_session_packet_send -#define nx_pppoe_server_session_terminate _nx_pppoe_server_session_terminate -#define nx_pppoe_server_session_get _nx_pppoe_server_session_get - -#else - -/* Services with error checking. */ - -#define nx_pppoe_server_create _nxe_pppoe_server_create -#define nx_pppoe_server_delete _nxe_pppoe_server_delete -#define nx_pppoe_server_enable _nxe_pppoe_server_enable -#define nx_pppoe_server_disable _nxe_pppoe_server_disable -#define nx_pppoe_server_callback_notify_set _nxe_pppoe_server_callback_notify_set -#define nx_pppoe_server_ac_name_set _nxe_pppoe_server_ac_name_set -#define nx_pppoe_server_service_name_set _nxe_pppoe_server_service_name_set -#define nx_pppoe_server_session_send _nxe_pppoe_server_session_send -#define nx_pppoe_server_session_packet_send _nxe_pppoe_server_session_packet_send -#define nx_pppoe_server_session_terminate _nxe_pppoe_server_session_terminate -#define nx_pppoe_server_session_get _nxe_pppoe_server_session_get - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, - VOID (* pppoe_discover_initiation_notify)(UINT session_index), - VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), - VOID (* pppoe_discover_terminate_notify)(UINT session_index), - VOID (* pppoe_discover_terminate_confirm)(UINT session_index), - VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), - VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); -UINT nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); -UINT nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); -UINT nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); -UINT nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); -UINT nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); -UINT nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); -VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr); - -#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE -VOID PppInitInd(UINT length, UCHAR *aData); -VOID PppDiscoverCnf(UINT length, UCHAR *aData, UINT interfaceHandle); -VOID PppOpenCnf(UCHAR accept, UINT interfaceHandle); -VOID PppCloseInd(UINT interfaceHandle, UCHAR *causeCode); -VOID PppCloseCnf(UINT interfaceHandle); -VOID PppTransmitDataCnf(UINT interfaceHandle, UCHAR *aData, UINT packet_id); -VOID PppReceiveDataInd(UINT interfaceHandle, UINT length, UCHAR *aData); -#endif - -#else - -UINT _nxe_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT _nx_pppoe_server_create(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *name, NX_IP *ip_ptr, UINT interface_index, - VOID (*pppoe_link_driver)(struct NX_IP_DRIVER_STRUCT *), NX_PACKET_POOL *pool_ptr, - VOID *stack_ptr, ULONG stack_size, UINT priority); -UINT _nxe_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nx_pppoe_server_delete(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nxe_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nx_pppoe_server_enable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nxe_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nx_pppoe_server_disable(NX_PPPOE_SERVER *pppoe_server_ptr); -UINT _nxe_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, - VOID (* pppoe_discover_initiation_notify)(UINT session_index), - VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), - VOID (* pppoe_discover_terminate_notify)(UINT session_index), - VOID (* pppoe_discover_terminate_confirm)(UINT session_index), - VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), - VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); -UINT _nx_pppoe_server_callback_notify_set(NX_PPPOE_SERVER *pppoe_server_ptr, - VOID (* pppoe_discover_initiation_notify)(UINT session_index), - VOID (* pppoe_discover_request_notify)(UINT session_index, ULONG length, UCHAR *data), - VOID (* pppoe_discover_terminate_notify)(UINT session_index), - VOID (* pppoe_discover_terminate_confirm)(UINT session_index), - VOID (* pppoe_data_receive_notify)(UINT session_index, ULONG length, UCHAR *data, UINT packet_id), - VOID (* pppoe_data_send_notify)(UINT session_index, UCHAR *data)); -UINT _nxe_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); -UINT _nx_pppoe_server_ac_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR *ac_name, UINT ac_name_length); -UINT _nxe_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); -UINT _nx_pppoe_server_service_name_set(NX_PPPOE_SERVER *pppoe_server_ptr, UCHAR **service_name, UINT service_name_count); -UINT _nxe_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); -UINT _nx_pppoe_server_session_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, UCHAR *data_ptr, UINT data_length); -UINT _nxe_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); -UINT _nx_pppoe_server_session_packet_send(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, NX_PACKET *packet_ptr); -UINT _nxe_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); -UINT _nx_pppoe_server_session_terminate(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index); -UINT _nxe_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); -UINT _nx_pppoe_server_session_get(NX_PPPOE_SERVER *pppoe_server_ptr, UINT session_index, ULONG *client_mac_msw, ULONG *client_mac_lsw, ULONG *session_id); -VOID _nx_pppoe_server_packet_deferred_receive(NX_PACKET *packet_ptr); - -#endif /* NX_PPPOE_SERVER_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_PPP_SERVER_H */ diff --git a/protocol_handlers/smtp/nxd_smtp_client.c b/protocol_handlers/smtp/nxd_smtp_client.c deleted file mode 100644 index e8c46093..00000000 --- a/protocol_handlers/smtp/nxd_smtp_client.c +++ /dev/null @@ -1,4752 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** */ -/** NetX SMTP Client Component */ -/** */ -/** Simple Mail Transfer Protocol (SMTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_smtp_client.c PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Simple Mail Transfer Protocol (SMTP) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - - -#define NX_SMTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module. */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - - - -#include "ctype.h" -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_ipv4.h" -#include "nxd_smtp_client.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_ipv6.h" -#endif -#include "nx_tcp.h" - -/* Necessary for threadx thread state macros. */ -extern TX_THREAD *_tx_thread_current_ptr; -extern TX_THREAD _tx_timer_thread; -extern volatile ULONG _tx_thread_system_state; - -#define NX_SMTP_BUFFER_SIZE 512 -static CHAR _nx_smtp_buffer[NX_SMTP_BUFFER_SIZE]; - - -/* Define internal SMTP Client functions. */ - -static VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT reverse); -static VOID _nx_smtp_base64_encode(UCHAR *name, UCHAR *base64name, UINT length); -static VOID _nx_smtp_base64_decode(UCHAR *base64name, UCHAR *name); -static UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr); -static UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines); -static UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout); -static UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer_ptr, UINT length); -static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout) ; -static UINT _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr); -static UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code); -static UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT arguement_index, - UINT buffer_length, UCHAR *arguement, UINT arguement_length, - UINT include_crlf); - -static NX_SMTP_CLIENT_STATES protocol_states[] = -{ - {_nx_smtp_cmd_idle , _nx_smtp_rsp_idle}, - {_nx_smtp_cmd_greeting , _nx_smtp_rsp_greeting}, - {_nx_smtp_cmd_ehlo , _nx_smtp_rsp_ehlo}, - {_nx_smtp_cmd_helo , _nx_smtp_rsp_helo}, - {_nx_smtp_cmd_mail , _nx_smtp_rsp_mail}, - {_nx_smtp_cmd_rcpt , _nx_smtp_rsp_rcpt}, - {_nx_smtp_cmd_data , _nx_smtp_rsp_data}, - {_nx_smtp_cmd_message , _nx_smtp_rsp_message}, - {_nx_smtp_cmd_rset , _nx_smtp_rsp_rset}, - {_nx_smtp_cmd_quit , _nx_smtp_rsp_quit}, - {_nx_smtp_cmd_noop , _nx_smtp_rsp_noop}, - {_nx_smtp_cmd_auth , _nx_smtp_rsp_auth}, - {_nx_smtp_cmd_auth_challenge , _nx_smtp_rsp_auth_challenge}, -}; - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_smtp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the client create service. */ -/* */ -/* Note: The string lengths of username,password,from_address and */ -/* client_domain are limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* client_ptr Pointer to SMTP Client instance */ -/* ip_ptr Pointer to IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* username Pointer to username */ -/* password Pointer to password */ -/* from_address Pointer to Client email address */ -/* client_domain Pointer to client domain */ -/* authentication_type SMTP authentication type */ -/* server_address Pointer to server address */ -/* server_port SMTP server TCP port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_SMTP_INVALID_PARAM Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_smtp_client_create Actual SMTP client create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, - CHAR *username, CHAR *password, CHAR *from_address, - CHAR *client_domain, UINT authentication_type, - NXD_ADDRESS *server_address, UINT port) -{ - -UINT status; - - - if ((ip_ptr == NX_NULL) || (client_ptr == NX_NULL) || (client_packet_pool_ptr == NX_NULL) || - (from_address == NX_NULL) || (username == NX_NULL) || (password == NX_NULL) || - (client_domain == NX_NULL) || (server_address == NX_NULL)) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (ip_ptr -> nx_ip_id != NX_IP_ID) - { - - return NX_SMTP_INVALID_PARAM; - } - - - /* Make sure the IP version is set correctly. */ - if((server_address -> nxd_ip_version != NX_IP_VERSION_V4) && - (server_address -> nxd_ip_version != NX_IP_VERSION_V6)) - { - return(NX_IP_ADDRESS_ERROR); - } - - /* Call the actual client create service. */ - status = _nxd_smtp_client_create(client_ptr, ip_ptr, client_packet_pool_ptr, username, password, - from_address, client_domain, authentication_type, - server_address, port); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_smtp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a SMTP client instance for sending mail to an */ -/* SMTP Server over IPv4 or IPv6 networks. It also creates the TCP */ -/* socket for making connections with the SMTP server, sets the */ -/* server IP address and port, and sets the Client username and SMTP */ -/* address (from address) used in all SMTP mail transmissions. */ -/* */ -/* Note: The string lengths of username,password,from_address and */ -/* client_domain are limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SMTP Client instance */ -/* ip_ptr Pointer to IP instance */ -/* packet_pool_ptr Pointer to client packet pool */ -/* username Pointer to username */ -/* password Pointer to password */ -/* from_address Pointer to Client email address */ -/* client_domain Pointer to client domain */ -/* authentication_type SMTP authentication type */ -/* server_address Pointer to server address */ -/* server_port SMTP server TCP port */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* memset Clear area of memory */ -/* memcpy Copy data to area of memory */ -/* nx_tcp_socket_create Create a NetX TCP socket */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, - CHAR *username, CHAR *password, CHAR *from_address, - CHAR *client_domain, UINT authentication_type, - NXD_ADDRESS *server_address, UINT port) -{ - -UINT status = NX_SUCCESS; -UINT str_length; -NX_SMTP_CLIENT_MAIL *mail_ptr; - - - /* Initialize client as not ready for SMTP yet. */ - client_ptr -> nx_smtp_client_init_status = NX_FALSE; - - mail_ptr = &client_ptr -> nx_smtp_client_mail; - - /* Clear the Client and session memory. */ - memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT)); - - /* Configure client with input parameters. */ - status = _nx_utility_string_length_check(username, &str_length, NX_SMTP_CLIENT_MAX_USERNAME); - if (status) - { - return(status); - } - - memcpy(client_ptr -> nx_smtp_username, username, str_length); - - status = _nx_utility_string_length_check(password, &str_length, NX_SMTP_CLIENT_MAX_PASSWORD); - if (status) - { - return(status); - } - - memcpy(client_ptr -> nx_smtp_password, password, str_length); - - status = _nx_utility_string_length_check(client_domain, &str_length, NX_SMTP_CLIENT_MAX_USERNAME); - if (status) - { - return(status); - } - - memcpy(client_ptr -> nx_smtp_client_domain, client_domain, str_length); - - /* Set the mail server IP address and port number. */ - -#ifdef FEATURE_NX_IPV6 - client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version; - client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[0] = server_address -> nxd_ip_address.v6[0] ; - client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[1] = server_address -> nxd_ip_address.v6[1] ; - client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[2] = server_address -> nxd_ip_address.v6[2] ; - client_ptr -> nx_smtp_server_address.nxd_ip_address.v6[3] = server_address -> nxd_ip_address.v6[3] ; -#else - - client_ptr -> nx_smtp_server_address.nxd_ip_version = server_address -> nxd_ip_version; - client_ptr -> nx_smtp_server_address.nxd_ip_address.v4 = server_address -> nxd_ip_address.v4; -#endif - client_ptr -> nx_smtp_server_port = (port & 0xFFFF); - - /* Set up the "from" address. */ - mail_ptr -> nx_smtp_client_mail_from_address = from_address; - - /* Check if authentication type is specified. */ - if ((authentication_type != NX_SMTP_CLIENT_AUTH_PLAIN) && - (authentication_type != NX_SMTP_CLIENT_AUTH_LOGIN) && - (authentication_type != NX_SMTP_CLIENT_AUTH_NONE)) - { - - /* No. Set the default authentication type. */ - authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; - } - - client_ptr -> nx_smtp_client_authentication_type = authentication_type; - - /* Configure client IP options. */ - client_ptr -> nx_smtp_client_ip_ptr = ip_ptr; - client_ptr -> nx_smtp_client_packet_pool_ptr = client_packet_pool_ptr; - - /* Set the Client ID to indicate the SMTP client thread is ready. */ - client_ptr -> nx_smtp_client_id = NX_SMTP_CLIENT_ID; - - /* Create a tcp socket to send/receive SMTP data. */ - status = nx_tcp_socket_create(client_ptr -> nx_smtp_client_ip_ptr, - &client_ptr -> nx_smtp_client_socket, "SMTP Client socket", - NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, - NX_SMTP_CLIENT_TCP_WINDOW_SIZE, - NX_NULL, NX_NULL); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Initialize client as ready for conducting an SMTP session. */ - client_ptr -> nx_smtp_client_init_status = NX_TRUE; - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_smtp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors on the client delete service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_client_delete Actual SMTP client delete service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_smtp_client_delete(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for the validity of input parameter. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_smtp_client_id != NX_SMTP_CLIENT_ID)) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - /* Call the actual client create service. */ - status = _nx_smtp_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created SMTP client and releases */ -/* all client resources (sockets, packet pools). */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SMTP Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_session_delete Delete the SMTP Client session */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_client_delete(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - if ((client_ptr -> nx_smtp_client_socket).nx_tcp_socket_state == NX_TCP_ESTABLISHED) - { - - nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, NX_SMTP_CLIENT_DISCONNECT_TIMEOUT); - - nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); - } - - status = nx_tcp_socket_delete(&(client_ptr -> nx_smtp_client_socket)); - - /* Check status. */ - if (status) - { - return status; - } - - /* Clear client memory. */ - memset(client_ptr, 0, sizeof(NX_SMTP_CLIENT)); - - /* Return success status. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_smtp_mail_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors on the mail send service. */ -/* */ -/* Note: The string lengths of recipient_address and subject are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client instance */ -/* recipient_address Pointer to recipient (To) address */ -/* priority Mail send priority level */ -/* subject Pointer to mail subject text */ -/* mail_body Pointer to mail message text */ -/* mail_body_length Size of mail message text */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_mail_send Actual SMTP mail send service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, - CHAR *subject, CHAR *mail_body, UINT mail_body_length) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if((client_ptr == NX_NULL) || (recipient_address == NX_NULL) || - (mail_body == NX_NULL) || (subject == NX_NULL)) - - { - return NX_PTR_ERROR; - } - - if (mail_body_length == 0) - { - return NX_SMTP_INVALID_PARAM; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_smtp_mail_send(client_ptr, recipient_address, priority, - subject, mail_body, mail_body_length); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_mail_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates and sends an SMTP mail item with the input */ -/* parameters for a previously created SMTP Client. It supports IPv4 */ -/* and IPv6 connections. */ -/* */ -/* Before calling this service, the SMTP application must initialize */ -/* the SMTP Client (nx_smtp_client_init). Thereafter it need not */ -/* reinitialize the SMTP Client to send subsequent mail items. */ -/* */ -/* This service assumes the syntax of the from_address is correct. */ -/* */ -/* Note: The string lengths of recipient_address and subject are */ -/* limited by internal buffer size. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client instance */ -/* recipient_address Pointer to recipient (To) address */ -/* priority Mail send priority level */ -/* subject Pointer to mail subject text */ -/* mail_body Pointer to mail message text */ -/* mail_body_length Size of mail message text */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Success completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear data in memory */ -/* _nx_smtp_client_process Conducts SMTP session for */ -/* transmitting mail message */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, - CHAR *recipient_address, - UINT priority, CHAR *subject, - CHAR *mail_body, UINT mail_body_length) -{ - -UINT status; -NX_SMTP_CLIENT_MAIL *mail_ptr; - - - client_ptr -> nx_smtp_client_mute = NX_FALSE; - - /* Verify Client is properly set up and ready to conduct an SMTP session. */ - if (client_ptr -> nx_smtp_client_init_status != NX_TRUE) - { - return NX_SMTP_CLIENT_NOT_INTIALIZED; - } - - /* Initialize the Client to idle. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - - /* Set local variables for convenience. */ - mail_ptr = &client_ptr -> nx_smtp_client_mail; - - /* Did we get a valid priority type? */ - if ((priority != NX_SMTP_MAIL_PRIORITY_LOW) && - (priority != NX_SMTP_MAIL_PRIORITY_NORMAL) && - (priority != NX_SMTP_MAIL_PRIORITY_HIGH)) - { - - /* No, default priority to normal. */ - mail_ptr -> nx_smtp_client_mail_priority = NX_SMTP_MAIL_PRIORITY_NORMAL; - } - else - { - - /* Yes, apply it to the session priority. */ - mail_ptr -> nx_smtp_client_mail_priority = priority; - } - mail_ptr -> nx_smtp_client_mail_subject = subject; - mail_ptr -> nx_smtp_client_mail_body = mail_body; - mail_ptr -> nx_smtp_client_mail_body_length = mail_body_length; - mail_ptr -> nx_smtp_client_mail_recipient_address = recipient_address; - - /* Mark mail item as unsent */ - client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS; - - /* Set up the recipient. */ - - /* Set up a local pointer to the session for convenience. */ - - /* Set session members to initial values. */ - client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED; - client_ptr -> nx_smtp_client_reply_code_status = 0; - - /* Start this session by setting the state to the first step in SMTP Protocol, greeting. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_GREETING; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_GREETING; - - status = _nx_smtp_client_process(client_ptr); - - /* Return success status. */ - return(status); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_client_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function executes the SMTP client state machine to transmit a */ -/* previously created mail item to an SMTP server. For more details, */ -/* See nx_smtp_mail_send. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SMTP Client instance */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Success completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* nx_tcp_client_socket_bind Bind NetX TCP socket to local port */ -/* nx_tcp_client_socket_unbind Release port from NetX TCP socket */ -/* nx_tcp_client_socket_connect Connect to a TCP server socket */ -/* nx_tcp_client_socket_disconnect Disconnect from TCP server socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_smtp_client_process(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT close_connection = NX_FALSE; - - - /* Initialize completion status to successful outcome. */ - status = NX_SUCCESS; - - /* Run the SMTP protocol state machine till session terminates. */ - while (status == NX_SUCCESS) - { - - /* Check if we are starting a mail transaction. */ - if (client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_GREETING) - { - - /* We are so we need to set up a connection. Bind the socket to client port. */ - status = nx_tcp_client_socket_bind(&client_ptr -> nx_smtp_client_socket, NX_ANY_PORT, 100); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Reset the Client to idle. The caller must resend the email. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - return status; - } - - /* Connect to the SMTP server using our tcp socket. */ - status = nxd_tcp_client_socket_connect(&client_ptr -> nx_smtp_client_socket, - &client_ptr -> nx_smtp_server_address, - client_ptr -> nx_smtp_server_port, - NX_SMTP_CLIENT_CONNECTION_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); - - /* Reset the Client to idle. The caller must resend the email.*/ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - return status; - } - - /* Successful connection set up. Now let the Client task process the GREETING command. */ - } - - /* Is the next command waiting the outcome of the previous reply handler? */ - if ((client_ptr -> nx_smtp_client_cmd_state == NX_SMTP_CLIENT_STATE_AWAITING_REPLY) && - /* Do not advance the state if the client is in mute. */ - (!client_ptr -> nx_smtp_client_mute)) - { - - /* Yes, update the session state to the next command to send. */ - client_ptr -> nx_smtp_client_cmd_state = client_ptr -> nx_smtp_client_rsp_state; - } - - if (!client_ptr -> nx_smtp_client_mute) - { - - /* Execute the next command in the SMTP state machine. */ - status = (*protocol_states[client_ptr -> nx_smtp_client_cmd_state].cmd)(client_ptr); - - /* Check for internal error state in the SMTP state machine. */ - if (status != NX_SUCCESS) - { - - /* This is likely an internal error and we need to break off the connection, reset the Client state - to an idle state. */ - - /* Set the status to close the connection down. */ - close_connection = NX_TRUE; - } - } - - /* Reset server reply to null. */ - client_ptr -> nx_smtp_client_reply_code_status = 0; - - /* Wait for a response unless we are closing the connection, or have - encountered an internal error (packet allocation error for example). */ - if (close_connection == NX_FALSE) - { - - /* Awaiting the server reply to the command just sent. */ - status = (*protocol_states[client_ptr -> nx_smtp_client_rsp_state].rsp)(client_ptr); - - /* Check for internal error state in the SMTP state machine. */ - if (status != NX_SUCCESS) - { - - /* This is an internal error or invalid server reply of some kind. Just shut down the - connection, notify the host application and set the Client to idle. */ - - /* Set the status to close the connection down. */ - close_connection = NX_TRUE; - } - - /* Are we at the end of the Client state (received a reply to our QUIT message to the server)? */ - else if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY) - { - - /* Yes, time to close it down and return to an idle state. */ - close_connection = NX_TRUE; - } - /* else keep the connection open... */ - } - - /* Check again if we need to break down the connection. */ - if (close_connection == NX_TRUE) - { - - UINT timeout = 0; - - /* We do. Depending on the reason for closing the connection, set the timeout. If we experienced - an internal error, e.g. packet allocation error, we probably won't be able to send - a fin or rst packet anyway, so set the timeout to zero and close down the connection. - - RFC 2821 Section 3.9: if client must abort processing due to internal conditions or socket reset, - it should handle as error code 451 from the server which is to abort processing immediately. - */ - if (status != NX_SUCCESS) - { - timeout = NX_NO_WAIT; - } - else - { - timeout = NX_SMTP_CLIENT_DISCONNECT_TIMEOUT; - } - - /* Disconnect client socket from server. */ - nx_tcp_socket_disconnect(&client_ptr -> nx_smtp_client_socket, timeout); - - /* Unbind the port from client socket. */ - nx_tcp_client_socket_unbind(&client_ptr -> nx_smtp_client_socket); - - /* Indicate the Client is idle. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - /* Did the session terminate normally (e.g. no internal errors)? */ - if (status == NX_SUCCESS) - { - - /* Yes, so set the mail transmit status as the completion status. */ - status = client_ptr -> nx_smtp_client_mail_status; - } - - return status; - } - - /* Clear the abort status. */ - close_connection = NX_FALSE; - } - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_greeting PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This is the start of the SMTP Client process for sending an mail */ -/* item. It sets the client state to send a greeting command to the */ -/* server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_greeting(NX_SMTP_CLIENT *client_ptr) -{ - - - /* Set session state to wait on the outcome of the greeting response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return successful session status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_idle PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Execute the idle state of the SMTP Client (do nothing while waiting */ -/* for the next send mail request. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_idle(NX_SMTP_CLIENT *client_ptr) -{ - - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - - /* Return successful session status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_idle PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Execute the idle state of the SMTP Client (waiting for the next */ -/* send mail request). The state machine has a 'response' state for */ -/* every command state, so this is the response handler for the idle */ -/* state. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_idle(NX_SMTP_CLIENT *client_ptr) -{ - - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - /* Return successful session status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_greeting PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This handles the server's response to the client greeting and set */ -/* the next session state and next command to send to the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code */ -/* Extracts the server reply code and */ -/* stores reply text to session buffer */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_greeting(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get the server greeting message. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_GREETING_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return (status); - } - - /* Process based on the reply protocol code from server. */ - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_GREETING_OK) - { - - /* Yes, set session state to next state, EHLO. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_EHLO; - } - else - { - - /* All other codes. */ - - /* Server did not accept the greeting, exit session gracefully. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_GREET_REPLY_ERROR; - - - } - - if (client_ptr -> nx_smtp_server_packet) - { - nx_packet_release(client_ptr -> nx_smtp_server_packet); - } - /* Return successful session state. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_helo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* Create the HELO command text and send to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status. */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Sends data to server. */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_helo(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; -UINT domain_length; - - - memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); - - if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME)) - { - return(NX_SIZE_ERROR); - } - - if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_HELO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) - { - - /* Buffer size too small. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - /* Format the HELO command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_HELO, sizeof(NX_SMTP_COMMAND_HELO) - 1); - index = sizeof(NX_SMTP_COMMAND_HELO) - 1; - - _nx_smtp_buffer[index++] = ' '; - - memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); - index += domain_length; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the HELO command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait next response from server. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_helo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the server reply to the HELO command and set */ -/* the next session state and next command to send to the server. This*/ -/* is the GREETING state where we do not initiate the greeting. */ -/* Instead we wait for the server's 'greeting' message. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* _nx_smtp_parse_response Parse specified argument from buffer */ -/* _nx_smtp_rsp_hello_command Handle HELO/EHLO reply from Server */ -/* nx_packet_release Release NetX receive packet */ -/* memcpy Copy data to specified area of memory */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_helo(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - /* Get the server response to the EHLO command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* This is either no packet received or an invalid server response. */ - - /* Return error status. */ - return status; - } - - /* Update session with specific services offered, if any, by server. */ - _nx_smtp_utility_parse_server_services(client_ptr); - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* if server rejected hello, set the session state to terminate */ - if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) - { - - /* Return successful session status to execute QUIT command. */ - return NX_SUCCESS; - } - - /* Handle the server reply code first. */ - _nx_smtp_rsp_hello_command(client_ptr); - - /* if server rejected hello, set the session state to terminate */ - if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) - { - - /* Return successful session status to execute QUIT command. */ - return NX_SUCCESS; - } - - /* Server accepted the HELO command. Continue the SMTP session. */ - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_ehlo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the EHLO command and sends it to the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_ehlo(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; -UINT domain_length; - - - memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); - - if (_nx_utility_string_length_check(client_ptr -> nx_smtp_client_domain, &domain_length, NX_SMTP_CLIENT_MAX_USERNAME)) - { - return(NX_SIZE_ERROR); - } - - if (NX_SMTP_BUFFER_SIZE < (sizeof(NX_SMTP_COMMAND_EHLO) + domain_length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) - { - - /* Buffer size too small. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - /* Format the EHLO command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_EHLO, sizeof(NX_SMTP_COMMAND_EHLO) - 1); - index = sizeof(NX_SMTP_COMMAND_EHLO) - 1; - - _nx_smtp_buffer[index++] = ' '; - memcpy(&_nx_smtp_buffer[index], client_ptr -> nx_smtp_client_domain, domain_length); - index += domain_length; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the EHLO command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait on the outcome of the EHLO response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_ehlo PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This handles the server reply to the EHLO command and determines the*/ -/* next session state and next command to send to the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_parse_server_services Parser for extracting server */ -/* services and reply code */ -/* _nx_smtp_utility_read_server_code Parse the server replies */ -/* code and text */ -/* _nx_smtp_rsp_hello_command Server HELO/EHLO reply */ -/* handler */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_ehlo(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get the server response to the EHLO command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* This is either no packet received or an invalid server response. */ - - /* Return error status. */ - return status; - } - - /* Update session with specific services offered, if any, by server. */ - _nx_smtp_utility_parse_server_services(client_ptr); - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - if (client_ptr -> nx_smtp_client_mute) - { - /* We expect another response packet from the server... - keep the same state, don't send anything. */ - return NX_SUCCESS; - } - - /* Handle the server reply code first. */ - _nx_smtp_rsp_hello_command(client_ptr); - - /* if server rejected hello, set the session state to terminate */ - if (client_ptr -> nx_smtp_client_rsp_state == NX_SMTP_CLIENT_STATE_QUIT) - { - - /* Return successful session status to execute QUIT command. */ - return NX_SUCCESS; - } - - /* Determine if we go to authenticatio next (otherwise we go to the MAIL state). */ - if (client_ptr -> nx_smtp_client_authentication_type != NX_SMTP_CLIENT_AUTH_NONE) - { - - /* Yes, set session to the AUTH state before going on to MAIL. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH; - } - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_hello_command PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the server response to HELO and EHLO commands */ -/* common to both command states. If server accepts the EHLO/HELO */ -/* command, proceed with the session */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* Session server EHLO reply handler */ -/* _nx_smtp_rsp_ehlo Session server HELO reply handler */ -/* _nx_smtp_rsp_helo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_hello_command(NX_SMTP_CLIENT* client_ptr) -{ - -UINT first_digit_server_reply; - - first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status/ 100; - - /* Process the server reply starting with the first digit. */ - if (first_digit_server_reply == 2) - { - - - /* Did server accept the EHLO/HELO command? */ - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) - { - - /* Set session to the next state (MAIL). */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; - - /* Return successful session status. */ - return NX_SUCCESS; - } - } - - /* If we are here, an error occurred. Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_HELLO_REPLY_ERROR; - - /* Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Return successful session status. */ - return NX_SUCCESS; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_auth PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the text of the SMTP AUTH command text and */ -/* sends it to the SMTP server. If the session is already */ -/* authenticated, this function proceeds to the MAIL state (next stage */ -/* of the SMTP protocol) instead. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_cmd_mail Send MAIL command to server */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* memset Clear area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP session */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_auth(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status = NX_SUCCESS; -UINT index; - - memset(&_nx_smtp_buffer[0], 0, NX_SMTP_BUFFER_SIZE); - - /* Is session already successfully authenticated? */ - if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_SUCCEEDED) - { - - /* Yes, server will reject any authentication command; skip to MAIL state. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_MAIL; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; - - /* Call the session MAIL service. */ - _nx_smtp_cmd_mail(client_ptr); - - /* Return successful session status. */ - return NX_SUCCESS; - } - - /* Mark the session authentication as in progress. */ - client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_IN_PROGRESS; - - /* Set the authentication prompt depending on the Client authentication type. */ - if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN) - { - - memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_LOGIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1); - index = sizeof(NX_SMTP_CLIENT_AUTH_LOGIN_TEXT) - 1; - } - else if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_CRAM_MD5) - { - - memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1); - index = sizeof(NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT) - 1; - } - else - { - - memcpy(&_nx_smtp_buffer[0], NX_SMTP_CLIENT_AUTH_PLAIN_TEXT, sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1); - index = sizeof(NX_SMTP_CLIENT_AUTH_PLAIN_TEXT) - 1; - } - - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the AUTH command to the server. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait on the outcome of the EHLO response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_auth PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the server reply to the AUTH command and set */ -/* determine the next session state and next command to send to the */ -/* server. */ -/* */ -/* During the authentication process, it attempts to find a match for */ -/* the server authentication type and decodes each server */ -/* authentication challenge (e.g. USERNAME, PASSWORD). It then sets the*/ -/* session authentication state depending on server acceptance of its */ -/* replies to its challenges. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parser for server reply */ -/* _nx_smtp_utility_authentication_challenge */ -/* Respond to server */ -/* authentication challenge*/ -/* _nx_smtp_rsp_auth When called by itself,respond */ -/* to server authentication */ -/* challenge */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* nx_packet_release Release NetX receive packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_auth(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT server_reply_first_digit; -UCHAR *carriage_return_linefeed_ptr; -UINT auth_length; - - - /* Initialize authentication flags. */ - carriage_return_linefeed_ptr = (CHAR)0x0; - - /* Get the server response to the AUTH command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* This is an server response or no packet received. */ - - /* Return error status. */ - return(status); - } - - /* Use the first digit to group possible server replies. */ - server_reply_first_digit = client_ptr -> nx_smtp_client_reply_code_status / 100; - - /* Process the reply code from server. */ - if (server_reply_first_digit == 2) - { - - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_AUTHENTICATION_SUCCESSFUL) - { - - /* Advance to the MAIL state. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; - - /* Mark the session as authenticated successfully. */ - client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_AUTHENTICATION_SUCCEEDED; - } - else - { - - /* The server returns a 2xx code. Determine if it is an error code. */ - if ((client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_CANNOT_VERIFY_RECIPIENT) || - (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_ACKNOWLEDGE_QUIT)) - { - - /* It is. Abort. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; - } - else - { - /* It is not the code expected. Discard and keep the SMTP Client in the same state. */ - } - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - return NX_SUCCESS; - } - } - else if (server_reply_first_digit == 3) - { - - /* Check if the server accepted our authentication type. */ - if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_AUTHENTICATION_TYPE_ACCEPTED) - { - - /* It did not. Or we may be out of synch with the SMTP Server, if we get a - 354 message for example. Abort the mail session. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - return NX_SUCCESS; - } - /* Authentication in progress. */ - - } - else - { - - /* Set session to the QUIT state. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - return NX_SUCCESS; - } - - /* Is authentication in progress? */ - if (client_ptr -> nx_smtp_client_authentication_state != NX_SMTP_AUTHENTICATION_SUCCEEDED) - { - - /* Set allowed authentication string length. */ - auth_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; - - /* Find the end (e.g. CRLF) of the server reply. */ - _nx_smtp_find_crlf(client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr, - auth_length, &carriage_return_linefeed_ptr, NX_FALSE); - - /* Check for invalid server reply (e.g. missing CRLF). */ - if (carriage_return_linefeed_ptr== NX_NULL) - { - - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return completion status. */ - return NX_SUCCESS; - } - - /* Yes, process (decode) the server's challenge. */ - status = _nx_smtp_utility_authentication_challenge(client_ptr, client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr, - (UINT)(carriage_return_linefeed_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr)); - - /* Did the session successfully handle server challenge? */ - if (status == NX_SUCCESS) - { - - /* Yes, set session to respond to the next server challenge. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_AUTH_CHALLENGE; - } - /* Did the session have problems parsing the server challenge? */ - else - { - - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_AUTH_REPLY_ERROR; - - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return completion status. */ - return NX_SUCCESS; - } - } - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful status. */ - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_auth_challenge PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a reply to the server authentication challenge*/ -/* It determines which challenge the server sent (e.g Username, */ -/* Password) and encodes the session response using base64 encryption. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* _nx_smtp_base64_encode Base64 encode specified text */ -/* memcpy Copy data to area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP session */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_auth_challenge(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; -UCHAR auth_reply_encoded[NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE + 1]; -UINT length; -UINT password_length; - - /* Initialize the encoded reply to NULL. */ - memset(auth_reply_encoded, 0, sizeof(auth_reply_encoded)); - - /* Verify string length. */ - if (_nx_utility_string_length_check(client_ptr -> nx_smtp_password, &password_length, NX_SMTP_CLIENT_MAX_PASSWORD)) - { - return(NX_SIZE_ERROR); - } - - /* Did the server send us the Username prompt? */ - if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT) - { - if (_nx_utility_string_length_check(client_ptr -> nx_smtp_username, &length, NX_SMTP_CLIENT_MAX_USERNAME)) - { - return(NX_SIZE_ERROR); - } - - - if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN) - { - - UCHAR plain_auth_buffer[NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE]; - - if (NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE < (length + 1 + length + password_length)) - { - - /* Buffer size too small. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - memset(&plain_auth_buffer[0], 0, NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE); - - /* Process the client name as per AUTH PLAIN syntax: authorization-id\0authentication-id\0password. */ - memcpy(&plain_auth_buffer[0], client_ptr -> nx_smtp_username, length); - length++; - memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_username, length); - length += length; - memcpy(&plain_auth_buffer[length], client_ptr -> nx_smtp_password, password_length); - length += password_length; - - /* Now encode the combined client username/password. */ - _nx_smtp_base64_encode(&plain_auth_buffer[0], auth_reply_encoded, length); - - } - else - { - /* Just encode the client username. */ - _nx_smtp_base64_encode((UCHAR *)client_ptr -> nx_smtp_username, auth_reply_encoded, - length); - } - - } - /* Or did the server send us the Password prompt? */ - else if (client_ptr -> nx_smtp_client_authentication_reply == NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT) - { - - /* Encode the client password. */ - _nx_smtp_base64_encode((UCHAR *)client_ptr -> nx_smtp_password, auth_reply_encoded, - password_length); - } - - else - { - - /* Unknown prompt: Send the '*' to terminate the authentication process. */ - memcpy(auth_reply_encoded, NX_SMTP_CANCEL_AUTHENTICATION, sizeof(NX_SMTP_CANCEL_AUTHENTICATION)); - } - - if (_nx_utility_string_length_check((CHAR *)auth_reply_encoded, &length, sizeof(auth_reply_encoded) - 1)) - { - return(NX_SIZE_ERROR); - } - - if (sizeof(_nx_smtp_buffer) < (length + sizeof(NX_SMTP_LINE_TERMINATOR) - 1)) - { - - /* Buffer size too small. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - /* Format the encoded response. */ - memcpy(&_nx_smtp_buffer[0],auth_reply_encoded, length); - index = length; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the response back to the server. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for successful. */ - if (status == NX_SUCCESS) - { - - /* Set session state to wait on the outcome of the AUTH challenge handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - } - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_auth_challenge PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This receives the server's response to the AUTH challenge sent by */ -/* the session previously and actually just calls the same session */ -/* AUTH server reply handler again. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_rsp_auth AUTH server reply handler */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_auth_challenge(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Run the session AUTH server reply handler directly. */ - status = _nx_smtp_rsp_auth(client_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_mail PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the MAIL command and sets the Client state to */ -/* send it to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_mail(NX_SMTP_CLIENT *client_ptr) -{ - -UINT index; -UINT status; -UINT mail_from_length; -NX_SMTP_CLIENT_MAIL *mail_ptr = &client_ptr -> nx_smtp_client_mail; - - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE)) - { - return(NX_SIZE_ERROR); - } - - /* Check if authentication status still left as 'in progress'. */ - if (client_ptr -> nx_smtp_client_authentication_state == NX_SMTP_AUTHENTICATION_IN_PROGRESS) - { - - /* For some reason, authentication did not complete. Reset status here. */ - client_ptr -> nx_smtp_client_authentication_state = NX_SMTP_NOT_AUTHENTICATED; - } - - /* Validate message size. */ - if((sizeof(NX_SMTP_COMMAND_MAIL) + mail_from_length + - sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE) - { - /* Message size exceeds buffer size. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - /* Create the command text. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_MAIL, sizeof(NX_SMTP_COMMAND_MAIL) - 1); - index = sizeof(NX_SMTP_COMMAND_MAIL) - 1; - - _nx_smtp_buffer[index++] = ':'; - _nx_smtp_buffer[index++] = '<'; - memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_from_address, mail_from_length); - index += mail_from_length; - _nx_smtp_buffer[index++] = '>'; - - _nx_smtp_buffer[index++] = ' '; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the session command we constructed above. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status.*/ - return status; - } - - /* Set session state to wait on the outcome of the MAIL response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return successful session status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_mail PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This receives the server's response to the MAIL command; it */ -/* extracts the server reply code and reply text and store both to the */ -/* Client session. It will also set the next SMTP command to send to */ -/* the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_mail(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - /* Get the server response to the MAIL command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* This is an invalid line or corrupted transmission from the server. */ - - /* Return error status. */ - return(status); - } - - /* Did server accept the MAIL command? */ - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) - { - - /* Yes, set the session to the RCPT state. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_RCPT; - } - else - { - - /* Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MAIL_REPLY_ERROR; - } - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful session status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_rcpt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the RCPT command and sets the Client state to */ -/* send it to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_rcpt(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; -UINT recipient_length; -NX_SMTP_CLIENT_MAIL *mail_ptr; - - - mail_ptr = &(client_ptr -> nx_smtp_client_mail); - - if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE)) - { - return(NX_SIZE_ERROR); - } - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - /* Validate message size. */ - if((sizeof(NX_SMTP_COMMAND_RCPT) + recipient_length + - sizeof(NX_SMTP_LINE_TERMINATOR) + 2) > NX_SMTP_BUFFER_SIZE) - { - /* Message size exceeds buffer size. */ - return(NX_SMTP_INTERNAL_ERROR); - } - - /* Create the command text. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RCPT, sizeof(NX_SMTP_COMMAND_RCPT) - 1); - index = sizeof(NX_SMTP_COMMAND_RCPT) - 1; - - _nx_smtp_buffer[index++] = ':'; - _nx_smtp_buffer[index++] = '<'; - memcpy(&_nx_smtp_buffer[index], mail_ptr -> nx_smtp_client_mail_recipient_address, - recipient_length); - index += recipient_length; - _nx_smtp_buffer[index++] = '>'; - _nx_smtp_buffer[index++] = ' '; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the RCPT command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait next response from server. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_rcpt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This service handles the server's response to the RCPT command and */ -/* set the next session state and next command to send to the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_rcpt(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get server response to RCPT command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Did server accept RCPT command? */ - if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE) - { - /* NO, Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_RCPT_REPLY_ERROR; - } - else - { - - /* Ok for server to send the mail message */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_DATA; - } - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the DATA command text, verifies the mail to send */ -/* has a valid recipient and sends it to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send SMTP commend to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_data(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; - - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - /* Format the DATA command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_DATA, sizeof(NX_SMTP_COMMAND_DATA) - 1); - index = sizeof(NX_SMTP_COMMAND_DATA) - 1; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the DATA command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait next response from server. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the server reply to the DATA command and set */ -/* the next SMTP Client command to send to the server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_data(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get the response to DATA command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return (status); - } - - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_SEND_MAIL_INPUT) - { - - /* Yes, set session state to next step. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MESSAGE; - } - else - { - - /* No, any other 3xy code in inappropriate. Quit the session. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_DATA_REPLY_ERROR; - } - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the mail message text handling for message */ -/* text. It attempts to fit as much of each message into each packet */ -/* as possible. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_NOT_ENABLED IPv6 not enabled */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_message(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -ULONG data_left_to_transmit; -ULONG packet_payload; -CHAR *data_to_send; -NX_PACKET_POOL *pool_ptr; -NX_SMTP_CLIENT_MAIL *mail_ptr; - - - /* Set local variable for convenience. */ - mail_ptr = &client_ptr -> nx_smtp_client_mail; - - /* Set session state to wait next response from server. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr; - - /* Compute packet payload after IP and TCP headers are subtracted. */ - if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV4_HEADER); -#else - return NX_NOT_ENABLED; -#endif /* NX_DISABLE_IPV4 */ - } - else - { -#ifdef FEATURE_NX_IPV6 - packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IPV6_HEADER); -#else - return NX_NOT_ENABLED; -#endif - } - - - /* Send the Mail header */ - status = _nx_smtp_utility_send_header_to_server(client_ptr, NX_SMTP_CLIENT_SEND_TIMEOUT); - if(status) - return(status); - - /* Set up local variable of size of mail message. */ - data_left_to_transmit = mail_ptr -> nx_smtp_client_mail_body_length; - - /* Set a local pointer to (rest of) mail message to send. */ - data_to_send = mail_ptr -> nx_smtp_client_mail_body; - - /* Send the next chunk of mail text buffer till nothing is left. */ - while(data_left_to_transmit) - { - - /* Check if remaining mail text will fit in a packet.*/ - if (packet_payload >= data_left_to_transmit) - { - - /* Yes, send it off! This will load the specified data into an packet from the SMTP client packet pool. */ - status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, data_left_to_transmit, - NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - break; - } - - /* No, break up mail message into multiple packets. */ - else - { - - /* Fill up the packet with as much data as it will hold and send it off! */ - status = _nx_smtp_utility_send_to_server(client_ptr, data_to_send, packet_payload, - NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Update pointer to remainder of message to send, update how much is left to send. */ - data_left_to_transmit -= packet_payload; - data_to_send += packet_payload; - } - } - - /* Send end of message (EOM) to server or it will handle subsequent commands as message text. */ - status = _nx_smtp_utility_send_to_server(client_ptr, NX_SMTP_EOM, sizeof(NX_SMTP_EOM) - 1, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Return normal session status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This receives the server's response to sending it mail message data.*/ -/* It extracts the server reply code and reply text and store both to */ -/* the Client session. It then sets the next session state, sets up */ -/* the next command to send to the server. */ -/* */ -/* If the server accepts the mail message, this function determines if */ -/* if there is more session mail to transact, and if so sets the next */ -/* Client mail. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply code */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_message(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get the server reply to receiving session mail message data. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_MESSAGE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error status. */ - return(status); - } - - /* Process server reply code by first digit. */ - if (client_ptr -> nx_smtp_client_reply_code_status == NX_SMTP_CODE_OK_TO_CONTINUE) - { - - /* Message accepted by server. Mark the Client mail as sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SUCCESS; - } - else - { - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_MESSAGE_REPLY_ERROR; - } - - /* We're done with this session */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful session status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_quit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the QUIT command text and and sends the Quit */ -/* command to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_quit(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; - - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - /* Format the QUIT command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_QUIT, sizeof(NX_SMTP_COMMAND_QUIT) - 1); - index = sizeof(NX_SMTP_COMMAND_QUIT) - 1; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR)); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the QUIT command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Set session state to wait on the outcome of the EHLO response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_quit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the server reply to the SMTP QUIT command and */ -/* sets the session state to the session has terminated normally. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_quit(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get server response to QUIT command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error status. */ - if (status != NX_SUCCESS) - { - - /* Return the error status. */ - return(status); - } - - /* Set the session state to normal termination. Normal is when the SMTP Client can - receive SMTP server replies and regardless if mail can be sent, can at least - terminate the session with the Quit command and normal TCP socket disconnect. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY; - - /* We are done with the packet now. */ - nx_packet_release(client_ptr -> nx_smtp_server_packet); - - /* Return successful session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_rset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This functions creates the RSET command for the Client task to send */ -/* it to the SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_rset(NX_SMTP_CLIENT *client_ptr) -{ - -ULONG timeout; -UINT status; -UINT index; - - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - /* Get TCP send timeout. */ - timeout = NX_SMTP_ENVELOPE_TIMEOUT; - - /* Format the RSET command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_RSET, sizeof(NX_SMTP_COMMAND_RSET) - 1); - index = sizeof(NX_SMTP_COMMAND_RSET) - 1; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof( NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the RSET command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, timeout); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait on the outcome of the EHLO response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_rset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the RSET server reply. */ -/* */ -/* Resetting an SMTP session means clearing the Client mail transaction*/ -/* including recipients and mail text. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_rset(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get server response to RSET command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return(status); - } - - /* Did the session receive the 250 OK from the server? */ - if (client_ptr -> nx_smtp_client_reply_code_status != NX_SMTP_CODE_OK_TO_CONTINUE) - { - - /* Yes, set the session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED; - } - else - { - - /* Yes, session accepted the RSET command with the 250 code. - Reset session state back to MAIL. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_MAIL; - - } - - /* Return successful session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_cmd_noop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates the SMTP NOOP command text and sends it to the*/ -/* SMTP server. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr SMTP Session for sending mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_send_to_server Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_cmd_noop(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT index; - - - memset(_nx_smtp_buffer, 0, NX_SMTP_BUFFER_SIZE); - - /* Format the NOOP command. */ - memcpy(&_nx_smtp_buffer[0], NX_SMTP_COMMAND_NOOP, sizeof(NX_SMTP_COMMAND_NOOP) - 1); - index = sizeof(NX_SMTP_COMMAND_NOOP) - 1; - memcpy(&_nx_smtp_buffer[index], NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1); - index += sizeof(NX_SMTP_LINE_TERMINATOR) - 1; - - /* Send the NOOP command. */ - status = _nx_smtp_utility_send_to_server(client_ptr, _nx_smtp_buffer, index, NX_SMTP_CLIENT_SEND_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Set session state to wait on the outcome of the EHLO response handler. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_AWAITING_REPLY; - - /* Return normal session status. */ - return NX_SUCCESS; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_rsp_noop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles the NOOP server reply. It will not */ -/* automatically advance the session state like most other SMTP client */ -/* commands. However, an indication of server problems will set the */ -/* session state to QUIT. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr TCP connection to send mail */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_utility_read_server_code Parse the server reply */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_client_process Runs the SMTP state machine */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_rsp_noop(NX_SMTP_CLIENT *client_ptr) -{ - -UINT status; -UINT first_digit_server_reply; - - - /* Get the response for NOOP command. */ - status = _nx_smtp_utility_read_server_code(client_ptr, NX_SMTP_ENVELOPE_TIMEOUT, NX_TRUE); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error status. */ - return(status); - } - - /* Get category of server reply from the first digit. */ - first_digit_server_reply = client_ptr -> nx_smtp_client_reply_code_status / 100; - - /* Is the server experiencing problems forcing the session to abort? */ - if (first_digit_server_reply == 4) - { - - /* Yes, set the session state to quit. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_CODE_RECEIVED; - } - - /* Return successful session status. */ - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_utility_read_server_code PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the 3 digit SMTP server code and stores the */ -/* text of the server reply if there is any to the session buffer. */ -/* Its use is intended primarily for session server reply handlers. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* timeout Timeout on receiving server reply */ -/* receive_all_lines Indicates if SMTP Client should expect*/ -/* one packet or multiple packets e.g. */ -/* a multi packet server reply. */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_parse_response Parse an argument from text */ -/* nx_tcp_socket_receive Receive data over TCP socket */ -/* nx_packet_release Release packet to packet pool */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Session server reply handlers Handle server replies to SMTP */ -/* commands in the session */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_utility_read_server_code(NX_SMTP_CLIENT *client_ptr, ULONG timeout, UINT receive_all_lines) -{ - -UINT status; -NX_PACKET *packet_ptr; -UCHAR server_code[NX_SMTP_SERVER_REPLY_CODE_SIZE + 1]; -UCHAR *work_ptr; -UINT buffer_length; - - NX_PARAMETER_NOT_USED(receive_all_lines); - - /* Initialize argument to NULL. */ - memset(server_code, 0, NX_SMTP_SERVER_REPLY_CODE_SIZE + 1); - - /* Process all packets received as part of server reply. A server response may - have several 'lines' in it e.g. 250-EHLO\r\n250-AUTH LOGIN\r\n250 HELP, - and this may be spread over multiple packets. */ - - /* Wait to receive the next packet. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_smtp_client_socket), &packet_ptr, timeout); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - /* Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Return error status. */ - return status; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(packet_ptr); - - /* Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; - - /* While there was an error with the packet, the SMTP Client is ok. So just return - completion status and we quit the session. */ - return NX_SUCCESS; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Save the location of the server response buffer. */ - client_ptr -> nx_smtp_server_packet = packet_ptr; - - work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr; - buffer_length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; - - /* Yes, parse the server code. Note that with SMTP protocol, the server reply - may be multiple lines/packets. To determine if we have the end of the reply - we look for the command code followed by a space (not a hyphen). */ - status = _nx_smtp_parse_response(client_ptr, work_ptr, 1, buffer_length, &server_code[0], - NX_SMTP_SERVER_REPLY_CODE_SIZE, NX_FALSE); - - /* Was a server reply code found in the first line? */ - if (status != NX_SUCCESS) - { - - /* No, it wasn't. */ - nx_packet_release(packet_ptr); - - /* Set session state to QUIT. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_QUIT; - - /* Indicate mail cannot be sent. */ - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_SERVER_ERROR_REPLY; - - /* While there was an error with the packet, the SMTP Client is ok. So just return - completion status and we quit the session. */ - return NX_SUCCESS; - } - - /* Convert server code from text to unsigned int and store to session. */ - client_ptr -> nx_smtp_client_reply_code_status = strtoul((const char *)server_code, NULL, 10); - - /* Return completion status. */ - return (NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_utility_send_to_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compiles the message/command to send the SMTP server. */ -/* It returns a non success status if packet allocation fails or an */ -/* error results from creating the SMTP command packet. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* buffer_ptr Pointer to buffer for to send */ -/* buffer_length Size of buffer */ -/* timeout Timeout for sending data out */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from specified pool */ -/* nx_packet_data_append Appends buffer to packet data */ -/* nx_packet_release Releases send packet back to pool */ -/* nx_tcp_socket_send Sends packet out over TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_session_run Runs the SMTP state machine */ -/* Session server reply handlers Handle server reply so SMTP command */ -/* Session SMTP command services Send SMTP commands to server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_utility_send_to_server(NX_SMTP_CLIENT *client_ptr, CHAR *buffer_ptr, UINT buffer_length, ULONG timeout) -{ - -UINT status; -NX_PACKET *packet_ptr; -UINT packet_type; - - - if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_smtp_client_packet_pool_ptr, - &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_PACKET_ALLOCATE_ERROR; - - /* Return error status. */ - return(status); - } - - /* Add message to packet data. */ - status = nx_packet_data_append(packet_ptr, buffer_ptr, buffer_length, - client_ptr -> nx_smtp_client_packet_pool_ptr, - NX_SMTP_CLIENT_PACKET_TIMEOUT); - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Abort further processing. This error is most likely a packet allocate. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR; - - /* Return error status. */ - return(status); - } - - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Abort further processing. If we are unable to send, we won't be able to send a quit message either. */ - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - - /* Return error status. */ - return(status); - } - - /* Return successful session status. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_utility_send_to_server PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compiles the message/command to send the SMTP server. */ -/* It returns a non success status if packet allocation fails or an */ -/* error results from creating the SMTP command packet. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* buffer_ptr Pointer to buffer for to send */ -/* buffer_length Size of buffer */ -/* timeout Timeout for sending data out */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from specified pool */ -/* nx_packet_data_append Appends buffer to packet data */ -/* nx_packet_release Releases send packet back to pool */ -/* nx_tcp_socket_send Sends packet out over TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_session_run Runs the SMTP state machine */ -/* Session server reply handlers Handle server reply so SMTP command */ -/* Session SMTP command services Send SMTP commands to server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_utility_send_header_to_server(NX_SMTP_CLIENT *client_ptr, ULONG timeout) -{ - -UINT status; -NX_PACKET *packet_ptr = NX_NULL; -UINT packet_type; -NX_SMTP_CLIENT_MAIL *mail_ptr; -NX_PACKET_POOL *pool_ptr; -UINT recipient_length; -UINT mail_from_length; -UINT subject_length; - - - mail_ptr = &client_ptr -> nx_smtp_client_mail; - - if (client_ptr -> nx_smtp_server_address.nxd_ip_version == NX_IP_VERSION_V6) - packet_type = NX_IPv6_TCP_PACKET; - else - packet_type = NX_IPv4_TCP_PACKET; - - /* Verify string length. */ - if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_recipient_address, &recipient_length, NX_SMTP_BUFFER_SIZE)) - { - return(NX_SIZE_ERROR); - } - - if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_from_address, &mail_from_length, NX_SMTP_BUFFER_SIZE)) - { - return(NX_SIZE_ERROR); - } - - if (_nx_utility_string_length_check(mail_ptr -> nx_smtp_client_mail_subject, &subject_length, NX_SMTP_BUFFER_SIZE)) - { - return(NX_SIZE_ERROR); - } - - - pool_ptr = client_ptr -> nx_smtp_client_packet_pool_ptr; - - /* Allocate a packet. */ - status = nx_packet_allocate(pool_ptr, &packet_ptr, packet_type, NX_SMTP_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status == NX_SUCCESS) - { - if (/* Add "To: CRLF" */ - (nx_packet_data_append(packet_ptr, NX_SMTP_TO_STRING, sizeof(NX_SMTP_TO_STRING) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_recipient_address, - recipient_length, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - /* Add "From: CRLF" */ - (nx_packet_data_append(packet_ptr, NX_SMTP_FROM_STRING, sizeof(NX_SMTP_FROM_STRING) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_from_address, - mail_from_length, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - /* Add "Subject: Subject_line CRLF" */ - (nx_packet_data_append(packet_ptr, NX_SMTP_SUBJECT_STRING, sizeof(NX_SMTP_SUBJECT_STRING) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, mail_ptr -> nx_smtp_client_mail_subject, - subject_length, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - (nx_packet_data_append(packet_ptr, NX_SMTP_LINE_TERMINATOR, sizeof(NX_SMTP_LINE_TERMINATOR) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS) && - /* Add the rest of the mail header components. */ - (nx_packet_data_append(packet_ptr, NX_SMTP_MAIL_HEADER_COMPONENTS, sizeof(NX_SMTP_MAIL_HEADER_COMPONENTS) - 1, - pool_ptr, NX_SMTP_CLIENT_PACKET_TIMEOUT) == NX_SUCCESS)) - { - /* Send the packet out. */ - status = nx_tcp_socket_send(&client_ptr -> nx_smtp_client_socket, packet_ptr, timeout); - - if(status) - { - /* Send failed. */ - status = NX_SMTP_INTERNAL_ERROR; - } - } - else - { - /* One of the Mail header components failed to be appended. */ - status = NX_SMTP_INTERNAL_ERROR; - } - } - - if(status) - { - - /* Abort the session. If we cannot allocate a packet we cannot send a QUIT message. */ - client_ptr -> nx_smtp_client_cmd_state = NX_SMTP_CLIENT_STATE_IDLE; - client_ptr -> nx_smtp_client_rsp_state = NX_SMTP_CLIENT_STATE_IDLE; - - client_ptr -> nx_smtp_client_mail_status = NX_SMTP_INTERNAL_ERROR; - - if(packet_ptr) - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - } - - - /* Return successful session status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_utility_authentication_challenge PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles parsing and decoding the server challenge, */ -/* and setting up the client response to the challenge. It does not */ -/* alter the session state or determine the next session command. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* server_challenge Buffer containing server challenge */ -/* length Size of server challenge buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SMTP_PARAM_ERROR Server parsing (parameter) error */ -/* */ -/* CALLS */ -/* */ -/* _nx_smtp_parse_response Parses argument from buffer text */ -/* _nx_smtp_base64_decode Decodes base64 text */ -/* memset Clears specified area of memory */ -/* memcmp Compares data between areas of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_rsp_auth AUTH server reply handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_utility_authentication_challenge(NX_SMTP_CLIENT *client_ptr, UCHAR *server_challenge, UINT length) -{ - -UCHAR encrypted_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1]; -UCHAR decoded_server_prompt[NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1]; - - if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN) - { - /* Set the session to reply to a username challenge. */ - client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT; - - /* Return successful session status. */ - return NX_SUCCESS; - } - - /* Clear buffers for storing encrypted and decoded server challenges. */ - memset(encrypted_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1); - memset(decoded_server_prompt, 0, NX_SMTP_SERVER_CHALLENGE_MAX_STRING + 1); - - /* Parse the 2nd argument for the server challenge we need to decode. */ - _nx_smtp_parse_response(client_ptr, &server_challenge[0], 2, length, &encrypted_server_prompt[0], - NX_SMTP_SERVER_CHALLENGE_MAX_STRING, NX_FALSE); - - /* Was a valid argument parsed? */ - if (*encrypted_server_prompt == NX_NULL) - { - - /* No , unable to parse server prompt. */ - - /* Return error status. */ - return NX_SMTP_INVALID_SERVER_REPLY; - } - - /* Decode the parsed server challenge. */ - _nx_smtp_base64_decode(encrypted_server_prompt, decoded_server_prompt); - - /* Is this a username prompt? */ - if (((decoded_server_prompt[0] == 'U') || (decoded_server_prompt[0] == 'u')) && - ((decoded_server_prompt[1] == 'S') || (decoded_server_prompt[1] == 's')) && - ((decoded_server_prompt[2] == 'E') || (decoded_server_prompt[2] == 'e')) && - ((decoded_server_prompt[3] == 'R') || (decoded_server_prompt[3] == 'r')) && - ((decoded_server_prompt[4] == 'N') || (decoded_server_prompt[4] == 'n')) && - ((decoded_server_prompt[5] == 'A') || (decoded_server_prompt[5] == 'a')) && - ((decoded_server_prompt[6] == 'M') || (decoded_server_prompt[6] == 'm')) && - ((decoded_server_prompt[7] == 'E') || (decoded_server_prompt[7] == 'e')) && - (decoded_server_prompt[8] == ':')) - { - - /* Yes, set the session to reply to a username challenge. */ - client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT; - } - /* Is this a password prompt? */ - else if (((decoded_server_prompt[0] == 'P') || (decoded_server_prompt[0] == 'p')) && - ((decoded_server_prompt[1] == 'A') || (decoded_server_prompt[1] == 'a')) && - ((decoded_server_prompt[2] == 'S') || (decoded_server_prompt[2] == 's')) && - ((decoded_server_prompt[3] == 'S') || (decoded_server_prompt[3] == 's')) && - ((decoded_server_prompt[4] == 'W') || (decoded_server_prompt[4] == 'w')) && - ((decoded_server_prompt[5] == 'O') || (decoded_server_prompt[5] == 'o')) && - ((decoded_server_prompt[6] == 'R') || (decoded_server_prompt[6] == 'r')) && - ((decoded_server_prompt[7] == 'D') || (decoded_server_prompt[7] == 'd')) && - (decoded_server_prompt[8] == ':')) - { - - /* Yes, set the session to reply to a password challenge. */ - client_ptr -> nx_smtp_client_authentication_reply = NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT; - } - else - { - - /* Indicate invalid authentication from server. */ - return NX_SMTP_CLIENT_REPLY_TO_UNKNOWN_PROMPT; - } - - /* Return successful session status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_utility_parse_server_services PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for the AUTH option in the server response. If */ -/* authentication is offered, it attempts to find a match between */ -/* authentication options offered by the server and the client */ -/* authentication type. If no match between client and server is found,*/ -/* or no authentication is listed in the server response, it sets the */ -/* client authentication type to PLAIN. */ -/* */ -/* INPUT */ -/* */ -/* session_ptr Session to send mail to SMTP Server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* strstr Search for a string within a string */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_rsp_ehlo EHLO server reply handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_utility_parse_server_services(NX_SMTP_CLIENT *client_ptr) -{ - -UINT plain_option = NX_FALSE; -UINT login_option = NX_FALSE; -UCHAR *work_ptr; -UCHAR *temp_ptr; -ULONG length, new_length; -UINT i; -UINT found = NX_FALSE; - - - /* Does the server list an authentication type, and does the client want authentication? */ - - /* Set local variable for convenience. */ - length = client_ptr -> nx_smtp_server_packet -> nx_packet_length; - - /* Find the location of the AUTH command. */ - work_ptr = client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr; - - for (i = 0; i < length - 4; i++) - { - if ( - ((*work_ptr == 'A') || (*work_ptr == 'a')) && - ((*(work_ptr + 1) == 'U') || (*(work_ptr + 1) == 'u')) && - ((*(work_ptr + 2) == 'T') || (*(work_ptr + 2) == 't')) && - ((*(work_ptr + 3) == 'H') || (*(work_ptr + 3) == 'h')) - ) - { - - found = NX_TRUE; - work_ptr += 4; - break; - } - - work_ptr++; - } - - /* Check if this packet has the AUTH keyword. */ - if (!found ) - { - - /* It does not. So leave the Client authentication type as is. */ - return NX_SUCCESS; - } - - /* Check if the client prefers no authentication. */ - if (found && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_NONE)) - { - - /* There is an AUTH keyword but the client prefers not to authenticate. */ - return NX_SUCCESS; - } - - /* Save the location where the search stopped. */ - temp_ptr = work_ptr; - - found = NX_FALSE; - new_length = (length - 5) - (ULONG)(temp_ptr - client_ptr -> nx_smtp_server_packet -> nx_packet_prepend_ptr); - - /* Search for supported authentication types. */ - for (i = 0; i < new_length; i++) - { - if ( - ((*work_ptr == 'L') || (*work_ptr == 'l')) && - ((*(work_ptr + 1) == 'O') || (*(work_ptr + 1) == 'o')) && - ((*(work_ptr + 2) == 'G') || (*(work_ptr + 2) == 'g')) && - ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) && - ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n')) - ) - { - found = NX_TRUE; - break; - } - - work_ptr++; - } - - /* Is there a LOGIN option offered? */ - if (found) - { - /* Yes, set the login option flag. */ - login_option = NX_TRUE; - } - - found = NX_FALSE; - - /* Restore the location for a new search. */ - work_ptr = temp_ptr; - - for (i = 0; i < new_length; i++) - { - if ( - ((*work_ptr == 'P') || (*work_ptr == 'p')) && - ((*(work_ptr + 1) == 'L') || (*(work_ptr + 1) == 'l')) && - ((*(work_ptr + 2) == 'A') || (*(work_ptr + 2) == 'a')) && - ((*(work_ptr + 3) == 'I') || (*(work_ptr + 3) == 'i')) && - ((*(work_ptr + 4) == 'N') || (*(work_ptr + 4) == 'n')) - ) - { - found = NX_TRUE; - break; - } - - work_ptr++; - } - - /* Is there a PLAIN option offered? */ - if (found) - { - /* Yes, set the plain option flag. */ - plain_option = NX_TRUE; - } - - /* Compare Server list of authentication types to client preferred authentication type. */ - - /* Handle the case of the client prefers LOGIN authentication. */ - if (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_LOGIN) - { - - /* Yes; Check if server supports offers LOGIN authentication. */ - if (login_option) - { - - return NX_SUCCESS; - } - else - { - /* Switch client to plain authentication. */ - client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; - - return NX_SUCCESS; - } - } - - /* Check if server listed PLAIN authentication. */ - if (plain_option && (client_ptr -> nx_smtp_client_authentication_type == NX_SMTP_CLIENT_AUTH_PLAIN)) - { - /* Yes, and there's a match, we're done here. */ - return NX_SUCCESS; - } - - /* If we are here, the server offers LOGIN authentication but the Client preference is something else. */ - if (login_option) - { - - /* Switch client to LOGIN authentication. */ - client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_LOGIN; - - return NX_SUCCESS; - } - - /* Handle the case of no matches between server/client. Assume the server requires authentication - and set Client type to plain. */ - client_ptr -> nx_smtp_client_authentication_type = NX_SMTP_CLIENT_AUTH_PLAIN; - - /* Return successful completion of checking options. */ - return NX_SUCCESS; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_parse_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses the argument specified by the argument index */ -/* from the supplied buffer. The first argument is at index 1. */ -/* If the specified argument can't be found the argument pointer at NULL.*/ -/* */ -/* Carriage return/line feeds can be treated as word word separator if */ -/* specified by the crlf_are_word_breaks parameter. For OK TO CONTINUE */ -/* messages (250), this function searches the whole message for the last */ -/* occurance of the server code e.g. code followed by a space. */ -/* */ -/* Carriage return/line feeds are removed if found on the end of the */ -/* parsed argument. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client instance */ -/* buffer Pointer to buffer to parse */ -/* argument_index Identify which argument to parse */ -/* buffer_length Size of buffer to parse */ -/* argument Argument to parse from buffer */ -/* argument_length Size of argument buffer */ -/* crlf_are_word_breaks Treat \r\n's as word breaks */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successfully parsed reply code or */ -/* authentication challenge */ -/* NX_SMTP_INVALID_PARAM Invalid input */ -/* */ -/* CALLS */ -/* */ -/* toupper Convert chars to upper case */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_parse_response(NX_SMTP_CLIENT *client_ptr, UCHAR *buffer, UINT argument_index, - UINT buffer_length, UCHAR *argument, - UINT argument_length, UINT crlf_are_word_breaks) -{ - - -UINT i = 0; -UINT j = 0; -UINT argument_char_count = 0; -UCHAR *work_ptr; -UINT is_last_code; - - - memset(&argument[0], 0, argument_length); - work_ptr = argument; - - /* Check for invalid input parameters. */ - if ((buffer == NX_NULL) || (argument == NX_NULL) || (buffer_length == 0) || - (argument_length == 0) || (argument_index == 0)) - { - - return NX_SMTP_INVALID_PARAM; - } - - /* Is this the first word? - The first word is the reply code, not an SMTP command parameter */ - if (argument_index == 1) - { - - /* Yes, search each character up to the end of the buffer for - the first separator. */ - while (i < buffer_length) - { - - /* Have we reached a word break? */ - if ( - (argument[0] != 0) && - ((*buffer == ' ') || (*buffer == '-')) - ) - { - /* Yes, this marks the end of the first argument (word). */ - break; - } - - /* Are we starting a number? */ - else if ((*buffer >= 0x30) && (*buffer <= 0x39)) - { - - /* Yes, copy to buffer. */ - *work_ptr = *buffer; - work_ptr++; - } - else - { - /* Not a number. make sure the argument buffer is reset */ - memset(&argument[0], 0, argument_length); - work_ptr = argument; - } - - /* Get the next character in the buffer. */ - buffer++; - i++; - } - - /* Are we at the end of the buffer? */ - if (i == buffer_length) - { - - /* Yes, is there a line terminator? */ - if (*(argument - 2) == 0x0D && *(argument - 1) == 0x0A) - { - - /* Yes, remove it with a null character */ - *(argument - 2) = (CHAR) 0x0; - } - } - } - else - { - /* No, we're not parsing the first argument. This is a special case for parsing - the server authentication challenge, not just the reply code. */ - - /* Mark the start of the argument at the separator after - the end of the previous argument. */ - while ((j < argument_index) && (i < buffer_length)) - { - - /* Keep track of the number of separators in the buffer */ - /* OD0A marks the end of a line usually in SMTP */ - - /* Did we hit a line terminator? */ - if ((*buffer == 0x0D) && (*(buffer + 1) == 0x0A)) - { - - /* Yes, Update the count of separators. */ - j++; - - /* Are line terminators as word breaks? */ - if (crlf_are_word_breaks == NX_FALSE) - { - - /* No, this is the end of the search buffer. - Argument not parsed from buffer, return error. */ - return NX_SMTP_INVALID_SERVER_REPLY; - } - - /* Get the next character after '\n' byte in the buffer. */ - i++; - buffer++; - } - /* Did we hit a space or a dash in the first argument? */ - else if ((*buffer == ' ') || ((*buffer == '-') && (j == 0))) - { - - /* Yes; these are counted as separators (note that dashes found in arguments - after the first argument are NOT considered separators. */ - j++; - } - else - { - - /* No, is this the argument to parse? */ - if (j == (argument_index - 1)) - { - /* Yes; did we go past the argument size limit before the next word break? */ - if (argument_char_count >= argument_length) - { - - /* Yes, unable to finish parsing this buffer. Return error. */ - return NX_SMTP_INVALID_SERVER_REPLY; - } - - /* No, copy the next character into the argument. */ - argument_char_count++; - - /* Convert to uppercase if the caller requests. */ - *argument++ = *buffer; - } - } - - /* Get the next character in the buffer. */ - buffer++; - i++; - } - } - - /* Determine if this is the last 250 in the message (e.g. followed by a space, not hyphen) */ - work_ptr = buffer - 3; - - if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == '-')) - { - - UINT status; - - /* Parse the rest of the buffer to see if this packet contains the last 250 code. */ - status = _nx_smtp_parse_250_response(buffer, buffer_length - i, &is_last_code); - if (status) - { - /* Error with parsing response. */ - return status; - } - - /* Did we parse the whole 250 response? */ - if (is_last_code != NX_TRUE) - { - /* NO, so we are waiting for another 250 packet. */ - client_ptr -> nx_smtp_client_mute = NX_TRUE; - } - else - { - - /* YES, so we are NOT waiting for a packet with the last 250 code. */ - client_ptr -> nx_smtp_client_mute = NX_FALSE; - } - } - else if ((*work_ptr == '2') && (*(work_ptr + 1) == '5') && (*(work_ptr + 2) == '0') && (*(work_ptr + 3) == ' ')) - { - client_ptr -> nx_smtp_client_mute = NX_FALSE; - } - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_parse_250_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called to search the rest of the message for the last*/ -/* instance of the server code 250. The first 250 has been found but */ -/* followed by a hyphen, indicating more 250's in the message. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to buffer to parse */ -/* buffer_length Size of buffer to parse */ -/* is_last_code Indicate if last 250 found */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successfully parsed last code */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_parse_response Parse (any) code in server message */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_smtp_parse_250_response(UCHAR *buffer_ptr, UINT buffer_length, UINT *is_last_code) -{ - - *is_last_code = NX_FALSE; - - /* Are there more 250 codes in this buffer? Advance the buffer - pointer and search for a 250 followed by a space. */ - - while (buffer_length > 3) - { - /* Find next 250[sp] in the buffer */ - if ((*buffer_ptr == '2') && - (*(buffer_ptr + 1) == '5') && - (*(buffer_ptr + 2) == '0') && - (*(buffer_ptr + 3) == ' ')) - { - *is_last_code = NX_TRUE; - break; - } - else - { - buffer_ptr++; - buffer_length--; - } - } - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_find_crlf PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns a pointer to the first carriage return/line */ -/* feed (CRLF) sequence found in the buffer. If no CRLF is found within */ -/* length specified, the CRLF pointer is left at NULL. If specified the */ -/* search can start at the end of the buffer and work backwards to the */ -/* first CRLF found. */ -/* */ -/* INPUT */ -/* */ -/* buffer Pointer to buffer to search */ -/* length Size of buffer to search */ -/* CRLF Pointer to CRLF found in buffer */ -/* in_reverse Search buffer in reverse direction */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_smtp_find_crlf(UCHAR *buffer, UINT length, UCHAR **CRLF, UINT in_reverse) -{ - -UINT i = 0; - - *CRLF = NULL; - - if ((buffer == NX_NULL) || (length == 0)) - { - return; - } - - - /* Search for CRLF from end to start of buffer (reverse) */ - if (in_reverse == NX_TRUE) - { - - /* Move pointer out to the end of the buffer. */ - buffer += length - 1; - - while (i < length - 1) - { - if (*(buffer - 1) == 0x0D && *buffer == 0x0A) - { - /* Set the location of CRLF sequence. */ - *CRLF = buffer - 1; - break; - } - - /* Move the pointer back one. */ - buffer--; - - /* Keep track how many bytes we've gone. */ - i++; - } - } - /* Search for CRLF starting at the beginning of the buffer */ - else - { - while( i < length - 1) - { - if (*buffer == 0x0D && *(buffer + 1) == 0x0A) - { - /* Set the location of CRLF sequence. */ - *CRLF = buffer; - - break; - } - i++; - buffer++; - } - } - - return ; -} - - -CHAR _nx_smtp_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_base64_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the input string into a base64 */ -/* representation. It is the caller's responsibility to match the */ -/* name and base64name buffers in size to avoid overwriting memory. */ -/* */ -/* INPUT */ -/* */ -/* name Pointer to name to encode */ -/* base64name Pointer to name base64 encoded */ -/* length Size of input buffer to encode */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_smtp_base64_encode(UCHAR *name, UCHAR *base64name, UINT length) -{ - -UINT pad; -UINT i, j; -UINT step; - - - /* Adjust the length to represent the base64 name. */ - length = ((length * 8) / 6); - - /* Default padding to none. */ - pad = 0; - - /* Determine if an extra conversion is needed. */ - if ((length * 6) % 24) - { - /* Some padding is needed. */ - - /* Calculate the number of pad characters. */ - pad = (length * 6) % 24; - pad = (24 - pad) / 6; - pad = pad - 1; - - /* Adjust the length to pickup the character fraction. */ - length++; - } - - /* Setup index into the base64name. */ - j = 0; - - /* Compute the base64name. */ - step = 0; - i = 0; - while (j < length) - { - /* Determine which step we are in. */ - if (step == 0) - { - /* Use first 6 bits of name character for index. */ - base64name[j++] = (UCHAR)_nx_smtp_base64_array[((UINT) name[i]) >> 2]; - step++; - } - else if (step == 1) - { - - /* Use last 2 bits of name character and first 4 bits of next name character for index. */ - base64name[j++] = (UCHAR)_nx_smtp_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; - i++; - step++; - } - else if (step == 2) - { - - /* Use last 4 bits of name character and first 2 bits of next name character for index. */ - base64name[j++] = (UCHAR)_nx_smtp_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; - i++; - step++; - } - else /* Step 3 */ - { - - /* Use last 6 bits of name character for index. */ - base64name[j++] = (UCHAR)_nx_smtp_base64_array[(((UINT) name[i]) & 0x3F)]; - i++; - step = 0; - } - } - - /* Determine if the index needs to be advanced. */ - if (step != 3) - i++; - - /* Now add the PAD characters. */ - while ((pad--) && (j < NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE)) - { - - /* Pad base64name with '=' characters. */ - base64name[j++] = '='; - } - - /* Put a NULL character in. */ - base64name[j] = NX_NULL; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_smtp_base64_decode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decodes the input base64 ASCII string and converts */ -/* it into a standard ASCII representation. It is the caller's */ -/* responsibility to match the name and base64name buffers in size to */ -/* avoid overwriting memory. */ -/* */ -/* INPUT */ -/* */ -/* base64name Encoded base64 name string */ -/* name Name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Get length of string */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_smtp_server_basic_authenticate Basic authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_smtp_base64_decode(UCHAR *base64name, UCHAR *name) -{ - -UINT length; -UINT i, j; -UINT value1, value2; -UINT step; - - - /* Calculate the name length. */ - if (_nx_utility_string_length_check((CHAR *)base64name, &length, NX_SMTP_SERVER_CHALLENGE_MAX_STRING)) - { - name[0] = NX_NULL; - return; - } - - /* Adjust the length to represent the ASCII name. */ - length = ((length * 6) / 8); - - /* Setup index into the ASCII name. */ - j = 0; - - /* Compute the ASCII name. */ - step = 0; - i = 0; - - while ((j < length) && (base64name[i]) && (base64name[i] != '=') && (j < NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE)) - { - - /* Derive values of the Base64 name. */ - if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) - value1 = (UINT) (base64name[i] - 'A'); - else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) - value1 = (UINT) (base64name[i] - 'a') + 26; - else if ((base64name[i] >= '0') && (base64name[i] <= '9')) - value1 = (UINT) (base64name[i] - '0') + 52; - else if (base64name[i] == '+') - value1 = 62; - else if (base64name[i] == '/') - value1 = 63; - else - value1 = 0; - - /* Derive value for the next character. */ - if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) - value2 = (UINT) (base64name[i+1] - 'A'); - else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) - value2 = (UINT) (base64name[i+1] - 'a') + 26; - else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) - value2 = (UINT) (base64name[i+1] - '0') + 52; - else if (base64name[i+1] == '+') - value2 = 62; - else if (base64name[i+1] == '/') - value2 = 63; - else - value2 = 0; - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first value and first 2 bits of second value. */ - name[j++] = (UCHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); - i++; - step++; - } - else if (step == 1) - { - - /* Use last 4 bits of first value and first 4 bits of next value. */ - name[j++] = (UCHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); - i++; - step++; - } - else if (step == 2) - { - - /* Use first 2 bits and following 6 bits of next value. */ - name[j++] = (UCHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); - i++; - i++; - step = 0; - } - } - - /* Put a NULL character in. */ - name[j] = NX_NULL; - - return; -} - diff --git a/protocol_handlers/smtp/nxd_smtp_client.h b/protocol_handlers/smtp/nxd_smtp_client.h deleted file mode 100644 index d055d598..00000000 --- a/protocol_handlers/smtp/nxd_smtp_client.h +++ /dev/null @@ -1,433 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX SMTP Client Component */ -/** */ -/** Simple Mail Transfer Protocol (SMTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_smtp_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Simple Mail Transfer Protocol (SMTP) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -#ifndef NXD_SMTP_CLIENT_H -#define NXD_SMTP_CLIENT_H - - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -/* NX SMTP Client configurable options. */ - -/* Set the TCP socket window size. */ - -#ifndef NX_SMTP_CLIENT_TCP_WINDOW_SIZE -#define NX_SMTP_CLIENT_TCP_WINDOW_SIZE 1460 -#endif - -/* Set timeout on Client packet allocation in ticks. */ - -#ifndef NX_SMTP_CLIENT_PACKET_TIMEOUT -#define NX_SMTP_CLIENT_PACKET_TIMEOUT (2 * NX_IP_PERIODIC_RATE) -#endif - -/* Set Client TCP connection timeout in seconds. */ - -#ifndef NX_SMTP_CLIENT_CONNECTION_TIMEOUT -#define NX_SMTP_CLIENT_CONNECTION_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -/* Set Client TCP disconnect timeout in seconds. */ - -#ifndef NX_SMTP_CLIENT_DISCONNECT_TIMEOUT -#define NX_SMTP_CLIENT_DISCONNECT_TIMEOUT (5 * NX_IP_PERIODIC_RATE) -#endif - -/* Set Client timeout in seconds for waiting for server reply to client greeting. */ - -#ifndef NX_SMTP_GREETING_TIMEOUT -#define NX_SMTP_GREETING_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - - -/* Set Client 'envelope' timeout in seconds for waiting for server reply to client commands. */ - -#ifndef NX_SMTP_ENVELOPE_TIMEOUT -#define NX_SMTP_ENVELOPE_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - - -/* Set Client timeout in seconds for waiting to receive server acceptance of client message data. */ - -#ifndef NX_SMTP_MESSAGE_TIMEOUT -#define NX_SMTP_MESSAGE_TIMEOUT (30 * NX_IP_PERIODIC_RATE) -#endif - - -/* Set timeout for TCP socket send completion. */ - -#ifndef NX_SMTP_CLIENT_SEND_TIMEOUT -#define NX_SMTP_CLIENT_SEND_TIMEOUT (5 * NX_IP_PERIODIC_RATE) -#endif - - -/* Define size for Client profile data. */ - -#ifndef NX_SMTP_CLIENT_MAX_USERNAME -#define NX_SMTP_CLIENT_MAX_USERNAME 40 -#endif - -#ifndef NX_SMTP_CLIENT_MAX_PASSWORD -#define NX_SMTP_CLIENT_MAX_PASSWORD 20 -#endif - - - -/* Define size of the buffer to extract the server challenge for authentication. - There is no specific size here so 200 bytes is sufficient to cover all digest string handling. */ -#ifndef NX_SMTP_SERVER_CHALLENGE_MAX_STRING -#define NX_SMTP_SERVER_CHALLENGE_MAX_STRING 200 -#endif - - -/* Define size for handling data for authentication (LOGIN, PLAIN): - PLAIN requires rooms for authorization-id\0authentication-id\0passwd'. - The two bytes are for the NULL byte between the first two auth id and - between auth id and password. */ - -#define NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE (NX_SMTP_CLIENT_MAX_USERNAME + NX_SMTP_CLIENT_MAX_USERNAME + NX_SMTP_CLIENT_MAX_PASSWORD + 2) -#define NX_SMTP_CLIENT_AUTH_CHALLENGE_ENCODED_SIZE (NX_SMTP_CLIENT_AUTH_CHALLENGE_SIZE * 4 / 3 + 1) - - -/* These define the states of the protocol state machine */ - -#define NX_SMTP_CLIENT_STATE_AWAITING_REPLY 0xFFFFFFFF /* Session state depends on outcome of current response handler. */ -#define NX_SMTP_CLIENT_STATE_COMPLETED_NORMALLY 0xFFFFFFFE /* No internal errors, session completed normally. */ -#define NX_SMTP_CLIENT_STATE_ERROR 0xFFFFFFFD /* Internal errors e.g. TCP send or receive fails; session terminated abnormally. */ - - -#define NX_SMTP_INVALID_PARAM 0xA5 /* Invalid non pointer input in an SMTP service call */ -#define NX_SMTP_INTERNAL_ERROR 0xA3 /* Internal processing error */ -#define NX_SMTP_AUTHENTICATION_ERROR 0xA0 /* Invalid input for creating Client authentication. */ -#define NX_SMTP_OVERSIZE_MAIL_DATA 0xA1 /* Mail message exceeds buffer size */ -#define NX_SMTP_INVALID_SERVER_REPLY 0xA2 /* Unknown or invalid server reply */ -#define NX_SMTP_SERVER_ERROR_CODE_RECEIVED 0xA4 /* Received an SMTP Server error code */ -#define NX_SMTP_PACKET_ALLOCATE_ERROR 0xA6 /* Error allocating packet for SMTP message transmission */ -#define NX_SMTP_GREET_REPLY_ERROR 0xA7 /* Error in response to Client SMTP GREET command */ -#define NX_SMTP_HELLO_REPLY_ERROR 0xA8 /* Error in response to Client SMTP HELO or EHLO command */ -#define NX_SMTP_MAIL_REPLY_ERROR 0xA9 /* Error in response to Client SMTP MAIL command */ -#define NX_SMTP_RCPT_REPLY_ERROR 0xAA /* Error in response to Client SMTP RCPT command */ -#define NX_SMTP_MESSAGE_REPLY_ERROR 0xAB /* Error in response to Client SMTP MESSAGE data sent */ -#define NX_SMTP_DATA_REPLY_ERROR 0xAC /* Error in response to Client SMTP DATA command */ -#define NX_SMTP_AUTH_REPLY_ERROR 0xAD /* Error in response to Client SMTP AUTH command */ -#define NX_SMTP_SERVER_ERROR_REPLY 0xAE /* Error in parsing Server reply code (not found or unknown) */ -#define NX_SMTP_TRANSMIT_ERROR 0xAF /* Error occurred during TCP packet transmission e.g. send queue full */ -#define NX_SMTP_INVALID_SERVER_CHALLENGE 0xB0 /* Invalid server challenge (e.g. missing enclosing angle brackets). */ -#define NX_SMTP_OVERSIZE_SERVER_REPLY 0xB1 /* Server reply exceeds client session buffer size */ -#define NX_SMTP_CLIENT_NOT_INTIALIZED 0xB2 /* Client not created successfully e.g. socket create failed. Cannot transmit mail. */ - -/* Basic SMTP commands supported by this NetX SMTP API. */ - -#define NX_SMTP_COMMAND_EHLO "EHLO" -#define NX_SMTP_COMMAND_HELO "HELO" -#define NX_SMTP_COMMAND_MAIL "MAIL FROM" -#define NX_SMTP_COMMAND_RCPT "RCPT TO" -#define NX_SMTP_COMMAND_AUTH "AUTH" -#define NX_SMTP_COMMAND_NOOP "NOOP" -#define NX_SMTP_COMMAND_DATA "DATA" -#define NX_SMTP_COMMAND_RSET "RSET" -#define NX_SMTP_COMMAND_QUIT "QUIT" - -/* List of common SMTP server reply codes */ - -#define NX_SMTP_CODE_GREETING_OK 220 -#define NX_SMTP_CODE_ACKNOWLEDGE_QUIT 221 -#define NX_SMTP_CODE_AUTHENTICATION_SUCCESSFUL 235 -#define NX_SMTP_CODE_OK_TO_CONTINUE 250 -#define NX_SMTP_CODE_CANNOT_VERIFY_RECIPIENT 252 -#define NX_SMTP_CODE_AUTHENTICATION_TYPE_ACCEPTED 334 -#define NX_SMTP_CODE_SEND_MAIL_INPUT 354 -#define NX_SMTP_CODE_SERVICE_NOT_AVAILABLE 421 -#define NX_SMTP_CODE_SERVICE_INTERNAL_SERVER_ERROR 451 -#define NX_SMTP_CODE_INSUFFICIENT_STORAGE 452 -#define NX_SMTP_CODE_AUTH_FAILED_INTERNAL_SERVER_ERROR 454 -#define NX_SMTP_CODE_COMMAND_SYNTAX_ERROR 500 -#define NX_SMTP_CODE_PARAMETER_SYNTAX_ERROR 501 -#define NX_SMTP_CODE_COMMAND_NOT_IMPLEMENTED 502 -#define NX_SMTP_CODE_BAD_SEQUENCE 503 -#define NX_SMTP_CODE_PARAMETER_NOT_IMPLEMENTED 504 -#define NX_SMTP_CODE_AUTH_REQUIRED 530 -#define NX_SMTP_CODE_AUTH_FAILED 535 -#define NX_SMTP_CODE_REQUESTED_ACTION_NOT_TAKEN 550 -#define NX_SMTP_CODE_USER_NOT_LOCAL 551 -#define NX_SMTP_CODE_OVERSIZE_MAIL_DATA 552 -#define NX_SMTP_CODE_BAD_MAILBOX 553 -#define NX_SMTP_CODE_TRANSACTION_FAILED 554 -#define NX_SMTP_CODE_BAD_SERVER_CODE_RECEIVED 555 - - -/* Common components of SMTP command messages */ - -#define NX_SMTP_LINE_TERMINATOR "\r\n" -#define NX_SMTP_EOM "\r\n.\r\n" -#define NX_SMTP_MESSAGE_ID "Message-ID" -#define NX_SMTP_TO_STRING "To: " -#define NX_SMTP_FROM_STRING "From: " -#define NX_SMTP_SUBJECT_STRING "Subject: " -#define NX_SMTP_MAIL_HEADER_COMPONENTS "MIME-Version: 1.0\r\n" \ - "Content-Type: text/plain;\r\n" \ - " charset=\"utf-8\"\r\n" \ - "Content-Transfer-Encoding: 8bit\r\n" \ - "\r\n" - - -/* Enumerated states of the protocol state machine. These MUST be in the - same order as the list of protocol states in NX_SMTP_CLIENT_STATES.*/ - -typedef enum NX_SMTP_CLIENT_STATE_ENUM -{ - NX_SMTP_CLIENT_STATE_IDLE = 0, - NX_SMTP_CLIENT_STATE_GREETING, /*1*/ - NX_SMTP_CLIENT_STATE_EHLO, /*2 */ - NX_SMTP_CLIENT_STATE_HELO, /*3*/ - NX_SMTP_CLIENT_STATE_MAIL, /*4*/ - NX_SMTP_CLIENT_STATE_RCPT, /*5*/ - NX_SMTP_CLIENT_STATE_DATA, /*6*/ - NX_SMTP_CLIENT_STATE_MESSAGE, /*7*/ - NX_SMTP_CLIENT_STATE_RSET, /*8*/ - NX_SMTP_CLIENT_STATE_QUIT, /*9*/ - NX_SMTP_CLIENT_STATE_NOOP, /*10 */ - NX_SMTP_CLIENT_STATE_AUTH, /*11*/ - NX_SMTP_CLIENT_STATE_AUTH_CHALLENGE /*12*/ - -} NX_SMTP_CLIENT_STATE; - - -/* Enumeration of common server challenges to the client */ - -#define NX_SMTP_CLIENT_REPLY_TO_UNKNOWN_PROMPT 1 -#define NX_SMTP_CLIENT_REPLY_TO_USERNAME_PROMPT 2 -#define NX_SMTP_CLIENT_REPLY_TO_PASSWORD_PROMPT 3 -#define NX_SMTP_CLIENT_REPLY_SERVER_CHALLENGE_PROMPT 4 - -/* Common server challenges from the SMTP server. */ - -#define NX_SMTP_USERNAME_PROMPT "Username:" -#define NX_SMTP_PASSWORD_PROMPT "Password:" - -/* ID for identifying as an SMTP client */ - -#define NX_SMTP_CLIENT_ID 0x534D5450UL - -/* Define the character to cancel authentication process (RFC mandated). */ - -#define NX_SMTP_CANCEL_AUTHENTICATION "*" - - -/* Enumeration of the state of authentication between server and client */ - -typedef enum NX_SMTP_AUTHENTICATION_STATE_ENUM -{ - NX_SMTP_NOT_AUTHENTICATED, - NX_SMTP_AUTHENTICATION_IN_PROGRESS, - NX_SMTP_AUTHENTICATION_FAILED, - NX_SMTP_AUTHENTICATION_SUCCEEDED - -} NX_SMTP_AUTHENTICATION_STATE; - - -/* Defines for deciding priority of mail. */ - -#define NX_SMTP_MAIL_PRIORITY_LOW 0x01 -#define NX_SMTP_MAIL_PRIORITY_NORMAL 0x02 -#define NX_SMTP_MAIL_PRIORITY_HIGH 0x04 - - -/* Defines for type of mail recipient. */ - -#define NX_SMTP_RECIPIENT_TO 0x01 -#define NX_SMTP_RECIPIENT_CC 0x02 -#define NX_SMTP_RECIPIENT_BCC 0x04 - - -/* Define size of SMTP reply status codes (RFC mandated). */ - -#define NX_SMTP_SERVER_REPLY_CODE_SIZE 3 - -#define NX_SMTP_CLIENT_AUTH_NONE 0xFFFF -#define NX_SMTP_CLIENT_AUTH_LOGIN 1 -#define NX_SMTP_CLIENT_AUTH_LOGIN_TEXT "AUTH LOGIN" -#define NX_SMTP_CLIENT_AUTH_CRAM_MD5 2 -#define NX_SMTP_CLIENT_AUTH_CRAM_MD5_TEXT "AUTH CRAM-MD5" -#define NX_SMTP_CLIENT_AUTH_PLAIN 3 -#define NX_SMTP_CLIENT_AUTH_PLAIN_TEXT "AUTH PLAIN" - -/* Define the NetX SMTP RECIPIENT structure */ - -/* Define the NetX SMTP MAIL structure */ - -typedef struct NX_SMTP_CLIENT_MAIL_STRUCT -{ - CHAR *nx_smtp_client_mail_recipient_address; /* Recipient's mailbox address */ - CHAR *nx_smtp_client_mail_from_address; /* Sender's mailbox address. */ - UINT nx_smtp_client_mail_priority; /* Mail item priority level */ - CHAR *nx_smtp_client_mail_subject; - CHAR *nx_smtp_client_mail_body; /* Pointer to text of mail to send. */ - UINT nx_smtp_client_mail_body_length; /* Size of mail buffer. */ -} NX_SMTP_CLIENT_MAIL; - - -/* Define the SMTP client structure */ - -typedef struct NX_SMTP_CLIENT_STRUCT -{ - ULONG nx_smtp_client_id; /* SMTP ID for identify client service. */ - CHAR nx_smtp_username[NX_SMTP_CLIENT_MAX_USERNAME + 1]; /* Client name (may be used in authentication) */ - CHAR nx_smtp_password[NX_SMTP_CLIENT_MAX_PASSWORD + 1]; /* Client password (used in authentication) */ - CHAR nx_smtp_client_domain[NX_SMTP_CLIENT_MAX_USERNAME + 1]; /* Client domain of the client (and sender) */ - UINT nx_smtp_client_authentication_type; /* Default Client authentication. */ - NX_IP *nx_smtp_client_ip_ptr; /* Client IP instance */ - NX_PACKET_POOL *nx_smtp_client_packet_pool_ptr; /* Client packet pool for sending data packets to the server */ - NX_SMTP_CLIENT_MAIL nx_smtp_client_mail; /* Session mail is the collection of parameters required to create an SMTP mail message. */ - UINT nx_smtp_client_init_status; /* If true SMTP client successfully created and ready for transmitting mail. */ - NXD_ADDRESS nx_smtp_server_address; /* Server IP address (IPv4 or IPv6). */ - USHORT nx_smtp_server_port; /* Server port. */ - NX_TCP_SOCKET nx_smtp_client_socket; /* Client NetX TCP socket. */ - UINT nx_smtp_client_cmd_state; /* Command state of the SMTP session. */ - UINT nx_smtp_client_rsp_state; /* Response state of the SMTP session. */ - UINT nx_smtp_client_reply_code_status; /* Reply code received from SMTP server. */ - NX_PACKET *nx_smtp_server_packet; /* Packet containing server reply. */ - UINT nx_smtp_client_authentication_reply; /* Buffer holding server reply text during authentication process */ - NX_SMTP_AUTHENTICATION_STATE nx_smtp_client_authentication_state; /* State of the authentication process */ - UINT nx_smtp_client_data_transparency_bytes; /* Extra bytes allowed for data transparency processing to add to message data. */ - UINT nx_smtp_client_mail_status; /* Status of mail acceptance by the server */ - UINT nx_smtp_client_mute; /* Mute command state; client waits for another packet in same SMTP state */ - -} NX_SMTP_CLIENT; - - -typedef struct NX_SMTP_CLIENT_STATES_STRUCT -{ - UINT (*cmd) (NX_SMTP_CLIENT *client_ptr); - UINT (*rsp) (NX_SMTP_CLIENT *client_ptr); - -} NX_SMTP_CLIENT_STATES; - - -#ifndef NX_SMTP_SOURCE_CODE - -/* Define the system API mappings based on the error checking - selected by the user. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - - -#ifdef NX_SMTP_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nxd_smtp_client_create _nxd_smtp_client_create -#define nx_smtp_client_delete _nx_smtp_client_delete -#define nx_smtp_mail_send _nx_smtp_mail_send -#else - -/* Services with error checking. */ -#define nxd_smtp_client_create _nxde_smtp_client_create -#define nx_smtp_client_delete _nxe_smtp_client_delete -#define nx_smtp_mail_send _nxe_smtp_mail_send - - -#endif /* NX_SMTP_DISABLE_ERROR_CHECKING */ - - -/* Define the prototypes accessible to the application software. */ -UINT nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, - CHAR *username, CHAR *password, CHAR *from_address, - CHAR *client_domain, UINT authentication_type, - NXD_ADDRESS *server_address, UINT port); - -UINT nx_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); -UINT nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, - CHAR *subject, CHAR *mail_body, UINT mail_body_length); - - -#else /* NX_SMTP_SOURCE_CODE */ - - -/* SMTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxd_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, - CHAR *username, CHAR *password, CHAR *from_address, - CHAR *client_domain, UINT authentication_type, - NXD_ADDRESS *server_address, UINT port); -UINT _nxde_smtp_client_create(NX_SMTP_CLIENT *client_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *client_packet_pool_ptr, - CHAR *username, CHAR *password, CHAR *from_address, - CHAR *client_domain, UINT authentication_type, - NXD_ADDRESS *server_address, UINT port); - -UINT _nx_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); -UINT _nxe_smtp_client_delete (NX_SMTP_CLIENT *client_ptr); - -UINT _nx_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, - CHAR *subject, CHAR *mail_body, UINT mail_body_length); - -UINT _nxe_smtp_mail_send(NX_SMTP_CLIENT *client_ptr, CHAR *recipient_address, UINT priority, - CHAR *subject, CHAR *mail_body, UINT mail_body_length); - - - - - -#endif /* NX_SMTP_SOURCE_CODE */ - -/* If a C++ compiler is being used....*/ -#ifdef __cplusplus -} -#endif - - -#endif /* NXD_SMTP_CLIENT_H */ diff --git a/protocol_handlers/snmp/nx_des.c b/protocol_handlers/snmp/nx_des.c deleted file mode 100644 index 2054bd64..00000000 --- a/protocol_handlers/snmp/nx_des.c +++ /dev/null @@ -1,546 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** DES Encryption Standard (DES) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#include "nx_api.h" -#include "nx_des.h" - - -/* Define macros for the DES transform function. */ - - -/* Define the eight S-box data structures used in the permutation. Keep them static, since there is no - reason to have these symbols referenced outside this file. */ - -static ULONG sb1[64] = -{ - - 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, - 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, - 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, - 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, - 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, - 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL -}; - -static ULONG sb2[64] = -{ - - 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, - 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, - 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, - 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, - 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, - 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, - 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, - 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL -}; - -static ULONG sb3[64] = -{ - - 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, - 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, - 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, - 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, - 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, - 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, - 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, - 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL -}; - -static ULONG sb4[64] = -{ - - 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, - 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, - 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, - 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, - 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, - 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, - 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, - 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL -}; - -static ULONG sb5[64] = -{ - - 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, - 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, - 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, - 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, - 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, - 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, - 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, - 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL -}; - -static ULONG sb6[64] = -{ - - 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, - 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, - 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, - 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, - 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, - 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, - 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, - 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL -}; - -static ULONG sb7[64] = -{ - - 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, - 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, - 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, - 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, - 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, - 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, - 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, - 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL -}; - -static ULONG sb8[64] = -{ - - 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, - 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, - 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, - 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, - 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, - 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, - 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, - 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL -}; - - -/* Define the left half bit swap table. */ - -static ULONG left_half_bit_swap[16] = -{ - - 0x00000000UL, 0x00000001UL, 0x00000100UL, 0x00000101UL, - 0x00010000UL, 0x00010001UL, 0x00010100UL, 0x00010101UL, - 0x01000000UL, 0x01000001UL, 0x01000100UL, 0x01000101UL, - 0x01010000UL, 0x01010001UL, 0x01010100UL, 0x01010101UL -}; - -/* Define the right half bit swap table. */ - -static ULONG right_half_bit_swap[16] = -{ - 0x00000000UL, 0x01000000UL, 0x00010000UL, 0x01010000UL, - 0x00000100UL, 0x01000100UL, 0x00010100UL, 0x01010100UL, - 0x00000001UL, 0x01000001UL, 0x00010001UL, 0x01010001UL, - 0x00000101UL, 0x01000101UL, 0x00010101UL, 0x01010101UL -}; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_des_key_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the 32 encryption keys as well as the 32 */ -/* decryption keys for the DES algorithm. It must be called before */ -/* either _nx_des_encrypt or _nx_des_decrypt can be called. */ -/* destination. */ -/* */ -/* INPUT */ -/* */ -/* context DES context pointer */ -/* key 8-byte (64-bit) key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_des_key_set(NX_DES *context, UCHAR key[8]) -{ - -ULONG left, right, temp; -ULONG *encrypt_keys_ptr; -ULONG *decrypt_keys_ptr; -UINT round; - - - /* Determine if the context is non-null. */ - if (context == NX_NULL) - return(NX_PTR_ERROR); - - /* First, convert the 8-byte raw key into two ULONG halves, in an endian neutral fashion. */ - left = (((ULONG) key[0]) << 24) | (((ULONG) key[1]) << 16) | (((ULONG) key[2]) << 8) | ((ULONG) key[3]); - right = (((ULONG) key[4]) << 24) | (((ULONG) key[5]) << 16) | (((ULONG) key[6]) << 8) | ((ULONG) key[7]); - - /* Perform permutation on the key halves. */ - temp = ((right >> 4) ^ left) & 0x0F0F0F0FUL; - left = left ^ temp; - right = right ^ (temp << 4); - temp = (right ^ left) & 0x10101010; - left = left ^ temp; - right = right ^ temp; - - left = (left_half_bit_swap[(left) & 0xf] << 3) | (left_half_bit_swap[(left >> 8) & 0xf] << 2) | - (left_half_bit_swap[(left >> 16) & 0xf] << 1) | (left_half_bit_swap[(left >> 24) & 0xf]) | - (left_half_bit_swap[(left >> 5) & 0xf] << 7) | (left_half_bit_swap[(left >> 13) & 0xf] << 6) | - (left_half_bit_swap[(left >> 21) & 0xf] << 5) | (left_half_bit_swap[(left >> 29) & 0xf] << 4); - left = left & 0x0fffffff; - - right = (right_half_bit_swap[(right >> 1) & 0xf] << 3) | (right_half_bit_swap[(right >> 9) & 0xf] << 2) | - (right_half_bit_swap[(right >> 17) & 0xf] << 1) | (right_half_bit_swap[(right >> 25) & 0xf]) | - (right_half_bit_swap[(right >> 4) & 0xf] << 7) | (right_half_bit_swap[(right >> 12) & 0xf] << 6) | - (right_half_bit_swap[(right >> 20) & 0xf] << 5) | (right_half_bit_swap[(right >> 28) & 0xf] << 4); - right = right & 0x0fffffff; - - /* Setup encryption keys pointer. */ - encrypt_keys_ptr = context -> nx_des_encryption_keys; - - /* Calculate the encryption keys. */ - for (round = 0; round < 16; round++) - { - - /* Modify the left and right portions of the keys. */ - if ((round < 2) || (round == 8) || (round == 15)) - { - - left = ((left << 1) | (left >> 27)) & 0x0FFFFFFFUL; - right = ((right << 1) | (right >> 27)) & 0x0FFFFFFFUL; - } - else - { - - left = ((left << 2) | (left >> 26)) & 0x0FFFFFFFUL; - right = ((right << 2) | (right >> 26)) & 0x0FFFFFFFUL; - } - - /* Setup the key. */ - *encrypt_keys_ptr++ = ((left << 4) & 0x24000000UL) | ((left << 28) & 0x10000000UL) | - ((left << 14) & 0x08000000UL) | ((left << 18) & 0x02080000UL) | - ((left << 6) & 0x01000000UL) | ((left << 9) & 0x00200000UL) | - ((left >> 1) & 0x00100000UL) | ((left << 10) & 0x00040000UL) | - ((left << 2) & 0x00020000UL) | ((left >> 10) & 0x00010000UL) | - ((right >> 13) & 0x00002000UL) | ((right >> 4) & 0x00001000UL) | - ((right << 6) & 0x00000800UL) | ((right >> 1) & 0x00000400UL) | - ((right >> 14) & 0x00000200UL) | (right & 0x00000100UL) | - ((right >> 5) & 0x00000020UL) | ((right >> 10) & 0x00000010UL) | - ((right >> 3) & 0x00000008UL) | ((right >> 18) & 0x00000004UL) | - ((right >> 26) & 0x00000002UL) | ((right >> 24) & 0x00000001UL); - - /* Setup the next key. */ - *encrypt_keys_ptr++ = ((left << 15) & 0x20000000UL) | ((left << 17) & 0x10000000UL) | - ((left << 10) & 0x08000000UL) | ((left << 22) & 0x04000000UL) | - ((left >> 2) & 0x02000000UL) | ((left << 1) & 0x01000000UL) | - ((left << 16) & 0x00200000UL) | ((left << 11) & 0x00100000UL) | - ((left << 3) & 0x00080000UL) | ((left >> 6) & 0x00040000UL) | - ((left << 15) & 0x00020000UL) | ((left >> 4) & 0x00010000UL) | - ((right >> 2) & 0x00002000UL) | ((right << 8) & 0x00001000UL) | - ((right >> 14) & 0x00000808UL) | ((right >> 9) & 0x00000400UL) | - ((right) & 0x00000200UL) | ((right << 7) & 0x00000100UL) | - ((right >> 7) & 0x00000020UL) | ((right >> 3) & 0x00000011UL) | - ((right << 2) & 0x00000004UL) | ((right >> 21) & 0x00000002UL); - } - - /* Reposition the encryption key pointer. */ - encrypt_keys_ptr = encrypt_keys_ptr - 2; - - /* Setup decryption pointer. */ - decrypt_keys_ptr = context -> nx_des_decryption_keys; - - /* Now setup decryption keys. */ - for (round = 0; round < 16; round++) - { - - /* Copy the reverse of the encryption keys. */ - *decrypt_keys_ptr++ = *encrypt_keys_ptr; - *decrypt_keys_ptr++ = *(encrypt_keys_ptr + 1); - - /* Adjust the encryption keys pointer. */ - encrypt_keys_ptr = encrypt_keys_ptr - 2; - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_des_encrypt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses the DES algorithm to encrypt 8-bytes (64-bits). */ -/* The result is 8 encrypted bytes. Note that the caller must make */ -/* sure the source and destination are 8-bytes in size! */ -/* */ -/* INPUT */ -/* */ -/* context DES context pointer */ -/* source 8-byte source */ -/* destination 8-byte destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_des_process_block Encrypt 8-bytes of source */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_des_encrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]) -{ - - /* Determine if the context is non-null. */ - if (context == NX_NULL) - return(NX_PTR_ERROR); - - /* Encrypt the block by supplying the encryption key set. */ - _nx_des_process_block(source, destination, context -> nx_des_encryption_keys); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_des_decrypt PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses the DES algorithm to decrypt 8-bytes (64-bits). */ -/* The result is 8 original source bytes. Note that the caller must */ -/* make sure the source and destination are 8-bytes in size! */ -/* */ -/* INPUT */ -/* */ -/* context DES context pointer */ -/* source 8-byte source */ -/* destination 8-byte destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_des_process_block Decrypt 8-bytes of source */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_des_decrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]) -{ - - /* Determine if the context is non-null. */ - if (context == NX_NULL) - return(NX_PTR_ERROR); - - /* Decrypt the block by supplying the decryption key set. */ - _nx_des_process_block(source, destination, context -> nx_des_decryption_keys); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_des_process_block PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function uses the DES algorithm to decrypt 8-bytes (64-bits). */ -/* The result is 8 original source bytes. Note that the caller must */ -/* make sure the source and destination are 8-bytes in size! */ -/* */ -/* INPUT */ -/* */ -/* source 8-byte source */ -/* destination 8-byte destination */ -/* keys Pointer to either the encrypt */ -/* or decrypt keys */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_des_process_block(UCHAR source[8], UCHAR destination[8], ULONG keys[32]) -{ - -ULONG left, right, temp; -ULONG *key_ptr; -UINT round; - - - /* First, convert the 8-byte source into two ULONG halves, in an endian neutral fashion. */ - left = (((ULONG) source[0]) << 24) | (((ULONG) source[1]) << 16) | (((ULONG) source[2]) << 8) | ((ULONG) source[3]); - right = (((ULONG) source[4]) << 24) | (((ULONG) source[5]) << 16) | (((ULONG) source[6]) << 8) | ((ULONG) source[7]); - - /* Compute the initial permutation. */ - temp = ((left >> 4) ^ right) & 0x0F0F0F0FUL; - right = right ^ temp; - left = left ^ (temp << 4); - temp = ((left >> 16) ^ right) & 0x0000FFFFUL; - right = right ^ temp; - left = left ^ (temp << 16); - temp = ((right >> 2) ^ left) & 0x33333333UL; - left = left ^ temp; - right = right ^ (temp << 2); - temp = ((right >> 8) ^ left) & 0x00FF00FFUL; - left = left ^ temp; - right = right ^ (temp << 8); - right = ((right << 1) | (right >> 31)) & 0xFFFFFFFFUL; - temp = (left ^ right) & 0xAAAAAAAAUL; - right = right ^ temp; - left = left ^ temp; - left = ((left << 1) | (left >> 31)) & 0xFFFFFFFFUL; - - /* Setup pointer to input keys. */ - key_ptr = keys; - - /* Now process the 16 rounds of the DES computation. There are two rounds per - loop. */ - for (round = 0; round < 8; round++) - { - - /* Calculate the left half. */ - temp = *key_ptr++ ^ right; - left = left ^ sb8[temp & 0x3F] ^ sb6[(temp >> 8) & 0x3F] ^ sb4[(temp >> 16) & 0x3F] ^ sb2[(temp >> 24) & 0x3F]; - - temp = *key_ptr++ ^ ((right << 28) | (right >> 4)); - left = left ^ sb7[temp & 0x3F] ^ sb5[(temp >> 8) & 0x3F] ^ sb3[(temp >> 16) & 0x3F] ^ sb1[(temp >> 24) & 0x3F]; - - /* Calculate the right half. */ - temp = *key_ptr++ ^ left; - right = right ^ sb8[temp & 0x3F] ^ sb6[(temp >> 8) & 0x3F] ^ sb4[(temp >> 16) & 0x3F] ^ sb2[(temp >> 24) & 0x3F]; - - temp = *key_ptr++ ^ ((left << 28) | (left >> 4)); - right = right ^ sb7[temp & 0x3F] ^ sb5[(temp >> 8) & 0x3F] ^ sb3[(temp >> 16) & 0x3F] ^ sb1[(temp >> 24) & 0x3F]; - } - - /* Now compute the final permutation. */ - right = ((right << 31) | (right >> 1)) & 0xFFFFFFFFUL; - temp = (right ^ left) & 0xAAAAAAAAUL; - right = right ^ temp; - left = left ^ temp; - left = ((left << 31) | (left >> 1)) & 0xFFFFFFFFUL; - temp = ((left >> 8) ^ right) & 0x00FF00FFUL; - right = right ^ temp; - left = left ^ (temp << 8); - temp = ((left >> 2) ^ right) & 0x33333333UL; - right = right ^ temp; - left = left ^ (temp << 2); - temp = ((right >> 16) ^ left) & 0x0000FFFFUL; - left = left ^ temp; - right = right ^ (temp << 16); - temp = ((right >> 4) ^ left) & 0x0F0F0F0FUL; - left = left ^ temp; - right = right ^ (temp << 4); - - /* Finally, build the output. */ - destination[0] = (UCHAR) (right >> 24); - destination[1] = (UCHAR) (right >> 16); - destination[2] = (UCHAR) (right >> 8); - destination[3] = (UCHAR) (right); - destination[4] = (UCHAR) (left >> 24); - destination[5] = (UCHAR) (left >> 16); - destination[6] = (UCHAR) (left >> 8); - destination[7] = (UCHAR) (left); -} - diff --git a/protocol_handlers/snmp/nx_des.h b/protocol_handlers/snmp/nx_des.h deleted file mode 100644 index eab9a3f9..00000000 --- a/protocol_handlers/snmp/nx_des.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** DES Encryption Standard (DES) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* COMPONENT DEFINITION RELEASE */ -/* */ -/* nx_des.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX DES encryption algorithm, derived */ -/* principally from FIPS-46. From an 8 bytes of raw input, the DES */ -/* encryption routine produces an 8-byte encryption of the input. */ -/* Conversely, from an 8-byte encryption, the decryption routine */ -/* produces the original 8 bytes of input. Note that the caller must */ -/* ensure 8 bytes of input and output are provided. */ -/* */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_DES_H -#define NX_DES_H - -/* Define the DES context structure. */ - -typedef struct NX_DES_STRUCT -{ - - ULONG nx_des_encryption_keys[32]; /* Contains the encryption keys */ - ULONG nx_des_decryption_keys[32]; /* Contains the decryption keys */ -} NX_DES; - - -/* Define the function prototypes for DES. */ - -UINT _nx_des_key_set(NX_DES *context, UCHAR key[8]); -UINT _nx_des_encrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]); -UINT _nx_des_decrypt(NX_DES *context, UCHAR source[8], UCHAR destination[8]); -VOID _nx_des_process_block(UCHAR source[8], UCHAR destination[8], ULONG keys[32]); - -#endif - diff --git a/protocol_handlers/snmp/nx_sha1.c b/protocol_handlers/snmp/nx_sha1.c deleted file mode 100644 index 05379076..00000000 --- a/protocol_handlers/snmp/nx_sha1.c +++ /dev/null @@ -1,494 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/* - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - ""AS IS"" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. -*/ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** SHA1 Digest Algorithm (SHA1) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#include "nx_api.h" -#include "nx_sha1.h" - -/* Define macros for the SHA1 transform function. */ - -/* Define the SHA1 basic F1, F2, F3, and F4 functions. */ - -#define F1(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define F2(x, y, z) ((x) ^ (y) ^ (z)) -#define F3(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) -#define F4(x, y, z) ((x) ^ (y) ^ (z)) - - -/* Define the SHA1 left shift circular function. */ - -#define LEFT_SHIFT_CIRCULAR(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - - -/* Define the padding array. This is used to pad the message such that its length is - 64 bits shy of being a multiple of 512 bits long. */ - -static UCHAR _nx_sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sha1_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes the SHA1 context. It must be called prior */ -/* to creating the SHA1 digest. */ -/* */ -/* INPUT */ -/* */ -/* context SHA1 context pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sha1_initialize(NX_SHA1 *context) -{ - - /* Determine if the context is non-null. */ - if (context == NX_NULL) - return(NX_PTR_ERROR); - - /* First, clear the bit count for this context. */ - context -> nx_sha1_bit_count[0] = 0; /* Clear the lower 32-bits of the count */ - context -> nx_sha1_bit_count[1] = 0; /* Clear the upper 32-bits of the count */ - - /* Finally, setup the context states. */ - context -> nx_sha1_states[0] = 0x67452301UL; /* Setup state A */ - context -> nx_sha1_states[1] = 0xEFCDAB89UL; /* Setup state B */ - context -> nx_sha1_states[2] = 0x98BADCFEUL; /* Setup state C */ - context -> nx_sha1_states[3] = 0x10325476UL; /* Setup state D */ - context -> nx_sha1_states[4] = 0xC3D2E1F0UL; /* Setup state E */ - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sha1_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the digest calculation with new input from */ -/* the caller. */ -/* */ -/* INPUT */ -/* */ -/* context SHA1 context pointer */ -/* input_ptr Pointer to byte(s) of input */ -/* input_length Length of bytes of input */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sha1_process_buffer Process complete buffer, */ -/* which is 64-bytes in size */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sha1_update(NX_SHA1 *context, UCHAR *input_ptr, UINT input_length) -{ - -ULONG current_bytes; -ULONG needed_fill_bytes; - - - /* Determine if the context is non-null. */ - if (context == NX_NULL) - return(NX_PTR_ERROR); - - /* Determine if there is a length. */ - if (input_length == 0) - return(NX_SUCCESS); - - /* Calculate the current byte count mod 64. Note the reason for the - shift by 3 is to account for the 8 bits per byte. */ - current_bytes = (context -> nx_sha1_bit_count[0] >> 3) & 0x3F; - - /* Calculate the current number of bytes needed to be filled. */ - needed_fill_bytes = 64 - current_bytes; - - /* Update the total bit count based on the input length. */ - context -> nx_sha1_bit_count[0] += (input_length << 3); - - /* Determine if there is roll-over of the bit count into the MSW. */ - if (context -> nx_sha1_bit_count[0] < (input_length << 3)) - { - - /* Yes, increment the MSW of the bit count. */ - context -> nx_sha1_bit_count[1]++; - } - - /* Update upper total bit count word. */ - context -> nx_sha1_bit_count[1] += (input_length >> 29); - - /* Check for a partial buffer that needs to be transformed. */ - if ((current_bytes) && (input_length >= needed_fill_bytes)) - { - - /* Yes, we can complete the buffer and transform it. */ - - /* Copy the appropriate portion of the input buffer into the internal - buffer of the context. */ - memcpy((void *) &(context -> nx_sha1_buffer[current_bytes]), (void *) input_ptr, needed_fill_bytes); - - /* Process the 64-byte (512 bit) buffer. */ - _nx_sha1_process_buffer(context, context -> nx_sha1_buffer); - - /* Adjust the pointers and length accordingly. */ - input_length = input_length - needed_fill_bytes; - input_ptr = input_ptr + needed_fill_bytes; - - /* Clear the remaining bits, since the buffer was processed. */ - current_bytes = 0; - } - - /* Process any and all whole blocks of input. */ - while (input_length >= 64) - { - - /* Process this 64-byte (512 bit) buffer. */ - _nx_sha1_process_buffer(context, input_ptr); - - /* Adjust the pointers and length accordingly. */ - input_length = input_length - 64; - input_ptr = input_ptr + 64; - } - - /* Determine if there is anything left. */ - if (input_length) - { - - /* Save the remaining bytes in the internal buffer after any remaining bytes - that it is processed later. */ - memcpy((void *) &(context -> nx_sha1_buffer[current_bytes]), (void *) input_ptr, input_length); - } - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sha1_digest_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finishes calculation of the SHA1 digest. It is called */ -/* where there is no further input needed for the digest. The resulting*/ -/* 20-byte (160-bit) SHA1 digest is returned to the caller. */ -/* */ -/* INPUT */ -/* */ -/* context SHA1 context pointer */ -/* digest Pointer to return digest in */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sha1_update Update the digest with padding*/ -/* and length of digest */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sha1_digest_calculate(NX_SHA1 *context, UCHAR digest[20]) -{ - -UCHAR bit_count_string[8]; -ULONG current_byte_count; -ULONG padding_bytes; - - - /* Move the lower portion of the bit count into the array. */ - bit_count_string[0] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 24); - bit_count_string[1] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 16); - bit_count_string[2] = (UCHAR) (context -> nx_sha1_bit_count[1] >> 8); - bit_count_string[3] = (UCHAR) (context -> nx_sha1_bit_count[1]); - bit_count_string[4] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 24); - bit_count_string[5] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 16); - bit_count_string[6] = (UCHAR) (context -> nx_sha1_bit_count[0] >> 8); - bit_count_string[7] = (UCHAR) (context -> nx_sha1_bit_count[0]); - - /* Calculate the current byte count. */ - current_byte_count = (context -> nx_sha1_bit_count[0] >> 3) & 0x3F; - - /* Calculate the padding bytes needed. */ - padding_bytes = (current_byte_count < 56) ? (56 - current_byte_count) : (120 - current_byte_count); - - /* Add any padding required. */ - _nx_sha1_update(context, _nx_sha1_padding, padding_bytes); - - /* Add the in the length. */ - _nx_sha1_update(context, bit_count_string, 8); - - /* Now store the digest in the caller specified destination. */ - digest[ 0] = (UCHAR) (context -> nx_sha1_states[0] >> 24); - digest[ 1] = (UCHAR) (context -> nx_sha1_states[0] >> 16); - digest[ 2] = (UCHAR) (context -> nx_sha1_states[0] >> 8); - digest[ 3] = (UCHAR) (context -> nx_sha1_states[0]); - digest[ 4] = (UCHAR) (context -> nx_sha1_states[1] >> 24); - digest[ 5] = (UCHAR) (context -> nx_sha1_states[1] >> 16); - digest[ 6] = (UCHAR) (context -> nx_sha1_states[1] >> 8); - digest[ 7] = (UCHAR) (context -> nx_sha1_states[1]); - digest[ 8] = (UCHAR) (context -> nx_sha1_states[2] >> 24); - digest[ 9] = (UCHAR) (context -> nx_sha1_states[2] >> 16); - digest[10] = (UCHAR) (context -> nx_sha1_states[2] >> 8); - digest[11] = (UCHAR) (context -> nx_sha1_states[2]); - digest[12] = (UCHAR) (context -> nx_sha1_states[3] >> 24); - digest[13] = (UCHAR) (context -> nx_sha1_states[3] >> 16); - digest[14] = (UCHAR) (context -> nx_sha1_states[3] >> 8); - digest[15] = (UCHAR) (context -> nx_sha1_states[3]); - digest[16] = (UCHAR) (context -> nx_sha1_states[4] >> 24); - digest[17] = (UCHAR) (context -> nx_sha1_states[4] >> 16); - digest[18] = (UCHAR) (context -> nx_sha1_states[4] >> 8); - digest[19] = (UCHAR) (context -> nx_sha1_states[4]); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sha1_process_buffer PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function actually uses the SHA1 algorithm to process a 64-byte */ -/* (512 bit) buffer. */ -/* */ -/* INPUT */ -/* */ -/* context SHA1 context pointer */ -/* buffer Pointer to 64-byte buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Applications */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sha1_process_buffer(NX_SHA1 *context, UCHAR buffer[64]) -{ - -ULONG *w; -UINT t; -ULONG temp; -ULONG a, b, c, d, e; - - - /* Setup pointers to the word array. */ - w = context -> nx_sha1_word_array; - - /* Initialize the first 16 words of the word array, taking care of the - endian issues at the same time. */ - for (t = 0; t < 16; t++) - { - - /* Setup each entry. */ - w[t] = (((ULONG) buffer[t * 4]) << 24) | (((ULONG) buffer[(t * 4) + 1]) << 16) | (((ULONG) buffer[(t * 4) + 2]) << 8) | ((ULONG) buffer[(t * 4) + 3]); - } - - /* Setup the remaining entries of the word array. */ - for (t = 16; t < 80; t++) - { - - /* Setup each entry. */ - w[t] = LEFT_SHIFT_CIRCULAR((w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]), 1); - } - - /* Initialize the state variables. */ - a = context -> nx_sha1_states[0]; - b = context -> nx_sha1_states[1]; - c = context -> nx_sha1_states[2]; - d = context -> nx_sha1_states[3]; - e = context -> nx_sha1_states[4]; - - /* Now, perform Round 1 operations. */ - for (t = 0; t < 20; t++) - { - - /* Compute round 1 (t = 0 through t = 19). */ - temp = LEFT_SHIFT_CIRCULAR(a, 5) + F1(b, c, d) + e + w[t] + 0x5A827999UL; - e = d; - d = c; - c = LEFT_SHIFT_CIRCULAR(b, 30); - b = a; - a = temp; - } - - /* Now, perform Round 2 operations. */ - for (t = 20; t < 40; t++) - { - - /* Compute round 2 (t = 20 through t = 39). */ - temp = LEFT_SHIFT_CIRCULAR(a, 5) + F2(b, c, d) + e + w[t] + 0x6ED9EBA1UL; - e = d; - d = c; - c = LEFT_SHIFT_CIRCULAR(b, 30); - b = a; - a = temp; - } - - /* Now, perform Round 3 operations. */ - for (t = 40; t < 60; t++) - { - - /* Compute round 3 (t = 40 through t = 59). */ - temp = LEFT_SHIFT_CIRCULAR(a, 5) + F3(b, c, d) + e + w[t] + 0x8F1BBCDCUL; - e = d; - d = c; - c = LEFT_SHIFT_CIRCULAR(b, 30); - b = a; - a = temp; - } - - /* Finally, perform Round 4 operations. */ - for (t = 60; t < 80; t++) - { - - /* Compute round 4 (t = 60 through t = 79). */ - temp = LEFT_SHIFT_CIRCULAR(a, 5) + F4(b, c, d) + e + w[t] + 0xCA62C1D6UL; - e = d; - d = c; - c = LEFT_SHIFT_CIRCULAR(b, 30); - b = a; - a = temp; - } - - /* Save the resulting in this SHA1 context. */ - context -> nx_sha1_states[0] += a; - context -> nx_sha1_states[1] += b; - context -> nx_sha1_states[2] += c; - context -> nx_sha1_states[3] += d; - context -> nx_sha1_states[4] += e; -} - diff --git a/protocol_handlers/snmp/nx_sha1.h b/protocol_handlers/snmp/nx_sha1.h deleted file mode 100644 index f265ed58..00000000 --- a/protocol_handlers/snmp/nx_sha1.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/* - Copyright (C) The Internet Society (2001). All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that the above copyright notice and this paragraph are - included on all such copies and derivative works. However, this - document itself may not be modified in any way, such as by removing - the copyright notice or references to the Internet Society or other - Internet organizations, except as needed for the purpose of - developing Internet standards in which case the procedures for - copyrights defined in the Internet Standards process must be - followed, or as required to translate it into languages other than - English. - - The limited permissions granted above are perpetual and will not be - revoked by the Internet Society or its successors or assigns. - - This document and the information contained herein is provided on an - ""AS IS"" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING - TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION - HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. -*/ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** SHA1 Digest Algorithm (SHA1) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* COMPONENT DEFINITION RELEASE */ -/* */ -/* nx_sha1.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX SHA1 algorithm, derived principally from */ -/* RFC3174. From a user-specified number of input bytes, this routine */ -/* produces a 20-byte (160-bit) digest or sometimes called a hash */ -/* value. The resulting digest is returned in a 20-byte array supplied */ -/* by the caller. */ -/* */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_SHA1_H -#define NX_SHA1_H - - -/* Define the SHA1 context structure. */ - -typedef struct NX_SHA1_STRUCT -{ - - ULONG nx_sha1_states[5]; /* Contains each state (A,B,C,D) */ - ULONG nx_sha1_bit_count[2]; /* Contains the 64-bit total bit */ - /* count, where index 0 holds the */ - /* least significant bit count and*/ - /* index 1 contains the most */ - /* significant portion of the bit */ - /* count */ - UCHAR nx_sha1_buffer[64]; /* Working buffer for SHA1 algorithm*/ - /* where partial buffers are */ - /* accumulated until a full block */ - /* can be processed */ - ULONG nx_sha1_word_array[80]; /* Working 80 word array */ -} NX_SHA1; - - -/* Define the function prototypes for SHA1. */ - -UINT _nx_sha1_initialize(NX_SHA1 *context); -UINT _nx_sha1_update(NX_SHA1 *context, UCHAR *input_ptr, UINT input_length); -UINT _nx_sha1_digest_calculate(NX_SHA1 *context, UCHAR digest[20]); -VOID _nx_sha1_process_buffer(NX_SHA1 *context, UCHAR buffer[64]); - -#endif diff --git a/protocol_handlers/snmp/nxd_snmp.c b/protocol_handlers/snmp/nxd_snmp.c deleted file mode 100644 index dc0ee3ee..00000000 --- a/protocol_handlers/snmp/nxd_snmp.c +++ /dev/null @@ -1,23756 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** Simple Network Management Protocol (SNMP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_SNMP_SOURCE_CODE - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nxd_snmp.h" - -#ifndef NX_IPV6_UTIL_INLINE -extern void COPY_NXD_ADDRESS(NXD_ADDRESS *copy_from, NXD_ADDRESS *copy_to); -#endif - - -/* To enable debug output, define this option. -#define NX_SNMPV3_PRINT_DEBUG_MESSAGE -*/ - -#define NX_SNMP_REQUEST_AUTH_SIZE 50 - -#ifndef NX_SNMP_DISABLE_V3 -/* Define locations in request buffer PDU in the event we need - to return the message e.g. error message response. */ -static UINT pdu_length; -static UCHAR *pdu_buffer_ptr; -static UCHAR *pdu_auth_parm_ptr; -static UCHAR *pdu_privacy_ptr; -#endif - -/* Enable or disable SNMPv3 debug message printout. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - #define NX_SNMPV3_DBG_PRINTF printf -#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE */ - - -/* Define global SNMP variables and strings. */ - -/* If the array size of _nx_snmp_v2_trap_ids is changed, these upper limit MUST by updated! */ -#define TRAP_ID_MAX 5 -UCHAR *_nx_snmp_v2_trap_ids[] = { (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss) */ - }; - - - -#ifndef NX_SNMP_DISABLE_V3 - -UCHAR *_nx_snmp_v3_trap_ids[] = { (UCHAR *) "1.3.6.1.6.3.1.1.5.1.0" /* (coldStart) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.2.0" /* (warmStart) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.3.0" /* (linkDown) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.4.0" /* (linkUp) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.5.0" /* (authenticationFailure) */, - (UCHAR *) "1.3.6.1.6.3.1.1.5.6.0" /* (egpNeighborLoss) */ - }; - -/* Define the default context engine information. This will be setup when the SNMP agent is - created. Note that this information isn't used for SNMP v1 and v2. Note the host application - should use the nx_snmp_agent_context_engine_set() service to set its own IPv4 (or MAC address - depending on format type) when creating the Engine ID. The engine size must match the total engine - data including the input context engine data as well. See documentation for more details. - - Note that this information isn't used for SNMP v1 and v2. */ - -UCHAR _nx_snmp_default_context_engine[NX_SNMP_MAX_CONTEXT_STRING] = {0x80, 0x00, 0x03, 0x10, 0x01, 0xc0, 0xa8, 0x64, 0xaf}; -UINT _nx_snmp_default_context_engine_size = 9; - -CHAR _nx_snmp_default_initial_user_name[] = "initial"; - -#endif - -/* As per RFC 3414 for SNMPv3 the discovery report must include the usmStats variables. */ -#define NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC "1.3.6.1.6.3.15.1.1.1.0" -#define NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM 1 -#define NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME "1.3.6.1.6.3.15.1.1.2.0" -#define NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM 2 -#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME "1.3.6.1.6.3.15.1.1.3.0" -#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM 3 -#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID "1.3.6.1.6.3.15.1.1.4.0" -#define NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM 4 - -/* Define the maximum difference between local time (in seconds) and browser notion of - local time recommended by RFC 3413. */ -#define NX_SNMP_TIME_WINDOW 150 - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_authenticate_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP authentication key */ -/* specification function call. To disable authentication, set */ -/* the key pointer to null. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Authenticate key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_authenticate_key_use Actual authentication key */ -/* setup function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - { - - return(NX_PTR_ERROR); - } - - if (key != NX_NULL) - { - - /* Check for valid authentication type. */ - if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) - { - return NX_SNMP_UNSUPPORTED_AUTHENTICATION; - } - } - - /* Call actual service. */ - status = _nx_snmp_agent_authenticate_key_use(agent_ptr, key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_authenticate_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the authenticate key to use for checking the */ -/* digest of the request. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Authenticate key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -#ifdef NX_SNMP_NO_SECURITY - return NX_NOT_ENABLED; -#else - - /* Set the authenticate pointer so authentication will use the specified key. Note this - key must have been created prior to calling this routine. */ - agent_ptr -> nx_snmp_agent_v3_authentication_key = key; - - /* Return success to the caller. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trap_auth_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the error checking service for the setting the trap*/ -/* message authentication key. To disable trap key authentication, set */ -/* the key pointer to null. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Authenticate key for traps */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_auth_trap_key_use Actual set trap authentication*/ -/* key service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - { - - return(NX_PTR_ERROR); - } - - if (key != NX_NULL) - { - - /* Check for invalid authentication type. */ - if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) - { - - return NX_SNMP_UNSUPPORTED_AUTHENTICATION; - } - } - - /* Call actual service. */ - status = _nx_snmp_agent_auth_trap_key_use(agent_ptr, key); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_auth_trap_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the authenticate key to use for creating */ -/* authentication parameters in SNMPv3 trap messages. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Authenticate key for traps */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -#ifdef NX_SNMP_NO_SECURITY - return NX_NOT_ENABLED; -#else - - - /* Set the authenticate pointer so authentication will use the specified key. Note this - key must have been created prior to calling this routine. */ - agent_ptr -> nx_snmp_agent_v3_auth_trap_key = key; - - /* Return success to the caller. */ - return(NX_SUCCESS); - -#endif -} -#endif /* NX_SNMP_DISABLE_V3 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_community_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP community get */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string_ptr Pointer to the community */ -/* string destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_community_get Actual community get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (community_string_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_community_get(agent_ptr, community_string_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_community_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the community string. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string_ptr Pointer to the community */ -/* string destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr) -{ - - /* Set a pointer to the community string for the caller. */ - *community_string_ptr = agent_ptr -> nx_snmp_agent_current_community_string; - - /* Return successful status. */ - return(NX_SUCCESS); -} - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_context_engine_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP context engine set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* context_engine Pointer to context engine */ -/* context_engine_size Number of bytes in the */ -/* context engine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_context_engine_set Actual context engine set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (context_engine == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for an invalid size. */ - if ((context_engine_size == 0) || (context_engine_size >= NX_SNMP_MAX_CONTEXT_STRING)) - return(NX_SNMP_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_context_engine_set(agent_ptr, context_engine, context_engine_size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_context_engine_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the context engine of the specified SNMP agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* context_engine Pointer to context engine */ -/* context_engine_size Number of bytes in the */ -/* context engine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size) -{ - -UINT i; - - - /* Verify V3 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) - { - return NX_NOT_ENABLED; - } - - /* Determine if the context engine is the correct size. */ - if (context_engine_size > NX_SNMP_MAX_CONTEXT_STRING) - { - - /* Return an error. */ - return(NX_SNMP_ERROR); - } - - /* Otherwise, store the context engine. */ - for (i = 0; i < context_engine_size; i++) - { - - /* Store a byte of the context engine. */ - agent_ptr -> nx_snmp_agent_v3_context_engine[i] = context_engine[i]; - } - - /* Set the context engine length. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_size = context_engine_size; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_context_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP context name set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* context_name Pointer to context name */ -/* context_name_size Number of bytes in the */ -/* context name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_context_name_set Actual context name set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Initialization */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (context_name == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for an invalid size. */ - if ((context_name_size == 0) || (context_name_size >= NX_SNMP_MAX_USER_NAME)) - return(NX_SNMP_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_context_name_set(agent_ptr, context_name, context_name_size); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_context_name_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the context name of the specified SNMP agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* context_name Pointer to context name */ -/* context_name_size Number of bytes in the */ -/* context name */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Initialization */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size) -{ - -UINT i; - - /* Determine if the context name is the correct size. */ - if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING) - { - - /* Return an error. */ - return(NX_SNMP_ERROR); - } - - /* Otherwise, store the context name. */ - for (i = 0; i < context_name_size; i++) - { - - /* Store a byte of the context name. */ - agent_ptr -> nx_snmp_agent_v3_context_name[i] = context_name[i]; - } - - /* Set the context name length. */ - agent_ptr -> nx_snmp_agent_v3_context_name_size = context_name_size; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_v3_context_boots_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP context boots set */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* boots Value to set agent boots to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_SNMP_ERROR Invalid boot count input */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_v3_context_boots_set Actual context boots set */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Initialization */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if (agent_ptr == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_v3_context_boots_set(agent_ptr, boots); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_v3_context_boots_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the context boot count of the specified SNMP */ -/* agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* boots Value to set agent boots to */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNMP_ERROR Invalid boot count input */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Initialization */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots) -{ - - /* Set the context name length. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boots = boots; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* snmp_agent_name Name of SNMP agent */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to stack for SNMP */ -/* thread */ -/* stack_size Size in bytes of thread stack */ -/* pool_ptr Default packet pool */ -/* snmp_agent_username_process Username callback routine */ -/* snmp_agent_get_process Get callback routine */ -/* snmp_agent_getnext_process Getnext callback routine */ -/* snmp_agent_set_process Set callback routine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_create Actual agent create function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), - UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id == NX_SNMP_ID) || (ip_ptr == NX_NULL) || (stack_ptr == NX_NULL) || - (pool_ptr == NX_NULL) || (!snmp_agent_username_process) || (!snmp_agent_get_process) || (!snmp_agent_getnext_process) || (!snmp_agent_set_process)) - return(NX_PTR_ERROR); - - /* Check for an invalid size. */ - if (stack_size == 0) - return(NX_SNMP_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_create(agent_ptr, snmp_agent_name, ip_ptr, stack_ptr, stack_size, pool_ptr, - snmp_agent_username_process, snmp_agent_get_process, snmp_agent_getnext_process, snmp_agent_set_process); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an SNMP agent. */ -/* */ -/* Note: The string length of username in snmp_agent_username_process */ -/* callback is limited by NX_SNMP_MAX_USER_NAME. */ -/* The string length of object_requested in snmp_agent_get_process, */ -/* snmp_agent_getnext_process and snmp_agent_set_process callback is */ -/* limited by NX_SNMP_MAX_OCTET_STRING. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* snmp_agent_name Name of SNMP agent */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Pointer to stack for SNMP */ -/* thread */ -/* stack_size Size in bytes of thread stack */ -/* pool_ptr Default packet pool */ -/* snmp_agent_username_process Username callback routine */ -/* snmp_agent_get_process Get callback routine */ -/* snmp_agent_getnext_process Getnext callback routine */ -/* snmp_agent_set_process Set callback routine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_bind Bind SNMP agent socket */ -/* nx_udp_socket_create Create SNMP agent socket */ -/* nx_udp_socket_delete Delete SNMP agent socket */ -/* nx_udp_socket_unbind Unbind SNMP agent socket */ -/* tx_thread_create Create SNMP agent thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), - UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)) -{ - -UINT status; - -#ifndef NX_SNMP_DISABLE_V3 -UINT i; -#endif - - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF( "Creating snmp agent of size %d\n\r", stack_size); -#endif - - /* Clear the SNMP agent structure. */ - memset((void *) agent_ptr, 0, sizeof(NX_SNMP_AGENT)); - - /* Create the agent's UDP socket. */ - status = nx_udp_socket_create(ip_ptr, &(agent_ptr -> nx_snmp_agent_socket), snmp_agent_name, - NX_SNMP_TYPE_OF_SERVICE, NX_SNMP_FRAGMENT_OPTION, - NX_SNMP_TIME_TO_LIVE, NX_SNMP_QUEUE_DEPTH); - - /* Determine if an error occurred. */ - if (status) - { - - /* Yes, return error code. */ - return(NX_SNMP_ERROR); - } - - /* Now create the SNMP Server thread. */ - status = tx_thread_create(&(agent_ptr -> nx_snmp_agent_thread), "SNMP Agent Thread", _nx_snmp_agent_thread_entry, - (ULONG) agent_ptr, stack_ptr, stack_size, NX_SNMP_AGENT_PRIORITY, NX_SNMP_AGENT_PRIORITY, - TX_NO_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred creating the thread. */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); - - /* Yes, return error code. */ - return(NX_SNMP_ERROR); - } - - /* Save the Server name. */ - agent_ptr -> nx_snmp_agent_name = snmp_agent_name; - - /* Save the IP pointer address. */ - agent_ptr -> nx_snmp_agent_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - agent_ptr -> nx_snmp_agent_packet_pool_ptr = pool_ptr; - - /* Default the SNMP network interface to the primary interface. */ - agent_ptr -> nx_snmp_agent_interface_index = 0; - - /* Initialize the agent as configured for all versions. - - Note that the #define options for disabling version support override dynamic version status. - - For example if NX_SNMP_DISABLE_V2 is disabled, setting nx_snmp_agent_v2_enabled - to NX_TRUE has no effect. If NX_SNMP_DISABLE_V2 is not disabled, then - nx_snmp_agent_v2_enabled determines at run time if the SNMP is enabled for V2.*/ - - agent_ptr -> nx_snmp_agent_v1_enabled = NX_TRUE; - agent_ptr -> nx_snmp_agent_v2_enabled = NX_TRUE; - agent_ptr -> nx_snmp_agent_v3_enabled = NX_TRUE; - - -#ifndef NX_SNMP_DISABLE_V3 - - /* Setup the SNMP v3 information. */ - - /* Setup the default context engine. */ - for (i = 0; i < _nx_snmp_default_context_engine_size; i++) - { - - /* Copy byte of default context engine. */ - agent_ptr -> nx_snmp_agent_v3_context_engine[i] = _nx_snmp_default_context_engine[i]; - } - - /* Set the default context engine size. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_size = _nx_snmp_default_context_engine_size; - - /* Start the time (in ticks) since the previous reboot. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - -#endif /* NX_SNMP_DISABLE_V3 */ - - /* Save the application request processing callback routines. */ - agent_ptr -> nx_snmp_agent_get_process = snmp_agent_get_process; - agent_ptr -> nx_snmp_agent_getnext_process = snmp_agent_getnext_process; - agent_ptr -> nx_snmp_agent_set_process = snmp_agent_set_process; - agent_ptr -> nx_snmp_agent_username_process = snmp_agent_username_process; - - /* Set the agent ID to indicate the SNMP agent thread is ready. */ - agent_ptr -> nx_snmp_agent_id = NX_SNMP_ID; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_request_get_type_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent get current */ -/* request type. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* is_get_type Pointer to request type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_request_get_type_test Actual request type service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type) -{ -UINT status; - - if ((agent_ptr == NX_NULL) || (is_get_type == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_request_get_type_test(agent_ptr, is_get_type); - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_request_get_type_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function indicates if the current request recieved from the */ -/* SNMP manager is a Get type (GET, GETNEXT etc) of a SET type. It is */ -/* intended for use in the username_callback for the host application */ -/* to process the request for matching community string (private for */ -/* set requests, public for get requests). */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* is_get_type Pointer to request type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type) -{ - - *is_get_type = agent_ptr -> nx_snmp_agent_request_get_type; - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent delete */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_delete Actual agent delete function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_delete(agent_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes the previously created SNMP agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_delete Delete SNMP agent socket */ -/* nx_udp_socket_unbind Unbind SNMP agent socket */ -/* tx_thread_delete Delete SNMP agent thread */ -/* tx_thread_terminate Terminate SNMP agent thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr) -{ - - /* Terminate the SNMP thread. */ - tx_thread_terminate(&(agent_ptr -> nx_snmp_agent_thread)); - - /* Delete the SNMP thread. */ - tx_thread_delete(&(agent_ptr -> nx_snmp_agent_thread)); - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); - - /* Clear the agent ID to indicate the SNMP agent is deleted. */ - agent_ptr -> nx_snmp_agent_id = 0; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_current_version_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get the received */ -/* packet SNMP version service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* version Pointer to packet SNMP version*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_current_version_get Actual get version service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version) -{ -UINT status; - - if ((agent_ptr == NX_NULL) || (version == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_current_version_get(agent_ptr, version); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_current_version_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the received packet's SNMP version. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* version Pointer to packet SNMP version*/ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version) -{ - - *version = agent_ptr -> nx_snmp_agent_current_version; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_set_version PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for (dis)enabling the SNMP */ -/* agent for SNMPV1, SNMPV2 and SNMPV3. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* enabled_v1 V1 enable status */ -/* enabled_v2 V2 enable status */ -/* enabled_v3 V3 enable status */ -/* Enable = 1 (NX_TRUE) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3) -{ -UINT status; - - /* Check for invalid input */ - if (agent_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Call the actual service. */ - status = _nx_snmp_agent_version_set(agent_ptr, enabled_v1, enable_v2, enable_v3); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_version_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the SNMP agent status for SNMPV1, SNMPV2 and */ -/* SNMPV3. */ -/* */ -/* Note that the #define options for disabling version support override*/ -/* dynamic version status. */ -/* */ -/* For example if NX_SNMP_DISABLE_V2 is disabled, setting */ -/* nx_snmp_agent_v2_enabled to NX_TRUE has no effect. If */ -/* NX_SNMP_DISABLE_V2 is not disabled, then nx_snmp_agent_v2_enabled */ -/* determines at run time if the SNMP is enabled for V2. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* enabled_v1 V1 enable status */ -/* enabled_v2 V2 enable status */ -/* enabled_v3 V3 enable status */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3) -{ - - /* Set the agent status for each of the SNMP versions. */ - agent_ptr -> nx_snmp_agent_v1_enabled = enabled_v1; - - agent_ptr -> nx_snmp_agent_v2_enabled = enable_v2; - - agent_ptr -> nx_snmp_agent_v3_enabled = enable_v3; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the SNMP network interface for the SNMP agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* if_index SNMP network interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index) -{ -UINT status; - - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_set_interface(agent_ptr, if_index); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the SNMP network interface for the SNMP agent. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* if_index SNMP network interface index */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index) -{ - - agent_ptr -> nx_snmp_agent_interface_index = if_index; - - return NX_SUCCESS; -} - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_md5_key_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP md5 key create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the MD5 key */ -/* destination_key Destination for the MD5 key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_md5_key_create Actual agent MD5 key create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (password == NX_NULL) || (destination_key == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_md5_key_create(agent_ptr, password, destination_key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_md5_key_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an MD5 key. */ -/* */ -/* Note: new API nx_snmp_agent_md5_key_create_extended is encouraged */ -/* to use. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the MD5 key */ -/* destination_key Destination for the MD5 key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* _nx_snmp_agent_md5_key_create_extended Agent MD5 key create function*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) -{ - - -/* Verify SNMP security is not disabled for this project. */ -#ifdef NX_SNMP_NO_SECURITY - /* Security is not supported, clear the key and return an error. */ - destination_key -> nx_snmp_security_key_type = 0; - destination_key -> nx_snmp_security_key_size = 0; - - /* Return an error. */ - return(NX_NOT_ENABLED); -#else - -UINT status; -UINT password_length; - - - /* Calculate the password length. */ - if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH)) - { - return(NX_SIZE_ERROR); - } - - /* Check length of password. */ - if (password_length == 0) - { - return(NX_SNMP_FAILED); - } - - /* Call actual service. */ - status = _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key); - - /* Return status to the caller. */ - return(status); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_md5_key_create_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP md5 key create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the MD5 key */ -/* password_length Length of password */ -/* destination_key Destination for the MD5 key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_md5_key_create_extended */ -/* Actual agent MD5 key create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_md5_key_create_extended(agent_ptr, password, password_length, destination_key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_md5_key_create_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an MD5 key. */ -/* */ -/* Note: The string of password must be NULL-terminated and length */ -/* of string matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the MD5 key */ -/* password_length Length of password */ -/* destination_key Destination for the MD5 key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_md5_initialize Initialize the MD5 algorithm */ -/* _nx_md5_update MD5 algorithm update */ -/* _nx_md5_digest_calculate Calculate the MD5 key */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) -{ - - -/* Verify SNMP security is not disabled for this project. */ -#ifdef NX_SNMP_NO_SECURITY - /* Security is not supported, clear the key and return an error. */ - destination_key -> nx_snmp_security_key_type = 0; - destination_key -> nx_snmp_security_key_size = 0; - - /* Return an error. */ - return(NX_NOT_ENABLED); -#else - -NX_MD5 MD; -UCHAR *cp, password_buf[64]; -ULONG password_index = 0; -ULONG count = 0, i; -UINT temp_password_length; - - - /* Get the length of password string. */ - if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length)) - return(NX_SNMP_FAILED); - - /* Check the password string length. */ - if (password_length != temp_password_length) - return(NX_SNMP_FAILED); - - /* Initialize MD5. */ - _nx_md5_initialize(&MD); - - /* Use while loop until we've done 1 Megabyte. */ - while (count < 1048576) - { - - cp = password_buf; - for (i = 0; i < 64; i++) - { - - /* Take the next octet of the password, wrapping - to the beginning of the password as necessary. */ - *cp++ = password[password_index++ % password_length]; - } - _nx_md5_update(&MD, password_buf, 64); - count += 64; - } - _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key); /* tell MD5 we're done */ - - /* Now localize the key with the engineID and pass - through MD5 to produce final key - May want to ensure that engineLength <= 32, - otherwise need to use a buffer larger than 64 */ - if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32) - return(NX_SNMP_FAILED); - - memcpy(password_buf, destination_key -> nx_snmp_security_key, 16); - memcpy(password_buf+16, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size); - memcpy(password_buf+16+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 16); - - _nx_md5_initialize(&MD); - _nx_md5_update(&MD, password_buf, 32+agent_ptr -> nx_snmp_agent_v3_context_engine_size); - _nx_md5_digest_calculate(&MD, destination_key -> nx_snmp_security_key); - - /* Setup other information in the key structure. */ - destination_key -> nx_snmp_security_key_type = NX_SNMP_MD5_KEY; - destination_key -> nx_snmp_security_key_size = 16; - - /* Return successful completion to the caller. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_privacy_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP privacy key */ -/* specification function call. To disable encryption, set the */ -/* key pointer to null. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Pointer to key to use for */ -/* privacy (encryption) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_privacy_key_use Actual privacy key setup */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - return(NX_PTR_ERROR); - - if (key != NX_NULL) - { - - /* Check for valid privacy key type. */ - if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) - { - return NX_SNMP_INVALID_PDU_ENCRYPTION; - } - } - - /* Call actual service. */ - status = _nx_snmp_agent_privacy_key_use(agent_ptr, key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_privacy_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the specified key to use for privacy. To */ -/* disable authentication, set the key pointer to null. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Pointer to key to use for */ -/* privacy (encryption) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -#ifdef NX_SNMP_NO_SECURITY - return NX_NOT_ENABLED; -#else - - - /* Set the privacy pointer so encryption/decryption will use the specified key. Note this - key must have been created prior to calling this routine. */ - agent_ptr -> nx_snmp_agent_v3_privacy_key = key; - - /* Return success to the caller. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_priv_trap_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for setting the privacy key */ -/* for SNMPv3 trap messages. To disable trap key encryption, set */ -/* the key pointer to null. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Pointer to key to use for */ -/* privacy (encryption) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_priv_trap_key_use Actual set privacy key for */ -/* SNMPv3 trap messages service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - { - return(NX_PTR_ERROR); - } - - if (key != NX_NULL) - { - - /* Check for valid privacy key type. */ - if ((key -> nx_snmp_security_key_type != NX_SNMP_MD5_KEY) && (key -> nx_snmp_security_key_type != NX_SNMP_SHA_KEY)) - { - return(NX_SNMP_INVALID_PDU_ENCRYPTION); - } - } - - /* Call actual service. */ - status = _nx_snmp_agent_priv_trap_key_use(agent_ptr, key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_priv_trap_key_use PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the specified key to use for privacy for */ -/* sending SNMPv3 trap messages. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* key Pointer to key to use for */ -/* privacy (encryption) */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key) -{ - -#ifdef NX_SNMP_NO_SECURITY - return NX_NOT_ENABLED; -#else - - /* Set the privacy pointer so encryption/decryption will use the specified key. Note this - key must have been created prior to calling this routine. */ - agent_ptr -> nx_snmp_agent_v3_priv_trap_key = key; - - /* Return success to the caller. */ - return(NX_SUCCESS); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_sha_key_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP SHA key create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the SHA key */ -/* destination_key Destination for the SHA key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_sha_key_create Actual agent SHA key create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (password == NX_NULL) || (destination_key == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_sha_key_create(agent_ptr, password, destination_key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_sha_key_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an SHA key. */ -/* */ -/* Note: new API nx_snmp_agent_sha_key_create_extended is encouraged */ -/* to use. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the SHA key */ -/* destination_key Destination for the SHA key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key) -{ - -/* Verify SNMP security is not disabled for this project. */ -#ifdef NX_SNMP_NO_SECURITY - - /* Security is not supported, clear the key and return an error. */ - destination_key -> nx_snmp_security_key_type = 0; - destination_key -> nx_snmp_security_key_size = 0; - - /* Return an error. */ - return(NX_NOT_ENABLED); -#else - -UINT status; -UINT password_length; - - - /* Calculate the password length. */ - if (_nx_utility_string_length_check((CHAR *)password, &password_length, NX_MAX_STRING_LENGTH)) - { - return(NX_SIZE_ERROR); - } - - /* Check length of password. */ - if (password_length == 0) - { - return(NX_SNMP_FAILED); - } - - /* Call actual service. */ - status = _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key); - - /* Return status. */ - return(status); -#endif /* NX_SNMP_NO_SECURITY */ - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_sha_key_create_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP SHA key create */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the SHA key */ -/* password_length Length of password */ -/* destination_key Destination for the SHA key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_sha_key_create_extended Actual agent SHA key create */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (password == NX_NULL) || (password_length == 0) || (destination_key == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_sha_key_create_extended(agent_ptr, password, password_length, destination_key); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_sha_key_create_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an SHA key. */ -/* */ -/* Note: The string of password must be NULL-terminated and length */ -/* of string matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* password Password for the SHA key */ -/* password_length Length of password */ -/* destination_key Destination for the SHA key */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sha1_initialize Initialize the SHA algorithm */ -/* _nx_sha1_update SHA algorithm update */ -/* _nx_sha1_digest_calculate Calculate the SHA key */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key) -{ - -/* Verify SNMP security is not disabled for this project. */ -#ifdef NX_SNMP_NO_SECURITY - - /* Security is not supported, clear the key and return an error. */ - destination_key -> nx_snmp_security_key_type = 0; - destination_key -> nx_snmp_security_key_size = 0; - - /* Return an error. */ - return(NX_NOT_ENABLED); -#else - -NX_SHA1 SH; -UCHAR *cp, password_buf[72]; -ULONG password_index = 0; -ULONG count = 0, i; -UINT temp_password_length; - - - /* Get the length of password string. */ - if (_nx_utility_string_length_check((CHAR *)password, &temp_password_length, password_length)) - return(NX_SNMP_FAILED); - - /* Check the password string length. */ - if (password_length != temp_password_length) - return(NX_SNMP_FAILED); - - memset(&SH, 0, sizeof(NX_SHA1)); - memset(&password_buf[0], 0, 72); - memset(destination_key, 0, sizeof(NX_SNMP_SECURITY_KEY)); - - /* Initialize SHA. */ - _nx_sha1_initialize(&SH); - - /* Use while loop until we've done 1 Megabyte. */ - while (count < 1048576) - { - - cp = password_buf; - for (i = 0; i < 64; i++) - { - - /* Take the next octet of the password, wrapping - to the beginning of the password as necessary. */ - *cp++ = password[password_index++ % password_length]; - } - _nx_sha1_update(&SH, password_buf, 64); - count += 64; - } - _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key); /* tell SHA we're done */ - - /* Now localize the key with the engineID and pass - through SHA to produce final key - May want to ensure that engineLength <= 32, - otherwise need to use a buffer larger than 72. */ - if(agent_ptr -> nx_snmp_agent_v3_context_engine_size > 32) - return(NX_SNMP_FAILED); - - memcpy(password_buf, destination_key -> nx_snmp_security_key, 20); - memcpy(password_buf+20, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size); - memcpy(password_buf+20+agent_ptr -> nx_snmp_agent_v3_context_engine_size, destination_key -> nx_snmp_security_key, 20); - - _nx_sha1_initialize(&SH); - _nx_sha1_update(&SH, password_buf, 40+agent_ptr -> nx_snmp_agent_v3_context_engine_size); - _nx_sha1_digest_calculate(&SH, destination_key -> nx_snmp_security_key); - - /* Setup other information in the key structure. */ - destination_key -> nx_snmp_security_key_type = NX_SNMP_SHA_KEY; - destination_key -> nx_snmp_security_key_size = 20; - - /* Return successful completion to the caller. */ - return(NX_SUCCESS); -#endif /* NX_SNMP_NO_SECURITY */ - -} -#endif /* NX_SNMP_DISABLE_V3 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_public_string_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the check of community */ -/* string against the agent's public community string. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to public string */ -/* is_public Pointer to outcome */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agents_public_string_test Check public string service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public) -{ - -UINT status; - - if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_public == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_public_string_test(agent_ptr, community_string, is_public); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_public_string_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs checks the input community string against the*/ -/* agent's public community string. */ -/* */ -/* Note: The string length of community_string is limited by */ -/* NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to public string */ -/* is_public Pointer to outcome */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public) -{ -UINT string_length1, string_length2; - - - if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME)) - { - return(NX_SIZE_ERROR); - } - - if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_public_community_string, &string_length2, NX_SNMP_MAX_USER_NAME)) - { - return(NX_SIZE_ERROR); - } - - /* Initialize the outcome */ - *is_public = NX_TRUE; - - if (string_length1 != string_length2) - { - /* Input string not the same as agent's public string. */ - *is_public = NX_FALSE; - return(NX_SUCCESS); - } - - /* The string lengths match, now match the actual strings. */ - if (memcmp(community_string, agent_ptr -> nx_snmp_agent_public_community_string, string_length1)) - { - - /* Input string not the same as agent's public string. */ - *is_public = NX_FALSE; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_private_string_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the nx_snmp_agent_receive_*/ -/* _private_string service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to received string */ -/* is_private Pointer to outcome */ -/* NX_TRUE if strings match */ -/* NX_FALSE if strings do not */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_private_string_test */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private) -{ - -UINT status; - - if ((agent_ptr == NX_NULL) || (community_string == NX_NULL) || (is_private == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_private_string_test(agent_ptr, community_string, is_private); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_private_string_test PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines if the community string of the received */ -/* SNMP packet matches the SNMP agent's private community string. */ -/* */ -/* Note: The string length of community_string is limited by */ -/* NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to received string */ -/* is_private Pointer to outcome */ -/* NX_TRUE if strings match */ -/* NX_FALSE if strings do not */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private) -{ -UINT string_length1, string_length2; - - if (_nx_utility_string_length_check((CHAR *)community_string, &string_length1, NX_SNMP_MAX_USER_NAME)) - { - return(NX_SIZE_ERROR); - } - - if (_nx_utility_string_length_check((CHAR *)agent_ptr -> nx_snmp_agent_private_community_string, &string_length2, NX_SNMP_MAX_USER_NAME)) - { - return(NX_SIZE_ERROR); - } - - /* Initialize the outcome */ - *is_private = NX_TRUE; - - if (string_length1 != string_length2) - { - /* Input string not the same as agent's private string. */ - *is_private = NX_FALSE; - return(NX_SUCCESS); - } - - /* The string lengths match, now match the actual strings. */ - if (memcmp(community_string, agent_ptr -> nx_snmp_agent_private_community_string, string_length1)) - { - - /* Input string not the same as agent's private string. */ - *is_private = NX_FALSE; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_private_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the nx_snmp_agent_set_ */ -/* _private_string service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to private string */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_private_string_set Set private string service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if ((agent_ptr == NX_NULL) || (community_string == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Call the actual service. */ - status = _nx_snmp_agent_private_string_set(agent_ptr, community_string); - - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_private_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the input string and size input as the Agent's */ -/* private string and private string size. */ -/* */ -/* Note: The string length of community_string is limited by */ -/* NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to private string */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) -{ - -UINT i; -UINT length; - - - /* Verify the string is not too large, leaving room for the null terminating string. */ - if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) - { - return NX_SNMP_ERROR_TOOBIG; - } - - /* Copy the string to the SNMP agent private community string. */ - for (i = 0; i < length; i++) - { - agent_ptr -> nx_snmp_agent_private_community_string[i] = *community_string; - community_string++; - } - - /* Null terminate the string. */ - agent_ptr -> nx_snmp_agent_private_community_string[i] = 0x0; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_public_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the nx_snmp_agent_set_ */ -/* _public_string service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to public string */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_public_string_set Set public string service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) -{ - -UINT status; - - if ((agent_ptr == NX_NULL) || (community_string == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_snmp_agent_public_string_set(agent_ptr, community_string); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_public_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the input string and size input as the Agent's */ -/* public string and public string size. */ -/* */ -/* Note: The string length of community_string is limited by */ -/* NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* community_string Pointer to public string */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string) -{ -UINT i; -UINT length; - - - /* Verify the string is not too large, leaving room for the null terminating character. */ - if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) - { - return NX_SNMP_ERROR_TOOBIG; - } - - /* Copy the string to the SNMP agent public community string. */ - for (i = 0; i < length; i++) - { - agent_ptr -> nx_snmp_agent_public_community_string[i] = *community_string; - community_string++; - } - - /* Null terminate the string. */ - agent_ptr -> nx_snmp_agent_public_community_string[i] = 0x0; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent start */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_start Actual agent start function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_start(NX_SNMP_AGENT *agent_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_start(agent_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the SNMP agent thread. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_resume Resume SNMP agent thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr) -{ - -UINT status; - - /* Bind the socket to a the well known SNMP UDP port number. */ - status = nx_udp_socket_bind(&(agent_ptr -> nx_snmp_agent_socket), NX_SNMP_AGENT_PORT, NX_NO_WAIT); - - /* Determine if an error occurred. */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(agent_ptr -> nx_snmp_agent_socket)); - - /* Yes, return error code. */ - return(NX_SNMP_ERROR); - } - - /* Start the SNMP agent thread. */ - tx_thread_resume(&(agent_ptr -> nx_snmp_agent_thread)); - - - /* Return successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent stop */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_stop Actual agent stop function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_stop(agent_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops the SNMP agent thread. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend SNMP agent thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr) -{ - - /* Stop the SNMP agent thread. */ - tx_thread_suspend(&(agent_ptr -> nx_snmp_agent_thread)); - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(agent_ptr -> nx_snmp_agent_socket)); - - /* Return successful status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry function of the SNMP agent thread. */ -/* */ -/* INPUT */ -/* */ -/* snmp_agent_address Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy Copy SNMP packet */ -/* nx_packet_release Release original SNMP packet */ -/* _nx_snmp_utility_sequence_get Get sequence number in packet */ -/* _nx_snmp_utility_version_get Get SNMP version number */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* nx_udp_socket_receive Receive SNMP request */ -/* nx_udp_source_extract Extract source IP and port */ -/* from request */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_agent_thread_entry(ULONG snmp_agent_address) -{ - -NX_SNMP_AGENT *agent_ptr; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT length; -UINT version; -UINT status; -UINT sequence_length; -INT buffer_length; -#ifndef NX_DISABLE_PACKET_CHAIN -NX_PACKET *new_packet_ptr; -#endif - - - /* Setup the agent pointer. */ - agent_ptr = (NX_SNMP_AGENT *) snmp_agent_address; - - /* Loop to process SNMP Manager requests. */ - while(1) - { - - /* Wait for a SNMP Manager request. */ - status = nx_udp_socket_receive(&(agent_ptr -> nx_snmp_agent_socket), &packet_ptr, NX_WAIT_FOREVER); - - /* Check for a successful packet reception. */ - if (status) - { - - /* If the error is other than no packet received, update the internal error count. */ - if (status != NX_NO_PACKET) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - } - - /* Go back and wait for another packet. */ - continue; - } - - - /* Pickup the source information for the packet - do this before the packet copy since the information - prior to the prepend pointer is not copied! */ - nxd_udp_source_extract(packet_ptr, &(agent_ptr -> nx_snmp_agent_current_manager_ip), - &(agent_ptr -> nx_snmp_agent_current_manager_port)); - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Determine if we have to copy the packet into a packet from the SNMP pool. */ - if (packet_ptr -> nx_packet_next) - { - - /* Copy the packet into a packet from the SNMP pool. */ - status = nx_packet_copy(packet_ptr, &new_packet_ptr, agent_ptr -> nx_snmp_agent_packet_pool_ptr, NX_SNMP_AGENT_TIMEOUT); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Determine if the copy was successful. */ - if (status || (new_packet_ptr -> nx_packet_next != NX_NULL)) - { - - /* No, the packet copy was not successful. */ - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Go back and wait for another packet. */ - continue; - } - - /* Otherwise, copy the new packet pointer to the standard packet pointer. */ - packet_ptr = new_packet_ptr; - } - -#endif /*NX_DISABLE_PACKET_CHAIN */ - - buffer_length = (INT)(packet_ptr -> nx_packet_length); - - /* Setup a pointer to the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the SEQUENCE field. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the unknown command error. */ - agent_ptr -> nx_snmp_agent_unknown_requests++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Go back and wait for another packet. */ - continue; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP VERSION field. */ - length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the unknown command error. */ - agent_ptr -> nx_snmp_agent_unknown_requests++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Go back and wait for another packet. */ - continue; - } - - /* Increment the total number of packets received. */ - agent_ptr -> nx_snmp_agent_packets_received++; - - /* We have a valid SNMP version, process relative to the type of SNMP version. */ - if (version == NX_SNMP_VERSION_1) - { - -#ifndef NX_SNMP_DISABLE_V1 - /* Verify V1 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE) - { - - /* It is not. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); - } - else - { - - /* Update the SNMP agent's version. */ - agent_ptr -> nx_snmp_agent_current_version = version; - - /* Process SNMP Version 1 request. */ - _nx_snmp_version_1_process(agent_ptr, packet_ptr); - } -#else - - - /* Invalid version. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); -#endif - } -#ifdef NX_SNMP_V2C_ONLY - else if (version == NX_SNMP_VERSION_2C) -#else - else if ((version == NX_SNMP_VERSION_2) || (version == NX_SNMP_VERSION_2C)) -#endif - { - -#ifndef NX_SNMP_DISABLE_V2 - - /* Verify V2 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE) - { - /* It is not. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); - } - else - { - /* Update the SNMP agent's version. */ - agent_ptr -> nx_snmp_agent_current_version = version; - - - /* Process SNMP Version 2 request. */ - _nx_snmp_version_2_process(agent_ptr, packet_ptr); - } -#else - - /* Invalid version. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); -#endif - } - else if (version == NX_SNMP_VERSION_3) - { - -#ifndef NX_SNMP_DISABLE_V3 - - /* Verify V3 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) - { - - /* It is not. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); - } - else - { - /* Update the SNMP agent's version. */ - agent_ptr -> nx_snmp_agent_current_version = version; - - /* Process SNMP Version 3 request. */ - _nx_snmp_version_3_process(agent_ptr, packet_ptr); - } -#else - - /* Invalid version. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); -#endif - } - else - { - - /* Invalid version. Increment error counter. */ - agent_ptr -> nx_snmp_agent_invalid_version++; - - /* Release packet. */ - nx_packet_release(packet_ptr); - } - } -} - - -#ifndef NX_SNMP_DISABLE_V1 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trap_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMPv1 trap send service. */ -/* */ -/* Developers are encouraged to use the nxd_snmp_agent_trap_send */ -/* service which supports IPv4 and IPv6 types. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* community Community string */ -/* enterprise Identifies the device that is */ -/* generating the trap */ -/* trap_type Type of trap */ -/* trap_code Additional trap information */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_trap_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, - UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL) || (enterprise == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid IP address. */ - if (ip_address == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_trap_send(agent_ptr, ip_address, community, enterprise, trap_type, trap_code, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(enterprise); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(trap_code); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_trap_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores the input IPv4 destination IP address in a NetX*/ -/* Duo data type that supports IPv4 and IPv6 address formats, and */ -/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ -/* and send the SNMPv1 trap message. */ -/* */ -/* Developers are encouraged to use nxd_snmp_agent_trap_send. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* community Community string */ -/* enterprise Identifies the device that is */ -/* generating the trap */ -/* trap_type Type of trap */ -/* trap_code Additional trap information */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_NOT_ENABLED Agent not enabled for V1 */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trap_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, - UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS ip_netxduo_address; - - - ip_netxduo_address.nxd_ip_address.v4 = ip_address; - ip_netxduo_address.nxd_ip_version = NX_IP_VERSION_V4; - - status = _nxd_snmp_agent_trap_send(agent_ptr, &ip_netxduo_address, community, enterprise, - trap_type, trap_code, elapsed_time, object_list_ptr); - - return status; -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(enterprise); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(trap_code); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_snmp_agent_trap_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMPv1 trap send service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community string */ -/* enterprise Identifies the device that is */ -/* generating the trap */ -/* trap_type Type of trap */ -/* trap_code Additional trap information */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trap_send Actual SNMPv1 trap send */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, - UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (community == NX_NULL) || (enterprise == NX_NULL) || (ip_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nxd_snmp_agent_trap_send(agent_ptr, ip_address, community, enterprise, trap_type, trap_code, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_snmp_agent_trap_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v1 trap message to the input */ -/* destination address. This service supports both IPv4 and IPv6 */ -/* addresses. */ -/* */ -/* Note: The string length of community and enterprise are limited by */ -/* the packet payload and NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community string */ -/* enterprise Identifies the device that is */ -/* generating the trap */ -/* trap_type Type of trap */ -/* trap_code Additional trap information */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate SNMP trap packet */ -/* nx_packet_release Release SNMP packet */ -/* nx_udp_socket_send Send SNMP trap via UDP */ -/* _nx_snmp_object_copy Copy object */ -/* _nx_snmp_utility_community_set Set the community name */ -/* _nx_snmp_utility_object_data_set Set the data value */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_version_set Set the SNMP v1 */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, - UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; -UINT trap_length; -UCHAR *trap_object_ptr; -NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; -NX_SNMP_OBJECT_DATA trap_object_data; -NX_PACKET *trap_packet_ptr; -UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; -UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; -UINT packet_type; - - - /* Verify V1 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v1_enabled == NX_FALSE) - { - - return NX_NOT_ENABLED; - } - - /* Now prepare trap message so we can process the variables one by one. */ - - - /* Determine which packet type we allocate based on the destination address type. */ - if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif /* FEATURE_NX_IPV6 */ - } - else - { - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; - } - - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a trap packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the trap packet. */ - trap_sequence_length = 0; - trap_type_length = 0; - trap_variable_list_length = 0; - - /* Setup a pointer to the trap packet's buffer area. */ - trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the trap sequence pointer. Remember it since we are going to have to - update it later with the actual length of the trap. */ - trap_sequence_ptr = trap_buffer_ptr; - - /* First, write the sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Now set the Version ID in the trap message. */ - trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_1, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the community in the trap message. */ - trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Remember the request type pointer, since it will need to be updated later. */ - trap_type_ptr = trap_buffer_ptr; - - /* Now set the request type in the trap message. */ - trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the enterprise ID in the trap message. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, enterprise, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the agent's IP address. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_IP_ADDRESS; - - -#ifndef NX_DISABLE_IPV4 - trap_object_data.nx_snmp_object_data_msw = - (LONG)(agent_ptr -> nx_snmp_agent_ip_ptr) -> nx_ip_interface[agent_ptr -> nx_snmp_agent_interface_index].nx_interface_ip_address; -#else - trap_object_data.nx_snmp_object_data_msw = 0; -#endif /* NX_DISABLE_IPV4 */ - - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Check that we have a valid trap type requested. */ - if (trap_type > TRAP_ID_MAX) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Set the trap type. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_INTEGER; - trap_object_data.nx_snmp_object_data_msw = (LONG)trap_type; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - if (trap_length == 0) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the specific trap type. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_INTEGER; - trap_object_data.nx_snmp_object_data_msw = (LONG)trap_code; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the specific time-stamp. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; - trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the trap's variable list field. */ - trap_variable_list_ptr = trap_buffer_ptr; - - /* Set up the variable list. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if an object is specified. */ - if (object_list_ptr) - { - - /* Setup object pointers from the supplied object list. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - - /* Loop to process all the objects in the list. */ - while (trap_object_ptr) - { - - /* Clear the trap variable length. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the object into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if there are more objects to insert into the trap message. */ - if (object_list_ptr) - { - - /* Move to the next object in the list. */ - object_list_ptr++; - - if (object_list_ptr == NX_NULL) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Determine if there is another object. */ - if (object_list_ptr -> nx_snmp_object_string_ptr) - { - - /* Setup the object and object data pointers. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - } - } - - /* At this point, several trap fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); - - /* Now the trap packet's pointers must be setup so it can be sent. */ - trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); - trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_traps_sent++; - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Send the trap packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, - ip_address, NX_SNMP_MANAGER_TRAP_PORT); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - } - - /* Return completion status. */ - return(status); -} -#endif /* NX_SNMP_DISABLE_V1 */ - - -#ifndef NX_SNMP_DISABLE_V2 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trapv2_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMPv2 trap send service. */ -/* */ -/* Developers are encouraged to use the nxd_snmp_agent_trapv2_send */ -/* service which supports IPv4 and IPv6 types. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* community Community name */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_trapv2_send Actual NetX (IPv4) SNMP trap */ -/* send service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (community == NX_NULL) || (ip_address == 0)) - return(NX_PTR_ERROR); - - /* Call actual netx service. */ - status = _nx_snmp_agent_trapv2_send(agent_ptr, ip_address, community, trap_type, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_trapv2_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores the input IPv4 destination IP address in a NetX*/ -/* Duo data type that supports IPv4 and IPv6 address formats, and */ -/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ -/* and send the SNMPv2 trap message. */ -/* */ -/* Developers are encouraged to use nxd_snmp_agent_trapv2_send. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* community Community name */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_NOT_ENABLED Agent not enabled for V2 */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv2_send Actual NetX Duo SNMP trap */ -/* send service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, - NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS ip_nxduo_address; - - - ip_nxduo_address.nxd_ip_version = NX_IP_VERSION_V4; - ip_nxduo_address.nxd_ip_address.v4 = ip_address; - - status = _nxd_snmp_agent_trapv2_send(agent_ptr, &ip_nxduo_address, community, trap_type, elapsed_time, object_list_ptr); - - return status; -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_snmp_agent_trapv2_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMPv2 trap send service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv2_send Actual SNMPv2 trap send */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, - NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || - (community == NX_NULL) || (ip_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nxd_snmp_agent_trapv2_send(agent_ptr, ip_address, community, trap_type, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_snmp_agent_trapv2_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMPv2 trap message to the input */ -/* destination address. This service supports both IPv4 and IPv6 */ -/* addresses. */ -/* */ -/* Note: The string length of community is limited by the packet */ -/* payload and NX_SNMP_MAX_USER_NAME. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate SNMP trap packet */ -/* nx_packet_release Release SNMP packet */ -/* nx_udp_socket_send Send SNMP trap via UDP */ -/* _nx_snmp_object_copy Copy object */ -/* _nx_snmp_utility_community_set Set the community name */ -/* _nx_snmp_utility_error_info_set Set error information */ -/* _nx_snmp_utility_object_data_set Set the data value */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ -/* _nx_snmp_utility_request_id_set Set the Trap ID */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_version_set Set the SNMP v1 */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, - ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; -UINT trap_length; -UCHAR *trap_object_ptr; -NX_SNMP_OBJECT_DATA trap_object_data; -NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; -NX_PACKET *trap_packet_ptr; -UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; -UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; -UINT packet_type; - - - /* Verify V2 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v2_enabled == NX_FALSE) - { - return NX_NOT_ENABLED; - } - - /* Determine which packet type we allocate based on the destination address type. */ - if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) - { -#ifndef FEATURE_NX_IPV6 - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif - } - else - { - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; - } - - - /* Now prepare trap message so we can process the variables one by one. */ - - /* Allocate the packet for the SNMP v2 trap. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a trap packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the trap packet. */ - trap_sequence_length = 0; - trap_type_length = 0; - trap_variable_list_length = 0; - trap_variable_length = 0; - - /* Setup a pointer to the trap packet's buffer area. */ - trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the trap sequence pointer. Remember it since we are going to have to - update it later with the actual length of the trap. */ - trap_sequence_ptr = trap_buffer_ptr; - - /* First, write the sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Now set the Version ID in the trap message. */ - trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the community in the trap message. */ - trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Remember the request type pointer, since it will need to be updated later. */ - trap_type_ptr = trap_buffer_ptr; - - /* Now set the request type in the trap message. */ - trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the trap ID in the trap message. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the trap error information. */ - trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the trap's variable list field. */ - trap_variable_list_ptr = trap_buffer_ptr; - - /* Setup the variable list. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the sysUpTime object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", - trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the SysTimerTicks into the trap buffer as the first item in the variable binding list. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; - trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Clear the trap variable size. */ - trap_variable_length = 0; - - /* Check that we have a valid trap type requested. */ - if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM)) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Check that we have a trap list if a custom trap is requested. */ - if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM)) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Check if this is an enumerated trap event. */ - if (trap_type <= TRAP_ID_MAX) - { - - /* Set up the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the snmpTrapOID object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", - trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Set an Object ID for the data. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; - trap_object_data.nx_snmp_object_data_msw = 0; - - /* Copy the object specified by the trap_type index. */ - _nx_snmp_object_copy(_nx_snmp_v2_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string); - - /* Add trap object data to trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - } - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if an object is specified. */ - if (object_list_ptr) - { - - /* Setup object pointers from the supplied object list. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - - /* Loop to process all the objects in the list. */ - while (trap_object_ptr) - { - - /* Clear the trap variable length. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the object into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if there are more objects to insert into the trap message. */ - if (object_list_ptr) - { - - /* Move to the next object in the list. */ - object_list_ptr++; - - if (object_list_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Determine if there is another object. */ - if (object_list_ptr -> nx_snmp_object_string_ptr) - { - - /* Setup the object and object data pointers. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - } - } - - /* At this point, several trap fields need to be updated with actual lengths. */ - - _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); - - /* Update the trap packet's pointers. */ - trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); - trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_traps_sent++; - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Send the trap packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, - ip_address, NX_SNMP_MANAGER_TRAP_PORT); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return an error. */ - return(NX_SNMP_ERROR); - } - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trapv2_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent v2 trap send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* OID OID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_trapv2_oid_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid IP address. */ - if (ip_address == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_trapv2_oid_send(agent_ptr, ip_address, community, oid, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(oid); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_trapv2__oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v2 trap message using the OID */ -/* directly from the caller. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* OID OID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv2_oid_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS ipduo_address; - - - ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; - ipduo_address.nxd_ip_address.v4 = ip_address; - - status = _nxd_snmp_agent_trapv2_oid_send(agent_ptr, &ipduo_address, community, oid, elapsed_time, object_list_ptr); - - return status; -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(community); - NX_PARAMETER_NOT_USED(oid); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_snmp_agent_trapv2_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent v2 trap send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* OID OID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv2_oid_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (community == NX_NULL) || - (ipduo_address == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Call actual service. */ - status = _nxd_snmp_agent_trapv2_oid_send(agent_ptr, ipduo_address, community, oid, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_snmp_agent_trapv2_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v2 trap message using the OID */ -/* directly from the caller. Supports IPv6 and IPv4 connections. */ -/* */ -/* Note: The string length of community is limited by the packet */ -/* payload and NX_SNMP_MAX_USER_NAME. The string length of oid is */ -/* limited by the packet payload and NX_SNMP_MAX_OCTET_STRING. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* OID OID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate SNMP trap packet */ -/* nx_packet_release Release SNMP packet */ -/* nx_udp_socket_send Send SNMP trap via UDP */ -/* _nx_snmp_object_copy Copy object */ -/* _nx_snmp_utility_community_set Set the community name */ -/* _nx_snmp_utility_error_info_set Set error information */ -/* _nx_snmp_utility_object_data_set Set the data value */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ -/* _nx_snmp_utility_request_id_set Set the Trap ID */ -/* _nx_snmp_utility_sequence_set_1byte */ -/* Set trap sequence */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_version_set Set the SNMP v1 */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; -UINT trap_length; -UCHAR *trap_object_ptr; -NX_SNMP_OBJECT_DATA trap_object_data; -NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; -NX_PACKET *trap_packet_ptr; -UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; -UINT trap_sequence_length, trap_type_length, trap_variable_list_length, trap_variable_length; -UINT packet_type = NX_UDP_PACKET; - - - if (ipduo_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - packet_type = NX_IPv6_UDP_PACKET; - } - else - { - packet_type = NX_IPv4_UDP_PACKET; - } - - /* Allocate the packet for the SNMP v2 trap. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a trap packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Now prepare trap message so we can process the variables one by one. */ - - /* Initialize the counters required for the length fields of the trap packet. */ - trap_sequence_length = 0; - trap_type_length = 0; - trap_variable_list_length = 0; - trap_variable_length = 0; - - /* Setup a pointer to the trap packet's buffer area. */ - trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the trap sequence pointer. Remember it since we are going to have to - update it later with the actual length of the trap. */ - trap_sequence_ptr = trap_buffer_ptr; - - /* First, write the sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Now set the Version ID in the trap message. */ - trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_2C, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the community in the trap message. */ - trap_length = _nx_snmp_utility_community_set(trap_buffer_ptr, community, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Remember the request type pointer, since it will need to be updated later. */ - trap_type_ptr = trap_buffer_ptr; - - /* Now set the request type in the trap message. */ - trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now set the trap ID in the trap message. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the trap error information. */ - trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the trap's variable list field. */ - trap_variable_list_ptr = trap_buffer_ptr; - - /* Setup the variable list. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the sysUpTime object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; - trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Clear the trap variable size. */ - trap_variable_length = 0; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the snmpTrapOID object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Set a Object ID for the data. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; - trap_object_data.nx_snmp_object_data_msw = 0; - - /* Check oid length. */ - if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING)) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string); - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if an object is specified. */ - if (object_list_ptr) - { - - /* Setup object pointers from the supplied object list. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - - /* Loop to process all the objects in the list. */ - while (trap_object_ptr) - { - - /* Clear the trap variable length. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the object into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if there are more objects to insert into the trap message. */ - if (object_list_ptr) - { - - /* Move to the next object in the list. */ - object_list_ptr++; - - if (object_list_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Determine if there is another object. */ - if (object_list_ptr -> nx_snmp_object_string_ptr) - { - - /* Setup the object and object data pointers. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - } - } - - /* At this point, several trap fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); - - /* Now the trap packet's pointers must be setup so it can be sent. */ - trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); - trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_traps_sent++; - agent_ptr -> nx_snmp_agent_packets_sent++; - - - /* Send the trap packet back to the requesting SNMP manager. */ - - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ipduo_address, NX_SNMP_MANAGER_TRAP_PORT); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return an error. */ - return(NX_SNMP_ERROR); - } - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -#endif /* NX_SNMP_DISABLE_V2 */ - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trapv3_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the NetX (IPv4) SNMP agent v3 */ -/* trap send service. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* username Username */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_trapv3_send Actual NetX (IPv4) SNMP agent */ -/* trap send service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, - ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) - || (username == NX_NULL) || (ip_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_trapv3_send(agent_ptr, ip_address, username, trap_type, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_trapv3_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stores the input IPv4 destination IP address in a NetX*/ -/* Duo data type that supports IPv4 and IPv6 address formats, and */ -/* uses the 'dual' trap send service _nxd_snmp_agent_trap_send to build*/ -/* and send the SNMPv3 trap message. */ -/* */ -/* Developers are encouraged to use nxd_snmp_agent_trapv3_send. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IPv4 address */ -/* username Username */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_NOT_ENABLED Agent not enabled for V3 */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv3_send Actual SNMPv3 trap send */ -/* service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, - ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS ip_nxduo_address; - - ip_nxduo_address.nxd_ip_version = NX_IP_VERSION_V4; - ip_nxduo_address.nxd_ip_address.v4 = ip_address; - - status = _nxd_snmp_agent_trapv3_send(agent_ptr, &ip_nxduo_address, username, trap_type, elapsed_time, object_list_ptr); - return status; -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(trap_type); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_snmp_agent_trapv3_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMPv3 trap send service. */ -/* */ -/* Developers are encouraged to use the nxd_snmp_agent_trapv3_send */ -/* service which supports IPv4 and IPv6 types. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* username Username */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv3_send Actual NetX Duo SNMP agent */ -/* trap send service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, - ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) - || (username == NX_NULL) || (ip_address == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nxd_snmp_agent_trapv3_send(agent_ptr, ip_address, username, trap_type, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_snmp_agent_trapv3_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v3 trap message to the input */ -/* destination address. This service supports both IPv4 and IPv6 */ -/* addresses. */ -/* */ -/* Note: The string length of username is limited by the packet */ -/* payload and NX_SNMP_MAX_OCTET_STRING. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* username Username */ -/* trap_type Type of trap */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_des_key_set Setup DES encryption */ -/* _nx_des_encrypt Encrypt bytes */ -/* _nx_md5_digest_calculate MD5 algorithm completion */ -/* _nx_md5_initialize MD5 algorithm initialization */ -/* _nx_md5_update MD5 algorithm computation */ -/* nx_packet_allocate Allocate SNMP trap packet */ -/* nx_packet_release Release SNMP packet */ -/* nx_udp_socket_send Send SNMP trap via UDP */ -/* _nx_snmp_object_copy Copy object */ -/* _nx_snmp_utility_error_info_set Set error information */ -/* _nx_snmp_utility_octet_set Set octet string */ -/* _nx_snmp_utility_object_data_set Set the data value */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ -/* _nx_snmp_utility_request_id_set Set the Request ID */ -/* _nx_snmp_utility_request_type_set_1byte Set trap request type */ -/* _nx_snmp_utility_version_set Set the SNMP v3 */ -/* _nx_sha1_digest_calculate SHA algorithm completion */ -/* _nx_sha1_initialize SHA algorithm initialization */ -/* _nx_sha1_update SHA algorithm computation */ -/* tx_time_get Get time */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, - NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; -UINT trap_length; -UCHAR *trap_object_ptr; -NX_SNMP_OBJECT_DATA trap_object_data; -NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; -NX_PACKET *trap_packet_ptr; -UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; -UINT trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length; -UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; -UINT i; -UCHAR *temp_ptr; -UINT j, padding; -UCHAR *trap_encryption_size_ptr = NX_NULL; -UCHAR *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; -UINT packet_type; -UCHAR message_security_options = 0; -UINT username_length; - - - /* Verify V3 is currently enabled for this agent. */ - if (agent_ptr -> nx_snmp_agent_v3_enabled == NX_FALSE) - { - - return NX_NOT_ENABLED; - } - - /* Determine which packet type we allocate based on the destination address type. */ - if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) - { -#ifndef FEATURE_NX_IPV6 - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif - } - else - { - return NX_SNMP_INVALID_IP_PROTOCOL_ERROR; - } - - /* Allocate the packet for the SNMP response. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a trap packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - memset(trap_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(trap_packet_ptr -> nx_packet_data_end - trap_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the trap packet. */ - trap_sequence_length = 0; - trap_header_length = 0; - trap_security_length = 0; - trap_pdu_length = 0; - trap_type_length = 0; - trap_variable_list_length = 0; - trap_variable_length = 0; - - /* Setup a pointer to the trap packet's buffer area. */ - trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap buffer response at 0x%x\n", trap_buffer_ptr); -#endif - /* This is also the trap sequence pointer. Remember it since we are going to have to - update it later with the actual length of the response. */ - trap_sequence_ptr = trap_buffer_ptr; - - /* First, write the sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - - /* Now set the Version ID in the trap message. */ - trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Save the pointer to the global header. */ - trap_header_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap3 header header at 0x%x\n", trap_header_ptr); -#endif - - /* Write the sequence for the global header in the trap packet. A zero is written for now. - This will be updated later. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /***************8 Now set the request ID. *********************8*/ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /********************* Now set the maximum message size. ***************************8*/ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /********************** Now set the security options e.g. Flags. ****************************/ - - /* Determine what the trap message security options are. These are not the same as - the general get/set request PDU options. */ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - message_security_options = NX_SNMP_SECURITY_AUTHORIZE; - } - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - message_security_options |= NX_SNMP_SECURITY_PRIVACY; - } - - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /******************* Now set the security type (always USM model). *********************/ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /* At this point, we have successfully built the security header. */ - - - /************************** Start the security parameters field. ************************/ - - /* First set up the octet string field. For now just put in zeros... we will update when - the actual size is known. */ - trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - trap_buffer_ptr[1] = 0; - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + 2; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + 2; - - /* Remember the security header length pointer. */ - trap_security_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap3 security header 0x%x\n", trap_security_ptr); -#endif - /* Now set the sequence of the USM security parameters. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /************************** Now set the context engine. ***************************/ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /****************** ***************** **********************/ - /* Now set BOOT COUNT. */ - /****************** ***************** **********************/ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /****************** ***************** **********************/ - /* Now set BOOT TIME. */ - /****************** ***************** **********************/ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Check username length. */ - if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING)) - { - return(NX_SIZE_ERROR); - } - - /****************** ***************** **********************/ - /* Now set USER NAME. */ - /****************** ***************** **********************/ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Initialize the temporary string to zero. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - temp_string[i] = 0; - - /****************** ***************** **********************/ - /* Now set AUTHENTICATION PARAMETER. */ - /****************** ***************** **********************/ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - - /* We have a valid authentication key, so initialize the string to zero. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end); - - trap_authentication_ptr = trap_buffer_ptr + 2; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr); -#endif - } - else - { - /* No security enabled so set this as an empty parameter. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - - /****************** ***************** **********************/ - /* Now set 8 char PRIVACY PARAMETER. */ - /****************** ***************** **********************/ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - - /* We will encrypt the message, so set to all zeros field initially. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end); - - trap_privacy_ptr = trap_buffer_ptr + 2; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr); -#endif - } - else - { - /* Not encrypting, so set the privacy field as an empty parameter. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* If privacy is required, set the response to have an encryption header. */ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - - /* Now setup the trap buffer to encapsulate the encrypted PDU. Note that - the actual encryption will be done after the complete trap has been - formed. */ - trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - trap_buffer_ptr[1] = 0x82; - trap_buffer_ptr[2] = 0x00; - trap_buffer_ptr[3] = 0x00; - - /* Save the trap encryption size pointer. This will be filled in below - as we build the message. */ - trap_encryption_size_ptr = trap_buffer_ptr + 2; - - /* Move the trap buffer forward. */ - trap_buffer_ptr = trap_buffer_ptr + 4; - - /* Increase the length of the total trap message. */ - trap_sequence_length = trap_sequence_length + 4; - } - - /* Save the trap pdu sequence pointer. */ - trap_pdu_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_pdu_ptr: 0x%x\n", trap_pdu_ptr); -#endif - - /****************** ***************** **********************/ - /* Now start the PDU SEQUENCE. */ - /****************** ***************** **********************/ - - /* A zero is written for now. This will be updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Increment the number of trap sequence bytes. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /****************************************************/ - /* Set the PDU engine ID */ - /****************************************************/ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (trap_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap pointer forward. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Increment the sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /****************************************************/ - /* Set the PDU engine name */ - /****************************************************/ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (trap_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap pointer forward. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Save the pointer to the trap type. */ - trap_type_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_type_ptr: 0x%x\n", trap_type_ptr); -#endif - - /* Increment the sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /****************************************************/ - /* Set the PDU request type */ - /****************************************************/ - trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /****************************************************/ - /* Set the PDU request ID */ - /****************************************************/ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up (this assumes two bytes but we may need more) . */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /****************************************************/ - /* Get the PDU error information */ - /****************************************************/ - - /* Assume everything is okay at this point. */ - trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the response's variable list field. */ - trap_variable_list_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_variable_list_ptr: 0x%x\n", trap_variable_list_ptr); -#endif - /* Setup the variable list. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_variable_ptr: 0x%x\n", trap_variable_ptr); -#endif - - /****************************************************/ - /* Start the PDU variable list length */ - /****************************************************/ - - /* Initialize the length to zero. We will update with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /****************************************************/ - /* Set the sysUpTime object ID */ - /****************************************************/ - - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", - trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /****************************************************/ - /* Set the sysUpTime Timer Ticks */ - /****************************************************/ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; - trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Clear the trap variable size. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Check for valid trap type. */ - if ((trap_type > TRAP_ID_MAX) && (trap_type != NX_SNMP_TRAP_CUSTOM)) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Check that we have a trap list if a custom trap is requested. */ - if ((object_list_ptr == NX_NULL) && (trap_type == NX_SNMP_TRAP_CUSTOM)) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Check if this is an enumerated trap type. */ - if (trap_type <= TRAP_ID_MAX) - { - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the snmpTrapOID object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", - trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Set a Object ID for the data. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; - trap_object_data.nx_snmp_object_data_msw = 0; - _nx_snmp_object_copy(_nx_snmp_v3_trap_ids[trap_type], trap_object_data.nx_snmp_object_octet_string); - - /* Add trap object data to trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - } - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if an object is specified. */ - if (object_list_ptr) - { - - /* Setup object pointers from the supplied object list. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - - /* Loop to process all the objects in the list. */ - while (trap_object_ptr) - { - - /* Clear the trap variable length. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the object into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set_1byte(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if there are more objects to insert into the trap message. */ - if (object_list_ptr) - { - - /* Move to the next object in the list. */ - object_list_ptr++; - - if (object_list_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Determine if there is another object. */ - if (object_list_ptr -> nx_snmp_object_string_ptr) - { - - /* Setup the object and object data pointers. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Next trap3 object data at 0x%x\n", trap_object_data_ptr); -#endif - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - } - } - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("\nSet trap3 sequence length at 0x%x to 0x%x\n Set global sequence length at 0x%x to 0x%x\n Set trap3 security length at 0x%x to 0x%x\n Set trap3 pdu length at 0x%x to 0x%x\n Set trap3 variable list length at 0x%x to 0x%x\n Set trap3 type length at 0x%x to 0x%x\n", - trap_sequence_ptr, trap_sequence_length, trap_header_ptr, trap_header_length, - trap_security_ptr, trap_security_length, trap_pdu_ptr, trap_pdu_length, - trap_variable_list_ptr, trap_variable_list_length, trap_type_ptr, trap_type_length); -#endif - - /* At this point, several trap fields need to be updated with actual lengths. */ - - _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set_1byte(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end); - - /* Setup the security OCTET string length. */ - - /* Backup to the OCTET string for the security size. */ - trap_security_ptr = trap_security_ptr - 2; -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Move trap3 security pointer by 2 0x%x (length %u)\n", trap_security_ptr, trap_security_length); -#endif - /* Account for the 2 byte Security Sequence field. */ - trap_security_length = trap_security_length + 2; - - /* Store the security size. */ - trap_security_ptr[1] = (UCHAR) (trap_security_length & 0xFF); - - /* Determine if privacy is required. If so, encrypt the PDU and setup the response - to have an encryption header. */ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - - /* Determine if any padding needs to be applied - account for the - two bytes of sequence information on the PDU. */ - trap_pdu_length = trap_pdu_length + 2; - padding = ((trap_pdu_length+7)/8)*8 - trap_pdu_length; - - /* Add the padding the trap PDU length and the trap sequence length. */ - trap_pdu_length = trap_pdu_length + padding; - trap_sequence_length = trap_sequence_length + padding; - - /* Clear the end of the trap message... just to be nice! */ - for (i = 0; i < padding; i++) - { - - /* Clear byte at the end of the response. */ - *trap_buffer_ptr++ = 0; - } - - /* Setup the size of the encrypted PDU. */ - trap_encryption_size_ptr[0] = (UCHAR) ((trap_pdu_length >> 8) & 0xFF); - trap_encryption_size_ptr[1] = (UCHAR) (trap_pdu_length & 0xFF); - - /* Update the total trap sequence length again. */ - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - - /* Increment the salt counter. */ - agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; - - /* Build the salt value for the decryption. */ - key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); - key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); - key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); - key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); - key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); - key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); - key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); - key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); - - /* Loop to store the salt in the privacy field. */ - for (i = 0; i < 8; i++) - { - - /* Store a byte of the salt. */ - trap_privacy_ptr[i] = key1[i]; - } - - /* Setup pointer to the actual PDU. */ - temp_ptr = trap_encryption_size_ptr + 2; - - /* Make the Initialization Vector (IV). */ - for (i = 0; i < 8; i++) - { - - key2[i] = (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i]; - } - - /* Setup the DES. */ - _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) -> nx_snmp_security_key); - - /* Setup the first input block - use the IV for the first block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[i] ^ key2[i]; - } - - /* Encrypt the first 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); - - /* Loop to encrypt the rest of the PDU. */ - j = 8; - do - { - - /* Setup the next input block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; - } - - /* Encrypt the next 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); - - /* Move the major index forward. */ - j = j + 8; - } while (j < trap_pdu_length); - } - - /* Now the trap packet's pointers must be setup so it can be sent. */ - trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); - trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; - - /* Determine if authentication is required. */ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - - /* Yes, authentication is required. */ - - /* Now determine which authentication is required. */ - if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) - { - - /* Copy the base MD5 key into key1. */ - for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base MD5 key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Calculate prepend Key1. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Prepend Key2 to the result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); - } - else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) - { - - /* Copy the base SHA key into key1. */ - for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base SHA key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Calculate prepend Key1. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Prepend Key2 to the result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); - } - else - { - - /* Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* At this point, key2 contains the computed digest of the message. This needs to be - place in the outgoing message. */ - - /* Loop to setup the outgoing digest. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - { - - /* Copy one byte of digest. */ - trap_authentication_ptr[i] = key2[i]; - } - } - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_traps_sent++; - agent_ptr -> nx_snmp_agent_packets_sent++; - agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length; - - /* Send the trap packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ip_address, NX_SNMP_MANAGER_TRAP_PORT); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return error. */ - return(NX_SNMP_ERROR); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_agent_trapv3_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent v3 trap send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* username Username */ -/* oid Enterprise ID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_agent_trapv3_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (username == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid IP address. */ - if (ip_address == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Call actual service. */ - status = _nx_snmp_agent_trapv3_oid_send(agent_ptr, ip_address, username, oid, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(oid); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_trapv3_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v3 trap message. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* username Username */ -/* OID Enterprise ID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv3_oid_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS ipduo_address; - - - ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; - ipduo_address.nxd_ip_address.v4 = ip_address; - - status = _nxd_snmp_agent_trapv3_oid_send(agent_ptr, &ipduo_address, username, oid, elapsed_time, object_list_ptr); - - return status; -#else - NX_PARAMETER_NOT_USED(agent_ptr); - NX_PARAMETER_NOT_USED(ip_address); - NX_PARAMETER_NOT_USED(username); - NX_PARAMETER_NOT_USED(oid); - NX_PARAMETER_NOT_USED(elapsed_time); - NX_PARAMETER_NOT_USED(object_list_ptr); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_snmp_agent_trapv3_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent v2 trap send */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* community Community name */ -/* OID OID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_snmp_agent_trapv3_oid_send Actual agent trap send */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((agent_ptr == NX_NULL) || (agent_ptr -> nx_snmp_agent_id != NX_SNMP_ID) || (username == NX_NULL) || - (ipduo_address == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Call actual service. */ - status = _nxd_snmp_agent_trapv3_oid_send(agent_ptr, ipduo_address, username, oid, elapsed_time, object_list_ptr); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_snmp_agent_trapv3_oid_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function builds and sends a SNMP v3 trap message. */ -/* */ -/* Note: The string length of username and oid are limited by the */ -/* packet payload and NX_SNMP_MAX_OCTET_STRING. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* ip_address Destination IP address */ -/* username Username */ -/* OID Enterprise ID to send */ -/* elapsed_time Elapsed time from last boot */ -/* of the device (sysUpTime) */ -/* object_list_ptr Variable list of application */ -/* objects to present with the */ -/* trap */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_des_key_set Setup DES encryption */ -/* _nx_des_encrypt Encrypt bytes */ -/* _nx_md5_digest_calculate MD5 algorithm completion */ -/* _nx_md5_initialize MD5 algorithm initialization */ -/* _nx_md5_update MD5 algorithm computation */ -/* nx_packet_allocate Allocate SNMP trap packet */ -/* nx_packet_release Release SNMP packet */ -/* nx_udp_socket_send Send SNMP trap via UDP */ -/* _nx_snmp_object_copy Copy object */ -/* _nx_snmp_utility_error_info_set Set error information */ -/* _nx_snmp_utility_octet_set Set octet string */ -/* _nx_snmp_utility_object_data_set Set the data value */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_sequence_set Set the ASN.1 sequence */ -/* _nx_snmp_utility_request_id_set Set the Request ID */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_version_set Set the SNMP v3 */ -/* _nx_sha1_digest_calculate SHA algorithm completion */ -/* _nx_sha1_initialize SHA algorithm initialization */ -/* _nx_sha1_update SHA algorithm computation */ -/* tx_time_get Get time */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr) -{ - -UINT status; -UINT trap_length; -UCHAR *trap_object_ptr; -NX_SNMP_OBJECT_DATA trap_object_data; -NX_SNMP_OBJECT_DATA *trap_object_data_ptr = NX_NULL; -NX_PACKET *trap_packet_ptr; -UCHAR *trap_buffer_ptr, *trap_sequence_ptr, *trap_header_ptr, *trap_security_ptr, *trap_pdu_ptr, *trap_type_ptr, *trap_variable_list_ptr, *trap_variable_ptr; -UINT trap_sequence_length, trap_header_length, trap_security_length, trap_pdu_length, trap_type_length, trap_variable_list_length, trap_variable_length; -UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; -UINT i; -#ifndef NX_SNMP_NO_SECURITY -UINT j, padding; -UCHAR *temp_ptr; -UCHAR *trap_encryption_size_ptr = NX_NULL; -UCHAR *trap_authentication_ptr = NX_NULL, *trap_privacy_ptr = NX_NULL; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; -#endif -UINT packet_type = NX_UDP_PACKET; -UCHAR message_security_options; -UINT username_length; - - - if (ipduo_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else - { - packet_type = NX_IPv6_UDP_PACKET; - } - - /* Allocate the packet for the SNMP response. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &trap_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a trap packet was allocated. */ - if (status != NX_SUCCESS) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return(NX_SNMP_ERROR); - - } - - - /* Initialize the counters required for the length fields of the trap packet. */ - trap_sequence_length = 0; - trap_header_length = 0; - trap_security_length = 0; - trap_pdu_length = 0; - trap_type_length = 0; - trap_variable_list_length = 0; - trap_variable_length = 0; - - /* Setup a pointer to the trap packet's buffer area. */ - trap_buffer_ptr = trap_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the trap sequence pointer. Remember it since we are going to have to - update it later with the actual length of the response. */ - trap_sequence_ptr = trap_buffer_ptr; - - /* First, write the sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Now set the Version ID in the trap message. */ - trap_length = _nx_snmp_utility_version_set(trap_buffer_ptr, NX_SNMP_VERSION_3, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Save the pointer to the global header. */ - trap_header_ptr = trap_buffer_ptr; - - /* Write the sequence for the global header in the trap packet. A zero is written for now. - This will be updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now setup the request ID. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /* Now setup the maximum message size. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /* Now setup the security options. */ - message_security_options = 0; - - /* Determine what the trap message security options are. These are not the same as - the general get/set request PDU options. */ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - message_security_options = NX_SNMP_SECURITY_AUTHORIZE; - } - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - message_security_options |= NX_SNMP_SECURITY_PRIVACY; - } - - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, (UCHAR *)&message_security_options, 1, trap_packet_ptr -> nx_packet_data_end); - - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /* Now setup the security type. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the header sequence length. */ - trap_header_length = trap_header_length + trap_length; - - /* At this point, we have successfully built the security header. Now, we need to build - the security parameters field. */ - - /* First setup the octet string field. */ - trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - trap_buffer_ptr[1] = 0x0; - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + 2; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + 2; - - /* Remember the security header length pointer. */ - trap_security_ptr = trap_buffer_ptr; - - /* Now set the sequence of the USM security parameters. */ - trap_length = _nx_snmp_utility_sequence_set_1byte(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now setup the context engine. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Now setup the number of engine boots. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Now setup the relative time since the last engine boot. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Check username length. */ - if (_nx_utility_string_length_check((CHAR *)username, &username_length, NX_SNMP_MAX_OCTET_STRING)) - { - return(NX_SIZE_ERROR); - } - - /* Now setup the user name, as specified by the input parameter. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, username, username_length, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Now setup the authentication parameter - it is a 12 character field set to zeros initially. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - temp_string[i] = 0; - - /****************** ***************** **********************/ - /* Now set AUTHENTICATION PARAMETER. */ - /****************** ***************** **********************/ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - - /* We have a valid authentication key, so initialize the string to zero. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, trap_packet_ptr -> nx_packet_data_end); - - trap_authentication_ptr = trap_buffer_ptr + 2; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap3 authentication header 0x%x\n", trap_authentication_ptr); -#endif - } - else - { - /* No security enabled so set this as an empty parameter. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /****************** ***************** **********************/ - /* Now set 8 char PRIVACY PARAMETER. */ - /****************** ***************** **********************/ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - - /* We will encrypt the message, so set to all zeros field initially. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string, 8, trap_packet_ptr -> nx_packet_data_end); - - trap_privacy_ptr = trap_buffer_ptr + 2; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Starting trap_privacy_ptr 0x%x\n", trap_privacy_ptr); -#endif - } - else - { - /* Not encrypting, so set the privacy field as an empty parameter. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, temp_string,0, trap_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Adjust the security sequence length. */ - trap_security_length = trap_security_length + trap_length; - - /* Determine if privacy is required. If so, decrypt the source PDU and setup the response - to have an encryption header. */ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - -#ifndef NX_SNMP_NO_SECURITY - - /* Now setup the trap buffer to encapsulate the encrypted PDU. Note that - the actual encryption will be done after the complete trap has been - formed. */ - trap_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - trap_buffer_ptr[1] = 0x82; - trap_buffer_ptr[2] = 0x00; - trap_buffer_ptr[3] = 0x00; - - /* Save the trap encryption size pointer. This will be filled in below - as we build the message. */ - trap_encryption_size_ptr = trap_buffer_ptr + 2; - - /* Move the trap buffer forward. */ - trap_buffer_ptr = trap_buffer_ptr + 4; - - /* Increase the length of the total trap message. */ - trap_sequence_length = trap_sequence_length + 4; - -#else - /* Encryption is not supported by this agent but is - specified in the request or by the agent. Simply - discard the message. */ - - /* Increment the privacy error counter. */ - agent_ptr -> nx_snmp_agent_privacy_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); -#endif - } - - /* Save the trap pdu sequence pointer. */ - trap_pdu_ptr = trap_buffer_ptr; - - /* First, write the PDU sequence in the trap packet. A zero is written for now. This will be - updated later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Increment the number of trap sequence bytes. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Now store the PDU context engine in the trap packet. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (trap_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap pointer forward. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Increment the sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Now store the PDU context name in the trap packet. */ - trap_length = _nx_snmp_utility_octet_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (trap_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap pointer forward. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Save the pointer to the trap type. */ - trap_type_ptr = trap_buffer_ptr; - - /* Increment the sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Setup the trap request type field. */ - trap_length = _nx_snmp_utility_request_type_set_multibyte(trap_buffer_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Now set the request ID in the trap message. */ - trap_length = _nx_snmp_utility_request_id_set(trap_buffer_ptr, agent_ptr -> nx_snmp_agent_traps_sent, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Set the trap error information. Assume everything is okay at this point. */ - trap_length = _nx_snmp_utility_error_info_set(trap_buffer_ptr, 0, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the response's variable list field. */ - trap_variable_list_ptr = trap_buffer_ptr; - - /* Setup the variable list. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the sysUpTime object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.2.1.1.3.0", trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_TIME_TICS; - trap_object_data.nx_snmp_object_data_msw = (LONG)elapsed_time; - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Clear the trap variable size. */ - trap_variable_length = 0; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the snmpTrapOID object ID into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, (UCHAR *) "1.3.6.1.6.3.1.1.4.1.0", trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Set a Object ID for the data. */ - trap_object_data.nx_snmp_object_data_type = NX_SNMP_ANS1_OBJECT_ID; - trap_object_data.nx_snmp_object_data_msw = 0; - - /* Check oid length. */ - if (_nx_utility_string_length_check((CHAR *)oid, NX_NULL, NX_SNMP_MAX_OCTET_STRING)) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - _nx_snmp_object_copy(oid, trap_object_data.nx_snmp_object_octet_string); - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, &trap_object_data, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if an object is specified. */ - if (object_list_ptr) - { - - /* Setup object pointers from the supplied object list. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - - /* Loop to process all the objects in the list. */ - while (trap_object_ptr) - { - - /* Clear the trap variable length. */ - trap_variable_length = 0; - - /* Remember the start of the variable. */ - trap_variable_ptr = trap_buffer_ptr; - - /* Setup the variable trap sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - trap_length = _nx_snmp_utility_sequence_set(trap_buffer_ptr, 0, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Place the object into the trap buffer. */ - trap_length = _nx_snmp_utility_object_id_set(trap_buffer_ptr, trap_object_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Insert the object's data into the trap buffer. */ - trap_length = _nx_snmp_utility_object_data_set(trap_buffer_ptr, trap_object_data_ptr, trap_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (trap_length == 0) - { - - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Move the trap buffer pointer up. */ - trap_buffer_ptr = trap_buffer_ptr + trap_length; - - /* Adjust the trap sequence length. */ - trap_sequence_length = trap_sequence_length + trap_length; - - /* Increment the pdu length. */ - trap_pdu_length = trap_pdu_length + trap_length; - - /* Adjust the trap request type length. */ - trap_type_length = trap_type_length + trap_length; - - /* Adjust the trap variable list size. */ - trap_variable_list_length = trap_variable_list_length + trap_length; - - /* Adjust the trap variable size. */ - trap_variable_length = trap_variable_length + trap_length; - - /* Now update the trap variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(trap_variable_ptr, trap_variable_length, trap_packet_ptr -> nx_packet_data_end); - - /* Default the object pointer to NULL. */ - trap_object_ptr = NX_NULL; - - /* Determine if there are more objects to insert into the trap message. */ - if (object_list_ptr) - { - - /* Move to the next object in the list. */ - object_list_ptr++; - - if (object_list_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - - /* Determine if there is another object. */ - if (object_list_ptr -> nx_snmp_object_string_ptr) - { - - /* Setup the object and object data pointers. */ - trap_object_ptr = object_list_ptr -> nx_snmp_object_string_ptr; - trap_object_data_ptr = object_list_ptr -> nx_snmp_object_data; - - /* Check for a valid operation. */ - if(trap_object_ptr != NX_NULL && trap_object_data_ptr == NX_NULL) - { - /* Release the trap packet. */ - nx_packet_release(trap_packet_ptr); - - /* Done, return to caller. */ - return(NX_SNMP_ERROR); - } - } - } - } - - /* At this point, several trap fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_header_ptr, trap_header_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set_1byte(trap_security_ptr, trap_security_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_pdu_ptr, trap_pdu_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(trap_variable_list_ptr, trap_variable_list_length, trap_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(trap_type_ptr, NX_SNMP_ANS1_TRAP2_REQUEST, trap_type_length, trap_packet_ptr -> nx_packet_data_end); - - /* Setup the security OCTET string length. */ - - /* Backup to the OCTET string for the security size. */ - trap_security_ptr = trap_security_ptr - 2; - - /* Account for the 2 byte Security Sequence field. */ - trap_security_length = trap_security_length + 2; - - /* Store the security size. */ - trap_security_ptr[1] = (UCHAR) (trap_security_length & 0xFF); - - /* Determine if privacy is required. If so, encrypt the PDU and setup the response - to have an encryption header. */ - if (agent_ptr -> nx_snmp_agent_v3_priv_trap_key) - { - -#ifndef NX_SNMP_NO_SECURITY - - /* Determine if any padding needs to be applied - account for the - four bytes of header information on the PDU. */ - trap_pdu_length = trap_pdu_length + 4; - padding = ((trap_pdu_length+7)/8)*8 - trap_pdu_length; - - /* Add the padding the trap PDU length and the trap sequence length. */ - trap_pdu_length = trap_pdu_length + padding; - trap_sequence_length = trap_sequence_length + padding; - - /* Clear the end of the trap message... just to be nice! */ - for (i = 0; i < padding; i++) - { - - /* Clear byte at the end of the response. */ - *trap_buffer_ptr++ = 0; - } - - /* Setup the size of the encrypted PDU. */ - trap_encryption_size_ptr[0] = (UCHAR) ((trap_pdu_length >> 8) & 0xFF); - trap_encryption_size_ptr[1] = (UCHAR) (trap_pdu_length & 0xFF); - - /* Update the total trap sequence length again. */ - _nx_snmp_utility_sequence_set(trap_sequence_ptr, trap_sequence_length, trap_packet_ptr -> nx_packet_data_end); - - /* Increment the salt counter. */ - agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; - - /* Build the salt value for the decryption. */ - key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); - key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); - key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); - key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); - key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); - key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); - key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); - key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); - - /* Loop to store the salt in the privacy field. */ - for (i = 0; i < 8; i++) - { - - /* Store a byte of the salt. */ - trap_privacy_ptr[i] = key1[i]; - } - - /* Setup pointer to the actual PDU. */ - temp_ptr = trap_encryption_size_ptr + 2; - - /* Make the Initialization Vector (IV). */ - for (i = 0; i < 8; i++) - { - - key2[i] = (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key[8+i] ^ key1[i]; - } - - /* Setup the DES. */ - _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_priv_trap_key)->nx_snmp_security_key); - - /* Setup the first input block - use the IV for the first block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[i] ^ key2[i]; - } - - /* Encrypt the first 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); - - /* Loop to encrypt the rest of the PDU. */ - j = 8; - do - { - - /* Setup the next input block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; - } - - /* Encrypt the next 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); - - /* Move the major index forward. */ - j = j + 8; - } while (j < trap_pdu_length); - -#else - - /* Increment the privacy error counter. */ - agent_ptr -> nx_snmp_agent_privacy_errors++; - - /* Release the trap packet too. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return NX_SNMP_ERROR; -#endif - } - - /* Now the trap packet's pointers must be setup so it can be sent. */ - trap_packet_ptr -> nx_packet_length = (ULONG)(trap_buffer_ptr - trap_packet_ptr -> nx_packet_prepend_ptr); - trap_packet_ptr -> nx_packet_append_ptr = trap_buffer_ptr; - -#ifndef NX_SNMP_NO_SECURITY - - /* Determine if authentication is required. */ - if (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) - { - - /* Yes, authentication is required. */ - - /* Now determine which authentication is required. */ - if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) - { - - /* Copy the base MD5 key into key1. */ - for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base MD5 key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Calculate prepend Key1. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Prepend Key2 to the result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); - } - else if ((agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) - { - - /* Copy the base SHA key into key1. */ - for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base SHA key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_auth_trap_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Calculate prepend Key1. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), trap_packet_ptr -> nx_packet_prepend_ptr, trap_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Prepend Key2 to the result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); - } - else - { - - /* Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return to caller. */ - return(NX_SNMP_ERROR); - } - - /* At this point, key2 contains the computed digest of the message. This needs to be - place in the outgoing message. */ - - /* Loop to setup the outgoing digest. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - { - - /* Copy one byte of digest. */ - trap_authentication_ptr[i] = key2[i]; - } - } -#endif - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_traps_sent++; - agent_ptr -> nx_snmp_agent_packets_sent++; - agent_ptr -> nx_snmp_agent_total_bytes_sent += trap_packet_ptr -> nx_packet_length; - - /* Send the trap packet back to the requesting SNMP manager. */ - - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), trap_packet_ptr, ipduo_address, NX_SNMP_MANAGER_TRAP_PORT); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(trap_packet_ptr); - - /* Return error. */ - return(NX_SNMP_ERROR); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -#endif /* NX_SNMP_DISABLE_V3 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_compare PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object compare */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* requested_object Pointer to requested object */ -/* actual_object Pointer to actual object */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_compare Actual agent object compare */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((requested_object == NX_NULL) || (actual_object == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_compare(requested_object, actual_object); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_compare PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares two objects. */ -/* */ -/* Note: new API nx_snmp_object_compare_extended is encouraged to use. */ -/* */ -/* INPUT */ -/* */ -/* requested_object Pointer to requested object */ -/* actual_object Pointer to actual object */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_compare_extended Call actual compare service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_compare(UCHAR *requested_object, UCHAR *actual_object) -{ - -UINT status; -UINT requested_object_length; -UINT actual_object_length; - - - /* Calculate the object length. */ - if ((_nx_utility_string_length_check((CHAR *)requested_object, &requested_object_length, NX_MAX_STRING_LENGTH)) || - (_nx_utility_string_length_check((CHAR *)actual_object, &actual_object_length, NX_MAX_STRING_LENGTH))) - { - return(NX_SIZE_ERROR); - } - - /* Call actual service. */ - status = _nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length); - - /* Return status to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_compare_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object compare */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* requested_object Pointer to requested object */ -/* requested_object_length Length of object requested */ -/* actual_object Pointer to actual object */ -/* actual_object_length Length of object requested */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_compare_extended Actual agent object compare */ -/* extended function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length) -{ - - - /* Check for invalid input pointers. */ - if ((requested_object == NX_NULL) || (actual_object == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - return(_nx_snmp_object_compare_extended(requested_object, requested_object_length, actual_object, actual_object_length)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_compare_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares two objects. */ -/* */ -/* Note: The strings of requested object and actual object must be */ -/* NULL-terminated and length of each string matches the length */ -/* */ -/* INPUT */ -/* */ -/* requested_object Pointer to requested object */ -/* requested_object_length Length of object requested */ -/* actual_object Pointer to actual object */ -/* actual_object_length Length of object requested */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length) -{ - -UINT i, j; -UINT request_value; -UINT actual_value; -UINT temp_requested_object_length; -UINT temp_actual_object_lenght; - - - /* Check object string and get the actual string length. */ - if ((_nx_utility_string_length_check((CHAR *)requested_object, &temp_requested_object_length, requested_object_length)) || - (_nx_utility_string_length_check((CHAR *)actual_object, &temp_actual_object_lenght, actual_object_length))) - return(NX_SNMP_ERROR); - - /* Check the actual string length. */ - if ((requested_object_length != temp_requested_object_length) || - (actual_object_length != temp_actual_object_lenght)) - return(NX_SNMP_ERROR); - - /* Loop to compare the first and second object name. Stop at the first NULL. */ - i = 0; - request_value = 0; - actual_value = 0; - while ((requested_object[i]) && (actual_object[i])) - { - - /* Update the requested object value. */ - if (requested_object[i] == '.') - request_value = 0; - else - request_value = (request_value * 10) + (UINT) (requested_object[i] - '0'); - - /* Update the actual object value. */ - if (actual_object[i] == '.') - actual_value = 0; - else - actual_value = (actual_value * 10) + (UINT) (actual_object[i] - '0'); - - /* Determine if the names are different. */ - if (requested_object[i] != actual_object[i]) - { - - /* Calculate the remainder - if any - of the requested value. */ - j = i; - while ((requested_object[j]) && (requested_object[j] != '.')) - { - - /* Update the request value. */ - request_value = (request_value * 10) + (UINT) (requested_object[j] - '0'); - - /* Move to next entry. */ - j++; - } - - - /* Calculate the remainder - if any - of the actual value. */ - j = i; - while ((actual_object[j]) && (actual_object[j] != '.')) - { - - /* Update the actual value. */ - actual_value = (actual_value * 10) + (UINT) (actual_object[j] - '0'); - - /* Move to next entry. */ - j++; - } - - /* Determine if the requested object name is less than the actual object name. */ - if (request_value < actual_value) - return(NX_SNMP_NEXT_ENTRY); - else - break; - } - - /* Move to next character. */ - i++; - } - - /* Now compare the names to check for a successful match. */ - if ((requested_object[i] == NX_NULL) && (actual_object[i] == NX_NULL)) - return(NX_SUCCESS); - - /* If the actual object is NULL, that means that everything else matched exactly. */ - if (actual_object[i] == NX_NULL) - return(NX_SUCCESS); - - /* Determine if the requested object name is NULL. This case is considered the next entry. */ - if (requested_object[i] == NX_NULL) - return(NX_SNMP_NEXT_ENTRY); - - /* Return an error condition. */ - return(NX_SNMP_ERROR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_copy PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object copy */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* source_object_name Pointer to source object */ -/* destination_object_name Pointer to destination object */ -/* */ -/* OUTPUT */ -/* */ -/* size If error, returns zero, else */ -/* returns number of bytes */ -/* copied */ -/* CALLS */ -/* */ -/* _nx_snmp_object_copy Actual agent object copy */ -/* function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_object_name == NX_NULL) || (destination_object_name == NX_NULL)) - return(0); - - /* Call actual service. */ - status = _nx_snmp_object_copy(source_object_name, destination_object_name); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_copy PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies the source object to the destination object. */ -/* */ -/* Note: new API nx_snmp_object_copy_extended is encouraged to use. */ -/* */ -/* INPUT */ -/* */ -/* source_object_name Pointer to source object */ -/* destination_object_name Pointer to destination object */ -/* */ -/* OUTPUT */ -/* */ -/* size If error, returns zero, else */ -/* returns number of bytes */ -/* copied */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name) -{ - -UINT i; - - - /* Calculate the object length. */ - if (_nx_utility_string_length_check((CHAR *)source_object_name, NX_NULL, NX_MAX_STRING_LENGTH)) - return(0); - - /* Loop to copy the name. */ - i = 0; - - while (source_object_name[i]) - { - - /* Copy a byte of the name. */ - destination_object_name[i] = source_object_name[i]; - - /* Move to next byte. */ - i++; - } - - /* Ensure name is null terminated. */ - destination_object_name[i] = NX_NULL; - - /* Return the size of the name. */ - return(i); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_copy_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object copy */ -/* function call. */ -/* */ -/* INPUT */ -/* */ -/* source_object_name Pointer to source object */ -/* source_object_name_length Length of source object */ -/* destination_object_name_buffer Pointer to destination object */ -/* destination_object_name_buffer_size Size of destination object */ -/* */ -/* OUTPUT */ -/* */ -/* size If error, returns zero, else */ -/* returns number of bytes */ -/* copied */ -/* CALLS */ -/* */ -/* _nx_snmp_object_copy_extended Actual agent object copy */ -/* extended function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, - UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size) -{ - - - /* Check for invalid input pointers. */ - if ((source_object_name == NX_NULL) || (destination_object_name_buffer == NX_NULL)) - return(0); - - /* Call actual service. */ - return(_nx_snmp_object_copy_extended(source_object_name, source_object_name_length, destination_object_name_buffer, destination_object_name_buffer_size)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_copy_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function copies the source object to the destination object. */ -/* */ -/* Note: the object name must be NULL-terminated, the size of */ -/* destination object buffer must be larger than source object length. */ -/* */ -/* INPUT */ -/* */ -/* source_object_name Pointer to source object */ -/* source_object_name_length Length of source object */ -/* destination_object_name_buffer Pointer to destination object */ -/* destination_object_name_buffer_size Size of destination object */ -/* */ -/* OUTPUT */ -/* */ -/* size If error, returns zero, else */ -/* returns number of bytes */ -/* copied */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, - UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size) -{ - -UINT temp_object_name_length; - - - /* Check the string length, the destination oject name buffer size must be larger than source object name length. */ - if ((source_object_name_length == 0) || (destination_object_name_buffer_size <= source_object_name_length)) - return(0); - - /* Check name string. */ - if (_nx_utility_string_length_check((CHAR *)source_object_name, &temp_object_name_length, source_object_name_length)) - return(0); - - /* Check the actual string length. */ - if (source_object_name_length != temp_object_name_length) - return(0); - - /* Copy the name and null-terminator. */ - memcpy(destination_object_name_buffer, source_object_name, source_object_name_length + 1); - - /* Return the size of the name. */ - return(source_object_name_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_counter_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object counter */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to counter source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_counter_get Actual agent object counter */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_counter_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_counter_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object counter from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to counter source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_COUNTER; - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_counter_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object counter */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to counter destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_counter_set Actual agent object counter */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_counter_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_counter_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object counter from the object data */ -/* structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to counter destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) destination_ptr; - - /* Copy the value into the object data structure. */ - *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_counter64_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent 64-bit object */ -/* counter get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to counter source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_counter64_get Actual agent object counter */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_counter64_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_counter64_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the 64-bit object counter from the */ -/* specified source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to counter source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_COUNTER64; - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG)value_ptr[0]; - object_data -> nx_snmp_object_data_lsw = (LONG)value_ptr[1]; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_counter64_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent 64-bit object */ -/* counter set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to counter destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_counter64_set Actual agent object counter */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_counter64_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_counter64_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the 64-bit object counter from the object */ -/* data structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to counter destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; -LONG temp = 0; - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_COUNTER64) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) destination_ptr; - - if (object_data -> nx_snmp_object_data_lsw == 0) - { - temp = object_data -> nx_snmp_object_data_msw; - value_ptr[0] = 0; - - } - if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFFFF00) == 0) - { - temp = object_data -> nx_snmp_object_data_msw << 8; - value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 24) & (0x000000FF)); - } - else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFFFF0000) == 0) - { - - temp = object_data -> nx_snmp_object_data_msw << 16; - value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 16) & (0x0000FFFF)); - } - else if ((object_data -> nx_snmp_object_data_lsw & (LONG)0xFF000000) == 0) - { - - temp = object_data -> nx_snmp_object_data_msw << 24; - value_ptr[0] = (ULONG)(((ULONG)object_data -> nx_snmp_object_data_msw >> 8) & (0x00FFFFFF)); - } - else - { - value_ptr[0] = (ULONG)(object_data -> nx_snmp_object_data_msw); - } - - value_ptr[1] = (ULONG)(object_data -> nx_snmp_object_data_lsw + temp); - - /* Value_ptr udpates the MIB data but we also need to display the data correctly in object. */ - - /* Update the object data to make the display correct as well. */ - object_data -> nx_snmp_object_data_lsw = (LONG)value_ptr[1]; - object_data -> nx_snmp_object_data_msw = (LONG)value_ptr[0]; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_end_of_mib PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent end-of-mib object */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_end_of_mib Actual agent object end-of-mib*/ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointer. */ - if (object_data == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_end_of_mib(not_used_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_end_of_mib PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places an end-of-mib value in the object data */ -/* structure. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_END_OF_MIB_VIEW; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_gauge_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object gauge */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to gauge source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_gauge_get Actual agent object gauge */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_gauge_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_gauge_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object gauge from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to gauge source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_GAUGE; - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_gauge_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object gauge */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to gauge destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_gauge_set Actual agent object gauge */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_gauge_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_gauge_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object gauge from the object data */ -/* structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to gauge destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_GAUGE) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) destination_ptr; - - /* Copy the value into the object data structure. */ - *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_id_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object ID */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to ID source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_id_get Actual agent object ID */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_id_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_id_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object ID from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to object ID source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT length; -UCHAR c; -CHAR *copy_source = (CHAR*)source_ptr; - - c = *((UCHAR *)source_ptr); - - /* Check if this is an empty string. */ - if ((c == 0x0) || (c == '0')) - { - copy_source = "0.0.0"; - } - - /* Check string length. */ - if (_nx_utility_string_length_check((CHAR *)copy_source, &length, NX_SNMP_MAX_OCTET_STRING)) - { - /* Incoming object data is too big to fit in. */ - return(NX_SNMP_ERROR); - } - - object_data -> nx_snmp_object_data_type = NX_SNMP_OBJECT_ID; - - memcpy(&object_data -> nx_snmp_object_octet_string[0], copy_source, length); - - /* NULL-terminate the string. */ - object_data -> nx_snmp_object_octet_string[length] = 0x0; - - /* Calculate the length. */ - object_data -> nx_snmp_object_octet_string_size = length; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_id_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object ID */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to ID destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_id_set Actual agent object ID */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_id_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_id_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object ID from the object data */ -/* structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to ID destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_OBJECT_ID) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Copy the object id into the destination string. */ - _nx_snmp_object_copy(object_data -> nx_snmp_object_octet_string, (UCHAR *) destination_ptr); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_integer_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object integer */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to integer source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_integer_get Actual agent integer */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_integer_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_integer_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object integer from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to integer source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -LONG *value_ptr; - - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_INTEGER; - - /* Setup pointer to the value. */ - value_ptr = (LONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = *value_ptr; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_integer_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object integer */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to integer destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_integer_set Actual agent object integer */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_integer_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_integer_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object integer from the object data */ -/* structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to integer destination*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -LONG *value_ptr; - - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_INTEGER) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (LONG *) destination_ptr; - - /* Copy the value into the object data structure. */ - *value_ptr = object_data -> nx_snmp_object_data_msw; - - /* Return success. */ - return(NX_SUCCESS); -} - -#ifdef FEATURE_NX_IPV6 - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_ipv6_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the set the IPv6 address */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to IPv6 address */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_ipv6_address_set Actual set address service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_ipv6_address_set(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - /* Determine if the correct type is specified. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - { - - /* Return an invalid pointer input. */ - return(NX_PTR_ERROR); - } - - status = _nx_snmp_object_ipv6_address_set(source_ptr, object_data); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_ipv6_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object IPv6 address from the object data*/ -/* structure and places it in the destination. Note that 1) the data */ -/* type is really an octet string of unspecified size and format, and */ -/* 2) the caller must set the nx_snmp_object_string_size before calling*/ -/* this function since it supplies the length of the octet data. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to IPv6 address */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT i; -UCHAR *string_ptr; - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - string_ptr = destination_ptr; - - /* Copy the object data structure into the destination pointer. */ - /* Copy this string into the destination. */ - for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) - { - - /* Determine if the string is too big. */ - if (i >= NX_SNMP_MAX_OCTET_STRING) - { - - /* Error, source string is too large. */ - string_ptr[0] = NX_NULL; - return(NX_SNMP_ERROR); - } - - /* Copy character. */ - string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; - } - - return NX_SUCCESS; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_ipv6_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the IPv6 address get */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to IPv6 address */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_ipv6_address_get Actual get IPv6 service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_ipv6_address_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_ipv6_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object IPv6 address from the object data*/ -/* structure and places it in the destination. Note that the caller */ -/* must set the length of the octet string (object -> */ -/* (nx_snmp_octet_string_size) before calling this service. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to IPv6 address */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT i; -UCHAR *source_string; - - - /* Setup pointer to source string. */ - source_string = (UCHAR *) source_ptr; - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_IPV6_ADDRESS; - - /* Copy this string into the destination. */ - for (i = 0; i < object_data->nx_snmp_object_octet_string_size; i++) - { - - /* Copy character. */ - object_data -> nx_snmp_object_octet_string[i] = source_string[i]; - } - - /* Return success. */ - return(NX_SUCCESS); - -} - -#endif /* FEATURE_NX_IPV6 */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_ip_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object IP address */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to IP address source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_ip_address_get Actual agent IP address */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_ip_address_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_ip_address_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object IP address from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to IP address source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - -ULONG *value_ptr; - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_IP_ADDRESS; - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_ip_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object IP address */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to IP address */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_ip_address_set Actual agent object IP address*/ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_ip_address_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_ip_address_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object IP address from the object data */ -/* structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to IP address */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - -ULONG *value_ptr; - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_IP_ADDRESS) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) destination_ptr; - - /* Copy the value into the object data structure. */ - *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_no_instance PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object no-instance*/ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used pointer */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_no_instance Actual agent object */ -/* no-instance set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (object_data == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_no_instance(not_used_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_no_instance PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places a no-instance value in the object data */ -/* structure. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NO_SUCH_INSTANCE; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_not_found PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent object not-found */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used pointer */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_not_found Actual agent object */ -/* not-found set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if (object_data == NX_NULL) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_not_found(not_used_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_not_found PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places an not-found value in the object data */ -/* structure. */ -/* */ -/* INPUT */ -/* */ -/* not_used_ptr Not used */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NO_SUCH_OBJECT; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG) not_used_ptr; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_octet_string_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent octet string */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to octet string source*/ -/* object_data Pointer to object data struct */ -/* length Length of octet string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_octet_string_get Actual agent octet string */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_octet_string_get(source_ptr, object_data, length) ; - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_octet_string_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object octet string from the specified */ -/* source location. Note that while this does have a length field */ -/* the caller must set the nx_snmp_object_string_size before calling */ -/* this function since it supplies the length. */ -/* */ -/* The length field is deprecated. It is only included for legacy code.*/ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to octet string source*/ -/* object_data Pointer to object data struct */ -/* length Length of octet string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length) -{ - -UINT i; -UCHAR *source_string; - - - NX_PARAMETER_NOT_USED(length); - - /* Setup pointer to source string. */ - source_string = (UCHAR *) source_ptr; - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_OCTET_STRING; - - if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) - { - return NX_SNMP_ERROR_TOOBIG; - } - - /* Copy this string into the destination. */ - for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) - { - - /* Copy character. */ - object_data -> nx_snmp_object_octet_string[i] = source_string[i]; - } - - /* The length input is deprecated. The caller sets the length from the MIB table - entry to the object_data instance before calling this function. */ - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_octet_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent octet string */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to octet string */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_octet_string_set Actual agent octet string */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_octet_string_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_octet_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object octet string from the object */ -/* data structure and places it in the destination. Note that the */ -/* length of the octet string must be set in the object string size. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to octet string */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT i; -UCHAR *string_ptr; - - - /* Check for the proper type. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - if (object_data -> nx_snmp_object_octet_string_size > NX_SNMP_MAX_OCTET_STRING) - { - return NX_SNMP_ERROR_TOOBIG; - } - - /* Setup pointer to the destination string. */ - string_ptr = (UCHAR *) destination_ptr; - - /* Copy this string into the destination. */ - for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) - { - - /* Determine if the string is too big. */ - if (i >= NX_SNMP_MAX_OCTET_STRING) - { - - /* Error, source string is too large. */ - string_ptr[0] = NX_NULL; - return(NX_SNMP_ERROR); - } - - /* Copy character. */ - string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; - } - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_string_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent string */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to string source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_string_get Actual agent string */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_string_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_string_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object ASCII string from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to ASCII string source*/ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT i; -UCHAR *source_string; - - - /* Setup pointer to source string. */ - source_string = (UCHAR *) source_ptr; - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_OCTET_STRING; - - /* Copy this string into the destination. */ - i = 0; - while (source_string[i]) - { - - /* Copy character. */ - object_data -> nx_snmp_object_octet_string[i] = source_string[i]; - - /* Move to next character. */ - i++; - - /* Check for size of source string. */ - if (i >= NX_SNMP_MAX_OCTET_STRING) - { - - /* Error, source string is too large. */ - object_data -> nx_snmp_object_octet_string[0] = NX_NULL; - object_data -> nx_snmp_object_octet_string_size = 0; - return(NX_SNMP_ERROR); - } - } - - /* Store the length of the string in the object data area. */ - object_data -> nx_snmp_object_octet_string_size = i; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent string */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to string */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_string_set Actual agent string */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_string_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_string_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object ASCII string from the object */ -/* data structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to ASCII string */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT i; -UCHAR *string_ptr; - - - /* Check for the proper type. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_OCTET_STRING) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the destination string. */ - string_ptr = (UCHAR *) destination_ptr; - - /* Copy this string into the destination. */ - for (i = 0; i < object_data -> nx_snmp_object_octet_string_size; i++) - { - - /* Determine if the string is too big. */ - if (i >= NX_SNMP_MAX_OCTET_STRING) - { - - /* Error, source string is too large. */ - return(NX_SNMP_ERROR); - } - - /* Copy character. */ - string_ptr[i] = object_data -> nx_snmp_object_octet_string[i]; - } - - /* Null terminate the destination. */ - string_ptr[i] = NX_NULL; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_timetics_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent timetics */ -/* get function call. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to timetics source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_timetics_get Actual agent timetics */ -/* get function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((source_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_timetics_get(source_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_timetics_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object timetics from the specified */ -/* source location. */ -/* */ -/* INPUT */ -/* */ -/* source_ptr Pointer to timetics source */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Setup the object data structure. */ - object_data -> nx_snmp_object_data_type = NX_SNMP_TIME_TICS; - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) source_ptr; - - /* Copy the value into the object data structure. */ - object_data -> nx_snmp_object_data_msw = (LONG)(*value_ptr); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_snmp_object_timetics_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the SNMP agent timetics */ -/* set function call. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to timetics */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_object_timetics_set Actual agent timetics */ -/* set function */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((destination_ptr == NX_NULL) || (object_data == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual service. */ - status = _nx_snmp_object_timetics_set(destination_ptr, object_data); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_object_timetics_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object timetics from the object */ -/* data structure and places it in the destination. */ -/* */ -/* INPUT */ -/* */ -/* destination_ptr Pointer to timetics */ -/* destination */ -/* object_data Pointer to object data struct */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data) -{ - -ULONG *value_ptr; - - - /* Determine if the correct type is specified. */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_TIME_TICS) - { - - /* Return an invalid type message. */ - return(NX_SNMP_ERROR_WRONGTYPE); - } - - /* Setup pointer to the value. */ - value_ptr = (ULONG *) destination_ptr; - - /* Copy the value into the object data structure. */ - *value_ptr = (ULONG)(object_data -> nx_snmp_object_data_msw); - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_community_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the community string from the supplied */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* community_string Pointer to place community */ -/* string */ -/* buffer_length Size of input buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process SNMP v1 request processing */ -/* _nx_snmp_version_2_process SNMP v2 request processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_community_get(UCHAR *buffer_ptr, UCHAR *community_string, INT buffer_length) -{ - -UINT i; -UINT length; -UINT total; - - - /* Buffer size must be at least 2 bytes. */ - if (buffer_length < 2) - { - return(0); - } - - /* Set community string to NULL. */ - *community_string = NX_NULL; - - /* First see if the ANS1 string type is present. */ - if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) - { - - /* Return a zero length. */ - return(0); - } - - if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) - { - - /* Get the type of length of the string */ - UINT temp = (UINT)(buffer_ptr[1] & 0x7F); - - if (temp == 2) - { - - /* Check the buffer length. */ - if (buffer_length < 4) - { - return(0); - } - - /* Length is in the next two bytes. Example: 0x04 0x82 0x98 0x01 */ - total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 4; - - /* Initialize the length. */ - length = 4; - } - - else if (temp == 1) - { - - /* Check the buffer length. */ - if (buffer_length < 3) - { - return(0); - } - - /* Length is in the next byte. Example: 0x04 0x81 0x98 */ - total = (UINT)(buffer_ptr[2]) ; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 3; - - /* Initialize the length. */ - length = 3; - } - else - { - - /* String is either null or too big, return a zero length to indicate an error. */ - return(0); - } - } - else - { - - /* Otherwise, assume we have one byte. Example: 0x04 0x98 */ - - /* Pickup the total length of the community character string. */ - total = (UINT) buffer_ptr[1]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 2; - - /* Initialize the length. */ - length = 2; - } - - if ((INT)(length + total) > buffer_length) - { - - /* Buffer is too small. */ - return(0); - } - - /* Determine if the length is within the maximum. */ - if (total > (NX_SNMP_MAX_USER_NAME-1)) - { - - /* String is too big, return a zero length to indicate an error. */ - return(0); - } - - /* Loop to pickup the remaining characters in the community string. */ - for (i = 0; i < total; i++) - { - - /* Move character from buffer into community string. */ - *community_string++ = *buffer_ptr++; - - /* Adjust the length. */ - length++; - } - - /* NULL-terminate the community string. */ - *community_string = NX_NULL; - - /* Return the length of the ANS1 string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_community_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the community string into the supplied */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* community_string Pointer to source of the */ -/* community string */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_community_set(UCHAR *buffer_ptr, UCHAR *community_string, UCHAR *buffer_end) -{ - -UINT i; -UINT header_size; -UINT length; - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* First, set the OCTET byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; - - /* Calculate the length byte. */ - if (_nx_utility_string_length_check((CHAR *)community_string, &length, NX_SNMP_MAX_USER_NAME)) - { - - /* Error, community length is too large. */ - return(0); - } - - /* Check for a length greater than 128. */ - if (length >= 128) - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < (3 + length)) - return(0); - - /* Indicate there are two length bytes. */ - *buffer_ptr++ = (UCHAR) 0x82; - - /* Set the first length byte. */ - *buffer_ptr++ = (UCHAR) (length >> 8); - - /* Set the second length byte. */ - *buffer_ptr++ = (UCHAR) (length & 0xFF); - - /* Set the header size. */ - header_size = 4; - } - else - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < (1 + length)) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) length; - - /* The header is 2 bytes. */ - header_size = 2; - } - - /* Loop to store rest of the community string. */ - for (i = 0; i < length; i++) - { - - /* Store the SNMP community string. */ - *buffer_ptr++ = (UCHAR) community_string[i]; - } - - /* Return the length of the community string. */ - return(length+header_size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_error_info_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the error information from the supplied */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* error_code Pointer to place error code */ -/* error_index Pointer to place error index */ -/* buffer_length Size of input buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_error_info_get(UCHAR *buffer_ptr, UINT *error_code, UINT *error_index, INT buffer_length) -{ - - /* Check for invalid input. */ - if (buffer_length < 6) - { - /* Invalid input. */ - *error_code = 0; - *error_index = 0; - - /* Return a zero length. */ - return(0); - } - - /* Determine if the error code and error index is correct. */ - if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) && - (buffer_ptr[1] == 1) && - (buffer_ptr[3] == NX_SNMP_ANS1_INTEGER) && - (buffer_ptr[4] == 1)) - { - - /* Yes, the SNMP version string is correct. */ - - /* Return the error code and error index. */ - *error_code = (UINT) buffer_ptr[2]; - *error_index = (UINT) buffer_ptr[5]; - - /* Return the length of the error code/index string. */ - return(6); - } - else - { - - /* No, the SNMP error code/index is invalid. */ - - /* Clear both. */ - *error_code = 0; - *error_index = 0; - - /* Return a zero length. */ - return(0); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_error_info_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the error information into the supplied */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* error_code Error code */ -/* error_index Error index */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_error_response Send error response to Manager*/ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_error_info_set(UCHAR *buffer_ptr, UINT error_code, UINT error_index, UCHAR *buffer_end) -{ - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 6) - return(0); - - /* First, set the INTEGER byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 1; - - /* Store the error code. */ - *buffer_ptr++ = (UCHAR) (error_code & 0xFF); - - /* Set the INTEGER byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 1; - - /* Store the error index. */ - *buffer_ptr++ = (UCHAR) (error_index & 0xFF); - - /* Return the length of the error info. */ - return(6); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_object_id_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object ID from the supplied buffer */ -/* and converts the object ID to an ASCII format. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* object_string Pointer to place object string*/ -/* buffer_length Size of input buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_utility_object_data_get Get object data */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_object_id_get(UCHAR *buffer_ptr, UCHAR *object_string, INT buffer_length) -{ - -UINT i; -UINT length; -ULONG value; -ULONG temp; -ULONG multiply; -UINT total; -UINT size; -UCHAR byte; -UCHAR saved_byte; -UCHAR *saved_ptr; -UINT string_length; - - - /* Buffer size must be at least 4 bytes. */ - if (buffer_length < 4) - { - return 0; - } - - /* Set object string to NULL. */ - *object_string = NX_NULL; - - /* Initialize the string length to 0. */ - string_length = 0; - - /* Initialize the sequence byte value to NULL. */ - value = 0; - - /* First see if the ANS1 object type is present. */ - if (buffer_ptr[0] != NX_SNMP_ANS1_OBJECT_ID) - { - - /* Return a zero length. */ - return(0); - } - - if (buffer_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) - { - - temp = buffer_ptr[1] & 0x7F; - - /* Determine if a two byte length is present. */ - if (temp == 2) - { - - /* Check the buffer length. */ - if (buffer_length < 5) - { - return(0); - } - - /* Pickup the total length of the object string. */ - total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); - - /* Pickup the first byte. */ - byte = buffer_ptr[4]; - - /* Save the pointer to the first byte. */ - saved_ptr = &buffer_ptr[4]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 4; - - /* Initialize the length. */ - length = 4; - } - else if (temp == 1) - { - - /* Pickup the total length of the object string. */ - total = buffer_ptr[2]; - - /* Pickup the first byte. */ - byte = buffer_ptr[3]; - - /* Save the pointer to the first byte. */ - saved_ptr = &buffer_ptr[3]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 3; - - /* Initialize the length. */ - length = 3; - } - else - { - - /* This is out of range or null. Invalid SNMP sequence. */ - return(0); - } - } - else - { - - /* Otherwise, assume one byte. */ - - /* Pickup the total length of the object string. */ - total = (UINT) buffer_ptr[1]; - - /* Check for invalid data size */ - if ((INT)total > (buffer_length - 1)) - { - /* Indicate an invalid request is received. */ - return 0; - } - - /* Pickup the first byte. */ - byte = buffer_ptr[2]; - - /* Save the index. */ - saved_ptr = &buffer_ptr[2]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 2; - - /* Initialize the length. */ - length = 2; - } - - /* Save the original byte. */ - saved_byte = byte; - - /* Calculate the first two characters of object string. */ - if (byte >= 80) - { - - /* This form starts with 2 as the first identifier. */ - *object_string++ = '2'; - - /* Increment the string length. */ - string_length++; - - /* Adjust the byte. */ - byte = (UCHAR)(byte - 80); - } - else if (byte >= 40) - { - - /* This form starts with 1 as the first identifier. */ - *object_string++ = '1'; - - /* Increment the string length. */ - string_length++; - - /* Adjust the byte. */ - byte = (UCHAR)(byte - 40); - } - else - { - - /* This form starts with 0 as the first identifier. */ - *object_string++ = '0'; - - /* Increment the string length. */ - string_length++; - } - - /* Always place a '.'. */ - *object_string++ = '.'; - - /* Increment the string length. */ - string_length++; - - /* Determine if the second identifier is legal. */ - if (byte & NX_SNMP_ANS1_MULTI_BYTES) - { - - /* Second identifier too large, return a zero length. */ - return(0); - } - - /* Write the byte back. */ - buffer_ptr[0] = byte; - - /* Loop to pickup the remaining characters in the object string. */ - while (total) - { - - /* Move the buffer pointer forward. */ - byte = *buffer_ptr++; - - /* Decrement the total. */ - total--; - - /* Increment the length. */ - length++; - - /* Determine if the next byte has the additional bytes - bit set (BIT 7). */ - if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) - { - - /* The specified sequence value is less than 128 and is actually in this byte! */ - value = (UINT) byte; - } - else - { - - /* Otherwise, we have a more complicated value that we must loop through - to calculate. */ - - /* Loop to calculate how many bytes there are representing the value. */ - i = 0; - multiply = 128; - while (buffer_ptr[i] & NX_SNMP_ANS1_MULTI_BYTES) - { - - /* Increment count. */ - i++; - - /* Adjust the multiplier. */ - multiply = multiply * 128; - } - - /* Determine if the count is reasonable. */ - if (i > 3) - { - - /* Restore the saved byte. */ - *saved_ptr = saved_byte; - - /* Nope, too big! */ - return(0); - } - - /* Loop to calculate the value. */ - do - { - - /* Pickup the number of bytes required to represent this value. */ - temp = (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); - - /* Calculate the temporary value. */ - temp = temp * multiply; - - /* Calculate total value. */ - value = value + temp; - - /* Adjust the multiply value. */ - multiply = multiply/128; - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Decrement the total. */ - if (total == 0) - { - - /* Restore the saved byte. */ - *saved_ptr = saved_byte; - - return(0); - } - else - total--; - - /* Increment the length. */ - length++; - - } while (byte & NX_SNMP_ANS1_MULTI_BYTES); - - /* Add in the remainder. */ - temp = (ULONG) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); - value = value + temp; - } - - /* Loop to convert value into ASCII. */ - size = 0; - do - { - - /* Shift the current digits over one. */ - for (i = size; i != 0; i--) - { - - /* Move each digit over one place. */ - object_string[i] = object_string[i-1]; - } - - /* Compute the next decimal digit. */ - byte = (UCHAR) (value % 10); - - /* Update the input number. */ - value = value / 10; - - /* Store the new digit in ASCII form. */ - object_string[0] = (UCHAR)(byte + 0x30); - - /* Increment the size. */ - size++; - - /* Increment the string length. */ - string_length++; - - /* Determine if the length is too long. */ - if (string_length >= NX_SNMP_MAX_OCTET_STRING) - { - - /* String is too long. */ - - /* Null-terminate the string. */ - *object_string = NX_NULL; - - /* Return the length. */ - return(length); - } - - } while ((size < 10) && (value)); - - /* Adjust the object string. */ - object_string = object_string + size; - - /* Determine if there are more tokens. */ - if (total) - { - - /* Still more nodes, place a dot in the string. */ - *object_string++ = '.'; - - /* Increment the string length. */ - string_length++; - - /* Determine if the length is too long. */ - if (string_length >= NX_SNMP_MAX_OCTET_STRING) - { - - /* String is too long. */ - - /* Null-terminate the string. */ - object_string--; - *object_string = NX_NULL; - - /* Return the length. */ - return(length); - } - } - } - - /* Restore the saved byte. */ - *saved_ptr = saved_byte; - - /* NULL-terminate the object string. */ - *object_string = NX_NULL; - - /* Return the length of the ANS1 string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_object_id_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the ASCII representation of the object into */ -/* ASN.1 format and then places it in the ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* object_string Object string in ASCII */ -/* buffer_end End of ASN.1 buffer for error */ -/* checking */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send SNMP v1 trap send */ -/* _nx_snmp_agent_trapv2_send SNMP v2 trap send */ -/* _nx_snmp_agent_trapv3_send SNMP v3 trap send */ -/* _nx_snmp_utility_object_data_set Object data set */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_object_id_set(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end) -{ - -UINT length; -UINT i; -ULONG value; -UCHAR *length_ptr; -UCHAR encoding_started; -UINT object_string_length; - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Check object string length. */ - if (_nx_utility_string_length_check((CHAR*)object_string, &object_string_length, (UINT)(buffer_end - buffer_ptr))) - return(0); - - /* Set the OBJECT byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_OBJECT_ID; - - /* Remember length pointer. */ - length_ptr = buffer_ptr; - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the length byte to zero for now. */ - *buffer_ptr++ = 0; - - /* Check object string length. */ - if (object_string_length < 2) - return(0); - - /* Determine if the object string is legal. */ - if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) || - (object_string[1] != '.')) - { - - /* Invalid object ID. */ - return(0); - } - - /* Calculate the value of the second identifier. */ - i = 2; - value = 0; - - while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) - { - - /* Compute the value. */ - value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); - - /* Move to the next character. */ - i++; - } - - if (object_string[i] == '.') - { - /* Move to the next character. */ - i++; - } - - /* The second identifier must be less that 128. */ - if (value >= 128) - { - - /* Invalid object ID. */ - return(0); - } - - /* Now determine how to set the first byte of the object ID. */ - if (object_string[0] == '1') - { - - /* Increment value by 40 per spec. */ - value = value + 40; - } - else if (object_string[0] == '2') - { - - /* Increment value by 40 per spec. */ - value = value + 80; - } - - /* Set the first byte, which is the combination of the first two bytes. */ - *buffer_ptr++ = (UCHAR) value; - - /* Set the length. */ - length = 1; - - /* Process all the characters in the ID. For now, the limit will be 128 characters in the - ID specification string. */ - while (object_string[i]) - { - - UCHAR *value_ptr; - UCHAR byte0; - ULONG mod_value; - - /* Initialize the encoding started flag. */ - encoding_started = NX_FALSE; - - /* Pickup the next value. */ - value = 0; - while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) - { - - /* Compute the value. */ - value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); - - /* Move to the next character. */ - i++; - } - - /* At this point we have a value to store in the ID string. */ - - /* Determine if it is simple encoding. */ - if (value < 128) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Place the value directly in the buffer. */ - *buffer_ptr++ = (UCHAR) value; - - /* Increment the length. */ - length++; - } - else - { - - /* Otherwise, we need to encode the numeric value such that it has - more bytes to represent it. */ - - if (value/268435456) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/268435456; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 268435456; - - /* Increment the length. */ - length++; - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value/2097152) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/2097152; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 2097152; - - /* Increment the length. */ - length++; - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value / 16384) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/16384; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 16384; - - /* Increment the length. */ - length++; - - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value /128) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/128; /* (0x100) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 128; - - /* Increment the length. */ - length++; - } - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Place the value directly in the buffer. */ - *buffer_ptr++ = (UCHAR) value; - - /* Increment the length. */ - length++; - } - - /* Determine if we are sitting on a dot. */ - if (object_string[i] == '.') - i++; - } - - /* Update the length. */ - length_ptr[0] = (UCHAR) (length & 0xFF); - - /* Return the length plus the header information. */ - return(length + 2); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_object_id_set_1byte PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the ASCII representation of the object into */ -/* ASN.1 format and then places it in the ASN.1 buffer. */ -/* */ -/* The difference with _nx_snmp_utility_object_id_set is that */ -/* this uses only a single byte length field e.g. 0x30 xx instead of */ -/* 0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* object_string Object string in ASCII */ -/* buffer_end End of ASN.1 buffer for error */ -/* checking */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_object_id_set_1byte(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end) -{ - -UINT length; -UINT i; -ULONG value; -UCHAR *length_ptr; -UCHAR encoding_started; - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the OBJECT byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_OBJECT_ID; - - /* Remember length pointer. */ - length_ptr = buffer_ptr; - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the length byte to zero for now. */ - *buffer_ptr++ = 0; - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Determine if the object string is legal. */ - if (((object_string[0] != '0') && (object_string[0] != '1') && (object_string[0] != '2')) || - (object_string[1] != '.')) - { - - /* Invalid object ID. */ - return(0); - } - - /* Calculate the value of the second identifier. */ - i = 2; - value = 0; - - while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) - { - - /* Compute the value. */ - value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); - - /* Move to the next character. */ - i++; - } - - if (object_string[i] == '.') - { - /* Move to the next character. */ - i++; - } - - /* The second identifier must be less that 128. */ - if (value >= 128) - { - - /* Invalid object ID. */ - return(0); - } - - /* Now determine how to set the first byte of the object ID. */ - if (object_string[0] == '1') - { - - /* Increment value by 40 per spec. */ - value = value + 40; - } - else if (object_string[0] == '2') - { - - /* Increment value by 40 per spec. */ - value = value + 80; - } - - /* Set the first byte, which is the combination of the first two bytes. */ - *buffer_ptr++ = (UCHAR) value; - - /* Set the length. */ - length = 1; - - /* Process all the characters in the ID. For now, the limit will be 128 characters in the - ID specification string. */ - while (object_string[i]) - { - - UCHAR *value_ptr; - UCHAR byte0; - ULONG mod_value; - - /* Initialize the encoding started flag. */ - encoding_started = NX_FALSE; - - /* Pickup the next value. */ - value = 0; - while ((object_string[i] != '.') && (object_string[i] != NX_NULL)) - { - - /* Compute the value. */ - value = (value * 10) + ((ULONG) (object_string[i] - 0x30)); - - /* Move to the next character. */ - i++; - } - - /* At this point we have a value to store in the ID string. */ - - /* Determine if it is simple encoding. */ - if (value < 128) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Place the value directly in the buffer. */ - *buffer_ptr++ = (UCHAR) value; - - /* Increment the length. */ - length++; - } - else - { - - /* Otherwise, we need to encode the numeric value such that it has - more bytes to represent it. */ - - if (value/268435456) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/268435456; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - - /* Update the value. */ - value = value % 268435456; - - /* Increment the length. */ - length++; - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value/2097152) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/2097152; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 2097152; - - /* Increment the length. */ - length++; - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value / 16384) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/16384; /* (0x10000000) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 16384; - - /* Increment the length. */ - length++; - - - /* Set the encoding started flag so that we put 0 bytes below in cases where value is less than the - next 128 divisor. */ - encoding_started = NX_TRUE; - } - - if ((value /128) || (encoding_started == NX_TRUE)) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* To avoid compiler warnings of casting an ULONG to a UCHAR (loss of information possible), - use an intermediate ULONG pointer. */ - - mod_value = value/128; /* (0x100) */ - - value_ptr = (UCHAR *)(&mod_value); - - /* A UCHAR will not hold more than one byte. */ - byte0 = *(value_ptr); - - *buffer_ptr = ((UCHAR) (byte0)) | NX_SNMP_ANS1_MULTI_BYTES; - - buffer_ptr++; - - /* Update the value. */ - value = value % 128; - - /* Increment the length. */ - length++; - } - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Place the value directly in the buffer. */ - *buffer_ptr++ = (UCHAR) value; - - /* Increment the length. */ - length++; - } - - /* Determine if we are sitting on a dot. */ - if (object_string[i] == '.') - i++; - } - - /* Update the length. */ - length_ptr[0] = (UCHAR) (length & 0xFF); - - /* Return the length plus the header information. */ - return(length + 2); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_object_data_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object data from the supplied ASN.1 */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* object_data Pointer to place object data */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_utility_object_id_get Get object ID */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_object_data_get(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, INT buffer_length) -{ - - -UINT i; -UINT length; -LONG data; -UINT total; -CHAR byte; -LONG temp = 0; -USHORT tlv_type, tlv_tag_class; -UCHAR *tlv_data; -UCHAR *work_ptr; -UINT status; - - - /* Check the buffer length. */ - if (buffer_length < 1) - { - return(0); - } - - work_ptr = buffer_ptr; - - /* First, pickup the request byte. */ - byte = (CHAR)(*buffer_ptr); - - /* Clear several value words. */ - object_data -> nx_snmp_object_data_msw = 0; - object_data -> nx_snmp_object_data_lsw = 0; - - /* Determine if a NULL is present. */ - if (byte == NX_SNMP_ANS1_NULL) - { - - /* Return NULL values in the input object, and set length to 2 (0x05 00). */ - object_data -> nx_snmp_object_data_type = NX_SNMP_ANS1_NULL; - object_data -> nx_snmp_object_data_msw = 0; - return(2); - } - - /* Determine if the object is a standard type. */ - else if ((byte == NX_SNMP_ANS1_OCTET_STRING) || (byte == NX_SNMP_ANS1_INTEGER) || - (byte == NX_SNMP_ANS1_TIME_TICS) || (byte == NX_SNMP_ANS1_GAUGE) || - (byte == NX_SNMP_ANS1_COUNTER) || (byte == NX_SNMP_ANS1_COUNTER64) || - (byte == NX_SNMP_IP_ADDRESS) || (byte == NX_SNMP_ANS1_NSAP_ADDRESS)) - { - - /* Standard object type. */ - - /* Check the buffer length. */ - if (buffer_length < 3) - { - return(0); - } - - /* If this is an integer, determine if we have a negative number (msb is set). */ - if ((*buffer_ptr == NX_SNMP_ANS1_INTEGER) && (*(buffer_ptr + 2) & 0x80)) - { - - /* This only applies if short form (size of length =1), not long form (size of length field > 1 byte) */ - if (((*(buffer_ptr + 1) & 0x80)== 0)) - temp = -1; - - /* We can only check the sign for long form data after we compute the length of length field below */ - } - - /* Update the object with the data type. */ - object_data -> nx_snmp_object_data_type = (UINT)byte; - - /* Extract the length of the length field and tag class. This sill update the pointer past the type - * and length fields to the actual data. */ - status = _nx_snmp_utility_tlv_block_parse(work_ptr, buffer_length, &tlv_type, &tlv_tag_class, (ULONG *)(&total), &tlv_data, (ULONG *)(&length)); - - if (status) - { - return 0; - } - - work_ptr = tlv_data; - - /* Initialize working data. */ - data = temp; - object_data -> nx_snmp_object_octet_string_size = 0; - - i = 0; - - /* handle the special case of a leading zero e.g. 00 DD 2F C9 CE 69 52 74 8D where total is 9 */ - if ((total == 9) && (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING)) - { - /* Skip the first byte and decrement total */ - work_ptr++; - total = total - 1; - } - - - /* Loop through the remaining request length bytes. */ - while (i < total) - { - - /* Pickup next byte. */ - byte = (CHAR)(*work_ptr++); - - /* Determine the type of the data. */ - if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) - { - - /* Check for string size. */ - if ((i) >= NX_SNMP_MAX_OCTET_STRING) - { - return(0); - } - - /* Copy byte into the string. */ - object_data -> nx_snmp_object_octet_string[i] = (UCHAR)byte; - - /* Increment the length. */ - object_data -> nx_snmp_object_octet_string_size++; - } - else - { - - /* Compute the request id based on the next value. */ - data = (data << 8) | ((LONG) (0x000000FF & byte)); - } - - /* Increment the length. */ - length++; - - i++; - - /* If we are dealing with a 64 bit number, store the rest (least) significant bytes in lsw. */ - if ((i == 4) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) - { - object_data -> nx_snmp_object_data_msw = data; - - data = 0x0; - - /* Finish the rest of the data into lsw */ - while(i < total) - { - /* Pickup next byte. */ - byte = (CHAR)(*work_ptr++); - - /* Compute the request id based on the next value. */ - data = (data << 8) | ((LONG) (0x000000FF & byte)); - - i++; - } - - object_data -> nx_snmp_object_data_lsw = data; - } - } - - /* If dealing with a 32 bit data type or less, store the data to msw */ - if (object_data -> nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) - { - object_data -> nx_snmp_object_data_msw = data; - } - else - { - /* Otherwise (e.g. this is a 64 bit data type) store the least significant bytes in the lsw */ - object_data -> nx_snmp_object_data_lsw = data; - } - /* Null terminate the data string. */ - if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) - { - - /* Null terminate string. */ - if ((i > 0) && (i < NX_SNMP_MAX_OCTET_STRING)) - { - object_data -> nx_snmp_object_octet_string[i] = NX_NULL; - } - } - - /* Return the length of the request id string. */ - return(length); - } - else if (byte == NX_SNMP_ANS1_OBJECT_ID) - { - - /* Setup the data type. */ - object_data -> nx_snmp_object_data_type = (UINT)byte; - - /* Convert the object ID to a string. */ - length = _nx_snmp_utility_object_id_get(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_length); - - /* Return length of the object id. */ - return(length); - } - - /* Error; return zero length. */ - return(0); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_object_data_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the object data and then places it in the */ -/* ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* object_data Object data structure */ -/* buffer_end End of ASN.1 buffer for error */ -/* checking */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* _nx_snmp_utility_object_id_set Set object ID */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send Send SNMP v1 Trap */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 Trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 Trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_object_data_set(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, UCHAR *buffer_end) -{ - -UINT i; -UINT length; -UINT data_msw; -UINT data_lsw; - - - /* Process relative to the type of request. */ - - /* See if the request is a NULL. */ - if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NULL) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_OBJECT) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NO_SUCH_INSTANCE) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 2) >= buffer_end) - return(0); - - /* Set the NULL type byte. */ - *buffer_ptr++ = (UCHAR) object_data -> nx_snmp_object_data_type; - *buffer_ptr = 0; - - /* Set the length. */ - length = 2; - } - - /* See if the request is an INTEGER. */ - else if ((object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_INTEGER) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_UINTEGER32) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_TIME_TICS) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_GAUGE) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS) || - (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_NSAP_ADDRESS)) - { - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the type byte. */ - *buffer_ptr++ = (UCHAR)object_data -> nx_snmp_object_data_type; - - /* Pickup the data most significant word. */ - data_msw = (UINT)(object_data -> nx_snmp_object_data_msw); - - /* Pickup the data least significant word. */ - data_lsw = (UINT)(object_data -> nx_snmp_object_data_lsw); - - /* Determine the size of the encoding. */ - if (((data_msw & 0xFF000000) || (data_msw & 0x00800000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 9) >= buffer_end) - return(0); - - /* Four bytes are required. */ - *buffer_ptr++ = ((UCHAR) 8); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); - - /* Update the length. */ - length = 10; - return(length); - } - else if (((data_msw & 0x00FF0000) || (data_msw & 0x00008000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 8) >= buffer_end) - return(0); - - /* Three bytes are required. */ - *buffer_ptr++ = ((UCHAR) 7); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); - - /* Update the length. */ - length = 9; - return(length); - } - else if (((data_msw & 0x0000FF00) || (data_msw & 0x00000080)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 7) >= buffer_end) - return(0); - - /* Two bytes are required. */ - *buffer_ptr++ = ((UCHAR) 6); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); - - /* Update the length. */ - length = 8; - return(length); - } - else if (((data_msw & 0x000000FF) || (data_lsw & 0x80000000)) && (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 6) >= buffer_end) - return(0); - - /* One byte is required. */ - *buffer_ptr++ = ((UCHAR) 5); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_lsw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_lsw & 0xFF); - - /* Update the length. */ - length = 7; - return(length); - } - else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_COUNTER64) - { - - /* Make the least significant word the most significant to use the normal integer processing below. */ - data_msw = data_lsw; - } - - /* Determine the size of the encoding. */ - if ((data_msw & 0xFF000000) || (data_msw & 0x00800000) || (object_data -> nx_snmp_object_data_type == NX_SNMP_IP_ADDRESS)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 5) >= buffer_end) - return(0); - - /* Four bytes are required. */ - *buffer_ptr++ = ((UCHAR) 4); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - - /* Update the length. */ - length = 6; - } - else if ((data_msw & 0x00FF0000) || (data_msw & 0x00008000)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 4) >= buffer_end) - return(0); - - /* Three bytes are required. */ - *buffer_ptr++ = ((UCHAR) 3); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - - /* Update the length. */ - length = 5; - } - else if ((data_msw & 0x0000FF00) || (data_msw & 0x00000080)) - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 3) >= buffer_end) - return(0); - - /* Two bytes are required. */ - *buffer_ptr++ = ((UCHAR) 2); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((data_msw >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - - /* Update the length. */ - length = 4; - } - else - { - - /* Check for the end of the buffer. */ - if ((buffer_ptr + 2) >= buffer_end) - return(0); - - /* One byte is required. */ - *buffer_ptr++ = ((UCHAR) 1); - - /* Set the value in successive bytes. */ - *buffer_ptr++ = (UCHAR) (data_msw & 0xFF); - - /* Update the length. */ - length = 3; - } - } - - /* See if the request is an octet string. Note that this includes the IPv6 address type. */ - else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the OCTET type byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Determine if a two byte length is required. */ - if (object_data -> nx_snmp_object_octet_string_size >= 128) - { - - /* A two byte length is required. */ - - /* Set the two byte length. */ - *buffer_ptr++ = 0x82; - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the first byte of the length. */ - *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size >> 8); - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the second byte of the length. */ - *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF); - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the length to represent the 4 byte header. */ - length = 4; - } - else - { - - /* Set the length byte. */ - *buffer_ptr++ = (UCHAR) (object_data -> nx_snmp_object_octet_string_size & 0xFF); - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Set the length to represent the 2 byte header. */ - length = 2; - } - - /* Loop to process the string. */ - i = 0; - while (i < object_data -> nx_snmp_object_octet_string_size) - { - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* Place octet string into buffer. */ - *buffer_ptr++ = object_data -> nx_snmp_object_octet_string[i++]; - } - - /* Account for the leading bytes in the length. */ - length = length + i; - } - - else if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OBJECT_ID) - { - - /* Call the object set routine. */ - length = _nx_snmp_utility_object_id_set(buffer_ptr, object_data -> nx_snmp_object_octet_string, buffer_end); - } - else - { - - /* Unhandled, return an error by setting length to 0. */ - length = 0; - } - - /* Return the length. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_octet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the octet string from the supplied ASN.1 */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* octet_string Pointer to destination for */ -/* the octet string */ -/* max_octet_length Size of octet string buffer */ -/* octet_length Pointer to length for octet */ -/* string */ -/* buffer_length Size of input buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_octet_get(UCHAR *buffer_ptr, UCHAR *octet_string, UINT max_octet_length, UINT *octet_length, INT buffer_length) -{ - -UINT i; -UINT length; -UINT total; - - - /* Buffer size must be at least 2 bytes. */ - if (buffer_length < 2) - { - return(0); - } - - /* Set the octet length to zero. */ - *octet_length = 0; - - /* First see if the ANS1 string type is present. */ - if (buffer_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) - { - - /* Return a zero length. */ - return(0); - } - - /* Determine if a two byte length is present. */ - if (*(buffer_ptr + 1) & NX_SNMP_ANS1_MULTI_BYTES) - { - - UINT temp = *(buffer_ptr + 1) & 0x7F; - - if (temp == 2) - { - - /* A two byte length is present. */ - - /* Check the buffer length. */ - if (buffer_length < 4) - { - return(0); - } - - /* Pickup the length. */ - total = (((UINT) buffer_ptr[2]) << 8) | ((UINT) buffer_ptr[3]); - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 4; - - /* Initialize the length. */ - length = 4; - } - else if (temp == 1) - { - - /* Check the buffer length. */ - if (buffer_length < 3) - { - return(0); - } - - /* Otherwise, pickup the total length of the octet string. */ - total = (UINT) buffer_ptr[2]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 3; - - /* Initialize the length. */ - length = 3; - } - else - { - - /* Invalid sequence. Too big or null size type. */ - return(0); - } - } - else - { - - /* Otherwise, assume 1 byte. Pickup the total length of the octet string. */ - total = (UINT) buffer_ptr[1]; - - /* Move the buffer pointer forward. */ - buffer_ptr = buffer_ptr + 2; - - /* Initialize the length. */ - length = 2; - } - - /* Check for invalid buffer size. */ - if ((INT)(length + total) > buffer_length) - { - /* Indicate an invalid request or packet is received. */ - return 0; - } - - /* Determine if the octet string is too large. */ - if (total > max_octet_length) - { - - /* Yes, the octet string is too large. Return an error. */ - return(0); - } - - /* Loop to pickup the remaining characters in the community string. */ - for (i = 0; i < total; i++) - { - - /* Move character from buffer into community string. */ - *octet_string++ = *buffer_ptr++; - - /* Adjust the length. */ - length++; - } - - /* return the length of the octet string. */ - *octet_length = total; - - /* Return the length of the ANS1 string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_octet_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the supplied octet string into the ASN.1 */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* octet_string Pointer to octet string */ -/* octet_length Length of the octet string */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_octet_set(UCHAR *buffer_ptr, UCHAR *octet_string, UINT octet_length, UCHAR *buffer_end) -{ - -UINT i; -UINT header_size; - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* First, set the OCTET byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_OCTET_STRING; - - /* Check for a length greater than the maximum. */ - if (octet_length > NX_SNMP_MAX_OCTET_STRING) - { - - /* Error, octet string is too large. */ - return(0); - } - - /* Determine if a two byte length is required. */ - if (octet_length >= 128) - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < (3 + octet_length)) - return(0); - - /* Set the two byte length flag. */ - *buffer_ptr++ = (UCHAR) 0x82; - - /* Set the first length byte. */ - *buffer_ptr++ = (UCHAR) (octet_length >> 8); - - /* Set the second length byte. */ - *buffer_ptr++ = (UCHAR) (octet_length & 0xFF); - - /* Set the header size. */ - header_size = 4; - } - else - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < (1 + octet_length)) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) octet_length; - - /* Set the header size. */ - header_size = 2; - } - - /* Loop to store rest of the community string. */ - for (i = 0; i < octet_length; i++) - { - - /* Store the SNMP octet string. */ - *buffer_ptr++ = (UCHAR) octet_string[i]; - } - - /* Return the length of the community string. */ - return(octet_length+header_size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_sequence_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the ASN.1 sequence from the supplied ASN.1 */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* sequence_value Pointer to destination for */ -/* the sequence value */ -/* buffer_length Size of buffer data */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_thread_entry SNMP Agent's thread entry */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_sequence_get(UCHAR *buffer_ptr, UINT *sequence_value, INT buffer_length) -{ - -UINT i; -UINT length; -UINT value; -UINT total; -UCHAR byte; - - - /* Buffer size must be at least 2 bytes. */ - if (buffer_length < 2) - { - return(0); - } - - /* First, pickup the sequence byte. */ - byte = *buffer_ptr++; - - /* Determine if the byte is a sequence byte (0x30). */ - if (byte != NX_SNMP_ANS1_SEQUENCE) - { - - /* Error, not a sequence byte, return a NULL. */ - *sequence_value = 0; - return(0); - } - - /* Otherwise, we have a valid sequence byte. */ - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Initialize the length of the sequence field to 2. */ - length = 2; - - /* Determine if the next byte has the additional bytes - bit set (BIT 7). */ - if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) - { - - /* The specified sequence value is less than 128 and is actually in this byte! */ - *sequence_value = (UINT) byte; - - /* Return the actual length of the ANS1 sequence string. */ - return(length); - } - - /* Otherwise, we have a more complicated sequence length that we must loop through - to calculate the actual sequence length. */ - - /* Pickup the number of bytes required to represent the sequence length. */ - total = (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); - - /* Check for invalid buffer size. */ - if ((INT)(length + total) > buffer_length) - { - /* Indicate an invalid request or packet is received. */ - return 0; - } - - value = 0; - - /* Loop through the remaining sequence bytes. */ - for (i = 0; i < total; i++) - { - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Compute the sequence based on the next value. */ - value = (value << 8) | ((UINT) byte); - - /* Increment the length. */ - length++; - } - - /* Return the calculated sequence value. */ - *sequence_value = value; - - /* Return the length of the sequence string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_sequence_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the sequence number into the ASN.1 */ -/* buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* sequence_value Sequence value */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_sequence_set(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end) -{ - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 4) - return(0); - - /* First, set the sequence byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_SEQUENCE; - - /* Next set the continue bit to force two additional bytes for length. */ - *buffer_ptr++ = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; - - /* Store the MSB. */ - *buffer_ptr++ = (UCHAR) ((sequence_value >> 8) & 0xFF); - - /* Store the LSB. */ - *buffer_ptr = (UCHAR) (sequence_value & 0xFF); - - /* Return the length of the sequence string. */ - return(4); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_sequence_set_1byte PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the sequence number into the ASN.1 */ -/* buffer. The difference with _nx_snmp_utility_sequence_set is that */ -/* this uses only a single byte length field e.g. 0x30 xx instead of */ -/* 0x30 0x82 xx yy where xx(yy) is the sequence length (1 vs 2 bytes). */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* sequence_value Sequence value */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_snmp_utility_sequence_set_1byte(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end) -{ - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 2) - return(0); - - /* First, set the sequence byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_SEQUENCE; - - /* Store the value. */ - *buffer_ptr = (UCHAR) (sequence_value & 0xFF); - - /* Return the length of the sequence string. */ - return(2); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_request_id_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the ASN.1 request ID from the supplied */ -/* ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* request_id Pointer to destination for */ -/* the request ID */ -/* buffer_length Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_request_id_get(UCHAR *buffer_ptr, ULONG *request_id, INT buffer_length) -{ - -UINT i; -UINT length; -ULONG value; -UINT total; -UCHAR byte; - - - /* Buffer size must be at least 2 bytes. */ - if (buffer_length < 2) - { - return(0); - } - - /* First, pickup the request byte. */ - byte = *buffer_ptr++; - - /* Determine if the byte is a valid SNMP request type. */ - if (byte != NX_SNMP_ANS1_INTEGER) - { - - /* Error, not request id, return a NULL. */ - *request_id = 0; - return(0); - } - - /* Otherwise, we have a valid request id. */ - - /* Pickup the ANS1 length byte. */ - total = (UINT) *buffer_ptr++; - - /* Initialize the length of the request field to 2. */ - length = 2; - - /* Check the length specified in the buffer against buffer size. */ - if ((INT)(length + total) > buffer_length) - { - *request_id = 0; - return(0); - } - - /* Initialize working request length. */ - value = 0; - - /* Loop through the remaining request length bytes. */ - for (i = 0; i < total; i++) - { - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Compute the request id based on the next value. */ - value = (value << 8) | ((ULONG) byte); - - /* Increment the length. */ - length++; - } - - /* Return the calculated request id. */ - *request_id = value; - - /* Return the length of the request id string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_request_id_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the request ID into the ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* request_id Request ID */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_request_id_set(UCHAR *buffer_ptr, ULONG request_id, UCHAR *buffer_end) -{ - -UINT length; - - - /* Check for the end of the buffer. */ - if (buffer_ptr >= buffer_end) - return(0); - - /* First, set the INTEGER byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; - - /* Determine how big the ID is. */ - if ((request_id & 0xFF000000UL) || (request_id & 0x00800000)) - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 5) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 4; - - /* Set the request ID in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((request_id >> 24) & 0xFF); - *buffer_ptr++ = (UCHAR) ((request_id >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (request_id & 0xFF); - - /* Update the length. */ - length = 6; - } - else if ((request_id & 0x00FF0000UL) || (request_id & 0x00008000)) - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 4) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 3; - - /* Set the request ID in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((request_id >> 16) & 0xFF); - *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (request_id & 0xFF); - - /* Update the length. */ - length = 5; - } - else if ((request_id & 0x0000FF00UL) || (request_id & 0x00000080)) - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 3) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 2; - - /* Set the request ID in successive bytes. */ - *buffer_ptr++ = (UCHAR) ((request_id >> 8) & 0xFF); - *buffer_ptr++ = (UCHAR) (request_id & 0xFF); - - /* Update the length. */ - length = 4; - } - else - { - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 2) - return(0); - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 1; - - /* Set the request ID in successive bytes. */ - *buffer_ptr++ = (UCHAR) (request_id & 0xFF); - - /* Update the length. */ - length = 3; - } - - /* Return the length of the request ID. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_request_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the ASN.1 request type from the supplied */ -/* ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* request_type Pointer to destination for */ -/* the request type */ -/* request_length Pointer to destination for */ -/* the request length */ -/* buffer_length Size of input buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_request_type_get(UCHAR *buffer_ptr, UINT *request_type, UINT *request_length, INT buffer_length) -{ - -UINT i; -UINT length; -UINT value; -UINT total; -UCHAR byte; - - - /* Buffer size must be at least 2 bytes. */ - if (buffer_length < 2) - { - return(0); - } - - /* First, pickup the request byte. */ - byte = *buffer_ptr++; - - /* Determine if the byte is a valid SNMP request type. */ - if ((byte < NX_SNMP_ANS1_SEQUENCE) || (byte > NX_SNMP_ANS1_TRAP2_REQUEST)) - { - - /* Error, not request, return a NULL. */ - *request_type = 0; - *request_length = 0; - return(0); - } - - /* Otherwise, we have a valid request. */ - - /* Store the request in the destination. */ - *request_type = (UINT) byte; - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Initialize the length of the request field to 2. */ - length = 2; - - /* Determine if the next byte has the additional bytes - bit set (BIT 7). */ - if ((byte & NX_SNMP_ANS1_MULTI_BYTES) == 0) - { - - /* The specified request length is less than 128 and is actually in this byte! */ - *request_length = (UINT) byte; - - /* Return the actual length of the ANS1 request string. */ - return(length); - } - - /* Otherwise, we have a more complicated request length that we must loop through - to calculate the actual length. */ - - /* Pickup the number of bytes required to represent the request length. */ - total = (UINT) (byte & ~NX_SNMP_ANS1_MULTI_BYTES); - - if ((INT)(length + total) > buffer_length) - { - /* Error, invalid request, return a NULL. */ - *request_type = 0; - *request_length = 0; - return(0); - } - - /* Initialize working request length. */ - value = 0; - - /* Loop through the remaining request length bytes. */ - for (i = 0; i < total; i++) - { - - /* Pickup next byte. */ - byte = *buffer_ptr++; - - /* Compute the request length based on the next value. */ - value = (value << 8) | ((UINT) byte); - - /* Increment the length. */ - length++; - } - - /* Return the calculated request length. */ - *request_length = value; - - /* Return the length of the request string. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_request_type_set_1byte PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the request type into the ASN.1 buffer. It is */ -/* intended for small requests whose size value can fit into one byte. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* request_type Request type */ -/* request_length Request length */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_request_type_set_1byte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end) -{ - - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 2) - return(0); - - /* First, set the request type byte. */ - *buffer_ptr++ = (UCHAR) request_type; - - /* Store the request_length. */ - *buffer_ptr = (UCHAR) (request_length & 0xFF); - - return 2; - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_request_type_set_multibyte PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the request type into the ASN.1 buffer. It is */ -/* intended for large requests whose size value requires more than one */ -/* byte, e.g. A2 82 xx yy. For get, getnext requests, and report and */ -/* trap responses, use _nx_snmp_utility_request_type_set_1byte. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* request_type Request type */ -/* request_length Request length */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_request_type_set_multibyte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end) -{ - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 4) - return(0); - - /* First, set the request type byte. */ - *buffer_ptr++ = (UCHAR) request_type; - - /* Set the continue bit to force two additional bytes for length. */ - *buffer_ptr++ = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; - - /* Store the MSB. */ - *buffer_ptr++ = (UCHAR) ((request_length >> 8) & 0xFF); - - /* Store the LSB. */ - *buffer_ptr = (UCHAR) (request_length & 0xFF); - - return 4; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_version_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the SNMP version from the supplied */ -/* ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* snmp_version Pointer to destination for */ -/* the snmp_version */ -/* buffer_length Size of buffer data */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_thread_entry SNMP Agent's thread entry */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_version_get(UCHAR *buffer_ptr, UINT *snmp_version, INT buffer_length) -{ - - if (buffer_length < 3) - { - - /* Clear the version. */ - *snmp_version = 0; - - /* Return a zero length. */ - return(0); - } - - /* Determine if the version string is correct. */ - if ((buffer_ptr[0] == NX_SNMP_ANS1_INTEGER) && - (buffer_ptr[1] == 1) && - ((buffer_ptr[2] == NX_SNMP_VERSION_1) || (buffer_ptr[2] == NX_SNMP_VERSION_2) || - (buffer_ptr[2] == NX_SNMP_VERSION_2C) || (buffer_ptr[2] == NX_SNMP_VERSION_3))) - { - - /* Yes, the SNMP version string is correct. */ - - /* Return the version. */ - *snmp_version = (UINT) buffer_ptr[2]; - - /* Return the length of the version string. */ - return(3); - } - else - { - - /* No, the SNMP version string is invalid. */ - - /* Clear the version. */ - *snmp_version = 0; - - /* Return a zero length. */ - return(0); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_utility_version_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the SNMP version into the ASN.1 buffer. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to ASN.1 buffer */ -/* snmp_version SNMP version number */ -/* buffer_end End of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* ASN.1 length Length of ASN.1 sequence, a */ -/* value of zero implies error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_trap_send Send SNMP v1 trap */ -/* _nx_snmp_agent_trapv2_send Send SNMP v2 trap */ -/* _nx_snmp_agent_trapv3_send Send SNMP v3 trap */ -/* _nx_snmp_version_1_process Process SNMP v1 request */ -/* _nx_snmp_version_2_process Process SNMP v2 request */ -/* _nx_snmp_version_3_report_send Send SNMP v3 report */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_version_set(UCHAR *buffer_ptr, UINT snmp_version, UCHAR *buffer_end) -{ - - /* Check for the end of the buffer. */ - if ((UINT)(buffer_end - buffer_ptr) < 3) - return(0); - - /* First, set the INTEGER byte. */ - *buffer_ptr++ = NX_SNMP_ANS1_INTEGER; - - /* Next set the length byte. */ - *buffer_ptr++ = (UCHAR) 1; - - /* Store the SNMP version. */ - *buffer_ptr = (UCHAR) (snmp_version & 0xFF); - - /* Return the length of the sequence string. */ - return(3); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_version_error_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function places the error information into the SNMP Manager's */ -/* request packet and returns it to the manager. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* packet_ptr Pointer to packet containing */ -/* the original SNMP request */ -/* request_type_ptr Pointer to place in ASN.1 */ -/* buffer for the request type */ -/* error_string_ptr Pointer to place in ASN.1 */ -/* buffer to place error info */ -/* error_code Error code */ -/* error_index Error index */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release the packet */ -/* nx_udp_socket_send Send the UDP packet */ -/* _nx_snmp_utility_error_info_set Set the error information */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_1_process SNMP v1 message processing */ -/* _nx_snmp_version_2_process SNMP v2 message processing */ -/* _nx_snmp_version_3_process SNMP v3 message processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, - UCHAR *error_string_ptr, UINT error_code, UINT error_index) -{ - -UINT status; -#ifndef NX_SNMP_DISABLE_V3 -ULONG temp; -#endif - - /* Increment the error counter. */ - agent_ptr -> nx_snmp_agent_request_errors++; - - /* Determine which specific error counter to increment. */ - switch(error_code) - { - case NX_SNMP_ERROR_TOOBIG: - agent_ptr -> nx_snmp_agent_too_big_errors++; - break; - case NX_SNMP_ERROR_BADVALUE: - case NX_SNMP_ERROR_WRONGVALUE: - case NX_SNMP_ERROR_WRONGENCODING: - case NX_SNMP_ERROR_WRONGTYPE: - case NX_SNMP_ERROR_WRONGLENGTH: - case NX_SNMP_ERROR_INCONSISTENTVALUE: - agent_ptr -> nx_snmp_agent_bad_value_errors++; - break; - case NX_SNMP_ERROR_NOSUCHNAME: - case NX_SNMP_ERROR_NOACCESS: - case NX_SNMP_ERROR_NOTWRITABLE: - case NX_SNMP_ERROR_NOCREATION: - case NX_SNMP_ERROR_INCONSISTENTNAME: - case NX_SNMP_ERROR_AUTHORIZATION: - agent_ptr -> nx_snmp_agent_no_such_name_errors++; - break; - case NX_SNMP_ERROR_GENERAL: - case NX_SNMP_ERROR_RESOURCEUNAVAILABLE: - case NX_SNMP_ERROR_COMMITFAILED: - case NX_SNMP_ERROR_UNDOFAILED: - agent_ptr -> nx_snmp_agent_general_errors++; - break; - } - - /* Set the request type to get/response. */ - *request_type_ptr = (UCHAR) NX_SNMP_ANS1_GET_RESPONSE; - - /* Update the error string with the error code and the object index. */ - _nx_snmp_utility_error_info_set(error_string_ptr, error_code, error_index, packet_ptr -> nx_packet_data_end); - -#ifndef NX_SNMP_DISABLE_V3 - /* Is the security set to encryption? */ - temp = (ULONG)agent_ptr -> nx_snmp_agent_v3_message_security_options; - if (temp & NX_SNMP_SECURITY_PRIVACY) - { - - /* Encrypt the PDU and setup the response to have an encryption header. This - will also compute our privacy parameter. */ - _nx_snmp_agent_encrypt_pdu(agent_ptr, NX_NULL, NX_NULL, - NX_NULL, NX_NULL, - NX_NULL, NX_NULL, pdu_privacy_ptr); - } - - /* Is the security set to authentication? */ - if (temp & NX_SNMP_SECURITY_AUTHORIZE) - { - - /* Compute our authentication parameter. */ - status = _nx_snmp_agent_add_auth_parameter(agent_ptr, packet_ptr, pdu_auth_parm_ptr); - } -#endif - - /* Increment the sent packet counter. */ - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Increment the get responses sent counter. */ - agent_ptr -> nx_snmp_agent_getresponse_sent++; - - /* Send the response packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), packet_ptr, - &(agent_ptr -> nx_snmp_agent_current_manager_ip), - agent_ptr -> nx_snmp_agent_current_manager_port); - - /* Check for successful call. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Return to caller. */ - return; -} - -#ifndef NX_SNMP_DISABLE_V1 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_version_1_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the SNMP v1 request from the manager. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* packet_ptr Pointer to packet containing */ -/* the SNMP request */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate response packet */ -/* nx_packet_release Release the packet */ -/* nx_udp_socket_send Send the UDP packet */ -/* _nx_snmp_utility_community_get Get the community name */ -/* _nx_snmp_utility_community_set Set the community name */ -/* _nx_snmp_utility_error_info_get Get the error information */ -/* _nx_snmp_utility_error_info_set Set the error information */ -/* _nx_snmp_utility_object_data_get Get the object data */ -/* _nx_snmp_utility_object_data_set Set the object data */ -/* _nx_snmp_utility_object_id_get Get the object ID */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_request_id_get Get the request ID */ -/* _nx_snmp_utility_request_id_set Set the request ID */ -/* _nx_snmp_utility_request_type_get Get the request type */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ -/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ -/* _nx_snmp_utility_version_get Get the SNMP version */ -/* _nx_snmp_utility_version_set Set the SNMP version */ -/* _nx_snmp_version_error_response Send SNMP Manager error */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_thread_entry SNMP Agent thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) -{ - -UINT sequence_length, version, request_type, request_length; -UINT error_code, error_index; -UINT variable_list_length, variable_length; -ULONG request_id; -UINT status, length, objects; -UCHAR *buffer_ptr; -UCHAR *variable_start_ptr = NX_NULL; -UCHAR *error_ptr, *request_type_ptr; -UINT response_length; -UINT total_variable_length = 0; -NX_PACKET *response_packet_ptr; -UCHAR *response_buffer_ptr; -UINT response_sequence_length, response_type_length; -UINT response_variable_list_length, response_variable_length; -UCHAR *response_sequence_ptr, *response_type_ptr; -UCHAR *response_variable_list_ptr, *response_variable_ptr; -UINT packet_type; -INT buffer_length; - - - buffer_length = (INT)(packet_ptr -> nx_packet_length); - - /* Setup a pointer to the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the SEQUENCE field. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP VERSION field. */ - length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP Community String field. */ - length = _nx_snmp_utility_community_get(buffer_ptr, - agent_ptr -> nx_snmp_agent_current_community_string, - buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Save the request type pointer. */ - request_type_ptr = buffer_ptr; - - /* Pickup the SNMP Request type. */ - length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; - if ((request_type == NX_SNMP_GET_REQUEST) || - (request_type == NX_SNMP_GET_NEXT_REQUEST) || - (request_type == NX_SNMP_GET_BULK_REQUEST)) - { - agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; - } - - /* Pickup the SNMP Request ID. */ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Save a pointer to the error string. */ - error_ptr = buffer_ptr; - - - /* Pickup the SNMP Error information. */ - length = _nx_snmp_utility_error_info_get(buffer_ptr, &error_code, &error_index, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Determine if the received packet size is too big. */ - if (packet_ptr -> nx_packet_next) - { - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); - - /* Done, return to caller. */ - return; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - if (agent_ptr -> nx_snmp_agent_username_process) - { - - status = agent_ptr -> nx_snmp_agent_username_process(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string); - - /* Determine if the callback routine generated an error. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of community/username errors. */ - agent_ptr -> nx_snmp_agent_username_errors++; - -#ifdef NX_SNMP_V1_AUTHORIZATION_ERROR_RESPONSE - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, 0); -#else - /* Authorization error response is not supported by version 1. */ - /* Release the packet. */ - nx_packet_release(packet_ptr); -#endif - - /* Done, return to caller. */ - return; - } - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP Variable list length. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* At this point we have parsed the incoming SNMP request up to the first - variable. */ - - /* Now prepare response message so we can process the variables one by one. */ - - /* Determine which packet type we allocate based on the destination address type. */ - if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif /* FEATURE_NX_IPV6 */ - } - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Allocate the packet for the SNMP response. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a response packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the response packet. */ - response_sequence_length = 0; - response_type_length = 0; - response_variable_list_length = 0; - - /* Setup a pointer to the response packet's buffer area. */ - response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the response sequence pointer. Remember it since we are going to have to - update it later with the actual length of the response. */ - response_sequence_ptr = response_buffer_ptr; - - /* First, write the sequence in the response packet. A zero is written for now. This will be - updated later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Now set the SNMP version in the response. */ - response_length = _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_1, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Set the SNMP community in the response message. */ - response_length = _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Remember the request type pointer, since it will need to be updated later. */ - response_type_ptr = response_buffer_ptr; - - /* Now set the request type in the response message. */ - response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Now set the request ID in the response message. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Set the response error information. Assume everything is okay at this point. */ - response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Remember the start of the response's variable list field. */ - response_variable_list_ptr = response_buffer_ptr; - - /* Setup the variable list response. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* At this point the response buffer is setup to exactly the same position the - SNMP Manager's input buffer is - right before the first variable. We can - now walk through the variable list to process each request and place the - result in the response buffer. */ - objects = 0; - do - { - - /* Remember the start of the variable. */ - variable_start_ptr = buffer_ptr; - - /* Pickup the first SNMP Variable length. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); - - /* Calculate the total variable size. */ - total_variable_length = variable_length + length; - - /* Determine if this variable will fit in the remaining length of the - variable list. */ - if ((length == 0) || (total_variable_length > variable_list_length)) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Send an SNMP version error response. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* Update the size of the remaining buffer. */ - buffer_length -= (INT)length; - - /* Now pickup the object ID. */ - length = _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length); - - /* Determine if the object retrieval was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* Update the size of the remaining buffer. */ - buffer_length -= (INT)length; - - /* Default the value to NULL. */ - agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; - - /* Determine if a value is present. */ - if (length != variable_length) - { - - /* Pickup the value associated with this variable. */ - length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); - - /* Determine if the object value was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Send an SNMP version error response. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - } - - /* At this point, we are ready to call the appropriate application request handling routine. - It is responsible for extracting or placing information in the object data structure. */ - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GET routine. */ - status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GETNEXT routine. */ - status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - { - - /* Increment the total number of set variables. */ - agent_ptr -> nx_snmp_agent_total_set_variables++; - - /* Call the application's SET routine. */ - status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Check for an error status from the agent's request processing callback routine. */ - if (status) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Per RFC2576 4.3 */ - switch(status) - { - case NX_SNMP_SUCCESS: - case NX_SNMP_ERROR_TOOBIG: - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects+1); - break; - case NX_SNMP_ERROR_BADVALUE: - case NX_SNMP_ERROR_WRONGVALUE: - case NX_SNMP_ERROR_WRONGENCODING: - case NX_SNMP_ERROR_WRONGTYPE: - case NX_SNMP_ERROR_WRONGLENGTH: - case NX_SNMP_ERROR_INCONSISTENTVALUE: - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); - break; - case NX_SNMP_ERROR_NOSUCHNAME: - case NX_SNMP_ERROR_NOACCESS: - case NX_SNMP_ERROR_NOTWRITABLE: - case NX_SNMP_ERROR_NOCREATION: - case NX_SNMP_ERROR_INCONSISTENTNAME: - case NX_SNMP_ERROR_AUTHORIZATION: - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects+1); - break; - case NX_SNMP_ERROR_GENERAL: - case NX_SNMP_ERROR_RESOURCEUNAVAILABLE: - case NX_SNMP_ERROR_COMMITFAILED: - case NX_SNMP_ERROR_UNDOFAILED: - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_GENERAL, objects+1); - break; - default: - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Done, return to caller. */ - return; - } - - /* Determine if the returning object is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Now ensure the returning object type is supported in V1. */ - if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && -#ifdef FEATURE_NX_IPV6 - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && -#endif - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID)) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Everything is okay, place the object and object data into the response buffer. */ - - /* Remember the start of the variable response sequence. */ - response_variable_ptr = response_buffer_ptr; - - /* Clear the response variable size. */ - response_variable_length = 0; - - /* Determine if there is enough room in the destination for the variable sequence. */ - if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); - - /* Done, return to caller. */ - return; - } - - /* Setup the variable response sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Place the object into the response buffer. */ - response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Insert the object's data into the response buffer. */ - response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects+1); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Now update the response variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); - - /* Adjust the pointer to the next variable. */ - buffer_ptr = variable_start_ptr + total_variable_length; - - /* Decrement the size of the variable list. */ - variable_list_length = variable_list_length - total_variable_length; - - /* Increment the object counter. */ - objects++; - - } while (variable_list_length); - - /* At this point, several response fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); - - /* Now the response packet's pointers must be setup so it can be sent. */ - response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); - response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; - - /* Release the original request packet. */ - nx_packet_release(packet_ptr); - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; - agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - agent_ptr -> nx_snmp_agent_get_requests++; - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - agent_ptr -> nx_snmp_agent_getnext_requests++; - else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) - agent_ptr -> nx_snmp_agent_getbulk_requests++; - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - agent_ptr -> nx_snmp_agent_set_requests++; - - /* Increment the sent packet counter. */ - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Increment the get responses sent counter. */ - agent_ptr -> nx_snmp_agent_getresponse_sent++; - - /* Send the response packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, - &(agent_ptr -> nx_snmp_agent_current_manager_ip), - agent_ptr -> nx_snmp_agent_current_manager_port); - - /* Check for successful call. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - } -} -#endif /* NX_SNMP_DISABLE_V1 */ - - -#ifndef NX_SNMP_DISABLE_V2 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_version_2_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the SNMP v2 request from the manager. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* packet_ptr Pointer to packet containing */ -/* the SNMP request */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate response packet */ -/* nx_packet_release Release the packet */ -/* nx_udp_socket_send Send the UDP packet */ -/* _nx_snmp_utility_community_get Get the community name */ -/* _nx_snmp_utility_community_set Set the community name */ -/* _nx_snmp_utility_error_info_get Get the error information */ -/* _nx_snmp_utility_error_info_set Set the error information */ -/* _nx_snmp_utility_object_data_get Get the object data */ -/* _nx_snmp_utility_object_data_set Set the object data */ -/* _nx_snmp_utility_object_id_get Get the object ID */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_request_id_get Get the request ID */ -/* _nx_snmp_utility_request_id_set Set the request ID */ -/* _nx_snmp_utility_request_type_get Get the request type */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ -/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ -/* _nx_snmp_utility_version_get Get the SNMP version */ -/* _nx_snmp_utility_version_set Set the SNMP version */ -/* _nx_snmp_version_error_response Send SNMP Manager error */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_thread_entry SNMP Agent thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_version_2_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) -{ - -UINT sequence_length, version, request_type, request_length; -UINT non_repeaters, max_repetitions, current_repetitions, next_object; -UINT variable_list_length, variable_length; -ULONG request_id; -UINT status, length, objects; -UCHAR *buffer_ptr; -UCHAR *variable_start_ptr = NX_NULL; -UCHAR *error_ptr, *request_type_ptr; -UINT response_length; -UINT total_variable_length = 0; -NX_PACKET *response_packet_ptr; -UCHAR *response_buffer_ptr; -UINT response_sequence_length, response_type_length; -UINT response_variable_list_length, response_variable_length; -UCHAR *response_sequence_ptr, *response_type_ptr; -UCHAR *response_variable_list_ptr, *response_variable_ptr; -UINT packet_type; -INT buffer_length; - - buffer_length = (INT)(packet_ptr -> nx_packet_length); - - /* Setup a pointer to the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the SEQUENCE field. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP VERSION field. */ - length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP Community String field. */ - length = _nx_snmp_utility_community_get(buffer_ptr, - agent_ptr -> nx_snmp_agent_current_community_string, - buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Save the request type pointer. */ - request_type_ptr = buffer_ptr; - - /* Pick up the SNMP Request type. */ - length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; - if ((request_type == NX_SNMP_GET_REQUEST) || - (request_type == NX_SNMP_GET_NEXT_REQUEST) || - (request_type == NX_SNMP_GET_BULK_REQUEST)) - { - agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; - } - - /* Pickup the SNMP Request ID. */ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Save a pointer to the error string. */ - error_ptr = buffer_ptr; - - /* Pickup the SNMP Error information. This is actually used to derive the GETBULK - information in SNMP V2 and above. */ - length = _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Determine if the received packet size is too big. */ - if (packet_ptr -> nx_packet_next) - { - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); - - /* Done, return to caller. */ - return; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - - - /* Check to see if there is a username processing routine. */ - if (agent_ptr -> nx_snmp_agent_username_process) - { - - /* Yes, there is a callback routine to process the community/username. */ - status = (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_community_string); - - /* Determine if the callback routine generated an error. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of community/username errors. */ - agent_ptr -> nx_snmp_agent_username_errors++; - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_AUTHORIZATION, 0); - - /* Done, return to caller. */ - return; - } - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP Variable list length. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* At this point we have parsed the incoming SNMP request up to the first - variable. */ - - /* Now prepare response message so we can process the variables one by one. */ - - /* Determine which packet type we allocate based on the destination address type. */ - if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif /* FEATURE_NX_IPV6 */ - - } - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Allocate the packet for the SNMP response. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a response packet was allocated. */ - if (status) - { - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the response packet. */ - response_sequence_length = 0; - response_type_length = 0; - response_variable_list_length = 0; - - /* Setup a pointer to the response packet's buffer area. */ - response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the response sequence pointer. Remember it since we are going to have to - update it later with the actual length of the response. */ - response_sequence_ptr = response_buffer_ptr; - - /* First, write the sequence in the response packet. A zero is written for now. This will be - updated later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Now set the SNMP version in the response. */ - response_length = _nx_snmp_utility_version_set(response_buffer_ptr, version, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Set the SNMP community in the response message. */ - response_length = _nx_snmp_utility_community_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_community_string, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Remember the request type pointer, since it will need to be updated later. */ - response_type_ptr = response_buffer_ptr; - - /* Now set the request type in the response message. */ - response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Now set the request ID in the response message. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Set the response error information. Assume everything is okay at this point. */ - response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Remember the start of the response's variable list field. */ - response_variable_list_ptr = response_buffer_ptr; - - /* Setup the variable list response. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* At this point the response buffer is setup to exactly the same position the - SNMP Manager's input buffer is - right before the first variable. We can - now walk through the variable list to process each request and place the - result in the response buffer. */ - objects = 0; - next_object = NX_TRUE; - current_repetitions = max_repetitions; - do - { - - /* Determine if the next object should be retrieved. */ - if (next_object) - { - - /* Remember the start of the variable. */ - variable_start_ptr = buffer_ptr; - - /* Pickup the first SNMP Variable length. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); - - /* Calculate the total variable size. */ - total_variable_length = variable_length + length; - - /* Determine if this variable will fit in the remaining length of the - variable list. */ - if ((length == 0) || (total_variable_length > variable_list_length)) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_SUCCESS, objects+1); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Now pickup the object ID. */ - length = _nx_snmp_utility_object_id_get(buffer_ptr, - agent_ptr -> nx_snmp_agent_current_octet_string, - buffer_length); - - /* Determine if the object retrieval was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Default the value to NULL. */ - agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; - - /* Determine if a value is present. */ - if (length != variable_length) - { - - /* Pickup the value associated with this variable. */ - length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); - - /* Determine if the object value was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Send an SNMP version error response. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - } - } - - /* At this point, we are ready to call the appropriate application request handling routine. - It is responsible for extracting or placing information in the object data structure. */ - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GET routine. */ - status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GETNEXT routine. */ - status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Clear the next object flag. */ - next_object = NX_FALSE; - - /* Call the application's GETNEXT routine. */ - status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); - - /* Decrement the number of non-repeaters. */ - if (non_repeaters) - { - - /* Decrement the number of non-repeaters. */ - non_repeaters--; - - /* Set the next object flag to move to the next entry of the request. */ - next_object = NX_TRUE; - } - else - { - - /* Decrement the repetitions. */ - if (current_repetitions) - current_repetitions--; - - /* Determine if there are more repetitions or if the end of MIB was detected. */ - if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - - /* Reset the current repetition. */ - current_repetitions = max_repetitions; - - /* Set the next object flag to true. */ - next_object = NX_TRUE; - } - } - } - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - { - - /* Increment the total number of set variables. */ - agent_ptr -> nx_snmp_agent_total_set_variables++; - - /* Call the application's SET routine. */ - status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Check for an error status from the agent's request processing callback routine. */ - if (status) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects); - - /* Done, return to caller. */ - return; - } - - /* Determine if the returning object is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Now ensure the returning object type is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && -#ifdef FEATURE_NX_IPV6 - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && -#endif - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_NOSUCHNAME, objects + 1); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Everything is okay, place the object and object data into the response buffer. */ - - /* Remember the start of the variable response sequence. */ - response_variable_ptr = response_buffer_ptr; - - /* Clear the response variable size. */ - response_variable_length = 0; - - /* Determine if there is enough room in the destination for the variable sequence. */ - if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Setup the variable response sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Place the object into the response buffer. */ - response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Insert the object's data into the response buffer. */ - response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Now update the response variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); - - /* Only update the source object information if the next object flag is set. */ - if (next_object) - { - - /* Adjust the pointer to the next variable. */ - buffer_ptr = variable_start_ptr + total_variable_length; - - /* Decrement the size of the variable list. */ - variable_list_length = variable_list_length - total_variable_length; - - /* Increment the object counter. */ - objects++; - } - - } while ((variable_list_length) || (next_object == NX_FALSE)); - - /* At this point, several response fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); - - /* Now the response packet's pointers must be setup so it can be sent. */ - response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); - response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; - - /* Release the original request packet. */ - nx_packet_release(packet_ptr); - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; - agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - agent_ptr -> nx_snmp_agent_get_requests++; - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - agent_ptr -> nx_snmp_agent_getnext_requests++; - else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) - agent_ptr -> nx_snmp_agent_getbulk_requests++; - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - agent_ptr -> nx_snmp_agent_set_requests++; - - /* Increment the sent packet counter. */ - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Increment the get responses sent counter. */ - agent_ptr -> nx_snmp_agent_getresponse_sent++; - - /* Send the response packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, - &(agent_ptr -> nx_snmp_agent_current_manager_ip), - agent_ptr -> nx_snmp_agent_current_manager_port); - - /* Check for successful call. */ - if (status) - { - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - } -} -#endif - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_version_3_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the SNMP v3 request from the manager. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* packet_ptr Pointer to packet containing */ -/* the SNMP request */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_des_encrypt Encrypt bytes */ -/* _nx_des_decrypt Decrypt bytes */ -/* _nx_des_key_set Set the DES key */ -/* _nx_md5_digest_calculate Finalize MD5 calculation */ -/* _nx_md5_initialize Initialize MD5 calculation */ -/* _nx_md5_update Update MD5 calculation */ -/* nx_packet_allocate Allocate response packet */ -/* nx_packet_release Release the packet */ -/* nx_udp_socket_send Send the UDP packet */ -/* _nx_snmp_utility_error_info_get Get the error information */ -/* _nx_snmp_utility_error_info_set Set the error information */ -/* _nx_snmp_utility_object_data_get Get the object data */ -/* _nx_snmp_utility_object_data_set Set the object data */ -/* _nx_snmp_utility_object_id_get Get the object ID */ -/* _nx_snmp_utility_object_id_set Set the object ID */ -/* _nx_snmp_utility_octet_get Get octet string */ -/* _nx_snmp_utility_octet_set Set octet string */ -/* _nx_snmp_utility_request_id_get Get the request ID */ -/* _nx_snmp_utility_request_id_set Set the request ID */ -/* _nx_snmp_utility_request_type_get Get the request type */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_sequence_get Get the ANS.1 sequence */ -/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ -/* _nx_snmp_utility_version_get Get the SNMP version */ -/* _nx_snmp_utility_version_set Set the SNMP version */ -/* _nx_snmp_version_error_response Send SNMP Manager error */ -/* _nx_snmp_version_3_discovery_respond Send discovery response */ -/* _nx_sha1_digest_calculate Finalize SHA calculation */ -/* _nx_sha1_initialize Initialize SHA calculation */ -/* _nx_sha1_update Update SHA calculation */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_agent_thread_entry SNMP Agent thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_version_3_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr) -{ - -UINT i, sequence_length, version, request_type, request_length; -UINT header_sequence_length, security_sequence_length, pdu_sequence_length; -UINT non_repeaters, max_repetitions, current_repetitions, next_object; -UINT variable_list_length, variable_length; -ULONG request_id; -UINT status, length, objects; -UCHAR *buffer_ptr; -UCHAR *variable_start_ptr = NX_NULL; -UCHAR *error_ptr, *request_type_ptr, *temp_ptr; -UINT response_length; -UINT total_variable_length = 0; -NX_PACKET *response_packet_ptr; -UINT context_engine_size, context_name_size; -UCHAR *response_buffer_ptr; -UINT response_sequence_length, response_header_length, response_security_length, response_pdu_length, response_type_length; -UINT response_variable_list_length, response_variable_length; -UCHAR *response_sequence_ptr, *response_header_ptr, *response_security_ptr, *response_pdu_ptr, *response_type_ptr; -UCHAR *response_variable_list_ptr, *response_variable_ptr; -UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; -UINT packet_type; -UCHAR *response_encryption_size_ptr = NX_NULL; -UCHAR *response_authentication_ptr = NX_NULL, *response_privacy_ptr = NX_NULL; -UCHAR *request_authentication_ptr = NX_NULL; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; -UINT authenticate_message = NX_FALSE; -UINT encrypt_message = NX_FALSE; -UCHAR message_sec_level; -UINT mask; -INT buffer_length; - - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("\nReceived a SNMPv3 request\n\r"); -#endif - - buffer_length = (INT)(packet_ptr -> nx_packet_length); - - /* Setup a pointer to the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup the SEQUENCE field. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Pickup the SNMP VERSION field. */ - length = _nx_snmp_utility_version_get(buffer_ptr, &version, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /***** Now we are positioned in front of the global header. *****/ - - /* Pickup the sequence for the header data, which includes the message ID, maximum reply size, - flags, and the security model. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &header_sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the message ID */ - /********************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_id), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the message size */ - /********************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_size), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the security options */ - /********************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_options), - sizeof(agent_ptr -> nx_snmp_agent_v3_message_security_options), &status, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Extracted security options: 0x%x\n\r", agent_ptr -> nx_snmp_agent_v3_message_security_options); -#endif - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - mask = NX_SNMP_SECURITY_AUTHORIZE | NX_SNMP_SECURITY_PRIVACY ; - - /* We want to mask out the reportable bit. */ - agent_ptr -> nx_snmp_agent_v3_message_security_options = (UCHAR)(agent_ptr -> nx_snmp_agent_v3_message_security_options & mask); - - /********************************************************/ - /* Get the security type */ - /********************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_message_security_type), buffer_length); - - /* Check for a valid packet. */ - if ((length == 0) || (agent_ptr -> nx_snmp_agent_v3_message_security_type != NX_SNMP_USM_SECURITY_MODEL)) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /**** Now we are positioned in front of the security parameters field. ****/ - - /* Determine if there are security parameters. */ - if ((buffer_ptr[0] == NX_SNMP_ANS1_OCTET_STRING) && (buffer_ptr[1])) - { - - /* Position the buffer pointer past the octet string. */ - buffer_ptr = buffer_ptr + 2; - - /* Pickup the sequence for the security data. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &security_sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the authoritative engine ID */ - /********************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_context_engine, - sizeof(agent_ptr -> nx_snmp_agent_v3_security_context_engine), - &(agent_ptr -> nx_snmp_agent_v3_security_context_engine_size), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the number of engine reboots */ - /********************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boots), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the engine boot time */ - /********************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the security username */ - /********************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, - sizeof(agent_ptr -> nx_snmp_agent_v3_security_user_name), &(agent_ptr -> nx_snmp_agent_v3_security_user_name_size), buffer_length); - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Security name parsed: %s Size: %d\n\r", &agent_ptr -> nx_snmp_agent_v3_security_user_name[0], agent_ptr -> nx_snmp_agent_v3_security_user_name_size); - -#endif - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Null terminate the User Name. */ - agent_ptr -> nx_snmp_agent_v3_security_user_name[agent_ptr -> nx_snmp_agent_v3_security_user_name_size] = 0; - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /********************************************************/ - /* Get the security authentication parameter */ - /********************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_authentication, - sizeof(agent_ptr -> nx_snmp_agent_v3_security_authentication), &(agent_ptr -> nx_snmp_agent_v3_security_authentication_size), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } -#ifndef NX_SNMP_NO_SECURITY - /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter. */ - - request_authentication_ptr = buffer_ptr + 2; -#endif - - /* Position to the next field. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - pdu_privacy_ptr = buffer_ptr + 2; - - /********************************************************/ - /* Get the security privacy parameter */ - /********************************************************/ - - /* This is effectively the salt which will be used to unencrypt the PDU. */ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_privacy, - sizeof(agent_ptr -> nx_snmp_agent_v3_security_privacy), &(agent_ptr -> nx_snmp_agent_v3_security_privacy_size), buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - } - else - { - - /* Position past the empty security parameter field. */ - length = 2; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Save the location where the request type is located (after context engine ID and name). */ - temp_ptr = buffer_ptr; - - /********************************************************/ - /* Determine if we send a report vs response */ - /********************************************************/ - - /* Check if Engine ID is missing AND the security user name is blank. */ - if ((agent_ptr -> nx_snmp_agent_v3_security_context_engine_size == 0) && - (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0)) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("No Engine ID, no user name, this is a discovery request. \n\r"); -#endif - agent_ptr -> nx_snmp_agent_unknown_engineid_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length); - - /* We're done ! Release the received SNMP packet. */ - nx_packet_release(packet_ptr); - - return; - } - /* Check for a mismatched Engine ID. */ - else if ((memcmp(&agent_ptr -> nx_snmp_agent_v3_context_engine[0], - &agent_ptr -> nx_snmp_agent_v3_security_context_engine[0], - agent_ptr -> nx_snmp_agent_v3_security_context_engine_size) != 0)) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Detect a mismatched (non null) engine ID\n\r"); -#endif - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_unknown_engineid_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* We will wait for the browser to make a discovery request (blank engine ID). */ - return; - } - /* Check for missing username in the securities header. */ - else if (agent_ptr -> nx_snmp_agent_v3_security_user_name_size == 0) - { - - /* Missing user name in the securities field. */ - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Request is missing a securities username\n\r"); -#endif - - /* Update the unknown or missing user name at least. */ - agent_ptr -> nx_snmp_agent_unknown_username_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; - } - /* Check for valid username in the security parameters. */ - else if (agent_ptr -> nx_snmp_agent_username_process) - { - - status = (agent_ptr -> nx_snmp_agent_username_process)(agent_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name); - - if (status != NX_SUCCESS) - { - /* Unknown user name in the securities field. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Error in username callback: 0x%x\n\r", status); -#endif - - agent_ptr -> nx_snmp_agent_unknown_username_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Engine ID and username appear acceptable, Not a disco request. Check the boot time. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Request has a valid Engine ID and user name. Check the boot and boot time\n\r"); -#endif - - /* Check if both sides have authentication enabled. */ - if (((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) && - (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL)) - { - /* They do. So now we must check for mismatched boot data. */ - if (agent_ptr -> nx_snmp_agent_v3_context_engine_boots != agent_ptr -> nx_snmp_agent_v3_security_engine_boots) - { - - /* Boot count does not match. */ - agent_ptr -> nx_snmp_agent_mismatched_time_count++; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Detect a %d'th mismatch in the boot count. Agent boot count: %d; Browser boot count %d\n\r", - agent_ptr -> nx_snmp_agent_mismatched_time_count, - agent_ptr -> nx_snmp_agent_v3_context_engine_boots, - agent_ptr -> nx_snmp_agent_v3_security_engine_boots); -#endif - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - /* Determine if the browser boot time exceeds ours by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */ - else if ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) && - ((agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time) > NX_SNMP_TIME_WINDOW)) - { - - agent_ptr -> nx_snmp_agent_mismatched_time_count++; - - /* Outside acceptable limits. Do not reply to this request. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is less than Browser boot time %d\n\r", - agent_ptr -> nx_snmp_agent_mismatched_time_count, - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, - agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time); -#endif - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - /* Determine if the our boot time exceeds the browser boot time by more than the acceptable limit recommended by RFC 3413 of 150 seconds. */ - else if ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time > agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) && - ((agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time - agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time) > NX_SNMP_TIME_WINDOW)) - { - - agent_ptr -> nx_snmp_agent_mismatched_time_count++; - - /* Outside acceptable limits. Do not reply to this request. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Detect %d'th invalid boot time; Agent boot time %d is greater than Browser boot time %d\n\r", - agent_ptr -> nx_snmp_agent_mismatched_time_count, - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, - agent_ptr -> nx_snmp_agent_v3_security_engine_boot_time); -#endif - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM, buffer_length); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - } - } - - - authenticate_message = NX_FALSE; - - /* Check again if the incoming request specifies authentication. */ - if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) - { - - /* Check if our key is not set up or authentication is not enabled (in which - case the authentication key is NULL anyway). */ - if (agent_ptr -> nx_snmp_agent_v3_authentication_key == NX_NULL) - { - - /* The request has an unsupported (as in none) authentication level requested. This is an error. */ - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__); -#endif - agent_ptr -> nx_snmp_agent_unsupported_sec_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); - - /* We're done ! Release the received SNMP packet. */ - nx_packet_release(packet_ptr); - - return; - } - else - { - /* Otherwise Ok to process authentication parameter. */ - authenticate_message = NX_TRUE; - } - } - /* Check if the incoming message is not requesting authentication. */ - else - { - - if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL) - { - - /* The request has an unsupported (as in none) authentication level requested. This - is an error. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels detected on line %d\n\r", __LINE__); -#endif - agent_ptr -> nx_snmp_agent_unsupported_sec_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); - - /* We're done ! Release the received SNMP packet. */ - nx_packet_release(packet_ptr); - - return; - } - } - - /********************************************************/ - /* Check Authentication Parameter */ - /********************************************************/ - - /* Are we processing the authentication parameter? */ - if (authenticate_message == NX_TRUE) - { - - /* Yes, authentication is required. */ - - /* Mark the location in the request buffer. */ - pdu_auth_parm_ptr = request_authentication_ptr; - - /* Clear the authentication field in the message. To calculate the - digest this must be cleared. Also position past the string and length. */ - for (i = 0; i < agent_ptr -> nx_snmp_agent_v3_security_authentication_size; i++) - { - - /* Clear the byte. */ - *request_authentication_ptr++ = 0; - } - /* Now determine which authentication is required. */ - if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY) - { - - /* Copy the base MD5 key into key1. */ - for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base MD5 key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Calculate prepend Key1. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Prepend Key2 to the result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); - } - else if (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY) - { - - /* Copy the base SHA key into key1. */ - for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base SHA key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Calculate prepend Key1. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), packet_ptr -> nx_packet_prepend_ptr, packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Prepend Key2 to the result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); - } - else - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Authentication error. Drop the request. Line %d \n\r", __LINE__); -#endif - /* Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* At this point, key2 contains the computed digest of the message. If this doesn't match, - then the message is invalid. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - { - - /* Check for a mismatch. */ - if (key2[i] != agent_ptr -> nx_snmp_agent_v3_security_authentication[i]) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Authentication mismatch. Drop the request. Line %d \n\r", __LINE__); -#endif - /* We are not. Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - } - } - - /* Now prepare response message so we can process the variables one by one. */ - - /* Determine which packet type we allocate based on the destination address type. */ - if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Device not enabled for IPv6\n\r"); -#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE*/ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif /* FEATURE_NX_IPV6 */ - - } - else - { - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Allocate the packet for the SNMP response. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &response_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a response packet was allocated. */ - if (status) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Response packet allocate error. Status: 0x%x\n\r", status); -#endif - - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - memset(response_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(response_packet_ptr -> nx_packet_data_end - response_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the response packet. */ - response_sequence_length = 0; - response_header_length = 0; - response_security_length = 0; - response_pdu_length = 0; - response_type_length = 0; - response_variable_list_length = 0; - - /* Setup a pointer to the response packet's buffer area. */ - response_buffer_ptr = response_packet_ptr -> nx_packet_prepend_ptr; - - /* This is also the response sequence pointer. Remember it since we are going to have to - update it later with the actual length of the response. */ - response_sequence_ptr = response_buffer_ptr; - - /* First, write the sequence in the response packet. A zero is written for now. This will be - updated later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /********************************************************/ - /* Set the Version ID */ - /********************************************************/ - response_length = _nx_snmp_utility_version_set(response_buffer_ptr, NX_SNMP_VERSION_3, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Save the pointer to the global header. */ - response_header_ptr = response_buffer_ptr; - - /* Write the sequence for the global header in the response packet. A zero is written for now. - This will be updated later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /********************************************************/ - /* Set the request ID */ - /********************************************************/ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the header sequence length. */ - response_header_length = response_header_length + response_length; - - /********************************************************/ - /* Set the maximum message size */ - /********************************************************/ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the header sequence length. */ - response_header_length = response_header_length + response_length; - - /********************************************************/ - /* Set the message security options */ - /********************************************************/ - message_sec_level = agent_ptr -> nx_snmp_agent_v3_message_security_options; - - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, (UCHAR *)&message_sec_level, 1, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the header sequence length. */ - response_header_length = response_header_length + response_length; - - /****************************************************/ - /* Set the security type */ - /****************************************************/ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the header sequence length. */ - response_header_length = response_header_length + response_length; - - /* At this point, we have successfully built the security header. Now, we need to build - the security parameters field. */ - - /* First setup the octet string field. */ - response_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - response_buffer_ptr[1] = 0; - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + 2; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + 2; - - /* Remember the security header length pointer. */ - response_security_ptr = response_buffer_ptr; - - /* Now set the sequence of the USM security parameters. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /****************************************************/ - /* Set the Context Engine */ - /****************************************************/ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - /****************************************************/ - /* Set the Boot Count */ - /****************************************************/ - if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0) - { - /* No security, no time synching, so set boot data to zero. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - } - else - { - /* Set the actual boot count. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, response_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - /****************************************************/ - /* Set the Boot Time */ - /****************************************************/ - - if (agent_ptr -> nx_snmp_agent_v3_message_security_options == 0) - { - /* No security, no time synching, so set boot data to zero. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - } - else - { - - /* Get the tick count since last boot up. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - - /* Set the actual boot count. */ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, response_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - /****************************************************/ - /* Set the security user name */ - /****************************************************/ - - /* (Use the security name in the request message) */ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - /* Initialize the temporary string to zero. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - temp_string[i] = 0; - - /****************************************************/ - /* Set the security Authentication parameter */ - /****************************************************/ - - /* Now setup the authentication parameter if authentication is enabled, and only if called for. */ - if (authenticate_message == NX_TRUE) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Authenticating: initialize auth parameter to zero in response packet. (Line %d) \n\r", __LINE__); -#endif - - /* All set to add an authentication parameter. For now, set to all zeroes. */ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, response_packet_ptr -> nx_packet_data_end); - - /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE byte authorization parameter. */ - response_authentication_ptr = response_buffer_ptr + 2; - } - else - { -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Not Authenticating: set auth parameter to null in response packet. (Line %d) \n\r", __LINE__); -#endif - /* No security enabled so set this as an empty parameter. */ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end); - - } - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - encrypt_message = NX_FALSE; - - /* Check if the incoming request specifies authentication. A discovery request should not have - the authentication (or encxryption) flags set. */ - if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY) >= 2) - { - - /* Check if our key is not set up or privacy is not enabled (in which - case the privacy key is NULL anyway). */ - if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) - { - - /* The request has an unsupported (as in none) privacy level requested. This is an error. */ - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__); -#endif - agent_ptr -> nx_snmp_agent_unsupported_sec_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* We're done ! Release the received SNMP packet. */ - nx_packet_release(packet_ptr); - - return; - } - else - { - /* Otherwise Ok to process encrypt/decrypt SNMPv3 data. */ - encrypt_message = NX_TRUE; - } - } - - /* Check if the incoming message is not requesting privacy. */ - else - { - - if (agent_ptr -> nx_snmp_agent_v3_privacy_key != NX_NULL) - { - - /* The request has an unsupported (as in none) privacy level requested. This - is an error. */ -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Mismatch of user security levels (privacy) detected on line %d\n\r", __LINE__); -#endif - agent_ptr -> nx_snmp_agent_unsupported_sec_count++; - - _nx_snmp_version_3_report_send(agent_ptr, buffer_ptr, NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM, buffer_length); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* We're done ! Release the received SNMP packet. */ - nx_packet_release(packet_ptr); - - return; - } - } - - /****************************************************/ - /* Set the security Privacy parameter */ - /****************************************************/ - - /* Are we applying encryption to our response? */ - if (encrypt_message == NX_FALSE) - { - - /* No, so set the privacy field as an empty parameter. */ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string,0, response_packet_ptr -> nx_packet_data_end); - } - else - { - - /* Initialize the 8 character privacy parameter (salt) to all zeros field initially. */ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, temp_string, 8, response_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - if (encrypt_message == NX_TRUE) - { - - /* Remember the pointer to the actual 8 byte privacy parameter. */ - response_privacy_ptr = response_buffer_ptr + 2; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Adjust the security sequence length. */ - response_security_length = response_security_length + response_length; - - /****************************************************/ - /* Decrypt the privacy data */ - /****************************************************/ - - /* Check if encryption is required */ - if (encrypt_message == NX_TRUE) - { - - response_encryption_size_ptr = 0x0; - - /* Save the location if we need to return an error message. */ - pdu_buffer_ptr = buffer_ptr; - - status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, response_buffer_ptr, &response_encryption_size_ptr, &response_length, buffer_length); - - if (status != NX_SUCCESS) - { - - /* Increment the privacy error counter. */ - agent_ptr -> nx_snmp_agent_privacy_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - return; - } - - /* This is typically coded as 0x30 0x29 [or whatever length] 0x04 0x82 or [length] without - the multi byte coding. This will also handle 0x81 "multi byte" coding. */ - if (buffer_ptr[3] & NX_SNMP_ANS1_MULTI_BYTES) - { - - /* Get the type of length of the string */ - UINT temp = (UINT)(buffer_ptr[3] & 0x7F); - - if (temp == 2) - { - - pdu_length = (UINT) (*(buffer_ptr+ 4) << 8) | ((UINT) *(buffer_ptr+5)); - pdu_buffer_ptr = buffer_ptr; - } - - else if (temp == 1) - { - pdu_length = *(buffer_ptr + 4); - pdu_buffer_ptr = buffer_ptr; - } - else - { - - /* String is either null or too big, return a zero length to indicate an error. */ - return; - } - } - else /* Assume one byte */ - { - pdu_length = *(buffer_ptr + 3); - pdu_buffer_ptr = buffer_ptr; - } - - response_length = 4; - - } - - /* Now we can process the request type pointer */ - while (temp_ptr < packet_ptr -> nx_packet_append_ptr) - { - temp_ptr++; - - /* Check for Get request type. */ - if ((*temp_ptr == NX_SNMP_ANS1_GET_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_GET_BULK_REQUEST)|| - (*temp_ptr == NX_SNMP_ANS1_GET_NEXT_REQUEST) || (*temp_ptr == NX_SNMP_ANS1_SET_REQUEST)) - { - break; - } - } - - /* Check for invalid packet. */ - if (temp_ptr == packet_ptr -> nx_packet_append_ptr) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Save the request type pointer. */ - request_type_ptr = temp_ptr; - - /* Save the response pdu sequence pointer. */ - response_pdu_ptr = response_buffer_ptr; - - /* Move the response buffer pointer. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Increment the number of response sequence bytes. */ - response_sequence_length = response_sequence_length + response_length; - - /****************************************************/ - /* Get the PDU sequence length */ - /****************************************************/ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &pdu_sequence_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /****************************************************/ - /* Get the PDU engine ID */ - /****************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_engine_size, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - - /******************************************************************************/ - /* SET the PDU Sequence Header if the response is encrypted. */ - /******************************************************************************/ - - /* If the message is encrypted we have to insert an PDU "inner" sequence header. Because - we will use the multibyte sequence 0x30 82 xx yy format, we have to update the enclosing - sequences (total response length and pdu length and their respective pointers accordingly. - */ - if (encrypt_message) - { - - /* Move the response buffer pointer. */ - response_buffer_ptr = response_buffer_ptr + 4; - - /* Increment the number of response sequence bytes. */ - response_sequence_length = response_sequence_length + 4; - - /* Increment the response pdu sequence pointer. */ - response_pdu_ptr = response_pdu_ptr + 4; - - /* Increment the pdu length for this sequence header. */ - response_pdu_length = response_pdu_length + 4; - - } - - /****************************************************/ - /* SET the PDU engine ID */ - /****************************************************/ - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (response_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response pointer forward. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Increment the sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /****************************************************/ - /* Get the PDU engine name */ - /****************************************************/ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &context_name_size, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - - /* The browser uses the context name from the SNMP Agent to confirm - the response is coming from the SNMP Agent it sent the request to. They must match. - The request ID only matches the request with response. A user may have multiple - requests. There may be circumstances where the SNMP Agent only responds with - one context name. Don't know what that would be. */ - - /* Check if the SNMP agent has set a PDU engine name yet. */ - if (agent_ptr -> nx_snmp_agent_v3_context_name_size == 0) - { - - /* No it has not, so let's set it here. */ - - /* First verify that this is a legal length to copy. */ - if (context_name_size > NX_SNMP_MAX_CONTEXT_STRING) - { - - /* Invalid length, this will overrun the buffer. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - memcpy(agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_current_octet_string, context_name_size); - - agent_ptr -> nx_snmp_agent_v3_context_name_size = context_name_size; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /****************************************************/ - /* SET the PDU engine name */ - /****************************************************/ - - response_length = _nx_snmp_utility_octet_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_name, agent_ptr -> nx_snmp_agent_v3_context_name_size, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid packet. */ - if (response_length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response pointer forward. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Save the pointer to the response type. */ - response_type_ptr = response_buffer_ptr; - - /* Increment the sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /****************************************************/ - /* Get the PDU request type */ - /****************************************************/ - length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - agent_ptr -> nx_snmp_agent_request_get_type = NX_FALSE; - if ((request_type == NX_SNMP_GET_REQUEST) || - (request_type == NX_SNMP_GET_NEXT_REQUEST) || - (request_type == NX_SNMP_GET_BULK_REQUEST)) - { - agent_ptr -> nx_snmp_agent_request_get_type = NX_TRUE; - } - - - /****************************************************/ - /* SET the PDU request type */ - /****************************************************/ - response_length = _nx_snmp_utility_request_type_set_multibyte(response_buffer_ptr, NX_SNMP_ANS1_GET_RESPONSE, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /****************************************************/ - /* Get the PDU request ID */ - /****************************************************/ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /****************************************************/ - /* SET the PDU request ID */ - /****************************************************/ - response_length = _nx_snmp_utility_request_id_set(response_buffer_ptr, request_id, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Save a pointer to the error string. */ - error_ptr = buffer_ptr; - - /****************************************************/ - /* Get the PDU error information */ - /****************************************************/ - /* This is actually used to derive the GETBULK information in SNMP V3 and above. */ - length = _nx_snmp_utility_error_info_get(buffer_ptr, &non_repeaters, &max_repetitions, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Determine if the received packet size is too big. */ - if (packet_ptr -> nx_packet_next) - { - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, 0); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Done, return to caller. */ - return; - } - -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /****************************************************/ - /* SET the PDU error information */ - /****************************************************/ - response_length = _nx_snmp_utility_error_info_set(response_buffer_ptr, 0, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /****************************************************/ - /* Get the PDU variable list length */ - /****************************************************/ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_list_length, buffer_length); - - /* Check for a valid packet. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* At this point we have parsed the incoming SNMP request up to the first - variable. */ - - /* Remember the start of the response's variable list field. */ - response_variable_list_ptr = response_buffer_ptr; - - /* Setup the variable list response. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Process the variable binding list, line %d \n\r", __LINE__); -#endif - - /* At this point the response buffer is setup to exactly the same position the - SNMP Manager's input buffer is - right before the first variable. We can - now walk through the variable list to process each request and place the - result in the response buffer. */ - objects = 0; - next_object = NX_TRUE; - current_repetitions = max_repetitions; - do - { - - /* Determine if the next object should be retrieved. */ - if (next_object) - { - - /* Remember the start of the variable. */ - variable_start_ptr = buffer_ptr; - - /* Pickup the first SNMP Variable length. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &variable_length, buffer_length); - - /* Calculate the total variable size. */ - total_variable_length = variable_length + length; - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Now pickup the object ID. */ - length = _nx_snmp_utility_object_id_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, buffer_length); - - /* Determine if the object retrieval was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the buffer pointer up. */ - buffer_ptr = buffer_ptr + length; - - /* The buffer pointer is moved by the length. Update buffer size */ - buffer_length -= (INT)length; - - /* Default the value to NULL. */ - agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type = 0; - - /* Determine if a value is present. */ - if (length != variable_length) - { - - /* Pickup the value associated with this variable. */ - length = _nx_snmp_utility_object_data_get(buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), buffer_length); - - /* Determine if the object value was successful. */ - if (length == 0) - { - - /* Increment the invalid packet error counter. */ - agent_ptr -> nx_snmp_agent_invalid_packets++; - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Send an SNMP version error response. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_BADVALUE, objects+1); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - } - } - - /* At this point, we are ready to call the appropriate application request handling routine. - It is responsible for extracting or placing information in the object data structure. */ - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GET routine. */ - status = (agent_ptr -> nx_snmp_agent_get_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Call the application's GETNEXT routine. */ - status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) - { - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Clear the next object flag. */ - next_object = NX_FALSE; - - /* Call the application's GETNEXT routine. */ - status = (agent_ptr -> nx_snmp_agent_getnext_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - - /* Decrement the number of non-repeaters. */ - if (non_repeaters) - { - - /* Decrement the number of non-repeaters. */ - non_repeaters--; - - /* Set the next object flag to move to the next entry of the request. */ - next_object = NX_TRUE; - } - else - { - - /* Decrement the repetitions. */ - if (current_repetitions) - current_repetitions--; - - /* Determine if there are more repetitions or if the end of MIB was detected. */ - if ((current_repetitions == 0) || (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type == NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - - /* Reset the current repetition. */ - current_repetitions = max_repetitions; - - /* Set the next object flag to true. */ - next_object = NX_TRUE; - } - } - } - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - { - - /* Increment the total number of set variables. */ - agent_ptr -> nx_snmp_agent_total_set_variables++; - - /* Call the application's SET routine. */ - status = (agent_ptr -> nx_snmp_agent_set_process)(agent_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - &(agent_ptr -> nx_snmp_agent_current_object_data)); - } - else - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Error processing variable binding items (invalid request type %d). Line %d \n\r", request_type, __LINE__); -#endif - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Check for an error status from the agent's request processing callback routine. */ - if (status) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Error processing variable binding get request callback. Line %d \n\r", __LINE__); -#endif - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, status, objects); - - /* Done, return to caller. */ - return; - } - - /* Determine if the returning object is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || - (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Error processing variable binding. Invalid object from get request callback. Line %d \n\r", __LINE__); -#endif - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Now ensure the returning object type is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && -#ifdef FEATURE_NX_IPV6 - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && -#endif - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Error processing variable binding (unknown object type). Line %d \n\r", __LINE__); -#endif - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - /* Everything is okay, place the object and object data into the response buffer. */ - - /* Remember the start of the variable response sequence. */ - response_variable_ptr = response_buffer_ptr; - - /* Clear the response variable size. */ - response_variable_length = 0; - - /* Determine if there is enough room in the destination for the variable sequence. */ - if ((response_buffer_ptr + 4) >= response_packet_ptr -> nx_packet_data_end) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Setup the variable response sequence. For now, the length will be zero. We - will overwrite this with the actual length later. */ - response_length = _nx_snmp_utility_sequence_set(response_buffer_ptr, 0, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the response packet too. */ - nx_packet_release(response_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Place the object into the response buffer. */ - response_length = _nx_snmp_utility_object_id_set(response_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Insert the object's data into the response buffer. */ - response_length = _nx_snmp_utility_object_data_set(response_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), response_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (response_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(response_packet_ptr); - - /* Call the error handling response routine. This will release the packet */ - _nx_snmp_version_error_response(agent_ptr, packet_ptr, request_type_ptr, error_ptr, NX_SNMP_ERROR_TOOBIG, objects); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - response_buffer_ptr = response_buffer_ptr + response_length; - - /* Adjust the response sequence length. */ - response_sequence_length = response_sequence_length + response_length; - - /* Increment the pdu length. */ - response_pdu_length = response_pdu_length + response_length; - - /* Adjust the response request type length. */ - response_type_length = response_type_length + response_length; - - /* Adjust the response variable list size. */ - response_variable_list_length = response_variable_list_length + response_length; - - /* Adjust the response variable size. */ - response_variable_length = response_variable_length + response_length; - - /* Now update the response variable sequence with the actual variable length. */ - _nx_snmp_utility_sequence_set(response_variable_ptr, response_variable_length, response_packet_ptr -> nx_packet_data_end); - - /* Only update the source object information if the next object flag is set. */ - if (next_object) - { - - /* Adjust the pointer to the next variable. */ - buffer_ptr = variable_start_ptr + total_variable_length; - - /* Decrement the size of the variable list. */ - variable_list_length = variable_list_length - total_variable_length; - - /* Increment the object counter. */ - objects++; - } - - } while ((variable_list_length) || (next_object == NX_FALSE)); - - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Variable binding processing completed\n\r"); -#endif - - /* At this point, several response fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(response_sequence_ptr, response_sequence_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(response_header_ptr, response_header_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(response_security_ptr, response_security_length, response_packet_ptr -> nx_packet_data_end); - if (encrypt_message == NX_FALSE) - { - _nx_snmp_utility_sequence_set_1byte(response_pdu_ptr, response_pdu_length, response_packet_ptr -> nx_packet_data_end); - } - _nx_snmp_utility_sequence_set(response_variable_list_ptr, response_variable_list_length, response_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(response_type_ptr, NX_SNMP_ANS1_GET_RESPONSE, response_type_length, response_packet_ptr -> nx_packet_data_end); - - /* Setup the security OCTET string length. */ - - /* Backup to the OCTET string for the security size. */ - response_security_ptr = response_security_ptr - 2; - - /* Account for the 4 byte Security Sequence field. */ - response_security_length = response_security_length + 4; - - /* Store the security size. */ - response_security_ptr[1] = (UCHAR) (response_security_length & 0xFF); - - /* Determine if privacy is required. If so, encrypt the PDU and setup the response - to have an encryption header. */ - if (encrypt_message == NX_TRUE) - { - - _nx_snmp_agent_encrypt_pdu(agent_ptr, &response_pdu_length, &response_sequence_length, - response_encryption_size_ptr, &response_sequence_ptr, - response_packet_ptr -> nx_packet_data_end, - &response_buffer_ptr, response_privacy_ptr); - } - - /* Now the response packet's pointers must be setup so it can be sent. */ - response_packet_ptr -> nx_packet_length = (ULONG)(response_buffer_ptr - response_packet_ptr -> nx_packet_prepend_ptr); - response_packet_ptr -> nx_packet_append_ptr = response_buffer_ptr; - - if (authenticate_message == NX_TRUE) - { - - /* Yes, authentication is required. */ - status = _nx_snmp_agent_add_auth_parameter(agent_ptr, response_packet_ptr, response_authentication_ptr); - - if (status != NX_SUCCESS) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r", __LINE__); -#endif - /* Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release the report packet too. */ - nx_packet_release(response_packet_ptr); - - /* Release the original request packet. */ - nx_packet_release(packet_ptr); - - return; - } - } - - /* Release the original request packet. */ - nx_packet_release(packet_ptr); - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_total_bytes_received += packet_ptr -> nx_packet_length; - agent_ptr -> nx_snmp_agent_total_bytes_sent += response_packet_ptr -> nx_packet_length; - if (request_type == NX_SNMP_ANS1_GET_REQUEST) - agent_ptr -> nx_snmp_agent_get_requests++; - else if (request_type == NX_SNMP_ANS1_GET_NEXT_REQUEST) - agent_ptr -> nx_snmp_agent_getnext_requests++; - else if (request_type == NX_SNMP_ANS1_GET_BULK_REQUEST) - agent_ptr -> nx_snmp_agent_getbulk_requests++; - else if (request_type == NX_SNMP_ANS1_SET_REQUEST) - agent_ptr -> nx_snmp_agent_set_requests++; - - /* Increment the sent packet counter. */ - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Increment the get responses sent counter. */ - agent_ptr -> nx_snmp_agent_getresponse_sent++; - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Sending the response to SNMPv3 request on line %d.\n\r", __LINE__); -#endif - - /* Send the response packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), response_packet_ptr, - &(agent_ptr -> nx_snmp_agent_current_manager_ip), - agent_ptr -> nx_snmp_agent_current_manager_port); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(response_packet_ptr); - } -} -#endif /* NX_SNMP_DISABLE_V3 */ - - -#ifndef NX_SNMP_DISABLE_V3 -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_version_3_report_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends reports to the SNMP Manager in response to */ -/* received requests. These are usually discovery requests, but can */ -/* also be USM violations such as unknown username, unsupported */ -/* security level or invalid boot data. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* discovery_respond Reason for report */ -/* buffer_length Size of buffer data */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate response packet */ -/* nx_packet_release Release the packet */ -/* nx_udp_socket_send Send the UDP packet */ -/* _nx_snmp_utility_error_info_set Set the error information */ -/* _nx_snmp_utility_octet_set Set the octet string */ -/* _nx_snmp_utility_request_id_set Set the request ID */ -/* _nx_snmp_utility_request_type_set_multibyte */ -/* Set trap request type */ -/* _nx_snmp_utility_sequence_set Set the ANS.1 sequence */ -/* _nx_snmp_utility_version_set Set the SNMP version */ -/* tx_time_get Get the time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_process Process SNMP v3 request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_version_3_report_send(NX_SNMP_AGENT *agent_ptr, UCHAR *buffer_ptr, UINT report_respond, INT buffer_length) -{ - -UINT status; -UINT report_length; -NX_PACKET *report_packet_ptr; -UCHAR *report_buffer_ptr, *report_sequence_ptr, *report_header_ptr, *report_security_ptr; -UCHAR *report_authentication_ptr = NX_NULL, *report_pdu_ptr, *report_type_ptr; -UINT report_sequence_length, report_header_length, report_security_length, report_pdu_length, report_type_length; -UCHAR *report_encryption_size_ptr = NX_NULL; -UCHAR temp_string[NX_SNMP_DIGEST_SIZE]; -UINT packet_type; -UCHAR *report_variable_list_ptr = NX_NULL; -UINT report_variable_length = 0; -UINT report_variable_list_length = 0; -UCHAR *report_variable_ptr = NX_NULL; -ULONG request_id; -UINT temp, i; -UINT length; -UINT request_type; -UINT request_length; -UINT authenticate, encryption, send_reply; -UCHAR report_security_level; - - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Processing the report...\n\r"); -#endif - - /* Now prepare report message so we can process the report. */ - - /* Determine which packet type we allocate based on the destination address type. */ - if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V4) - { - packet_type = NX_IPv4_UDP_PACKET; - } - else if (agent_ptr -> nx_snmp_agent_current_manager_ip.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Report: IPv6 not enabled on this device.\n\r"); -#endif /* NX_SNMPV3_PRINT_DEBUG_MESSAGE */ - - return; -#else - packet_type = NX_IPv6_UDP_PACKET; -#endif /* FEATURE_NX_IPV6 */ - } - else - { - return; - } - - /* Allocate the packet for the SNMP report. */ - status = nx_packet_allocate(agent_ptr -> nx_snmp_agent_packet_pool_ptr, &report_packet_ptr, packet_type, NX_SNMP_AGENT_TIMEOUT); - - /* Determine if a report packet was allocated. */ - if (status) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Report: error allocating packet 0x%x.\n\r", status); -#endif - /* Increment the packet allocation error counter. */ - agent_ptr -> nx_snmp_agent_allocation_errors++; - - /* Return to caller. */ - return; - } - - memset(report_packet_ptr -> nx_packet_prepend_ptr, 0, - (UINT)(report_packet_ptr -> nx_packet_data_end - report_packet_ptr -> nx_packet_prepend_ptr)); - - /* Initialize the counters required for the length fields of the report packet. */ - report_sequence_length = 0; - report_header_length = 0; - report_security_length = 0; - report_pdu_length = 0; - report_type_length = 0; - - /* Setup a pointer to the report packet's buffer area. */ - report_buffer_ptr = report_packet_ptr -> nx_packet_prepend_ptr; - - _nx_snmp_agent_security_response_status(agent_ptr, &authenticate, &encryption, &send_reply); - - if (send_reply == NX_FALSE) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Report: received request with encryption set. Encryption not enabled on device; no report sent.\n\r"); -#endif - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - return; - } - - /* We need to set our own security level in case the report security settings differ from the incoming request. */ - report_security_level = (UCHAR)authenticate; - - /* Find out if we need to decrypt this message. */ - if (encryption == NX_TRUE) - { - - /* We do. Decrypt the data. We need to get the PDU data, request id and other data. */ - status = _nx_snmp_agent_decrypt_pdu(agent_ptr, &buffer_ptr, NX_NULL, &report_encryption_size_ptr, &report_length, buffer_length); - - if (status != NX_SUCCESS) - { - - /* Release the report packet. */ - nx_packet_release(report_packet_ptr); - - return; - } - } - - /* Get the PDU sequence location. */ - length = _nx_snmp_utility_sequence_get(buffer_ptr, &temp, buffer_length); - - if (length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - buffer_ptr += length; - buffer_length -= (INT)length; - - /* Get the SNMP v3 PDU context engine field location. */ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length); - - if (length == 0) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - buffer_ptr += length; - buffer_length -= (INT)length; - - /* Get the SNMP v3 PDU context name field location. */ - length = _nx_snmp_utility_octet_get(buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, - sizeof(agent_ptr -> nx_snmp_agent_current_octet_string), &temp, buffer_length); - if (length == 0) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - buffer_ptr += length; - buffer_length -= (INT)length; - - /* Pick up the SNMP Request type and location. */ - length = _nx_snmp_utility_request_type_get(buffer_ptr, &request_type, &request_length, buffer_length); - if (length == 0) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - buffer_ptr += length; - buffer_length -= (INT)length; - - /* Get the SNMP Request ID. We need this for our report. */ - length = _nx_snmp_utility_request_id_get(buffer_ptr, &request_id, buffer_length); - if (length == 0) - { - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* This is also the report sequence pointer. Remember it since we are going to have to - update it later with the actual length of the report. */ - report_sequence_ptr = report_buffer_ptr; - - /* First, write the sequence in the report packet. A zero is written for now. This will be - updated later. */ - report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /********************************************************/ - /* Set the version ID */ - /********************************************************/ - report_length = _nx_snmp_utility_version_set(report_buffer_ptr, NX_SNMP_VERSION_3, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Save the pointer to the global header. */ - report_header_ptr = report_buffer_ptr; - - /* Write the sequence for the global header in the report packet. A zero is written for now. - This will be updated later. */ - report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /********************************************************/ - /* Set the request ID */ - /********************************************************/ - - /* This must match the request specified by the discovery request. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_message_id, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the header sequence length. */ - report_header_length = report_header_length + report_length; - - /********************************************************/ - /* Set the maximum message size */ - /********************************************************/ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, (NX_SNMP_PACKET_SIZE - NX_UDP_PACKET), report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the header sequence length. */ - report_header_length = report_header_length + report_length; - - /********************************************************/ - /* Set the security options */ - /********************************************************/ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, (UCHAR *)&(report_security_level), 1, report_packet_ptr -> nx_packet_data_end); - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Setting report security level to 0x%x\n\r", report_security_level); -#endif - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the header sequence length. */ - report_header_length = report_header_length + report_length; - - /********************************************************/ - /* Set the security type */ - /********************************************************/ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, NX_SNMP_USM_SECURITY_MODEL, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the header sequence length. */ - report_header_length = report_header_length + report_length; - - /* At this point, we have successfully built the security header. Now, we need to build - the security parameters field. */ - - /* First setup the octet string field. */ - report_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - report_buffer_ptr[1] = 0; - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + 2; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + 2; - - /* Remember the security header pointer. */ - report_security_ptr = report_buffer_ptr; - - report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /********************************************************/ - /* Set the context engine */ - /********************************************************/ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /********************************************************/ - /* Set the boot count */ - /********************************************************/ - if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) - { - - /* Set boot count to zero for discovery requests. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - } - else - { - - /* Use the current SNMP boot count for all others. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boots, report_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /* Start the time (in ticks) since the previous reboot. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - - /********************************************************/ - /* Set the boot time */ - /********************************************************/ - if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) - { - - /* Set boot time to zero. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - } - else - { - - /* Start the time (in ticks) since the previous reboot. */ - agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time = (UINT) (tx_time_get()/NX_IP_PERIODIC_RATE); - /* Use the current SNMP boot time. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine_boot_time, report_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /********************************************************/ - /* Set the security user name */ - /********************************************************/ - - /* Set the security user name as specified in the request message. */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_security_user_name, agent_ptr -> nx_snmp_agent_v3_security_user_name_size, report_packet_ptr -> nx_packet_data_end); - - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /* Initialize the temporary string to zero. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - temp_string[i] = 0; - /********************************************************/ - /* Set the security authentication parameter */ - /********************************************************/ - - if (authenticate == NX_TRUE) - { - - - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to zero in report. (Line %d) \n\r", __LINE__); -#endif - /* All set to add an authentication parameter. For now, set to all zeros. */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, NX_SNMP_DIGEST_SIZE, report_packet_ptr -> nx_packet_data_end); - - /* Remember the pointer to the actual NX_SNMP_DIGEST_SIZE (12) byte authorization parameter. */ - report_authentication_ptr = report_buffer_ptr + 2; - } - else - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Report: set authentication parameter to empty. \n\r"); -#endif - /* No security enabled so set this as an empty parameter. */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); - } - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /* Set the Privacy Parameter field to empty (encryption/privacy not used in reports). */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the security sequence length. */ - report_security_length = report_security_length + report_length; - - /* Remember the PDU sequence pointer. */ - report_pdu_ptr = report_buffer_ptr; - - /* Now set the sequence of the PDU. We will replace this sequence type with 'opaque' - if encryption is required later. */ - report_length = _nx_snmp_utility_sequence_set(report_pdu_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /********************************************************/ - /* Set the Context Engine ID */ - /********************************************************/ - - /* The Context Engine ID should be the same as the msgAuthoritativeEngine ID since there is no proxy. */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, agent_ptr -> nx_snmp_agent_v3_context_engine, - agent_ptr -> nx_snmp_agent_v3_context_engine_size, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Now setup the PDU context name field - it is a null field in the response. */ - report_length = _nx_snmp_utility_octet_set(report_buffer_ptr, temp_string, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Remember the type field's starting address. */ - report_type_ptr = report_buffer_ptr; - - /* Now setup the message type field. */ - report_length = _nx_snmp_utility_request_type_set_multibyte(report_buffer_ptr, NX_SNMP_ANS1_REPORT_REQUEST, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /********************************************************/ - /* Set PDU request ID */ - /********************************************************/ - /* Set the PDU request to zero instead of matching the request if the request is encrypted. - Otherwise the request ID must match the request specified by the browser request. */ - if (encryption) - { - request_id = 0; - } - - /* Set the PDU request ID. */ - report_length = _nx_snmp_utility_request_id_set(report_buffer_ptr, request_id, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the report type length. */ - report_type_length = report_type_length + report_length; - - /********************************************************/ - /* Set the error info */ - /********************************************************/ - report_length = _nx_snmp_utility_error_info_set(report_buffer_ptr, 0, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the report type length. */ - report_type_length = report_type_length + report_length; - - /* Mark the beginning of the variable list. */ - report_variable_list_ptr = report_buffer_ptr; - - /********************************************************/ - /* Set up the variable list */ - /********************************************************/ - - /* Now setup the sequence for the variable list. This is set to zero for now. */ - report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the report buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the report sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Adjust the PDU sequence length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the report type length. */ - report_type_length = report_type_length + report_length; - - /* Remember the start of the variable response sequence. */ - report_variable_ptr = report_buffer_ptr; - - /* Clear the response variable size. */ - report_variable_length = 0; - - /* Determine if there is enough room in the destination for the variable sequence. */ - if ((report_buffer_ptr + 4) >= report_packet_ptr -> nx_packet_data_end) - { - - /* Release the response packet. */ - nx_packet_release(report_packet_ptr); - - /* Done, return to caller. */ - return; - } - - /********************************************************/ - /* Initialize variable response sequence to zero */ - /********************************************************/ - - /* We will overwrite this with the actual length later. */ - report_length = _nx_snmp_utility_sequence_set(report_buffer_ptr, 0, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the response sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Increment the pdu length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the response request type length. */ - report_type_length = report_type_length + report_length; - - /********************************************************/ - /* Adjust the response variable list size. */ - /********************************************************/ - - /* Adjust the response variable list size. */ - report_variable_list_length = report_variable_list_length + report_length; - - /********************************************************/ - /* Set the report OID object */ - /********************************************************/ - - if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID_NUM) - { - /* This report is responding to a discovery request. */ - memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID, - sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_ENGINEID)); - - status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_engineid_count), - &agent_ptr -> nx_snmp_agent_current_object_data); - - } - else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC_NUM) - { - /* This report is responding to a mismatch ("unsupported") in security level. */ - memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC, - sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNSUPPORTED_SEC)); - - status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unsupported_sec_count), - &agent_ptr -> nx_snmp_agent_current_object_data); - } - else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM) - { - - /* This report is responding to an unknown user name. */ - memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME, - sizeof(NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME)); - - status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_unknown_username_count), - &agent_ptr -> nx_snmp_agent_current_object_data); - } - else if (report_respond == NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME_NUM) - { - - /* This report is responding to invalid boot time or boot count data received. */ - memcpy(&agent_ptr -> nx_snmp_agent_current_octet_string[0], NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME, - sizeof(NX_SNMP_DISCOVERY_RESPONSE_MISMATCHED_TIME)); - - status = _nx_snmp_object_counter_get((VOID *)(&agent_ptr -> nx_snmp_agent_mismatched_time_count), - &agent_ptr -> nx_snmp_agent_current_object_data); - } - else - { - - /* Unknown report type. Abort! */ - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Unknown report parameter %d. Abort report processing. \n\r", report_respond); -#endif - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - return; - } - - /* Check for a valid operation. */ - if (status != NX_SUCCESS) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the response packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* Increment the total number of get variables. */ - agent_ptr -> nx_snmp_agent_total_get_variables++; - - /* Determine if the returning object is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_octet_string[0] != '1') || (agent_ptr -> nx_snmp_agent_current_octet_string[1] != '.') || - (agent_ptr -> nx_snmp_agent_current_octet_string[2] != '3') || (agent_ptr -> nx_snmp_agent_current_octet_string[3] != '.')) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Invalid object from application GET routine on line %d.\n\r", __LINE__); -#endif - /* Release the response packet. */ - nx_packet_release(report_packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Now ensure the returning object type is valid. */ - if ((agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_INTEGER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OCTET_STRING) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NULL) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_TIME_TICS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_GAUGE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_COUNTER64) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_IP_ADDRESS) && -#ifdef FEATURE_NX_IPV6 - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_IPV6_ADDRESS) && -#endif - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NSAP_ADDRESS) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_OBJECT_ID) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_OBJECT) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_NO_SUCH_INSTANCE) && - (agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type != NX_SNMP_ANS1_END_OF_MIB_VIEW)) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Invalid object type (%d) from application GET routine on line %d.\n\r", - agent_ptr -> nx_snmp_agent_current_object_data.nx_snmp_object_data_type, __LINE__); -#endif - - /* Release the response packet. */ - nx_packet_release(report_packet_ptr); - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Done, return to caller. */ - return; - } - - /* Place the object into the response buffer. */ - report_length = _nx_snmp_utility_object_id_set_1byte(report_buffer_ptr, agent_ptr -> nx_snmp_agent_current_octet_string, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(report_packet_ptr); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the response sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Increment the pdu length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the response request type length. */ - report_type_length = report_type_length + report_length; - - /* Adjust the response variable list size. */ - report_variable_list_length = report_variable_list_length + report_length; - - /* Adjust the response variable size. */ - report_variable_length = report_variable_length + report_length; - - /* Insert the object's data into the response buffer. */ - report_length = _nx_snmp_utility_object_data_set(report_buffer_ptr, &(agent_ptr -> nx_snmp_agent_current_object_data), report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Release the response packet. */ - nx_packet_release(report_packet_ptr); - - /* Done, return to caller. */ - return; - } - - /* Move the response buffer pointer up. */ - report_buffer_ptr = report_buffer_ptr + report_length; - - /* Adjust the response sequence length. */ - report_sequence_length = report_sequence_length + report_length; - - /* Increment the pdu length. */ - report_pdu_length = report_pdu_length + report_length; - - /* Adjust the response request type length. */ - report_type_length = report_type_length + report_length; - - /* Adjust the response variable list size. */ - report_variable_list_length = report_variable_list_length + report_length; - - /* Adjust the response variable size. */ - report_variable_length = report_variable_length + report_length; - - /* Now update the response variable sequence with the actual variable length. */ - report_length = _nx_snmp_utility_sequence_set(report_variable_ptr, report_variable_length, report_packet_ptr -> nx_packet_data_end); - - /* Check for a valid operation. */ - if (report_length == 0) - { - - /* Increment the internal error counter. */ - agent_ptr -> nx_snmp_agent_internal_errors++; - - /* Release the report packet too. */ - nx_packet_release(report_packet_ptr); - - /* Return to caller. */ - return; - } - - /* At this point, several report fields need to be updated with actual lengths. */ - _nx_snmp_utility_sequence_set(report_sequence_ptr, report_sequence_length, report_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(report_header_ptr, report_header_length, report_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(report_security_ptr, report_security_length, report_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(report_pdu_ptr, report_pdu_length, report_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_sequence_set(report_variable_list_ptr, report_variable_list_length, report_packet_ptr -> nx_packet_data_end); - _nx_snmp_utility_request_type_set_multibyte(report_type_ptr, NX_SNMP_ANS1_REPORT_REQUEST, report_type_length, report_packet_ptr -> nx_packet_data_end); - - /* Now the report packet's pointers must be setup so it can be sent. */ - report_packet_ptr -> nx_packet_length = (ULONG)(report_buffer_ptr - report_packet_ptr -> nx_packet_prepend_ptr); - report_packet_ptr -> nx_packet_append_ptr = report_buffer_ptr; - - /********************************************************/ - /* Set the authorization parameter */ - /********************************************************/ - - /* Also adjust the length of the security parameters field. */ - report_security_ptr = report_security_ptr - 2; - - /* Adjust the report security length. */ - report_security_length = report_security_length + 4; - - /* Store the security string size. */ - report_security_ptr[1] = (UCHAR) (report_security_length & 0xFF); - - /* Update various statistics. */ - agent_ptr -> nx_snmp_agent_reports_sent++; - - /* Increment the sent packet counter. */ - agent_ptr -> nx_snmp_agent_packets_sent++; - - /* Set the authentication parameter if we have determined it needs to be set, and only if we - have a valid user name. (Otherwise there would be no shared key for the other side to check - our authentication.)*/ - if ((authenticate == NX_TRUE) && (report_respond != NX_SNMP_DISCOVERY_RESPONSE_UNKNOWN_USERNAME_NUM)) - { - - /* Fill in the authentication parameter. */ - status = _nx_snmp_agent_add_auth_parameter(agent_ptr, report_packet_ptr, report_authentication_ptr); - - if (status != NX_SUCCESS) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Authentication error creating authentication parameter. Line %d \n\r", __LINE__); -#endif - - /* Increment the authentication error counter. */ - agent_ptr -> nx_snmp_agent_authentication_errors++; - - /* Release the original request packet. */ - nx_packet_release(report_packet_ptr); - - return; - } - } - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Sending the report on line %d.\n\r", __LINE__); -#endif - - /* Send the report packet back to the requesting SNMP manager. */ - status = nxd_udp_socket_send(&(agent_ptr -> nx_snmp_agent_socket), report_packet_ptr, - &(agent_ptr -> nx_snmp_agent_current_manager_ip), - agent_ptr -> nx_snmp_agent_current_manager_port); - - /* Determine if the packet needs to be released. */ - if (status) - { - - /* Release packet. */ - nx_packet_release(report_packet_ptr); - } - - - /* Return to caller. */ - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_add_auth_parameter PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function updates the specified SNMPv3 response with an */ -/* authentication parameter. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* response_packet_ptr Pointer to reply message data */ -/* response_authentication_ptr Pointer to authentication */ -/* parameter in the reply */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successfully added */ -/* authentication parameter */ -/* */ -/* CALLS */ -/* */ -/* _nx_md5_update Calculate MD5 message digest */ -/* _nx_md5_digest_calculate MD5 digest calculated */ -/* _nx_md5_initialize Prepare data for MD5 calc */ -/* _nx_sha_update Calculate SHa message digest */ -/* _nx_sha__digest_calculate SHa digest calculated */ -/* _nx_sha__initialize Prepare data for SHa calc */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_process Process SNMP v3 request reply */ -/* _nx_snmp_version_3_report_send Process SNMP v3 report */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_agent_add_auth_parameter(NX_SNMP_AGENT *agent_ptr, NX_PACKET *response_packet_ptr, UCHAR *response_authentication_ptr) -{ - -UINT i; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; - - - /* Determine which authentication is required. */ - if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && - ((agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key_type == NX_SNMP_MD5_KEY)) - { - - /* Copy the base MD5 key into key1. */ - for (i = 0; i < NX_SNMP_MD5_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base MD5 key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_MD5_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Calculate prepend Key1. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_md5_initialize(&(agent_ptr -> nx_snmp_agent_v3_md5_data)); - - /* Prepend Key2 to the result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_md5_update(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key1, NX_SNMP_MD5_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_md5_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_md5_data), key2); - } - else if ((agent_ptr -> nx_snmp_agent_v3_authentication_key) && - (agent_ptr -> nx_snmp_agent_v3_authentication_key -> nx_snmp_security_key_type == NX_SNMP_SHA_KEY)) - { - - /* Copy the base SHA key into key1. */ - for (i = 0; i < NX_SNMP_SHA_DIGEST_SIZE; i++) - { - - /* Copy a byte of the base SHA key. */ - key1[i] = (agent_ptr -> nx_snmp_agent_v3_authentication_key) -> nx_snmp_security_key[i]; - } - - /* Extend key1 to 64 bytes. */ - for (i = NX_SNMP_SHA_DIGEST_SIZE; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key1[i] = 0; - } - - /* Create key1 and key2. */ - for (i = 0; i < NX_SNMP_DIGEST_WORKING_SIZE; i++) - { - key2[i] = key1[i] ^ 0x5C; - key1[i] = key1[i] ^ 0x36; - } - - /* Calculate the MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Calculate prepend Key1. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the message. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), response_packet_ptr -> nx_packet_prepend_ptr, response_packet_ptr -> nx_packet_length); - - /* Final calculation of the first pass. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1); - - /* Prepare to calculate the final MAC. */ - _nx_sha1_initialize(&(agent_ptr -> nx_snmp_agent_v3_sha_data)); - - /* Prepend Key2 to the result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2, NX_SNMP_DIGEST_WORKING_SIZE); - - /* Calculate the previous result. */ - _nx_sha1_update(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key1, NX_SNMP_SHA_DIGEST_SIZE); - - /* Calculate the final MAC. */ - _nx_sha1_digest_calculate(&(agent_ptr -> nx_snmp_agent_v3_sha_data), key2); - } - else - { - - /* Return to caller. */ - return NX_SNMP_UNSUPPORTED_AUTHENTICATION; - } - - /* At this point, key2 contains the computed digest of the message. This needs to be - placed in the outgoing message. */ - - /* Loop to setup the outgoing digest. */ - for (i = 0; i < NX_SNMP_DIGEST_SIZE; i++) - { - - /* Copy the next byte of digest into the response buffer. */ - response_authentication_ptr[i] = key2[i]; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_encrypt_pdu PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encrypts data pointed to by the response buffer pointer*/ -/* and updates the necessary SNMPv3 header size in the header sequence */ -/* data. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* [These pointers pertain to the encrypted data to send:] */ -/* response_pdu_length Size of the PDU data */ -/* response_sequence_length Size of the response sequence */ -/* response_encryption_size_ptr Size of encryption data */ -/* response_sequence_ptr Pointer to the SNMPv3 sequence*/ -/* response_buffer_ptr Pointer to the SNMPv3 response*/ -/* response_privacy_ptr Pointer to privacy parameter */ -/* response_length Updated size of response */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Data successfully decrypted */ -/* NX_SNMP_INVALID_PDU_ENCRYPTION Invalid encrypted data */ -/* NX_SNMP_INVALID_ENCRYPT_LENGTH Decryption processing error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_process Process SNMP v3 request reply */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_snmp_agent_encrypt_pdu(NX_SNMP_AGENT *agent_ptr, UINT *response_pdu_length, UINT *response_sequence_length, UCHAR *response_encryption_size_ptr, - UCHAR **response_sequence_ptr, UCHAR *response_sequence_buffer_end, UCHAR **response_buffer_ptr, UCHAR *response_privacy_ptr) -{ - -UINT i, j; -UINT padding = 0; -UCHAR *temp_ptr; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; -UINT pdu_sequence_length; -UINT adjusted_pdu_length; - - if (response_pdu_length != NX_NULL) - { - - /* Determine if any padding needs to be applied - account for the - four bytes of header information on the PDU. */ - padding = ((*response_pdu_length+7)/8)*8 - *response_pdu_length; - - /* Add the padding the response PDU length and the response sequence length. */ - *response_pdu_length = *response_pdu_length + padding; - *response_sequence_length = *response_sequence_length + padding; - - /* Use a work pointer to initialize the padding buffer. */ - temp_ptr = *response_buffer_ptr; - - /* Clear the end of the response message... just to be nice! */ - for (i = 0; i < padding; i++) - { - - /* Clear byte at the end of the response. */ - *temp_ptr++ = 0; - } - - adjusted_pdu_length = *response_pdu_length; - } - else - { - /* Set the temp ptr to where the PDU starts in the request packet. */ - temp_ptr = pdu_buffer_ptr; - adjusted_pdu_length = pdu_length; - } - - /* If this is not for our outgoing response e.g. we are re-encrypting the received packet as part - of an error message, use the length from that packet. */ - if ((response_encryption_size_ptr == NX_NULL) || (response_pdu_length == NX_NULL)) - { - - pdu_sequence_length = pdu_length; - } - else - { - - /* We need to set the PDU "inner" sequence length; it comes just after the main PDU sequence header. */ - pdu_sequence_length = *response_pdu_length - 4; - - /* Do not include padding in the inner pdu size! */ - pdu_sequence_length = pdu_sequence_length - padding; - } - - if ((response_encryption_size_ptr != NX_NULL) && (response_pdu_length != NX_NULL)) - { - - /* Now we set the PDU "inner" sequence header. Use the multibyte sequence 0x30 82 xx yy format. - Note that calling function has already set the pointer for writing encyrpted PDU data past this - inner header. */ - response_encryption_size_ptr[2] = 0x30; - response_encryption_size_ptr[3] = ((UCHAR) 2) | NX_SNMP_ANS1_MULTI_BYTES; - response_encryption_size_ptr[4] = (UCHAR) ((pdu_sequence_length >> 8) & 0xFF); - response_encryption_size_ptr[5] = (UCHAR) (pdu_sequence_length & 0xFF); - - /* Update our response buffer pointer. */ - *response_buffer_ptr = temp_ptr; - - response_encryption_size_ptr[0] = (UCHAR) ((*response_pdu_length >> 8) & 0xFF); - response_encryption_size_ptr[1] = (UCHAR) (*response_pdu_length & 0xFF); - - /* Update the total response sequence length again. */ - _nx_snmp_utility_sequence_set(*response_sequence_ptr, *response_sequence_length, response_sequence_buffer_end); - } - - /* Increment the salt counter. */ - agent_ptr -> nx_snmp_agent_v3_context_salt_counter++; - - /* Build the salt value for the encryption. */ - key1[0] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 24) & 0xFF); - key1[1] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 16) & 0xFF); - key1[2] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_engine_boots >> 8) & 0xFF); - key1[3] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_engine_boots & 0xFF); - key1[4] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 24) & 0xFF); - key1[5] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 16) & 0xFF); - key1[6] = (UCHAR) ((agent_ptr -> nx_snmp_agent_v3_context_salt_counter >> 8) & 0xFF); - key1[7] = (UCHAR) (agent_ptr -> nx_snmp_agent_v3_context_salt_counter & 0xFF); - - - if (response_privacy_ptr != NX_NULL) - { - - /* Loop to store the salt in the privacy field. */ - for (i = 0; i < 8; i++) - { - - /* Store a byte of the salt. */ - response_privacy_ptr[i] = key1[i]; - } - } - - /* Setup pointer to the actual PDU. */ - if (response_encryption_size_ptr) - { - temp_ptr = response_encryption_size_ptr + 2; - } - - /* Make the Initialization Vector (IV). */ - for (i = 0; i < 8; i++) - { - - key2[i] = (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key[8+i] ^ key1[i]; - } - - /* Setup the DES. */ - _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key)->nx_snmp_security_key); - - /* Set up the first input block - use the IV for the first block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[i] ^ key2[i]; - } - - /* Encrypt the first 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[0]); - - /* Loop to encrypt the rest of the PDU. */ - j = 8; - do - { - - /* Setup the next input block. */ - for (i = 0; i < 8; i++) - { - - key1[i] = temp_ptr[j+i] ^ temp_ptr[(j-8)+i]; - } - - /* Encrypt the next 8 bytes. */ - _nx_des_encrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &key1[0], &temp_ptr[j]); - - /* Move the major index forward. */ - j = j + 8; - - } while (j < adjusted_pdu_length); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_decrypt_pdu PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decrypts the data pointed to by the buffer pointer */ -/* input. If the input response buffer pointer is not null, it will set */ -/* up the initial sequence header for the encrypted data around the */ -/* msgData header */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* buffer_ptr Pointer to data to decrypt */ -/* response_buffer_ptr Pointer to response to send */ -/* [If response_buffer_ptr is null, these have no effect:] */ -/* response_encryption_size_ptr Pointer to encrypted data in */ -/* response */ -/* response_length Size of encrypted data so far */ -/* buffer_length Size of buffer data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Data successfully decrypted */ -/* NX_SNMP_INVALID_PDU_ENCRYPTION Invalid encrypted data */ -/* NX_SNMP_INVALID_ENCRYPT_LENGTH Decryption processing error */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_process Process SNMP v3 request reply */ -/* _nx_snmp_version_3_report_send PRocess SNMP v3 report */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_snmp_agent_decrypt_pdu(NX_SNMP_AGENT *agent_ptr, UCHAR **buffer_ptr, UCHAR *response_buffer_ptr, - UCHAR **response_encryption_size_ptr, UINT *response_length, INT buffer_length) -{ - -UINT i, j, encrypted_size; -UCHAR key1[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR key2[NX_SNMP_DIGEST_WORKING_SIZE]; -UCHAR *temp_ptr; - - - *response_length = 0; - temp_ptr = *buffer_ptr; - - /* Decrypt the source PDU and setup the response to have an encryption header. */ - if (temp_ptr[0] != NX_SNMP_ANS1_OCTET_STRING) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Encryption error (no privacy key in the request). Line %d \n\r", __LINE__); -#endif - /* Return to caller. */ - return NX_SNMP_INVALID_PDU_ENCRYPTION; - } - - /* Pickup the encrypted PDU size. */ - if (temp_ptr[1] & NX_SNMP_ANS1_MULTI_BYTES) - { - - UINT temp = temp_ptr[1] & 0x7F; - if (temp == 2) - { - - /* Two byte octet string. */ - encrypted_size = (((UINT) temp_ptr[2]) << 8) | ((UINT) temp_ptr[3]); - - /* Move the buffer pointer up to the actual encrypted PDU contents. */ - temp_ptr = temp_ptr + 4; - } - else if (temp == 1) - { - - /* One byte octet string e.g. 0x04 0x81 0xXY */ - encrypted_size = (UINT) temp_ptr[2]; - - /* Move the buffer pointer up to the actual encrypted PDU contents. */ - temp_ptr = temp_ptr + 3; - - } - else - { - /* Either null or too big. Invalid size type.*/ - return NX_SNMP_ERROR_WRONGENCODING; - } - } - else - { - - /* One byte octet string. */ - encrypted_size = (UINT) temp_ptr[1]; - - /* Move the buffer pointer up to the actual encrypted PDU contents. */ - temp_ptr = temp_ptr + 2; - - } - - /* Check for invalid buffer size. */ - if ((INT)encrypted_size > buffer_length) - { - - /* Invalid buffer size. */ - return NX_SNMP_INVALID_PDU_ENCRYPTION; - } - - /* Determine if the length is valid. */ - if (encrypted_size % 8) - { - -#ifdef NX_SNMPV3_PRINT_DEBUG_MESSAGE - NX_SNMPV3_DBG_PRINTF("Encryption error (invalid length).Drop the request. Line %d \n\r", __LINE__); -#endif - /* Return to caller. */ - return NX_SNMP_INVALID_ENCRYPT_LENGTH; - } - - /* Create the Initialization Vector (IV). */ - for (i = 0; i < 8; i++) - { - - key2[i] = (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key[8+i] ^ agent_ptr -> nx_snmp_agent_v3_security_privacy[i]; - } - - /* Initialize the DES component. */ - _nx_des_key_set(&(agent_ptr -> nx_snmp_agent_v3_des_data), (agent_ptr -> nx_snmp_agent_v3_privacy_key) -> nx_snmp_security_key); - - /* Decrypt the first 8 bytes. */ - _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), temp_ptr, key1); - - /* XOR with the IV. */ - for (i = 0; i < 8; i++) - { - - /* XOR a byte of the IV. */ - key1[i] = key1[i] ^ key2[i]; - } - - /* Loop to decrypt the entire PDU. */ - j = 8; - do - { - - /* Decrypt the next 8-byte block. */ - _nx_des_decrypt(&(agent_ptr -> nx_snmp_agent_v3_des_data), &temp_ptr[j], key2); - - /* XOR with the previous encrypted 8-byte block. */ - for (i = 0; i < 8; i++) - { - - /* XOR result with previous block. */ - key2[i] = key2[i] ^ temp_ptr[(j-8)+i]; - - /* Copy a byte of the decrypted block over the source. */ - temp_ptr[(j-8)+i] = key1[i]; - - /* Save this byte of the new decrypted block. */ - key1[i] = key2[i]; - } - - /* Move j up to the next 8 octet sequence. */ - j = j + 8; - } while (j < encrypted_size); - - /* Flush the last block out to the buffer. */ - for (i = 0; i < 8; i++) - { - - /* Copy a byte of the decrypted block over the source. */ - temp_ptr[(j-8)+i] = key1[i]; - } - - *buffer_ptr = temp_ptr; - - /* If the caller is going to encrypt its response it will send a non null response buffer pointer. */ - if (response_buffer_ptr != NX_NULL) - { - - /* Now setup the response buffer to encapsulate the encrypted PDU. Note that - the actual encryption will be done after the complete response has been - formed. */ - response_buffer_ptr[0] = NX_SNMP_ANS1_OCTET_STRING; - response_buffer_ptr[1] = 0x82; - response_buffer_ptr[2] = 0x00; - response_buffer_ptr[3] = 0x00; - - /* Save the response encryption size pointer. This will be filled in below - as we build the message. */ - *response_encryption_size_ptr = response_buffer_ptr + 2; - - *response_length = 4 ; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_agent_security_response_status PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function determines how to set authentication and privacy */ -/* parameters in the USM header. */ -/* */ -/* INPUT */ -/* */ -/* agent_ptr Pointer to SNMP agent */ -/* */ -/* OUTPUT */ -/* */ -/* *authenticate If true, authentication */ -/* parameter should be set */ -/* *encryption If true, privacy parameter */ -/* should be set */ -/* *send_reply If not true, no reply or */ -/* report should be sent */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_version_3_report_send PRocess SNMP v3 report */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_snmp_agent_security_response_status(NX_SNMP_AGENT *agent_ptr, UINT *authenticate, UINT *encryption, UINT *send_reply) -{ - - - /* Initialize the security parameters to off. */ - *encryption = NX_FALSE; - *authenticate = NX_FALSE; - - /* In all but one or two cases we always send a reply. Initialize to true. */ - *send_reply = NX_TRUE; - - /* Check if the incoming request specifies encryption (privacy). */ - if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_PRIVACY ) >= 2) - { - - /* It is. Check if the SNMP agent has created an encryption key. */ - if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) - { - - /* We cannot decrypt the incoming message, (need the request ID), so we cannot send a reply. */ - *send_reply = NX_FALSE; - - return; - } - - /* Ok to apply privacy security level. */ - *encryption = NX_TRUE; - } - else - { - - /* Incoming message does not specify privacy. */ - - /* Check if the SNMP agent has created an encryption key. */ - if (agent_ptr -> nx_snmp_agent_v3_privacy_key == NX_NULL) - { - - /* It has not. The SNMP agent is not configured for privacy here. All good. */ - } - /* else - Same result, indicate no privacy applied to our response. */ - - } - - /* Now if the incoming message security level is set for authentication regardless - of matching privacy levels. */ - if ((agent_ptr -> nx_snmp_agent_v3_message_security_options & NX_SNMP_SECURITY_AUTHORIZE) >= 1) - { - - /* It is. Check if the SNMP agent has created an authentication key. */ - if (agent_ptr -> nx_snmp_agent_v3_authentication_key != NX_NULL) - { - - /* Ok to authenticate (even if not going apply privacy). */ - *authenticate = NX_TRUE; - } - /*else - Cannot authenticate, but we will still send a reply. */ - } - - return; -} - -#endif /*NX_SNMP_DISABLE_V3 */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_snmp_asn1_tlv_block_parse PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function parses an ASN.1 type-length-value (TLV) block for use */ -/* by the SNMP Agent parsing data received from the browser. */ -/* */ -/* INPUT */ -/* */ -/* buffer Pointer to data to be parsed */ -/* buffer_length Size of input buffer */ -/* tlv_type Return block type */ -/* tlv_tag_class Return class of the tag */ -/* tlv_length Return parsed length */ -/* tlv_data Return pointer to block data */ -/* header_length Return length of block itself */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_snmp_utility_object_get Extract data from sender */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_snmp_utility_tlv_block_parse(UCHAR *buffer, INT buffer_length, USHORT *tlv_type, - USHORT *tlv_tag_class, ULONG *tlv_length, - UCHAR **tlv_data, ULONG *header_length) -{ -UINT current_index = 0; -USHORT current_tag; -ULONG length; -ULONG length_bytes; - - - /* Check the buffer length. */ - if ((INT)current_index >= buffer_length) - { - return(NX_SNMP_ERROR_WRONGLENGTH); - } - - current_tag = buffer[current_index]; - - /* Handle multi-byte encoded tags. */ - if ((current_tag & NX_SNMP_ASN_TAG_MULTIBYTE_MASK) == NX_SNMP_ASN_TAG_MULTIBYTE_MASK) - { - return(NX_SNMP_MULTIBYTE_TAG_UNSUPPORTED); - } - else - { - *header_length = 1; - } - - /* Get the class of the tag so we can return it. */ - *tlv_tag_class = (USHORT)((current_tag & NX_SNMP_ASN_TAG_CLASS_MASK) >> 6); - - /* Make sure we have a valid tag class. */ - if (*tlv_tag_class == NX_SNMP_ASN_TAG_CLASS_PRIVATE) - { - /* The tag class is invalid, return error. */ - return(NX_SNMP_INVALID_TAG_CLASS); - } - - /* The caller actually handles what happens based on the tag type. */ - if (current_tag & NX_SNMP_ASN_TAG_CONSTRUCTED_MASK) - { - current_tag = current_tag & (USHORT)(~NX_SNMP_ASN_TAG_CONSTRUCTED_MASK); - } - - /* Clear out the class and constructed bits before returning the tag value. */ - *tlv_type = current_tag & NX_SNMP_ASN_TAG_MASK; - current_index++; - - /* Check the buffer length. */ - if ((INT)current_index >= buffer_length) - { - return(NX_SNMP_ERROR_WRONGLENGTH); - } - - if (current_tag == NX_SNMP_ANS1_NULL) - { - /* If tag is NULL, there is no length byte, just a value of zero, */ - *tlv_length = 1; - - /* Set the data pointer and return. */ - *tlv_data = &buffer[current_index]; - - return(NX_SUCCESS); - } - - /* Handle the length. */ - length = buffer[current_index]; - current_index++; - *header_length = *header_length + 1; - - /* Check for multi-byte length by looking at the top bit of the length byte. */ - if (length & 0x80) - { - /* Multi-byte length: - > 127, high bit is set, and lower 7 bits becomes the number of following bytes of *length* - so 841 bytes of Value is encoded as 0x82, 0x03, 0x49 (0x82 = 2 bytes of length, 0x0349 = 841). - */ - - /* Mask off top bit to get the number of bytes in length. */ - length_bytes = length & 0x7F; - length = 0; - - /* Check for length too big to handle. */ - if (length_bytes > 4) - { - - return(NX_SNMP_ASN1_LENGTH_TOO_LONG); - } - - /* Update header length. */ - *header_length = *header_length + length_bytes; - - /* Check the buffer length. */ - if ((INT)(current_index + length_bytes) > buffer_length) - { - return(NX_SNMP_ERROR_WRONGLENGTH); - } - - while (length_bytes > 0) - { - /* Shift length one byte up and add in next byte. */ - length <<= 8; - length += buffer[current_index]; - - /* Advance our index by one byte. */ - current_index++; - length_bytes--; - } - } - else - { - /* Single-byte length: - <= 127 (7 bits), length is the number of bytes of Value */ - *tlv_length = length; - } - - /* Set the length to return to caller. */ - *tlv_length = length; - - /* Check the buffer length. */ - if ((INT)current_index >= buffer_length) - { - return(NX_SNMP_ERROR_WRONGLENGTH); - } - - /* Now, we can set the tld value */ - *tlv_data = &buffer[current_index]; - - return(NX_SUCCESS); -} - - diff --git a/protocol_handlers/snmp/nxd_snmp.h b/protocol_handlers/snmp/nxd_snmp.h deleted file mode 100644 index 2e604aa7..00000000 --- a/protocol_handlers/snmp/nxd_snmp.h +++ /dev/null @@ -1,888 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** Simple Network Management Protocol (SNMP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_snmp.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Simple Network Management Protocol */ -/* (SNMP) component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_SNMP_H -#define NXD_SNMP_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Include necessary digest and encryption files. */ - -#include "nx_api.h" -#ifndef NX_SNMP_DISABLE_V3 -#include "nx_md5.h" -#include "nx_sha1.h" -#include "nx_des.h" -#endif - - -/* Disable SNMP V1 message processing. -#define NX_SNMP_DISABLE_V1 -*/ - -/* Disable SNMP V2 message processing. -#define NX_SNMP_DISABLE_V2 -*/ - -/* Disable SNMP V3 message processing. -#define NX_SNMP_DISABLE_V3 -*/ - -/* Default support of SNMP V2 to only V2C. -#define NX_SNMP_V2C_ONLY -*/ - -/* By default support for security (authentication and encryption) is enabled. To disable - it define this option. -#define NX_SNMP_NO_SECURITY -*/ - - -/* Define the SNMP ID. */ - -#define NX_SNMP_ID 0x534E4D50UL - - -/* Define SNMP UDP socket create options. */ - -#ifndef NX_SNMP_TYPE_OF_SERVICE -#define NX_SNMP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_SNMP_FRAGMENT_OPTION -#define NX_SNMP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_SNMP_TIME_TO_LIVE -#define NX_SNMP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_SNMP_AGENT_PRIORITY -#define NX_SNMP_AGENT_PRIORITY 16 -#endif - -#ifndef NX_SNMP_AGENT_TIMEOUT -#define NX_SNMP_AGENT_TIMEOUT (1 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_SNMP_MAX_OCTET_STRING -#define NX_SNMP_MAX_OCTET_STRING 255 -#else -#if NX_SNMP_MAX_OCTET_STRING < 23 -#error "NX_SNMP_MAX_OCTET_STRING should not be smaller than 23." -#endif -#endif - -#ifndef NX_SNMP_MAX_CONTEXT_STRING -#define NX_SNMP_MAX_CONTEXT_STRING 32 -#endif - -#ifndef NX_SNMP_MAX_USER_NAME -#define NX_SNMP_MAX_USER_NAME 64 -#endif - -#ifndef NX_SNMP_MAX_TRAP_NAME -#define NX_SNMP_MAX_TRAP_NAME 64 -#endif - - -#ifndef NX_SNMP_MAX_SECURITY_KEY -#define NX_SNMP_MAX_SECURITY_KEY 64 -#else -#if NX_SNMP_MAX_SECURITY_KEY < 20 -#error "NX_SNMP_MAX_SECURITY_KEY should not be smaller than 20." -#endif -#endif - -#ifndef NX_SNMP_MAX_TRAP_KEY -#define NX_SNMP_MAX_TRAP_KEY 64 -#endif - -#ifndef NX_SNMP_PACKET_SIZE -#define NX_SNMP_PACKET_SIZE 560 -#endif - - -/* Define the maximum number of packets that can be queued on the SNMP Agent's UDP Port. */ - -#define NX_SNMP_QUEUE_DEPTH 5 - -/* Define a symbol for indicating trap contains proprietary data (instead of just standard cold start, warm start etc. */ -#define NX_SNMP_TRAP_CUSTOM 0xFFFFFFFF - - -/* Define the SNMP versions supported. */ - -#define NX_SNMP_VERSION_1 0 -#define NX_SNMP_VERSION_2C 1 -#define NX_SNMP_VERSION_2 2 -#define NX_SNMP_VERSION_3 3 - -/* Define constants for ASN1 BER encoding */ - -#define NX_SNMP_ASN_TAG_CONSTRUCTED_MASK 0x20 /* If bit 6 is set, it is a constructed type. */ -#define NX_SNMP_ASN_TAG_MULTIBYTE_MASK 0x1F /* Some ASN1 tags are multi-byte. */ -#define NX_SNMP_ASN_TAG_CLASS_MASK 0xC0 /* Top 2 bits of tag are the "class". */ -#define NX_SNMP_ASN_TAG_MASK 0x1F /* Bottom 6 bits are the tag itself. */ - -/* Tag classes. Bits refer to bit locations in the tag octet. - * Note that "Application" and "Private" are not recommended for use and - * should probably never be encountered in SNMP. - * Class | Bit 7 | Bit 8 | - * --------------------------------------------- - * Universal | 0 | 0 | - * Application | 0 | 1 | - * Context-specific | 1 | 0 | - * Private | 1 | 1 | - */ -#define NX_SNMP_ASN_TAG_CLASS_UNIVERSAL 0x00 /* ASN.1 standard tag values. */ -#define NX_SNMP_ASN_TAG_CLASS_APPLICATION 0x01 /* (UNUSED) Application-specific tag values. */ -#define NX_SNMP_ASN_TAG_CLASS_CONTEXT 0x02 /* Context-specific tag values. */ -#define NX_SNMP_ASN_TAG_CLASS_PRIVATE 0x03 /* (UNUSED) Private tag values. */ - -/* Define the SNMP/ANS1 control characters. */ - -#define NX_SNMP_ANS1_SEQUENCE 0x30 /* ANS1 Code for SEQUENCE */ -#define NX_SNMP_ANS1_INTEGER 0x02 /* ANS1 Code for INTEGER */ -#define NX_SNMP_ANS1_BIT_STRING 0x03 /* ANS1 Code for BIT STRING */ -#define NX_SNMP_ANS1_OCTET_STRING 0x04 /* ANS1 Code for OCTET STRING */ -#define NX_SNMP_ANS1_NULL 0x05 /* ANS1 Code for NULL */ -#define NX_SNMP_ANS1_OBJECT_ID 0x06 /* ANS1 Code for OBJECT ID */ -#define NX_SNMP_ANS1_IP_ADDRESS 0x40 /* ANS1 Code for IP ADDRESS */ -#define NX_SNMP_ANS1_COUNTER 0x41 /* ANS1 Code for COUNTER */ -#define NX_SNMP_ANS1_GAUGE 0x42 /* ANS1 Code for GAUGE */ -#define NX_SNMP_ANS1_TIME_TICS 0x43 /* ANS1 Code for TIME TICS */ -#define NX_SNMP_ANS1_OPAQUE 0x44 /* ANS1 Code for OPAQUE */ -#define NX_SNMP_ANS1_NSAP_ADDRESS 0x45 /* ANS1 Code for NSAP ADDRESS */ -#define NX_SNMP_ANS1_COUNTER64 0x46 /* ANS1 Code for COUNTER64 */ -#define NX_SNMP_ANS1_UINTEGER32 0x47 /* ANS1 Code for UINTEGER32 */ -#define NX_SNMP_ANS1_NO_SUCH_OBJECT 0x80 /* ANS1 Code for No Such Object */ -#define NX_SNMP_ANS1_NO_SUCH_INSTANCE 0x81 /* ANS1 Code for No Such Instance */ -#define NX_SNMP_ANS1_END_OF_MIB_VIEW 0x82 /* ANS1 Code for End of MIB view */ -#define NX_SNMP_ANS1_GET_REQUEST 0xA0 /* ANS1 Code for SNMP GET */ -#define NX_SNMP_ANS1_GET_NEXT_REQUEST 0xA1 /* ANS1 Code for SNMP GET NEXT */ -#define NX_SNMP_ANS1_GET_RESPONSE 0xA2 /* ANS1 Code for SNMP GET RESPONSE */ -#define NX_SNMP_ANS1_SET_REQUEST 0xA3 /* ANS1 Code for SNMP SET */ -#define NX_SNMP_ANS1_TRAP_REQUEST 0xA4 /* ANS1 Code for SNMP TRAP */ -#define NX_SNMP_ANS1_GET_BULK_REQUEST 0xA5 /* ANS1 Code for SNMP GET BULK (v2) */ -#define NX_SNMP_ANS1_INFORM_REQUEST 0xA6 /* ANS1 Code for SNMP INFORM (v2) */ -#define NX_SNMP_ANS1_TRAP2_REQUEST 0xA7 /* ANS1 Code for SNMP TRAP (v2) */ -#define NX_SNMP_ANS1_REPORT_REQUEST 0xA8 /* ANS1 Code for SNMP REPORT (v3) */ -#define NX_SNMP_ANS1_MULTI_BYTES 0x80 /* ANS1 Bit for Multiple Bytes */ -#ifdef FEATURE_NX_IPV6 -#define NX_SNMP_ANS1_IPV6_ADDRESS NX_SNMP_ANS1_OCTET_STRING /* ANS1 Code for OCTET string */ -#endif -/* Define the SNMP application GET/GETNEXT/SET callback return error codes. */ - -#define NX_SNMP_SUCCESS 0 /* Everything is okay */ -#define NX_SNMP_ERROR_TOOBIG 1 /* Can't fit reply in outgoing message */ -#define NX_SNMP_ERROR_NOSUCHNAME 2 /* Object could not be found */ -#define NX_SNMP_ERROR_BADVALUE 3 /* Invalid value of set operation */ -#define NX_SNMP_ERROR_READONLY 4 /* Object is read only and cannot be set*/ -#define NX_SNMP_ERROR_GENERAL 5 /* General error */ -#define NX_SNMP_ERROR_NOACCESS 6 -#define NX_SNMP_ERROR_WRONGTYPE 7 -#define NX_SNMP_ERROR_WRONGLENGTH 8 -#define NX_SNMP_ERROR_WRONGENCODING 9 -#define NX_SNMP_ERROR_WRONGVALUE 10 -#define NX_SNMP_ERROR_NOCREATION 11 -#define NX_SNMP_ERROR_INCONSISTENTVALUE 12 -#define NX_SNMP_ERROR_RESOURCEUNAVAILABLE 13 -#define NX_SNMP_ERROR_COMMITFAILED 14 -#define NX_SNMP_ERROR_UNDOFAILED 15 -#define NX_SNMP_ERROR_AUTHORIZATION 16 -#define NX_SNMP_ERROR_NOTWRITABLE 17 -#define NX_SNMP_ERROR_INCONSISTENTNAME 18 -#define NX_SNMP_UNKNOWN_USERNAME 19 -#define NX_SNMP_UNSUPPORTED_AUTHENTICATION 20 -#define NX_SNMP_INVALID_PDU_ENCRYPTION 21 -#define NX_SNMP_INVALID_ENCRYPT_LENGTH 22 -#define NX_SNMP_MULTIBYTE_TAG_UNSUPPORTED 23 -#define NX_SNMP_INVALID_TAG_CLASS 24 -#define NX_SNMP_ASN1_LENGTH_TOO_LONG 25 - -/* Define SNMP Traps. */ - -#define NX_SNMP_TRAP_COLDSTART 0 -#define NX_SNMP_TRAP_WARMSTART 1 -#define NX_SNMP_TRAP_LINKDOWN 2 -#define NX_SNMP_TRAP_LINKUP 3 -#define NX_SNMP_TRAP_AUTHENTICATE_FAILURE 4 -#define NX_SNMP_TRAP_EGPNEIGHBORLOSS 5 -#define NX_SNMP_TRAP_ENTERPRISESPECIFIC 6 - - -/* Define SNMP requests for use by the agent request processing callback routine. */ - -#define NX_SNMP_GET_REQUEST NX_SNMP_ANS1_GET_REQUEST -#define NX_SNMP_GET_NEXT_REQUEST NX_SNMP_ANS1_GET_NEXT_REQUEST -#define NX_SNMP_SET_REQUEST NX_SNMP_ANS1_SET_REQUEST -#define NX_SNMP_GET_BULK_REQUEST NX_SNMP_ANS1_GET_BULK_REQUEST - - -/* Define SNMP object type definitions. These will be mapped to the internal ANS1 equivalents. */ - -#define NX_SNMP_INTEGER NX_SNMP_ANS1_INTEGER -#define NX_SNMP_BIT_STRING NX_SNMP_ANS1_BIT_STRING -#define NX_SNMP_OCTET_STRING NX_SNMP_ANS1_OCTET_STRING -#define NX_SNMP_NULL NX_SNMP_ANS1_NULL -#define NX_SNMP_OBJECT_ID NX_SNMP_ANS1_OBJECT_ID -#define NX_SNMP_IP_ADDRESS NX_SNMP_ANS1_IP_ADDRESS -#define NX_SNMP_COUNTER NX_SNMP_ANS1_COUNTER -#define NX_SNMP_GAUGE NX_SNMP_ANS1_GAUGE -#define NX_SNMP_TIME_TICS NX_SNMP_ANS1_TIME_TICS -#define NX_SNMP_OPAQUE NX_SNMP_ANS1_OPAQUE -#define NX_SNMP_NSAP_ADDRESS NX_SNMP_ANS1_NSAP_ADDRESS -#define NX_SNMP_COUNTER64 NX_SNMP_ANS1_COUNTER64 -#define NX_SNMP_UINTEGER32 NX_SNMP_ANS1_UINTEGER32 -#define NX_SNMP_NO_SUCH_OBJECT NX_SNMP_ANS1_NO_SUCH_OBJECT -#define NX_SNMP_NO_SUCH_INSTANCE NX_SNMP_ANS1_NO_SUCH_INSTANCE -#define NX_SNMP_END_OF_MIB_VIEW NX_SNMP_ANS1_END_OF_MIB_VIEW - - -/* Define return code constants. */ - -#define NX_SNMP_ERROR 0x100 /* SNMP internal error */ -#define NX_SNMP_NEXT_ENTRY 0x101 /* SNMP found next entry */ -#define NX_SNMP_ENTRY_END 0x102 /* SNMP end of entry */ -#define NX_SNMP_TIMEOUT 0x101 /* SNMP timeout occurred */ -#define NX_SNMP_FAILED 0x102 /* SNMP error */ -#define NX_SNMP_POOL_ERROR 0x103 /* SNMP packet pool size error */ -#define NX_SNMP_INVALID_IP_PROTOCOL_ERROR 0x104 /* Invalid packet IP version */ - -/* Define the SNMP Agent UDP port number */ - -#ifndef NX_SNMP_AGENT_PORT -#define NX_SNMP_AGENT_PORT 161 /* Port for SNMP Agent */ -#endif - -#ifndef NX_SNMP_MANAGER_TRAP_PORT -#define NX_SNMP_MANAGER_TRAP_PORT 162 /* Trap Port for SNMP Manager */ -#endif - - -/* Define SNMP v3 constants. */ - -#define NX_SNMP_USM_SECURITY_MODEL 3 /* Value for USM Security model */ -#define NX_SNMP_SECURITY_AUTHORIZE 0x1 /* Authorization required bit */ -#define NX_SNMP_SECURITY_PRIVACY 0x2 /* Privacy (encryption) required bit */ -#define NX_SNMP_SECURITY_REPORTABLE 0x4 /* Reportable bit */ - - -/* Define SNMP authentication/encryption key types. */ - -#define NX_SNMP_MD5_KEY 1 -#define NX_SNMP_SHA_KEY 2 -#define NX_SNMP_DES_DEY 3 -#define NX_SNMP_AES_KEY 4 /* Future expansion */ - - -/* Define SNMP USM digest size. */ - -#define NX_SNMP_DIGEST_SIZE 12 /* Size of SNMP authentication digest */ -#define NX_SNMP_MD5_DIGEST_SIZE 16 /* Size of pure MD5 digest */ -#define NX_SNMP_SHA_DIGEST_SIZE 20 /* Size of pure SHA digest */ -#define NX_SNMP_DIGEST_WORKING_SIZE 64 /* Size of keys for the digest routines */ - -#define NX_SNMP_TCP_TIMER_RATE NX_IP_PERIODIC_RATE/NX_TCP_TRANSMIT_TIMER_RATE - - -/* Define the key data types that will be used by the digest and/or encryption routines. */ - -typedef struct NX_SNMP_SECURITY_KEY_STRUCT -{ - - UINT nx_snmp_security_key_size; - UINT nx_snmp_security_key_type; - UCHAR nx_snmp_security_key[NX_SNMP_MAX_SECURITY_KEY]; - -} NX_SNMP_SECURITY_KEY; - - - -/* Define the SNMP Agent object data structure. This structure is used for holding a single - variable's value. It is passed between the SNMP Agent and the application callback functions - in order to get/set variables. */ - -typedef struct NX_SNMP_OBJECT_DATA_STRUCT -{ - - UINT nx_snmp_object_data_type; /* Type of SNMP data contained */ - LONG nx_snmp_object_data_msw; /* Most significant 32 bits */ - LONG nx_snmp_object_data_lsw; /* Least significant 32 bits */ - UINT nx_snmp_object_octet_string_size; /* Size of OCTET string */ - UCHAR nx_snmp_object_octet_string[NX_SNMP_MAX_OCTET_STRING + 1]; - -} NX_SNMP_OBJECT_DATA; - - -/* Define the SNMP Agent object list type that defines application objects to be included in the - trap calls. */ - -typedef struct NX_SNMP_TRAP_OBJECT_STRUCT -{ - - UCHAR *nx_snmp_object_string_ptr; - NX_SNMP_OBJECT_DATA *nx_snmp_object_data; -} NX_SNMP_TRAP_OBJECT; - - -/* Define the SNMP Agent data structure. */ - -typedef struct NX_SNMP_AGENT_STRUCT -{ - ULONG nx_snmp_agent_id; /* SNMP Agent ID */ - CHAR *nx_snmp_agent_name; /* Name of this SNMP Agent */ - NX_IP *nx_snmp_agent_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_snmp_agent_packet_pool_ptr; /* Pointer to SNMP agent packet pool */ - UINT nx_snmp_agent_current_version; /* Current SNMP Version */ - UINT nx_snmp_agent_request_get_type; /* Indicate if last request received is Get or Set type*/ - UINT nx_snmp_agent_interface_index; /* SNMP network interface index */ - UINT nx_snmp_agent_v1_enabled; /* SNMP agent enabled for V1 status */ - UINT nx_snmp_agent_v2_enabled; /* SNMP agent enabled for V2/V2C status */ - UINT nx_snmp_agent_v3_enabled; /* SNMP agent enabled for V3 status */ -#ifndef NX_SNMP_DISABLE_V3 - ULONG nx_snmp_agent_v3_message_id; /* SNMP v3 message id */ - ULONG nx_snmp_agent_v3_message_size; /* SNMP v3 message size */ - ULONG nx_snmp_agent_v3_message_security_type; /* SNMP v3 message security type */ - UCHAR nx_snmp_agent_v3_message_security_options; /* SNMP v3 message security flags */ - UCHAR nx_snmp_agent_v3_security_context_engine[NX_SNMP_MAX_CONTEXT_STRING]; /* Context engine */ - UINT nx_snmp_agent_v3_security_context_engine_size; /* SNMP v3 security context engine size */ - ULONG nx_snmp_agent_v3_security_engine_boots; /* SNMP v3 security engine boot count */ - ULONG nx_snmp_agent_v3_security_engine_boot_time; /* SNMP v3 security engine boot time */ - UCHAR nx_snmp_agent_v3_security_user_name[NX_SNMP_MAX_USER_NAME]; /* SNMPv3 security username */ - UINT nx_snmp_agent_v3_security_user_name_size; /* SNMP v3 security user name size */ - UCHAR nx_snmp_agent_v3_security_trap_name[NX_SNMP_MAX_TRAP_NAME]; /* SNMPv3 username to send trap messages */ - UINT nx_snmp_agent_v3_security_trap_name_size; /* SNMP v3 security username size for trap messages */ - UINT nx_snmp_agent_unsupported_sec_count; /* Count of reports with no security */ - UINT nx_snmp_agent_unknown_engineid_count; /* Count of unknown engine ID reports */ - UINT nx_snmp_agent_unknown_username_count; /* Count of no username reports */ - UINT nx_snmp_agent_mismatched_time_count; /* Count of time out of synch reports */ - UCHAR nx_snmp_agent_v3_security_authentication[NX_SNMP_MAX_SECURITY_KEY]; /* security authentication */ - UINT nx_snmp_agent_v3_security_authentication_size; /* SNMP v3 security authentication size */ - UCHAR nx_snmp_agent_v3_security_privacy[NX_SNMP_MAX_SECURITY_KEY];/* SNMP v3 security privacy */ - UINT nx_snmp_agent_v3_security_privacy_size; /* SNMP v3 security privacy size */ - UCHAR nx_snmp_agent_v3_trap_authentication[NX_SNMP_MAX_TRAP_KEY]; /* security authentication */ - UINT nx_snmp_agent_v3_trap_authentication_size; /* SNMPv3 trap message authentication size */ - UCHAR nx_snmp_agent_v3_trap_privacy[NX_SNMP_MAX_TRAP_KEY];/* SNMP v3 trap message privacy */ - UINT nx_snmp_agent_v3_trap_privacy_size; /* SNMP v3 trap message privacy size */ - UCHAR nx_snmp_agent_v3_context_engine[NX_SNMP_MAX_CONTEXT_STRING]; /* SNMP v3 context name */ - UINT nx_snmp_agent_v3_context_engine_size; /* SNMP v3 context engine size */ - UCHAR nx_snmp_agent_v3_context_name[NX_SNMP_MAX_CONTEXT_STRING]; /* SNMPv3 context name */ - UINT nx_snmp_agent_v3_context_name_size; /* SNMP v3 context engine size */ - UINT nx_snmp_agent_v3_context_engine_boots; /* SNMP v3 context engine boots */ - UINT nx_snmp_agent_v3_context_engine_boot_time; /* SNMP v3 context engine boot time */ - UINT nx_snmp_agent_v3_context_salt_counter; /* SNMP v3 context salt counter */ - NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_authentication_key; /* SNMP v3 authentication key */ - NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_auth_trap_key; /* SNMP v3 authentication key for traps */ - NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_privacy_key; /* SNMP v3 privacy key */ - NX_SNMP_SECURITY_KEY *nx_snmp_agent_v3_priv_trap_key; /* SNMP v3 privacy key for traps */ - NX_MD5 nx_snmp_agent_v3_md5_data; /* SNMP v3 MD5 authentication data */ - NX_SHA1 nx_snmp_agent_v3_sha_data; /* SNMP v3 SHA authentication data */ - NX_DES nx_snmp_agent_v3_des_data; /* SNMP v3 DES encryption data */ -#endif /* NX_SNMP_DISABLE_V3 */ - UCHAR nx_snmp_agent_current_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Received Community string */ - UCHAR nx_snmp_agent_private_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Agent's private community string */ - UCHAR nx_snmp_agent_public_community_string[NX_SNMP_MAX_USER_NAME + 1]; /* Agent's public community string */ - UCHAR nx_snmp_agent_current_octet_string[NX_SNMP_MAX_OCTET_STRING + 1]; /* Current SNMP Object ID*/ - NX_SNMP_OBJECT_DATA nx_snmp_agent_current_object_data; /* Current SNMP Object information */ - NXD_ADDRESS nx_snmp_agent_current_manager_ip; /* Current SNMP Manager IPv6/IPv4 address*/ - UINT nx_snmp_agent_current_manager_port; /* Current SNMP Manager UDP port */ - ULONG nx_snmp_agent_packets_received; /* Number of SNMP packets received */ - ULONG nx_snmp_agent_packets_sent; /* Number of SNMP packets sent */ - ULONG nx_snmp_agent_invalid_version; /* Number of invalid SNMP versions */ - ULONG nx_snmp_agent_total_get_variables; /* Number of variables to get */ - ULONG nx_snmp_agent_total_set_variables; /* Number of variables to set */ - ULONG nx_snmp_agent_too_big_errors; /* Number of too big errors sent */ - ULONG nx_snmp_agent_no_such_name_errors; /* Number of no such name errors sent */ - ULONG nx_snmp_agent_bad_value_errors; /* Number of bad value errors sent */ - ULONG nx_snmp_agent_general_errors; /* Number of general errors sent */ - ULONG nx_snmp_agent_request_errors; /* Number of errors on SNMP requests */ - ULONG nx_snmp_agent_get_requests; /* Number of GET requests */ - ULONG nx_snmp_agent_getnext_requests; /* Number of GETNEXT requests */ - ULONG nx_snmp_agent_getbulk_requests; /* Number of GETBULK requests */ - ULONG nx_snmp_agent_set_requests; /* Number of SET requests */ - ULONG nx_snmp_agent_reports_sent; /* Number of DISCOVERY requests */ - ULONG nx_snmp_agent_internal_errors; /* Number of internal errors detected */ - ULONG nx_snmp_agent_traps_sent; /* Number of traps sent */ - ULONG nx_snmp_agent_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_snmp_agent_total_bytes_received; /* Number of total bytes received */ - ULONG nx_snmp_agent_unknown_requests; /* Number of unknown commands received */ - ULONG nx_snmp_agent_invalid_packets; /* Number of invalid SNMP packets */ - ULONG nx_snmp_agent_allocation_errors; /* Number of allocation errors */ - ULONG nx_snmp_agent_username_errors; /* Number of community/username errors */ - ULONG nx_snmp_agent_authentication_errors; /* Number of authentication errors */ - ULONG nx_snmp_agent_privacy_errors; /* Number of privacy errors */ - ULONG nx_snmp_agent_getresponse_sent; /* Number of getresponse sent */ - NX_UDP_SOCKET nx_snmp_agent_socket; /* SNMP Server UDP socket */ - TX_THREAD nx_snmp_agent_thread; /* SNMP agent thread */ - UINT (*nx_snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); - UINT (*nx_snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); - UINT (*nx_snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); - UINT (*nx_snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username); - -} NX_SNMP_AGENT; - - - -#ifndef NX_SNMP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_snmp_agent_authenticate_key_use _nx_snmp_agent_authenticate_key_use -#define nx_snmp_agent_auth_trap_key_use _nx_snmp_agent_auth_trap_key_use -#define nx_snmp_agent_community_get _nx_snmp_agent_community_get -#define nx_snmp_agent_context_engine_set _nx_snmp_agent_context_engine_set -#define nx_snmp_agent_context_name_set _nx_snmp_agent_context_name_set -#define nx_snmp_agent_v3_context_boots_set _nx_snmp_agent_v3_context_boots_set -#define nx_snmp_agent_create _nx_snmp_agent_create -#define nx_snmp_agent_delete _nx_snmp_agent_delete -#define nx_snmp_agent_request_get_type_test _nx_snmp_agent_request_get_type_test -#define nx_snmp_agent_current_version_get _nx_snmp_agent_current_version_get -#define nx_snmp_agent_version_set _nx_snmp_agent_version_set -#define nx_snmp_agent_set_interface _nx_snmp_agent_set_interface -#ifndef NX_SNMP_DISABLE_V3 -#define nx_snmp_agent_md5_key_create _nx_snmp_agent_md5_key_create -#define nx_snmp_agent_md5_key_create_extended _nx_snmp_agent_md5_key_create_extended -#define nx_snmp_agent_privacy_key_use _nx_snmp_agent_privacy_key_use -#define nx_snmp_agent_sha_key_create _nx_snmp_agent_sha_key_create -#define nx_snmp_agent_sha_key_create_extended _nx_snmp_agent_sha_key_create_extended -#endif -#define nx_snmp_agent_priv_trap_key_use _nx_snmp_agent_priv_trap_key_use -#define nx_snmp_agent_private_string_set _nx_snmp_agent_private_string_set -#define nx_snmp_agent_public_string_set _nx_snmp_agent_public_string_set -#define nx_snmp_agent_public_string_test _nx_snmp_agent_public_string_test -#define nx_snmp_agent_private_string_test _nx_snmp_agent_private_string_test -#define nx_snmp_agent_start _nx_snmp_agent_start -#define nx_snmp_agent_stop _nx_snmp_agent_stop -#define nx_snmp_agent_trap_send _nx_snmp_agent_trap_send -#define nx_snmp_agent_trapv2_send _nx_snmp_agent_trapv2_send -#define nx_snmp_agent_trapv3_send _nx_snmp_agent_trapv3_send -#define nxd_snmp_agent_trap_send _nxd_snmp_agent_trap_send -#define nxd_snmp_agent_trapv2_send _nxd_snmp_agent_trapv2_send -#define nxd_snmp_agent_trapv3_send _nxd_snmp_agent_trapv3_send -#define nx_snmp_object_compare _nx_snmp_object_compare -#define nx_snmp_object_compare_extended _nx_snmp_object_compare_extended -#define nx_snmp_object_copy _nx_snmp_object_copy -#define nx_snmp_object_copy_extended _nx_snmp_object_copy_extended -#define nx_snmp_object_counter_get _nx_snmp_object_counter_get -#define nx_snmp_object_counter_set _nx_snmp_object_counter_set -#define nx_snmp_object_counter64_get _nx_snmp_object_counter64_get -#define nx_snmp_object_counter64_set _nx_snmp_object_counter64_set -#define nx_snmp_object_end_of_mib _nx_snmp_object_end_of_mib -#define nx_snmp_object_gauge_get _nx_snmp_object_gauge_get -#define nx_snmp_object_gauge_set _nx_snmp_object_gauge_set -#define nx_snmp_object_id_get _nx_snmp_object_id_get -#define nx_snmp_object_id_set _nx_snmp_object_id_set -#define nx_snmp_object_integer_get _nx_snmp_object_integer_get -#define nx_snmp_object_integer_set _nx_snmp_object_integer_set -#define nx_snmp_object_ip_address_get _nx_snmp_object_ip_address_get -#define nx_snmp_object_ip_address_set _nx_snmp_object_ip_address_set -#ifdef FEATURE_NX_IPV6 -#define nx_snmp_object_ipv6_address_get _nx_snmp_object_ipv6_address_get -#define nx_snmp_object_ipv6_address_set _nx_snmp_object_ipv6_address_set -#endif -#define nx_snmp_object_no_instance _nx_snmp_object_no_instance -#define nx_snmp_object_not_found _nx_snmp_object_not_found -#define nx_snmp_object_octet_string_get _nx_snmp_object_octet_string_get -#define nx_snmp_object_octet_string_set _nx_snmp_object_octet_string_set -#define nx_snmp_object_string_get _nx_snmp_object_string_get -#define nx_snmp_object_string_set _nx_snmp_object_string_set -#define nx_snmp_object_timetics_get _nx_snmp_object_timetics_get -#define nx_snmp_object_timetics_set _nx_snmp_object_timetics_set -#define nx_snmp_agent_trapv2_oid_send _nx_snmp_agent_trapv2_oid_send -#define nx_snmp_agent_trapv3_oid_send _nx_snmp_agent_trapv3_oid_send - - -#else - -/* Services with error checking. */ - -#define nx_snmp_agent_authenticate_key_use _nxe_snmp_agent_authenticate_key_use -#define nx_snmp_agent_auth_trap_key_use _nxe_snmp_agent_auth_trap_key_use -#define nx_snmp_agent_community_get _nxe_snmp_agent_community_get -#define nx_snmp_agent_context_engine_set _nxe_snmp_agent_context_engine_set -#define nx_snmp_agent_context_name_set _nxe_snmp_agent_context_name_set -#define nx_snmp_agent_v3_context_boots_set _nxe_snmp_agent_v3_context_boots_set -#define nx_snmp_agent_create _nxe_snmp_agent_create -#define nx_snmp_agent_delete _nxe_snmp_agent_delete -#define nx_snmp_agent_request_get_type_test _nxe_snmp_agent_request_get_type_test -#define nx_snmp_agent_current_version_get _nxe_snmp_agent_current_version_get -#define nx_snmp_agent_version_set _nxe_snmp_agent_version_set -#define nx_snmp_agent_set_interface _nxe_snmp_agent_set_interface -#ifndef NX_SNMP_DISABLE_V3 -#define nx_snmp_agent_md5_key_create _nxe_snmp_agent_md5_key_create -#define nx_snmp_agent_md5_key_create_extended _nxe_snmp_agent_md5_key_create_extended -#define nx_snmp_agent_sha_key_create _nxe_snmp_agent_sha_key_create -#define nx_snmp_agent_sha_key_create_extended _nxe_snmp_agent_sha_key_create_extended -#define nx_snmp_agent_privacy_key_use _nxe_snmp_agent_privacy_key_use -#define nx_snmp_agent_priv_trap_key_use _nxe_snmp_agent_priv_trap_key_use -#endif -#define nx_snmp_agent_private_string_set _nxe_snmp_agent_private_string_set -#define nx_snmp_agent_public_string_set _nxe_snmp_agent_public_string_set -#define nx_snmp_agent_private_string_test _nxe_snmp_agent_private_string_test -#define nx_snmp_agent_public_string_test _nxe_snmp_agent_public_string_test -#define nx_snmp_agent_start _nxe_snmp_agent_start -#define nx_snmp_agent_stop _nxe_snmp_agent_stop -#define nx_snmp_agent_trap_send _nxe_snmp_agent_trap_send -#define nx_snmp_agent_trapv2_send _nxe_snmp_agent_trapv2_send -#define nx_snmp_agent_trapv3_send _nxe_snmp_agent_trapv3_send -#define nxd_snmp_agent_trap_send _nxde_snmp_agent_trap_send -#define nxd_snmp_agent_trapv2_send _nxde_snmp_agent_trapv2_send -#define nxd_snmp_agent_trapv3_send _nxde_snmp_agent_trapv3_send -#define nx_snmp_object_compare _nxe_snmp_object_compare -#define nx_snmp_object_compare_extended _nxe_snmp_object_compare_extended -#define nx_snmp_object_copy _nxe_snmp_object_copy -#define nx_snmp_object_copy_extended _nxe_snmp_object_copy_extended -#define nx_snmp_object_counter_get _nxe_snmp_object_counter_get -#define nx_snmp_object_counter_set _nxe_snmp_object_counter_set -#define nx_snmp_object_counter64_get _nxe_snmp_object_counter64_get -#define nx_snmp_object_counter64_set _nxe_snmp_object_counter64_set -#define nx_snmp_object_end_of_mib _nxe_snmp_object_end_of_mib -#define nx_snmp_object_gauge_get _nxe_snmp_object_gauge_get -#define nx_snmp_object_gauge_set _nxe_snmp_object_gauge_set -#define nx_snmp_object_id_get _nxe_snmp_object_id_get -#define nx_snmp_object_id_set _nxe_snmp_object_id_set -#define nx_snmp_object_integer_get _nxe_snmp_object_integer_get -#define nx_snmp_object_integer_set _nxe_snmp_object_integer_set -#define nx_snmp_object_ip_address_get _nxe_snmp_object_ip_address_get -#define nx_snmp_object_ip_address_set _nxe_snmp_object_ip_address_set -#ifdef FEATURE_NX_IPV6 -#define nx_snmp_object_ipv6_address_get _nxe_snmp_object_ipv6_address_get -#define nx_snmp_object_ipv6_address_set _nxe_snmp_object_ipv6_address_set -#endif -#define nx_snmp_object_no_instance _nxe_snmp_object_no_instance -#define nx_snmp_object_not_found _nxe_snmp_object_not_found -#define nx_snmp_object_octet_string_get _nxe_snmp_object_octet_string_get -#define nx_snmp_object_octet_string_set _nxe_snmp_object_octet_string_set -#define nx_snmp_object_string_get _nxe_snmp_object_string_get -#define nx_snmp_object_string_set _nxe_snmp_object_string_set -#define nx_snmp_object_timetics_get _nxe_snmp_object_timetics_get -#define nx_snmp_object_timetics_set _nxe_snmp_object_timetics_set -#define nx_snmp_agent_trapv2_oid_send _nxe_snmp_agent_trapv2_oid_send -#define nx_snmp_agent_trapv3_oid_send _nxe_snmp_agent_trapv3_oid_send - - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -UINT nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -UINT nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); -UINT nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); -UINT nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); -UINT nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); -UINT nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), - UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); -UINT nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); -UINT nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); -UINT nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); -UINT nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); -UINT nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); -UINT nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); -UINT nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); -UINT nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); -UINT nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); -UINT nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); -UINT nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); -UINT nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT nx_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); -UINT nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); -UINT nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); -UINT nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); -UINT nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -#ifdef FEATURE_NX_IPV6 -UINT nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -#endif -UINT nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); -UINT nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); - - - -#else - -/* SNMP source code is being compiled, do not perform any API mapping. */ - -UINT _nx_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nxe_snmp_agent_authenticate_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nx_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nxe_snmp_agent_auth_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -#ifndef NX_SNMP_DISABLE_V3 -UINT _nx_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nxe_snmp_agent_md5_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nx_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nxe_snmp_agent_md5_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nx_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nxe_snmp_agent_privacy_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nx_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nxe_snmp_agent_priv_trap_key_use(NX_SNMP_AGENT *agent_ptr, NX_SNMP_SECURITY_KEY *key); -UINT _nx_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nxe_snmp_agent_sha_key_create(NX_SNMP_AGENT *agent_ptr, UCHAR *password, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nx_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -UINT _nxe_snmp_agent_sha_key_create_extended(NX_SNMP_AGENT *agent_ptr, UCHAR *password, UINT password_length, NX_SNMP_SECURITY_KEY *destination_key); -#endif -UINT _nx_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); -UINT _nxe_snmp_agent_community_get(NX_SNMP_AGENT *agent_ptr, UCHAR **community_string_ptr); -UINT _nx_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); -UINT _nxe_snmp_agent_context_engine_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_engine, UINT context_engine_size); -UINT _nx_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); -UINT _nxe_snmp_agent_context_name_set(NX_SNMP_AGENT *agent_ptr, UCHAR *context_name, UINT context_name_size); -UINT _nx_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); -UINT _nxe_snmp_agent_v3_context_boots_set(NX_SNMP_AGENT *agent_ptr, UINT boots); -UINT _nx_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), - UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); -UINT _nxe_snmp_agent_create(NX_SNMP_AGENT *agent_ptr, CHAR *snmp_agent_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*snmp_agent_username_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *username), - UINT (*snmp_agent_get_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_getnext_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data), - UINT (*snmp_agent_set_process)(struct NX_SNMP_AGENT_STRUCT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)); -UINT _nx_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); -UINT _nxe_snmp_agent_delete(NX_SNMP_AGENT *agent_ptr); -UINT _nx_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); -UINT _nxe_snmp_agent_request_get_type_test(NX_SNMP_AGENT *agent_ptr, UINT *is_get_type); -UINT _nx_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); -UINT _nxe_snmp_agent_current_version_get(NX_SNMP_AGENT *agent_ptr, UINT *version); -UINT _nxe_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); -UINT _nx_snmp_agent_version_set(NX_SNMP_AGENT *agent_ptr, UINT enabled_v1, UINT enable_v2, UINT enable_v3); -UINT _nx_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); -UINT _nxe_snmp_agent_private_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_private); -UINT _nx_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); -UINT _nxe_snmp_agent_public_string_test(NX_SNMP_AGENT *agent_ptr, UCHAR *community_string, UINT *is_public); -UINT _nxe_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); -UINT _nx_snmp_agent_set_interface(NX_SNMP_AGENT *agent_ptr, UINT if_index); -UINT _nx_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); -UINT _nxe_snmp_agent_private_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *private_string); -UINT _nx_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); -UINT _nxe_snmp_agent_public_string_set(NX_SNMP_AGENT *agent_ptr, UCHAR *public_string); -UINT _nx_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); -UINT _nxe_snmp_agent_start(NX_SNMP_AGENT *agent_ptr); -UINT _nx_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); -UINT _nxe_snmp_agent_stop(NX_SNMP_AGENT *agent_ptr); -UINT _nxe_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxe_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxe_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxe_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxe_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, ULONG ip_address, UCHAR *username, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxd_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxde_snmp_agent_trap_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UCHAR *enterprise, UINT trap_type, UINT trap_code, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxd_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxde_snmp_agent_trapv2_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *community, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxd_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxde_snmp_agent_trapv3_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ip_address, UCHAR *username, UINT trap_type, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxd_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxde_snmp_agent_trapv2_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxd_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nxde_snmp_agent_trapv3_oid_send(NX_SNMP_AGENT *agent_ptr, NXD_ADDRESS *ipduo_address, UCHAR *community, UCHAR *oid, ULONG elapsed_time, NX_SNMP_TRAP_OBJECT *object_list_ptr); -UINT _nx_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); -UINT _nxe_snmp_object_compare(UCHAR *requested_object, UCHAR *reference_object); -UINT _nx_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); -UINT _nxe_snmp_object_compare_extended(UCHAR *requested_object, UINT requested_object_length, UCHAR *actual_object, UINT actual_object_length); -UINT _nx_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); -UINT _nxe_snmp_object_copy(UCHAR *source_object_name, UCHAR *destination_object_name); -UINT _nx_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); -UINT _nxe_snmp_object_copy_extended(UCHAR *source_object_name, UINT source_object_name_length, UCHAR *destination_object_name_buffer, UINT destination_object_name_buffer_size); -UINT _nx_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_counter_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_counter_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_counter64_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_counter64_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_end_of_mib(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_gauge_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_gauge_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_id_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_id_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_integer_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_integer_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_ip_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_ip_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -#ifdef FEATURE_NX_IPV6 -UINT _nx_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_ipv6_address_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_ipv6_address_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -#endif -UINT _nx_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_no_instance(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_not_found(VOID *not_used_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); -UINT _nxe_snmp_object_octet_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); -UINT _nx_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_octet_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_string_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_string_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_timetics_get(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nx_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); -UINT _nxe_snmp_object_timetics_set(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); - - -/* Define internal SNMP routines. */ - -VOID _nx_snmp_agent_thread_entry(ULONG snmp_agent_address); -UINT _nx_snmp_utility_community_get(UCHAR *buffer_ptr, UCHAR *community_string, INT buffer_length); -UINT _nx_snmp_utility_community_set(UCHAR *buffer_ptr, UCHAR *community_string, UCHAR *buffer_end); -UINT _nx_snmp_utility_error_info_get(UCHAR *buffer_ptr, UINT *error_code, UINT *error_index, INT buffer_length); -UINT _nx_snmp_utility_error_info_set(UCHAR *buffer_ptr, UINT error_code, UINT error_index, UCHAR *buffer_end); -UINT _nx_snmp_utility_object_id_get(UCHAR *buffer_ptr, UCHAR *object_string, INT buffer_length); -UINT _nx_snmp_utility_object_id_set(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end); -UINT _nx_snmp_utility_object_id_set_1byte(UCHAR *buffer_ptr, UCHAR *object_string, UCHAR *buffer_end); -UINT _nx_snmp_utility_object_data_get(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, INT buffer_length); -UINT _nx_snmp_utility_object_data_set(UCHAR *buffer_ptr, NX_SNMP_OBJECT_DATA *object_data, UCHAR *buffer_end); -UINT _nx_snmp_utility_octet_get(UCHAR *buffer_ptr, UCHAR *octet_string, UINT max_octet_length, UINT *octet_length, INT buffer_length); -UINT _nx_snmp_utility_octet_set(UCHAR *buffer_ptr, UCHAR *octet_string, UINT octet_length, UCHAR *buffer_end); -UINT _nx_snmp_utility_sequence_get(UCHAR *buffer_ptr, UINT *sequence_value, INT buffer_length); -UINT _nx_snmp_utility_sequence_set(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end); -UINT _nx_snmp_utility_sequence_set_1byte(UCHAR *buffer_ptr, UINT sequence_value, UCHAR *buffer_end); -UINT _nx_snmp_utility_request_id_get(UCHAR *buffer_ptr, ULONG *request_id, INT buffer_length); -UINT _nx_snmp_utility_request_id_set(UCHAR *buffer_ptr, ULONG request_id, UCHAR *buffer_end); -UINT _nx_snmp_utility_request_type_get(UCHAR *buffer_ptr, UINT *request_type, UINT *request_length, INT buffer_length); -UINT _nx_snmp_utility_request_type_set_1byte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end); -UINT _nx_snmp_utility_request_type_set_multibyte(UCHAR *buffer_ptr, UINT request_type, UINT request_length, UCHAR *buffer_end); -UINT _nx_snmp_utility_version_get(UCHAR *buffer_ptr, UINT *snmp_version, INT buffer_length); -UINT _nx_snmp_utility_version_set(UCHAR *buffer_ptr, UINT snmp_version, UCHAR *buffer_end); -UINT _nx_snmp_utility_tlv_block_parse(UCHAR *buffer, INT buffer_length, USHORT *tlv_type, USHORT *tlv_tag_class, ULONG *tlv_length, UCHAR **tlv_data, ULONG *header_length); -VOID _nx_snmp_version_error_response(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr, UCHAR *request_type_ptr, UCHAR *error_string_ptr, UINT status, UINT objects); -VOID _nx_snmp_version_1_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); -VOID _nx_snmp_version_2_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); -VOID _nx_snmp_version_3_report_send(NX_SNMP_AGENT *agent_ptr, UCHAR *buffer_ptr, UINT discovery_response, INT buffer_length); -VOID _nx_snmp_version_3_process(NX_SNMP_AGENT *agent_ptr, NX_PACKET *packet_ptr); -UINT _nx_snmp_agent_encrypt_pdu(NX_SNMP_AGENT *agent_ptr, UINT *response_pdu_length, UINT *response_sequence_length, UCHAR *response_encryption_size_ptr, - UCHAR **response_sequence_ptr, UCHAR *response_sequence_buffer_end, UCHAR **response_buffer_ptr,UCHAR *response_privacy_ptr); -UINT _nx_snmp_agent_add_auth_parameter(NX_SNMP_AGENT *agent_ptr, NX_PACKET *response_packet_ptr, UCHAR *response_authentication_ptr); -UINT _nx_snmp_agent_decrypt_pdu(NX_SNMP_AGENT *agent_ptr, UCHAR **buffer_ptr, UCHAR *response_buffer_ptr, UCHAR **response_encryption_size_ptr, UINT *response_length, INT buffer_length); -VOID _nx_snmp_agent_security_response_status(NX_SNMP_AGENT *agent_ptr, UINT *authenticate, UINT *encryption, UINT *send_reply); - - -#endif /* NX_SNMP_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_SNMP_H */ - diff --git a/protocol_handlers/sntp/nxd_sntp_client.c b/protocol_handlers/sntp/nxd_sntp_client.c deleted file mode 100644 index ccaf4967..00000000 --- a/protocol_handlers/sntp/nxd_sntp_client.c +++ /dev/null @@ -1,6362 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX SNTP Client Component */ -/** */ -/** Simple Network Time Protocol (SNTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_sntp_client.c PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Simple Network Time Protocol (SNTP) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#define NX_SNTP_SOURCE_CODE - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -#include "nx_api.h" -#include "nx_udp.h" - -#include "nx_ipv4.h" -#include "nxd_sntp_client.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_ipv6.h" -#endif - - -#include - -extern TX_THREAD *_tx_thread_current_ptr; -extern TX_THREAD _tx_timer_thread; -extern volatile ULONG _tx_thread_system_state; - -TX_EVENT_FLAGS_GROUP nx_sntp_client_events; - -static UINT _nx_sntp_client_number_to_ascii(CHAR *buffer_ptr, UINT buffer_size, UINT number); - -/* Define internal time variables for offsets between - receipt of SNTP packet and application to - SNTP Client local time. */ -static ULONG send_timerticks = 0; -static ULONG receive_timerticks = 0; -static ULONG process_timerticks = 0; - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the SNTP client create */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* ip_ptr Pointer to client IP instance */ -/* iface_index Index of SNTP network interface */ -/* packet_pool_ptr Pointer to client packet pool */ -/* socket_ptr Pointer to client UDP socket */ -/* leap_second_handler Pointer to leap second handler */ -/* random_number_generator Random number generator callback */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* NX_INVALID_INTERFACE Invalid network interface */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_create Actual SNTP client create service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, - UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), - UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), - VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (client_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL)) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - /* Check for invalid network interface input. */ - if (iface_index >= NX_MAX_PHYSICAL_INTERFACES) - { - - return NX_INVALID_INTERFACE; - } - - /* Call the actual client create service. */ - status = _nx_sntp_client_create(client_ptr, ip_ptr, iface_index, packet_pool_ptr, - leap_second_handler, kiss_of_death_handler, random_number_generator); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a SNTP client with the input NetX and SNTP */ -/* parameters. Note the host application must initialize and start the */ -/* SNTP client using the nx_sntp_broadcast/unicast_initialize and */ -/* nx_sntp_run_broadcast/unicast services to receive SNTP time updates.*/ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to client struct */ -/* ip_ptr Pointer to client IP instance */ -/* iface_index Index of SNTP network interface */ -/* packet_pool_ptr Pointer to client packet pool */ -/* socket_ptr Pointer to client UDP socket */ -/* leap_second_handler Pointer to leap second handler */ -/* random_number_generator Random number generator callback */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD */ -/* Invalid packet pool payload */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* CALLS */ -/* */ -/* tx_timer_create Create ThreadX timer service */ -/* tx_timer_delete Delete ThreadX timer service */ -/* tx_mutex_create Create ThreadX mutex service */ -/* tx_mutex_delete Delete ThreadX mutex service */ -/* nx_udp_socket_create Create the SNTP Client socket */ -/* nx_udp_socket_delete Delete the SNTP Client socket */ -/* nx_udp_socket_bind Bind the SNTP Client to SNTP port */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, - UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), - UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), - VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)) -{ - -UINT status; - - - /* Null the members of NX_SNTP_CLIENT. */ - memset(client_ptr, 0, sizeof(NX_SNTP_CLIENT)); - - /* Set the Client ID to indicate the SNTP client thread is ready. */ - client_ptr -> nx_sntp_client_id = NXD_SNTP_ID; - - /* Set the IP instance. */ - client_ptr -> nx_sntp_client_ip_ptr = ip_ptr; - - /* Set the SNTP network interface. */ - client_ptr -> nx_sntp_client_interface_index = iface_index; - - /* Check for minimal packet size requirement. */ -#ifndef NX_DISABLE_IPV4 - if (packet_pool_ptr -> nx_packet_pool_payload_size < - (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) - { - - return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; - } -#endif /* NX_DISABLE_IPV4 */ - - - /* This only assures IPv4 packets will work. We do not know yet if the Client expects to receive - SNTP packets over ipv6 networks. When sending packets, the SNTP Client will have set its - SNTP server from which the IP type will be determined. However, for receiving packets, - it is up to the host to ensure its packet payload will be large enough for IPv6 packets: - - sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE) - 40 bytes 8 bytes 48 bytes - */ - - client_ptr -> nx_sntp_client_packet_pool_ptr = packet_pool_ptr; - - /* Create a udp socket to receive SNTP time data. */ - status = nx_udp_socket_create(client_ptr -> nx_sntp_client_ip_ptr, &(client_ptr -> nx_sntp_client_udp_socket), - NX_SNTP_CLIENT_UDP_SOCKET_NAME, NX_IP_NORMAL, - NX_FRAGMENT_OKAY, NX_SNTP_CLIENT_TIME_TO_LIVE, - NX_SNTP_CLIENT_MAX_QUEUE_DEPTH); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Register a receive notify callback. */ - status = nx_udp_socket_receive_notify(&(client_ptr -> nx_sntp_client_udp_socket), _nx_sntp_client_receive_notify); - - /* Check for errors. */ - if (status != NX_SUCCESS) - { - - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - return status; - } - - /* Set callback for leap second handler (optional). */ - client_ptr -> leap_second_handler = leap_second_handler; - - /* Set callback for kiss of death server packet handler (optional). */ - client_ptr -> kiss_of_death_handler = kiss_of_death_handler; - - /* Set callback for random number generator (Only applicable for unicast clients - configured for random wait on startup). */ - client_ptr -> random_number_generator = random_number_generator; - - /* Create the SNTP update timeout timer. */ - status = tx_timer_create(&client_ptr -> nx_sntp_update_timer, "SNTP Client Update Timer", - _nx_sntp_client_update_timeout_entry, (ULONG)client_ptr, - (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL), - (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL), TX_NO_ACTIVATE); - - /* Check for error. */ - if (status != TX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Return error status. */ - return(status); - } - - /* Create the SNTP mutex. */ - status = tx_mutex_create(&(client_ptr -> nx_sntp_client_mutex), "NetX SNTP Client Mutex", TX_NO_INHERIT); - - /* Determine if the semaphore creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Delete the timer. */ - tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); - - /* No, return error status. */ - return(status); - } - - /* Create the SNTP event flag group. */ - status = tx_event_flags_create(&nx_sntp_client_events, "NetX SNTP Client Events"); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Delete the timer. */ - tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); - - /* Delete the Client mutex. */ - tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex); - - /* Error present, return error code. */ - return(status); - } - - /* Create the SNTP Client processing thread. */ - status = tx_thread_create(&(client_ptr -> nx_sntp_client_thread), "NetX SNTP Client", _nx_sntp_client_thread_entry, (ULONG)client_ptr, - client_ptr -> nx_sntp_client_thread_stack, NX_SNTP_CLIENT_THREAD_STACK_SIZE, - NX_SNTP_CLIENT_THREAD_PRIORITY, NX_SNTP_CLIENT_PREEMPTION_THRESHOLD, 1, TX_DONT_START); - - /* Determine if the thread creation was successful. */ - if (status != NX_SUCCESS) - { - - /* Delete the mutex. */ - tx_mutex_delete(&(client_ptr -> nx_sntp_client_mutex)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Delete the timer. */ - tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&nx_sntp_client_events); - - /* No, return error status. */ - return(status); - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors on the client delete service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer parameter */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_delete Actual SNTP client delete service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_delete(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for the validity of input parameter. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_sntp_client_id != NXD_SNTP_ID)) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual client create service. */ - status = _nx_sntp_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created SNTP Client and releases */ -/* ThreadX and NetX resources held by the Client. */ -/* */ -/* Note that it is the application's responsibility to delete/release */ -/* the Client packet pool. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_timer_delete Delete ThreadX timer service */ -/* tx_mutex_delete Delete ThreadX mutex service */ -/* tx_timer_deactivate Deschedule ThreadX timer */ -/* nx_udp_socket_unbind Release NetX UDP socket port */ -/* nx_udp_socket_delete Delete NetX UDP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_delete(NX_SNTP_CLIENT *client_ptr) -{ - - /* Suspend the SNTP Client thread. */ - tx_thread_suspend(&client_ptr -> nx_sntp_client_thread); - - /* Terminate SNTP Client thread. */ - tx_thread_terminate(&client_ptr -> nx_sntp_client_thread); - - /* Delete SNTP Client thread. */ - tx_thread_delete(&client_ptr -> nx_sntp_client_thread); - - /* Delete the Client mutex. */ - tx_mutex_delete(&client_ptr -> nx_sntp_client_mutex); - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - /* Delete the update timer. */ - tx_timer_delete(&(client_ptr -> nx_sntp_update_timer)); - - /* Make sure the socket is in an unbound state. */ - nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Ok to delete the UDP socket. */ - nx_udp_socket_delete(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Delete the Client event flags group. */ - tx_event_flags_delete(&nx_sntp_client_events); - - /* Return success status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_update_timeout_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decrements the Client's time remaining since it last */ -/* received a time update. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX ThreadX timer callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_update_timeout_entry(ULONG info) -{ - -NX_SNTP_CLIENT *client_ptr; - - - client_ptr = (NX_SNTP_CLIENT *)info; - - /* Is the Client's time remaining large enough to decrement by the timeout interval? */ - if (client_ptr -> nx_sntp_update_time_remaining >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL)) - { - - /* Yes; ok to decrement time remaining. */ - client_ptr -> nx_sntp_update_time_remaining -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL); - } - else - { - /* No, set the time remaining to NULL. */ - client_ptr -> nx_sntp_update_time_remaining = 0; - } - - /* Update time elapsed. */ - client_ptr -> nx_sntp_client_local_ntp_time_elapsed += NX_SNTP_UPDATE_TIMEOUT_INTERVAL; - - /* Is the client operating in unicast? */ - if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) - { - - /* Yes; Update the time remaining till it is time to poll the SNTP server. */ - if (client_ptr -> nx_sntp_client_unicast_poll_interval >= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL)) - { - client_ptr -> nx_sntp_client_unicast_poll_interval -= (NX_IP_PERIODIC_RATE * NX_SNTP_UPDATE_TIMEOUT_INTERVAL); - } - else - { - - /* Time is up. Client should send out another update request. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = 0; - } - } - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_create_time_request_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts NTP time data from the input buffer into a */ -/* unicast time data and copies into the supplied packet buffer. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* packet_ptr Pointer to time update packet */ -/* time_message_ptr Pointer to time request */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_send_unicast_request Send unicast request to server */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, - NX_SNTP_TIME_MESSAGE *time_message_ptr) -{ - NX_PARAMETER_NOT_USED(client_ptr); - - if (40u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) - { - return(NX_SIZE_ERROR); - } - - /* Clear packet data. */ - memset(packet_ptr -> nx_packet_append_ptr, 0, 40); - - *(packet_ptr -> nx_packet_append_ptr) = (UCHAR)(time_message_ptr -> flags); - - /* Skip to transmit time; all other fields are not used for a client unicast request. */ - packet_ptr -> nx_packet_append_ptr += 40; - packet_ptr -> nx_packet_length += 40; - - /* Copy the transmit time stamp from time request into the packet buffer. */ - time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0]; - time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1]; - - /* Now copy the data to the buffer. */ - *((ULONG*)(packet_ptr -> nx_packet_append_ptr)) = (ULONG)(time_message_ptr -> transmit_time.seconds); - *((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4)) = (ULONG)(time_message_ptr -> transmit_time.fraction); - - /* Change endian to network order. */ - NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr))); - NX_CHANGE_ULONG_ENDIAN(*((ULONG*)(packet_ptr -> nx_packet_append_ptr + 4))); - - packet_ptr -> nx_packet_append_ptr += 8; - packet_ptr -> nx_packet_length += 8; - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_sntp_client_initialize_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the service that */ -/* initializes the Client for unicast service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* unicast_time_server Pointer to unicast server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server) -{ - -UINT status; - - - /* Check pointer input. */ - if ((client_ptr == NX_NULL) || (unicast_time_server == NX_NULL)) - { - - /* Return error status. */ - return NX_PTR_ERROR; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual Client for initialize unicast service. */ - status = _nxd_sntp_client_initialize_unicast(client_ptr, unicast_time_server); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_sntp_client_initialize_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the Client to operate in unicast mode with the*/ -/* supplied IPv4 or IPv6 SNTP server as the primary (current) server. */ -/* */ -/* For adding IPv4 and IPv6 SNTP servers to the unicast server list, */ -/* use the nxd_sntp_client_duo_add_unicast_server_to_list service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* unicast_poll_interval Interval between update requests */ -/* unicast_time_server Pointer to unicast server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_PARAM_ERROR Invalid server list input */ -/* */ -/* CALLS */ -/* */ -/* memset Copy data to area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server) -{ - - - /* Set the Client polling interval. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE); - - /* Initialize the number of times we've increased the backoff rate to zero. */ - client_ptr -> nx_sntp_client_backoff_count = 0; - - /* Clear the Client's current server IP. */ - memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS)); - -#ifdef FEATURE_NX_IPV6 - /* Set as the Client's unicast server. */ - COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_unicast_time_server); - - /* Set as the Client's current SNTP server. */ - COPY_NXD_ADDRESS(unicast_time_server, &client_ptr -> nx_sntp_server_ip_address); -#else - /* Set as the Client's unicast server. */ - client_ptr -> nx_sntp_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_unicast_time_server.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4; - - /* Set as the Client's current SNTP server. */ - client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = unicast_time_server -> nxd_ip_address.v4; - -#endif /* FEATURE_NX_IPV6 */ - - - /* Set the Client operational mode to unicast mode. */ - client_ptr -> nx_sntp_client_protocol_mode = UNICAST_MODE; - - /* Indicate the Client task is ready to run! */ - client_ptr -> nx_sntp_client_unicast_initialized = NX_TRUE; - - /* Initialize the server status as good (receiving updates). */ - client_ptr -> nx_sntp_valid_server_status = NX_TRUE; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_initialize_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors on the initialize Client for unicast*/ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* unicast_time_server SNTP unicast server to use */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - /* Check input parameters. */ - if (client_ptr == NX_NULL) - { - - /* Return error status. */ - return NX_PTR_ERROR; - } - - if (unicast_time_server == 0x0) - { - return NX_INVALID_PARAMETERS; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - - /* Call the actual Client for initialize unicast service. */ - status = _nx_sntp_client_initialize_unicast(client_ptr, unicast_time_server); - - /* Return completion status. */ - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(unicast_time_server); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_initialize_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the input address to the NetX Duo address */ -/* format and calls the 'duo' equivalent service, nxd_sntp_client_ */ -/* _initialize_unicast. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* unicast_time_server SNTP unicast server to use */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* _nxd_sntp_client_initialize_unicast */ -/* Duo initialize unicast service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS duo_unicast_time_server; - - - - duo_unicast_time_server.nxd_ip_address.v4 = unicast_time_server; - duo_unicast_time_server.nxd_ip_version = NX_IP_VERSION_V4; - - status = _nxd_sntp_client_initialize_unicast(client_ptr, &duo_unicast_time_server); - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(unicast_time_server); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_run_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the run unicast service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* _nx_sntp_client_run_unicast Actual run unicast service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual run unicast service. */ - status = _nx_sntp_client_run_unicast(client_ptr); - - /* Return actual completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_run_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the SNTP Client for unicast SNTP processing */ -/* by activating the SNTP timer and main processing thread. The Client */ -/* is checked for being initialized for unicast SNTP and if it is */ -/* not, the function returns an error status. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */ -/* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_timer_activate Start the ThreadX timer */ -/* tx_thread_resume Resume the specified thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; -ULONG startup_ticks; - - - status = tx_mutex_get(&client_ptr -> nx_sntp_client_mutex, TX_WAIT_FOREVER); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - return status; - } - - /* Determine if SNTP has already been started. */ - if (client_ptr -> nx_sntp_client_started) - { - - /* Error SNTP has already been started. */ - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return completion status. */ - return(NX_SNTP_CLIENT_ALREADY_STARTED); - } - - /* Verify the client is ready to start receiving time data. */ - if (client_ptr -> nx_sntp_client_unicast_initialized == NX_FALSE) - { - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return the error condition. */ - return NX_SNTP_CLIENT_NOT_INITIALIZED; - } - - /* Should the first time request sleep for a random timeout? */ - if ((NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP == NX_TRUE) && (client_ptr -> random_number_generator)) - { - - /* Yes, generate a random number of ticks to sleep.*/ - (client_ptr -> random_number_generator)(client_ptr, &startup_ticks); - - /* Sleep for the random length. */ - tx_thread_sleep(startup_ticks); - } - - /* Set status that the first update is expected. */ - client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE; - - /* Initialize missed broadcasts and bad time updates from server. */ - client_ptr -> nx_sntp_client_invalid_time_updates = 0; - - - /* Set the maximum timeout to the full count. */ - client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); - - /* Activate SNTP update timer. */ - status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer)); - - /* Check for error. Ignore timer is already active error. */ - if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR) - { - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return the error condition. */ - return status; - } - - /* Bind the UDP socket to the IP port. */ - status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - return status; - } - - status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread)); - - /* Start the SNTP Client thread. */ - if (status != NX_SUCCESS) - { - - /* Release the socket port. */ - nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - return status; - } - - /* The client thread is successfully started, so set the started flag to true. */ - client_ptr -> nx_sntp_client_started = NX_TRUE; - - /* Clear the sleep flag. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; - - /* Set poll interval to 0 to send request immediately. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = 0; - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_run_unicast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if the SNTP client has received a packet, and if*/ -/* so processes it for valid SNTP data and resets the timeouts */ -/* for sending (polling) and receiving updates. If no packet received it*/ -/* checks if the timeout to receive an update has expired. If so, it */ -/* sends out another SNTP request. */ -/* */ -/* When a timeout expires, the poll interval is increased as per */ -/* RFC guidelines until it exceeds the maximum time without an update. */ -/* An error flag is set, and it is up to the host application to */ -/* change its unicast SNTP server. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_reset_current_time_message */ -/* Save time update before next update */ -/* _nx_sntp_client_receive_time_update */ -/* Receive server update packets */ -/* _nx_sntp_client_process_time_data */ -/* Process time data in server update */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_process_unicast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; -ULONG sntp_events; - - - /* Check for a receive event. */ - status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT); - - if (status == NX_SUCCESS) - { - - /* Listen for a server update packet. */ - status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT); - - if (status == NX_SUCCESS) - { - - /* Process the server update packet and apply to local time if valid. */ - status = _nx_sntp_client_process_update_packet(client_ptr); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - return; - } - - /* Reset the Client poll timeout to the original poll interval. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE); - - /* Reset the Client timeout for maximum time lapse without a valid update. */ - client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); - - /* Indicate the client has received at least one valid time update with the current server. */ - client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE; - - client_ptr -> nx_sntp_client_backoff_count = 0; - /* Set the server status as good (receiving updates). */ - client_ptr -> nx_sntp_valid_server_status = NX_TRUE; - - return; - } - } - - /* Has the timeout expired on the maximum lapse without a valid update? */ - if (client_ptr -> nx_sntp_update_time_remaining == 0) - { - - /* Yes, it has. Set the server status as no longer valid. */ - client_ptr -> nx_sntp_valid_server_status = NX_FALSE; - } - - /* Is it time to send another SNTP request? */ - if (client_ptr -> nx_sntp_client_unicast_poll_interval == 0) - { - - - /* Save the last server message before the next update. We need this for comparing time data. */ - _nx_sntp_client_reset_current_time_message(client_ptr); - - /* Create and send a unicast request . */ - _nx_sntp_client_send_unicast_request(client_ptr); - - - /* Check if we have received an update since the previous unicast poll. */ - if ((NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE - client_ptr -> nx_sntp_update_time_remaining) > - (NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE)) - { - - /* No we have not. Increase the count of times we've increased the back off rate. */ - client_ptr -> nx_sntp_client_backoff_count++; - - client_ptr -> nx_sntp_client_unicast_poll_interval = - NX_IP_PERIODIC_RATE * NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_SNTP_CLIENT_EXP_BACKOFF_RATE * client_ptr -> nx_sntp_client_backoff_count; - } - else - { - - /* Reset the polling interval to it's normal value. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL * NX_IP_PERIODIC_RATE; - } - - /* Check that the poll interval does not exceed the maximum lapse without a valid update. */ - if (client_ptr -> nx_sntp_client_unicast_poll_interval > (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE)) - { - - /* Set the poll interval equal to that lapse. */ - client_ptr -> nx_sntp_client_unicast_poll_interval = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); - } - } - - /* Nothing to do but wait...*/ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_sntp_client_initialize_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the initialize Client for */ -/* IPv4 broadcast time updates service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* multicast_server_address Multicast server address */ -/* broadcast_time_server Broadcast server address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_SNTP_PARAM_ERROR Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* _nxd_sntp_client_initialize_duo_broadcast */ -/* Initialize broadcast Client service*/ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check for missing broadcast server input. */ - if ((multicast_server_address == NX_NULL) && (broadcast_server_address == NX_NULL)) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check for illegal broadcast address in IPv6. */ - if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V6)) - { - - return NX_SNTP_PARAM_ERROR; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual initialize client for broadcast time update service. */ - status = _nxd_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address); - - /* Return completion status. */ - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_sntp_client_initialize_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets up the Client to operate in broadcast mode with */ -/* either an IPv6 or an IPv4 broadcast server. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* multicast_server_address Multicast server address */ -/* broadcast_time_server Broadcast server address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_server_address) -{ - - - /* Clear Client's current server IP. */ - memset(&client_ptr -> nx_sntp_server_ip_address, 0, sizeof(NXD_ADDRESS)); - - /* Was a multicast IP was supplied? */ - if (multicast_server_address != NX_NULL) - { - -#ifdef FEATURE_NX_IPV6 - /* Set the Client multicast server. */ - COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_multicast_server_address); - - /* Set this as the Client's current SNTP server. */ - COPY_NXD_ADDRESS(multicast_server_address, &client_ptr -> nx_sntp_server_ip_address); -#else - /* Set the Client multicast server. */ - client_ptr -> nx_sntp_multicast_server_address.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_multicast_server_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4; - - /* Set this as the Client's current SNTP server. */ - client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = multicast_server_address -> nxd_ip_address.v4; - -#endif /* FEATURE_NX_IPV6 */ - } - - /* No multicast address supplied, so was a broadcast address specified? This must be an IPv4 address - since IPv6 does not support broadcast. */ - else if ((broadcast_server_address != NX_NULL) && (broadcast_server_address -> nxd_ip_version == NX_IP_VERSION_V4)) - { - - -#ifdef FEATURE_NX_IPV6 - /* Set the Client broadcast server. */ - COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_broadcast_time_server); - - /* Set this as the Client's current SNTP server. */ - COPY_NXD_ADDRESS(broadcast_server_address, &client_ptr -> nx_sntp_server_ip_address); -#else - /* Set the Client broadcast server. */ - client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_broadcast_time_server.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4; - - /* Set this as the Client's current SNTP server. */ - client_ptr -> nx_sntp_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4 = broadcast_server_address -> nxd_ip_address.v4; - -#endif /* FEATURE_NX_IPV6 */ - } - - /* Set client to work in broadcast (non unicast) mode. */ - client_ptr -> nx_sntp_client_protocol_mode = BROADCAST_MODE; - - /* Indicate the client task is ready to run! */ - client_ptr -> nx_sntp_client_broadcast_initialized = NX_TRUE; - - /* Initialize the server status as good (receiving updates) even though it has - not received one with the current server. */ - client_ptr -> nx_sntp_valid_server_status = NX_TRUE; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_initialize_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the initialize Client for */ -/* broadcast time updates service. Note that broadcast and multicast */ -/* services are only available for IPv4 SNTP communcations. For */ -/* multicast service, the host IP instance must be enabled for IGMP. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* multicast_server_address Server multicast address */ -/* broadcast_server_aaddres Broadcast server address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* _nx_sntp_client_initialize_broadcast */ -/* Actual initialize broadcast service*/ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - if ((multicast_server_address == 0x0) && (broadcast_server_address == 0x0)) - { - - return NX_INVALID_PARAMETERS; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual initialize client for broadcast time update service. */ - status = _nx_sntp_client_initialize_broadcast(client_ptr, multicast_server_address, broadcast_server_address); - - /* Return completion status. */ - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(multicast_server_address); - NX_PARAMETER_NOT_USED(broadcast_server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_initialize_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the IPv4 addresses to the NetX Duo address */ -/* format and calls the 'duo' equivalent service, nxd_sntp_client_ */ -/* _initialize_broadcast. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* multicast_server_address Server multicast address */ -/* broadcast_server_address Broadcast server address */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxd_sntp_client_initialize_broadcast */ -/* Duo initialize broadcast service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; -NXD_ADDRESS server_address; - - - /* Was a multicast IP was supplied? */ - if (multicast_server_address != 0x0) - { - - server_address.nxd_ip_address.v4 = multicast_server_address; - server_address.nxd_ip_version = NX_IP_VERSION_V4; - status = _nxd_sntp_client_initialize_broadcast(client_ptr, &server_address, NX_NULL); - } - - /* Was a broadcast SNTP server specified? */ - else if (broadcast_server_address != 0x0) - { - - server_address.nxd_ip_address.v4 = broadcast_server_address; - server_address.nxd_ip_version = NX_IP_VERSION_V4; - status = _nxd_sntp_client_initialize_broadcast(client_ptr, NX_NULL, &server_address); - } - else - return NX_INVALID_PARAMETERS; - - return status; -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(multicast_server_address); - NX_PARAMETER_NOT_USED(broadcast_server_address); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the SNTP client thread stop*/ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_sntp_client_sto Actual stop SNTP service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_stop(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - status = _nx_sntp_client_stop(client_ptr); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function halts the SNTP Client thread and returns the SNTP */ -/* Client to an initial state. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client instance*/ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind the SNTP UDP socket */ -/* tx_thread_preemption_change Change the thread preemption */ -/* tx_thread_suspend Suspend SNTP processing */ -/* tx_thread_wait_abort Remove any thread suspension */ -/* tx_mutex_get Get the SNTP mutex */ -/* tx_mutex_put Release the SNTP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr) -{ - -UINT current_preemption; - - - /* Get the SNTP mutex. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - /* Determine if the SNTP client is started. */ - if (client_ptr -> nx_sntp_client_started == NX_FALSE) - { - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* SNTP client is not started so it can't be stopped. */ - return(NX_SNTP_CLIENT_NOT_STARTED); - } - - /* Clear the started flag here to ensure other threads can't issue a stop while - this stop is in progress. */ - client_ptr -> nx_sntp_client_started = NX_FALSE; - - /* Indicate the client needs to be re-initialized to run again. */ - client_ptr -> nx_sntp_client_unicast_initialized = NX_FALSE; - client_ptr -> nx_sntp_client_broadcast_initialized = NX_FALSE; - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Loop to wait for the SNTP Client thread to be in a position to be stopped. */ - while (client_ptr -> nx_sntp_client_sleep_flag != NX_TRUE) - { - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Sleep temporarily. */ - tx_thread_sleep(1); - - /* Get the SNTP mutex. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - } - - /* Clear the sleep flag. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; - - /* Get rid of any previous server message. */ - memset(&(client_ptr -> nx_sntp_previous_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Get rid of the current server message if there is one. */ - memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - /* Suspend the SNTP Client thread. */ - tx_thread_suspend(&(client_ptr -> nx_sntp_client_thread)); - - /* Abort the wait on the SNTP Client thread. */ - tx_thread_wait_abort(&(client_ptr -> nx_sntp_client_thread)); - - /* Unbind the port. */ - nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Restore preemption. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_run_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the run broadcast service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_run_broadcast Actual run broadcast service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for pointer error. */ - if (client_ptr == NX_NULL) - { - - /* Return error status. */ - return NX_PTR_ERROR; - } - - /* Verify this is called from thread context only. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual run broadcast service. */ - status = _nx_sntp_client_run_broadcast(client_ptr); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_run_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts the SNTP Client for broadcast SNTP processing */ -/* by activating the SNTP timer and main processing thread. The Client */ -/* is checked for being initialized for broadcast SNTP and if it is */ -/* not, the function returns an error status. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_CLIENT_NOT_INITIALIZED Client initialized flag not set */ -/* NX_SNTP_CLIENT_ALREADY_STARTED Client already started */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_timer_activate Start the ThreadX timer */ -/* tx_thread_resume Resume the specified thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Get the SNTP mutex. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - /* Determine if SNTP has already been started. */ - if (client_ptr -> nx_sntp_client_started) - { - - /* Error SNTP has already been started. */ - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return completion status. */ - return(NX_SNTP_CLIENT_ALREADY_STARTED); - } - - /* Verify the client is ready to start receiving time data. */ - if (client_ptr -> nx_sntp_client_broadcast_initialized == NX_FALSE) - { - - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - /* Return error condition. */ - return NX_SNTP_CLIENT_NOT_INITIALIZED; - } - - - /* Set the maximum timeout to the full count. */ - client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); - - /* Activate the SNTP update timer. */ - status = tx_timer_activate(&(client_ptr -> nx_sntp_update_timer)); - - /* Check for error. Ignore timer is already active error. */ - if (status != TX_SUCCESS && status != TX_ACTIVATE_ERROR) - { - - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - /* Return the error condition. */ - return status; - } - - /* Bind the UDP socket to the IP port. */ - status = nx_udp_socket_bind(&(client_ptr -> nx_sntp_client_udp_socket), NX_SNTP_CLIENT_UDP_PORT, NX_WAIT_FOREVER); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - return status; - } - - /* Set status that the first update is expected. */ - client_ptr -> nx_sntp_client_first_update_pending = NX_TRUE; - - status = tx_thread_resume(&(client_ptr -> nx_sntp_client_thread)); - - if (status != NX_SUCCESS) - { - - /* Release the socket port. */ - nx_udp_socket_unbind(&(client_ptr -> nx_sntp_client_udp_socket)); - - /* Deactivate SNTP update timer. */ - tx_timer_deactivate(&(client_ptr -> nx_sntp_update_timer)); - - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return status; - } - - /* Clear the sleep flag. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; - - client_ptr -> nx_sntp_client_started = NX_TRUE; - - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_process_broadcast PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if the SNTP client has received a packet, and if*/ -/* so processes it for valid SNTP data and resets the timeouts */ -/* for receiving the next update. */ -/* */ -/* If the invalid packet update count exceeds the maximum allowed */ -/* updates, or no valid packet is received within the maximum interval, */ -/* an error flag is set, and it is up to the host application to change */ -/* its broadcast SNTP server. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_reset_current_time_message */ -/* Save time update before next update */ -/* _nx_sntp_client_receive_time_update */ -/* Receive server update packets */ -/* _nx_sntp_client_process_time_data */ -/* Process time data in server update */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_process_broadcast(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; -ULONG sntp_events; - - - /* Check for a receive event. */ - status = tx_event_flags_get(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR_CLEAR, &sntp_events, TX_NO_WAIT); - - if (status == NX_SUCCESS) - { - - /* Save this server time update before receiving the next server time update. */ - _nx_sntp_client_reset_current_time_message(client_ptr); - - /* Listen for a server update packet. */ - status = _nx_sntp_client_receive_time_update(client_ptr, TX_NO_WAIT); - - if (status == NX_SUCCESS) - { - - /* Process the server update packet and apply to local time if valid. */ - status = _nx_sntp_client_process_update_packet(client_ptr); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Have we exceeded the max number of invalid or missed updates from this server? */ - if (client_ptr -> nx_sntp_client_invalid_time_updates > NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT) - { - - /* Yes, set the server status as no longer valid. */ - client_ptr -> nx_sntp_valid_server_status = NX_FALSE; - } - - return; - } - - /* Reset the Client timeout for receiving broadcast updates, zero out invalid update count. */ - client_ptr -> nx_sntp_update_time_remaining = (NX_SNTP_CLIENT_MAX_TIME_LAPSE * NX_IP_PERIODIC_RATE); - - client_ptr -> nx_sntp_client_invalid_time_updates = 0; - - /* Set the server status as good (receiving updates). */ - client_ptr -> nx_sntp_valid_server_status = NX_TRUE; - - /* Indicate the client has received at least one valid time update with the current server. */ - client_ptr -> nx_sntp_client_first_update_pending = NX_FALSE; - - return; - } - } - - /* Has the timeout for receiving the next time update expired? */ - if (client_ptr -> nx_sntp_update_time_remaining == 0) - { - - /* Yes, set the server status as no longer valid. */ - client_ptr -> nx_sntp_valid_server_status = NX_FALSE; - } - - /* Nothing to do but wait...*/ - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_send_unicast_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a packet from the Client packet pool,creates*/ -/* a time request time message, transfers the request message into the */ -/* packet buffer, and sends the packet via the Client UDP socket. It */ -/* then releases the packet back to the packet pool. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* nx_packet_allocate Allocate packet from packet pool */ -/* nx_packet_release Release packet back to packet pool */ -/* nx_udp_socket_send Transmit packet via UDP socket */ -/* _nx_sntp_client_utility_convert_time_to_UCHAR */ -/* Copy NX_SNTP_TIME data into a */ -/* UCHAR[4] time stamp field */ -/* _nx_sntp_client_create_time_request_packet */ -/* Create packet with time request data*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_run_unicast Send and receive unicast time data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT *client_ptr) -{ - -NX_PACKET *packet_ptr; -UINT status; -NX_SNTP_TIME_MESSAGE *unicast_request; -NX_SNTP_TIME local_time; - - - /* Lock access to the SNTP Client while we create a unicast request. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - unicast_request = &(client_ptr -> nx_sntp_current_time_message_request); - - /* Clear the time request. */ - memset(unicast_request, 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Add client version to the time request flags. */ - unicast_request -> flags = NX_SNTP_CLIENT_NTP_VERSION << 3; - - /* Set the Client association (mode) in the last three bits of the flag field. */ - unicast_request -> flags |= PROTOCOL_MODE_CLIENT; - - /* Release the mutex before a potentially blocking call. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - /* Allocate a packet from the Client pool. */ - status = nx_packet_allocate(client_ptr -> nx_sntp_client_packet_pool_ptr, &packet_ptr, NX_UDP_PACKET, NX_SNTP_CLIENT_PACKET_TIMEOUT); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Reacquire the lock to SNTP Client while we process request. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - /* Check for minimal packet size requirement. */ - - - /* IPv6 packets require more space for the IPv6 header. */ - if (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - nx_packet_release(packet_ptr); - - /* Release the mutex. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return NX_SNTP_INVALID_IP_ADDRESS; -#else - - if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size < - (sizeof(NX_IPV6_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) - { - - nx_packet_release(packet_ptr); - - /* Release the mutex. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; - } -#endif /* FEATURE_NX_IPV6 */ - } - else /* IPv4 */ - { - -#ifdef NX_DISABLE_IPV4 - nx_packet_release(packet_ptr); - - /* Release the mutex. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return NX_SNTP_INVALID_IP_ADDRESS; -#else - - if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size < - (sizeof(NX_IPV4_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) - { - - nx_packet_release(packet_ptr); - - /* Release the mutex. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; - } -#endif /* NX_DISABLE_IPV4 */ - } - - - /* Convert the local time into the request's transmit time stamp field. */ - local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds + - client_ptr -> nx_sntp_client_local_ntp_time_elapsed; - local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; - _nx_sntp_client_utility_convert_time_to_UCHAR(&local_time, unicast_request, TRANSMIT_TIME); - - /* Create the request packet with the unicast request message. */ - status = _nx_sntp_client_create_time_request_packet(client_ptr, packet_ptr, unicast_request); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - - /* Release the mutex. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - /* Return error status. */ - return status; - } - - /* Release the lock. we're done with the SNTP Client data. */ - tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); - - /* Send the time request packet. */ - status = nxd_udp_socket_send(&(client_ptr -> nx_sntp_client_udp_socket), packet_ptr, &client_ptr -> nx_sntp_server_ip_address, NX_SNTP_SERVER_UDP_PORT); - - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return status; - } - - send_timerticks = tx_time_get(); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_receive_time_update PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives UDP data on the Client socket with specified */ -/* wait (timeout option). Received packets are checked for valid */ -/* and sender IP and port. Packet data is then extracted and stored */ -/* in the specified time message. The packet is released regardless of */ -/* validity of packet received. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* timeout Wait option to receive packet */ -/* */ -/* OUTPUT */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_receive Listen for packets on UDP socket */ -/* nx_packet_release Release packet back to packet pool*/ -/* tx_mutex_get Obtain exclusive lock on list */ -/* memset Clear specified area of memory */ -/* _nx_sntp_client_add_server_ULONG_to_list */ -/* Add sender address to Client list */ -/* _nx_sntp_client_utility_convert_LONG_to_IP */ -/* Convert IP to string for display */ -/* _nx_sntp_client_extract_time_message_from_packet */ -/* Extract packet data to time message*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_run_unicast Send and receive server time updates*/ -/* _nx_sntp_client_run_broadcast Listen for server update broadcasts */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout) -{ - -UINT status; -UINT length; -NX_PACKET *receive_packet; -UINT sender_port; -NX_UDP_HEADER *udp_header_ptr; -NXD_ADDRESS source_ip_address, destination_ip_address; - - /* Loop to receive packets. */ - for(;;) - { - - /* Indicate the SNTP Client can be stopped while the SNTP client waits for a packet. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE; - - /* Wait to receive packets on the Client UDP socket. */ - status = nx_udp_socket_receive(&(client_ptr -> nx_sntp_client_udp_socket), &receive_packet, timeout * NX_IP_PERIODIC_RATE); - - /* Indicate the SNTP Client can not be stopped. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - /* Check the sender port in the UDP packet header. */ - udp_header_ptr = (NX_UDP_HEADER *)(receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER)); - sender_port = (UINT)udp_header_ptr -> nx_udp_header_word_0 >> NX_SHIFT_BY_16; - - /* Check if this is the server port the Client expects. */ - if (sender_port != NX_SNTP_CLIENT_UDP_PORT) - { - - /* No, reject the packet. */ - nx_packet_release(receive_packet); - - continue; - } - - - /* If this an IPv6 packet? An SNTP client with an IPv6 SNTP server will only accept IPv6 packets. */ - if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V6) && - (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V6)) - { - -#ifndef FEATURE_NX_IPV6 - nx_packet_release(receive_packet); - continue; -#else - NX_IPV6_HEADER *ipv6_header_ptr; - - /* Pick up the IPv6 header from the packet. */ - ipv6_header_ptr = (NX_IPV6_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV6_HEADER)); - - /* Copy sender address into a local variable. */ - COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_source_ip, &(source_ip_address.nxd_ip_address.v6[0])); - source_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - /* Copy destination address into a local variable. */ - COPY_IPV6_ADDRESS(ipv6_header_ptr -> nx_ip_header_destination_ip, &(destination_ip_address.nxd_ip_address.v6[0])); - destination_ip_address.nxd_ip_version = NX_IP_VERSION_V6; - - if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) - { - - /* Does the source address match the expected server address? */ - if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0])) - { - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - /* Set update time to null. */ - memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); - - continue; - } - } - else /* Multicast mode */ - { - - /* Define the all hosts multicast address. */ - NXD_ADDRESS All_Hosts_Multicast; - All_Hosts_Multicast.nxd_ip_version = NX_IP_VERSION_V6; - All_Hosts_Multicast.nxd_ip_address.v6[0] = 0xff020000; - All_Hosts_Multicast.nxd_ip_address.v6[1] = 0x00000000; - All_Hosts_Multicast.nxd_ip_address.v6[2] = 0x00000000; - All_Hosts_Multicast.nxd_ip_address.v6[3] = 0x00000001; - - /* Does the source address match the expected server address )? */ - if (!CHECK_IPV6_ADDRESSES_SAME(&client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v6[0], &source_ip_address.nxd_ip_address.v6[0])) - { - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - /* Set update time to null. */ - memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); - - continue; - } - - /* Does the destination address match the expected server address (all hosts address FF02::1)? */ - if (!CHECK_IPV6_ADDRESSES_SAME(&destination_ip_address.nxd_ip_address.v6[0], &All_Hosts_Multicast.nxd_ip_address.v6[0])) - { - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - /* Set update time to null. */ - memset(&(client_ptr -> nx_sntp_server_update_time), 0, sizeof(NX_SNTP_TIME)); - - continue; - } - - } -#endif /* FEATURE_NX_IPV6 */ - - } - /* Otherwise is this an IPv4 packet and is the SNTP client set for IPv4? */ - else if ((receive_packet -> nx_packet_ip_version == NX_IP_VERSION_V4) && - (client_ptr -> nx_sntp_server_ip_address.nxd_ip_version == NX_IP_VERSION_V4)) - { -#ifdef NX_DISABLE_IPV4 - nx_packet_release(receive_packet); - continue; -#else - - NX_IPV4_HEADER *ipv4_header_ptr; - - ipv4_header_ptr = (NX_IPV4_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IPV4_HEADER)); - - /* Copy into a local variable. */ - source_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_source_ip; - source_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - - /* Copy into a local variable. */ - destination_ip_address.nxd_ip_address.v4 = ipv4_header_ptr -> nx_ip_header_destination_ip; - destination_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - - if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) - { - /* Compare the sender address with the Client's current sntp server. */ - if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4) - { - /* This is an untrusted server or the client had a broadcast server already, - reject this packet and return an error condition. */ - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - continue; - } - } - else /* BROADCAST_MODE */ - { - - ULONG network_mask; - UINT iface_index; - - /* Compare the sender address with the Client's current sntp server. */ - if (source_ip_address.nxd_ip_address.v4 != client_ptr -> nx_sntp_server_ip_address.nxd_ip_address.v4) - { - - /* This is an untrusted server or the client had a broadcast server already, - reject this packet and return an error condition. */ - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - continue; - } - - /* Set a local variable on the SNTP network index. */ - iface_index = client_ptr -> nx_sntp_client_interface_index; - - /* Set a local variable to the network mask. */ - network_mask = client_ptr -> nx_sntp_client_ip_ptr -> nx_ip_interface[iface_index].nx_interface_ip_network_mask; - - /* Now verify this is a broadcast packet. */ - if ((destination_ip_address.nxd_ip_address.v4 & ~network_mask) != ~network_mask) - { - /* This is not a broadcast packet on the local network. */ - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - continue; - } - } -#endif /* NX_DISABLE_IPV4 */ - } - else - { - /* Not interested, discard the packet. */ - nx_packet_release(receive_packet); - - continue; - } - - /* Check that the packet has the proper length for an NTP message. */ - length = receive_packet -> nx_packet_length; - - /* Verify the packet data contains at least the minimum time update data, - but no more than the max size with authentication data appended. */ - - if ((length < NX_SNTP_TIME_MESSAGE_MIN_SIZE) || (length > NX_SNTP_TIME_MESSAGE_MAX_SIZE)) - { - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - continue; - } - - memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Extract time message data from packet data into time message. */ - _nx_sntp_client_extract_time_message_from_packet(client_ptr, receive_packet); - - /* No further need for the receive packet. Release back to the client pool. */ - nx_packet_release(receive_packet); - - return NX_SUCCESS; - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_extract_time_message_from_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function extracts time data from an SNTP server packet and */ -/* copies the information into the specified time message buffer. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* packet_ptr Pointer to server packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Copy data to area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_receive_time_update Process SNTP server packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ - -ULONG *ntp_word_0; -NX_SNTP_TIME_MESSAGE *time_message_ptr; - - - time_message_ptr = &(client_ptr -> nx_sntp_current_server_time_message); - - process_timerticks = tx_time_get(); - - memset(time_message_ptr, 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Pickup the pointer to the head of the UDP packet. */ - ntp_word_0 = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - - /* Extract fields from the first 32 bits of the time message. */ - time_message_ptr -> flags = (*ntp_word_0 & 0xFF000000UL) >> 24; - - time_message_ptr -> peer_clock_stratum = (*ntp_word_0 & 0x00FF0000UL) >> 16; - - time_message_ptr -> peer_poll_interval = (*ntp_word_0 & 0x0000FF00UL) >> 8; - - time_message_ptr -> peer_clock_precision = (*ntp_word_0 & 0x00000000FFUL); - - /* Advance to the next 32 bit field and extract the root delay field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - - time_message_ptr -> root_delay = (ULONG)(*ntp_word_0); - - /* Advance to the next 32 bit field and extract the clock dispersion field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - - time_message_ptr -> clock_dispersion= *ntp_word_0; - - /* Advance to the next 32 bit field and extract the reference clock ID field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - memcpy(time_message_ptr -> reference_clock_id, ntp_word_0, 4); - - /* Advance to the next field (64 bit field) and extract the reference time stamp field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> reference_clock_update_time_stamp[0] = *ntp_word_0; - - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> reference_clock_update_time_stamp[1] = *ntp_word_0; - - /* If a non zero reference time was supplied, separate out seconds and fraction. */ - if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> reference_clock_update_time_stamp), 8) == NX_FALSE) - { - - time_message_ptr -> reference_clock_update_time.seconds = time_message_ptr -> reference_clock_update_time_stamp[0]; - - time_message_ptr -> reference_clock_update_time.fraction = time_message_ptr -> reference_clock_update_time_stamp[1]; - } - - /* Copy the first 32 bits into the originate time stamp seconds field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> originate_time_stamp[0] = *ntp_word_0; - - /* Copy the next 32 bits into the originate time stamp fraction field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> originate_time_stamp[1] = *ntp_word_0; - - /* If an originate time was supplied, separate out seconds and fraction. */ - if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> originate_time_stamp), 8) == NX_FALSE) - { - - time_message_ptr -> originate_time.seconds = time_message_ptr -> originate_time_stamp[0]; - - time_message_ptr -> originate_time.fraction = time_message_ptr -> originate_time_stamp[1]; - } - - - /* Copy the first 32 bits into the receive time stamp seconds field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> receive_time_stamp[0] = *ntp_word_0; - - /* Copy the next 32 bits into the receive time stamp fraction field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> receive_time_stamp[1] = *ntp_word_0; - - /* If an receive time was supplied, separate out seconds and fraction. */ - if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> receive_time_stamp), 8) == NX_FALSE) - { - - time_message_ptr -> receive_time.seconds = time_message_ptr -> receive_time_stamp[0]; - time_message_ptr -> receive_time.fraction = time_message_ptr -> receive_time_stamp[1]; - } - - /* Copy the first 32 bits into the transmit time stamp seconds field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> transmit_time_stamp[0] = *ntp_word_0; - - /* Copy the next 32 bits into the transmit time stamp fraction field. */ - ntp_word_0++; - NX_CHANGE_ULONG_ENDIAN(*ntp_word_0); - time_message_ptr -> transmit_time_stamp[1] = *ntp_word_0; - - /* If an transmit time was supplied, separate out seconds and fraction. */ - if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(time_message_ptr -> transmit_time_stamp), 8) == NX_FALSE) - { - - time_message_ptr -> transmit_time.seconds = time_message_ptr -> transmit_time_stamp[0]; - - time_message_ptr -> transmit_time.fraction = time_message_ptr -> transmit_time_stamp[1]; - - } - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_reset_current_time_message PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function saves the current time message from the server to */ -/* the previous time message field, and clears the current time message*/ -/* field. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_receive_time_update Process received update packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr) -{ - - /* Does the client have a non NULL current server time update? */ - if (client_ptr -> nx_sntp_current_server_time_message.flags) - { - - /* Yes, copy to the previous time update. */ - memcpy(&client_ptr -> nx_sntp_previous_server_time_message, &client_ptr -> nx_sntp_current_server_time_message, sizeof(NX_SNTP_TIME_MESSAGE)); - - /* Clear the current time update data. */ - memset(&(client_ptr -> nx_sntp_current_server_time_message), 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - } - - /* Clear the current time update request. */ - memset(&(client_ptr -> nx_sntp_current_time_message_request), 0, sizeof(NX_SNTP_TIME_MESSAGE)); - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_process_update_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes SNTP time data received in a server update */ -/* packet, applies sanity checks, calculates round trip time, and */ -/* updates the Client time with the SNTP server time. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_BAD_SERVER_ROOT_DISPERSION Server dispersion too high */ -/* receive_status Actual packet receive status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Copy data to area of memory */ -/* _nx_sntp_client_apply_sanity_checks Apply sanity checks to update */ -/* _nx_sntp_client_check_server_clock_dispersion */ -/* Check server clock dispersion */ -/* _nx_sntp_client_calculate_roundtrip */ -/* Compute roundtrip time to server*/ -/* _nx_sntp_client_process_time_data Apply server time to local time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_process_unicast Process unicast SNTP data */ -/* _nx_sntp_client_process_broadcast Process broadcast SNTP data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; - - /* Apply client's set of sanity checks on the data. */ - status = _nx_sntp_client_apply_sanity_checks(client_ptr); - - /* Check for sanity check errors. */ - if (status != NX_SUCCESS) - { - - /* Count these as bad updates from the server. */ - client_ptr -> nx_sntp_client_invalid_time_updates++; - - /* Ok to continue Client task. */ - return status; - } - - /* Check server clock dispersion (if any reported) in first update - from current server for unicast clients. */ - if ((client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) - { - - status = _nx_sntp_client_check_server_clock_dispersion(client_ptr); - - /* Is the server clock variance acceptable? */ - if (status != NX_SUCCESS) - { - - /* Return the error status. */ - return status; - } - } - - /* At this point we have received a valid server response. */ - - /* Clear the count of (consecutive) bad time updates received from this server. */ - client_ptr -> nx_sntp_client_invalid_time_updates = 0; - - /* Apply server time to local device time. */ - status = _nx_sntp_client_process_time_data(client_ptr); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error condition*/ - return status; - } - - /* If the Client is configured with a time update callback, call it now. */ - if (client_ptr -> nx_sntp_client_time_update_notify) - { - - client_ptr -> nx_sntp_client_time_update_notify(&(client_ptr -> nx_sntp_current_server_time_message), - &(client_ptr -> nx_sntp_client_local_ntp_time)); - } - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_duplicate_update_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs a comparison of time values between two */ -/* time messages to verify they are not duplicates. Duplicate updates */ -/* can be a form of denial of service/clogging attack on a host. */ -/* */ -/* INPUT */ -/* */ -/* timeA_msg_ptr Pointer to first time update */ -/* timeB_msg_ptr Pointer to second time update */ -/* is_a_dupe Result of comparison */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Copy data to area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_apply_sanity_checks Verify received SNTP data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr, - NX_SNTP_TIME_MESSAGE *timeB_msg_ptr, - UINT *is_a_dupe) -{ - - *is_a_dupe = NX_FALSE; - - if ( (!memcmp(timeA_msg_ptr -> transmit_time_stamp, - timeB_msg_ptr -> transmit_time_stamp, 8)) && - (!memcmp(timeA_msg_ptr -> receive_time_stamp, - timeB_msg_ptr -> receive_time_stamp, 8)) && - (!memcmp(timeA_msg_ptr -> originate_time_stamp, - timeB_msg_ptr -> originate_time_stamp, 8)) && - (!memcmp(timeA_msg_ptr -> reference_clock_update_time_stamp, - timeB_msg_ptr -> reference_clock_update_time_stamp, 8)) && - (!memcmp(timeA_msg_ptr -> reference_clock_id, - timeB_msg_ptr -> reference_clock_id, 4)) && - (timeA_msg_ptr -> root_delay == timeB_msg_ptr -> root_delay) && - (timeA_msg_ptr -> clock_dispersion == timeB_msg_ptr -> clock_dispersion) - ) - { - - *is_a_dupe = NX_TRUE; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_apply_sanity_checks PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for invalid SNTP data received from server. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_DUPE_SERVER_PACKET Duplicate server packet received */ -/* NX_SNTP_INVALID_SERVER_MODE Server mode won't work with Client */ -/* NX_SNTP_INVALID_NTP_VERSION Server NTP version won't work with */ -/* Client NTP version. */ -/* NX_SNTP_SERVER_CLOCK_NOT_SYNC Server is not ready to send updates*/ -/* NX_SNTP_INVALID_SERVER_STRATUM Server stratum not acceptable */ -/* NX_SNTP_NULL_SERVER_TIMESTAMP Invalid or NULL timestamp in update*/ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Copy data into area of memory */ -/* _nx_sntp_client_duplicate_update_check */ -/* Check for duplicate updates service*/ -/* _nx_sntp_client_utility_get_msec_diff */ -/* Check for time difference in msecs */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_run_broadcast Receive broadcast SNTP updates */ -/* _nx_sntp_client_run_unicast Send and receive SNTP updates */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr) -{ - - -UINT status; -UINT mode; -UINT leap_second_indicator; -UINT server_ntp_version; -UINT is_a_dupe_check; -ULONG msecs; -NX_SNTP_TIME_MESSAGE *server_time_msg_ptr; - - server_time_msg_ptr = &(client_ptr -> nx_sntp_current_server_time_message); - - /* Was a previous response received from the server? */ - if (client_ptr -> nx_sntp_previous_server_time_message.flags) - { - - /* Yes; perform a duplicate packet check. */ - status = _nx_sntp_client_duplicate_update_check(&(client_ptr -> nx_sntp_current_server_time_message), - &(client_ptr -> nx_sntp_previous_server_time_message), - &is_a_dupe_check); - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return error status. */ - return status; - } - - /* Is this a duplicate packet (e.g. possible 'clogging' attack)? */ - if (is_a_dupe_check) - { - - return NX_SNTP_DUPE_SERVER_PACKET; - } - } - - /* Get the association type from the server. */ - mode = server_time_msg_ptr ->flags & 0x07; - - /* Is the server of the correct association for a unicast client? */ - if ((mode != PROTOCOL_MODE_SERVER_UNICAST) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) - { - - /* Return error status. */ - return NX_SNTP_INVALID_SERVER_MODE; - } - /* Is the server of the correct association for a broadcast client? */ - else if ((mode != PROTOCOL_MODE_SERVER_BROADCAST) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE)) - { - - /* Return error status. */ - return NX_SNTP_INVALID_SERVER_MODE; - } - - /* Extract server's NTP version from the flags field. */ - server_ntp_version = (server_time_msg_ptr -> flags & 0x38) >> 3; - - /* As per NTP protocol, check if the server reply has the same SNTP version that - the Client sent in its unicast request. */ - if ((server_ntp_version != NX_SNTP_CLIENT_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE)) - { - - /* Return the error condition. */ - return NX_SNTP_INVALID_NTP_VERSION; - } - /* If broadcast, verify the server SNTP version is compatible with the Client. */ - else if ((server_ntp_version < NX_SNTP_CLIENT_MIN_NTP_VERSION) && (client_ptr -> nx_sntp_client_protocol_mode == BROADCAST_MODE)) - { - - /* Return the error condition. */ - return NX_SNTP_INVALID_NTP_VERSION; - } - - /* Get the leap second indicator from the flags field. */ - leap_second_indicator = (server_time_msg_ptr -> flags & 0xC0) >> 6; - - /* Is the server clock not yet synchronized? */ - if (leap_second_indicator == 3) - { - /* Return the error condition. */ - return NX_SNTP_SERVER_CLOCK_NOT_SYNC; - } - - /* Has the server sent a 'kiss of death' (stratum = 0) packet? */ - if (server_time_msg_ptr -> peer_clock_stratum == 0) - { - - /* Does the Client have a kiss of death handler? */ - if (client_ptr -> kiss_of_death_handler) - { - UINT code_id; - - /* Convert the message to code.*/ - _nx_sntp_client_utility_convert_refID_KOD_code(server_time_msg_ptr -> reference_clock_id, &code_id); - - /* Yes, let the handler deal with this server response. */ - status = (client_ptr -> kiss_of_death_handler)(client_ptr, code_id); - - /* Is it ok to continue with this server? */ - if (status != NX_SUCCESS) - { - - /* No, it is not. Return the error condition. */ - return status; - } - } - else - { - /* It is not ok to continue. Return the error condition. */ - return NX_SNTP_KOD_SERVER_NOT_AVAILABLE; - } - } - - /* Is the server stratum a valid stratum ? */ - else if (server_time_msg_ptr -> peer_clock_stratum & STRATUM_RESERVED) - { - - /* Return error status. */ - return NX_SNTP_INVALID_SERVER_STRATUM; - - } - /* Does the server stratum acceptable to the Client? */ - else if (server_time_msg_ptr -> peer_clock_stratum > NX_SNTP_CLIENT_MIN_SERVER_STRATUM) - { - - /* Return error status. */ - return NX_SNTP_INVALID_SERVER_STRATUM; - } - - /* Is the Client operating in unicast mode? */ - if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) - { - UINT pos_diff = NX_TRUE; - - /* Yes; Are any server time stamps NULL? */ - - /* Special case: the client has not set its local time. Only check server's receive and transmit time. */ - if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0) - { - if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) || - (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)) - { - - /* Return error status. */ - return NX_SNTP_INVALID_TIMESTAMP; - } - - } - else - { - /* Check all server time stamps to be non null. */ - if ((_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> originate_time_stamp), 8) == NX_TRUE) || - (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> receive_time_stamp), 8) == NX_TRUE) || - (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE)) - { - - /* Return error status. */ - return NX_SNTP_INVALID_TIMESTAMP; - } - - } - - /* Get the time difference server transmit time - server receive time. */ - status = _nx_sntp_client_utility_get_msec_diff(&(server_time_msg_ptr -> receive_time), - &(server_time_msg_ptr -> transmit_time), - &msecs, &pos_diff); - - /* Is the server transmit time <= server receive time [physically not possible]? */ - if (status != NX_SUCCESS) - { - - /* Yes; Return the error condition. */ - return status; - } - else if (pos_diff == NX_FALSE) - { - - /* treat as an error in this case. */ - return NX_SNTP_INVALID_TIMESTAMP; - } - } - /* Client is in broadcast mode. */ - else - { - - /* Is the broadcast server transmit time stamp is NULL? */ - if (_nx_sntp_client_utility_is_zero_data((UCHAR *)(server_time_msg_ptr -> transmit_time_stamp), 8) == NX_TRUE) - - { - - /* Return the error status. */ - return NX_SNTP_INVALID_TIMESTAMP; - } - } - - /* Is there an impending leap second adjustment? */ - if ((leap_second_indicator == 1) || (leap_second_indicator == 2)) - { - - /* Does the Client have a leap second handler?*/ - if (client_ptr -> leap_second_handler) - { - - /* Yes, invoke the leap second handler for impending leap second event. */ - (client_ptr -> leap_second_handler)(client_ptr, leap_second_indicator); - } - } - - /* Return successful completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_check_server_clock_dispersion PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks server clock dispersion extracted from server */ -/* time message in 32 bit representation: */ -/* sum of 1/(2 ^ bit) of bits 16-31 in the time message format */ -/* and compares it against the Client's dispersion tolerance. */ -/* */ -/* If NX_SNTP_CLIENT_MAX_ROOT_DISPERSION is set to zero, the function */ -/* simply returns a successful result but does no calculations. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS dispersion is acceptable */ -/* NX_SNTP_BAD_SERVER_ROOT_DISPERSION dispersion is too large */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_process_update_packet */ -/* Process time data in update packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr) -{ - -#if (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) -UINT mask = 0x8000; -UINT bit = 1; -ULONG divisor; -ULONG dispersion_usecs; - - /* Check for zero clock dispersion reported in server update. */ - if (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion == 0) - { - - /* Return successful status. */ - return NX_SUCCESS; - } - - /* Get the most significant 16 bits of dispersion field and convert to microseconds.*/ - dispersion_usecs = (client_ptr -> nx_sntp_current_server_time_message.clock_dispersion >> 16) * 1000000; - - /* Compare seconds in the most significant 16 bits against the Client dispersion tolerance. */ - if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION) - { - - /* Yes, indicate that server clock dispersion exceeds tolerance. */ - return NX_SNTP_BAD_SERVER_ROOT_DISPERSION; - } - - /* Compare fraction from least significant 16 bits; sum of (1 / 2 ^ bit field) of lower 16 bits. */ - - /* Get the lower 16 bits. */ - client_ptr -> nx_sntp_current_server_time_message.clock_dispersion = - client_ptr -> nx_sntp_current_server_time_message.clock_dispersion & 0xFFFF; - - /* Compute the dispersion. */ - while(mask) - { - if (mask & client_ptr -> nx_sntp_current_server_time_message.clock_dispersion) - { - divisor = (ULONG)(1 << bit); - if ((divisor < 1000000) && (divisor > 0)) - { - dispersion_usecs += 1000000/divisor; - } - } - bit++; - mask >>= 1; - } - - /* Is the computed clock dispersion more than the max tolerance? */ - if (dispersion_usecs > NX_SNTP_CLIENT_MAX_ROOT_DISPERSION) - { - /* Yes, indicate that server clock dispersion exceeds tolerance. */ - return NX_SNTP_BAD_SERVER_ROOT_DISPERSION; - } -#else - NX_PARAMETER_NOT_USED(client_ptr); -#endif /* (NX_SNTP_CLIENT_MAX_ROOT_DISPERSION != 0) */ - - /* Return successful computation. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the processing thread for the SNTP Client. It */ -/* executes periodic SNTP tasks with SNTP Client mutex protection, then*/ -/* briefly sleeps to allow the host application to call SNTP Client */ -/* services. */ -/* */ -/* INPUT */ -/* */ -/* sntp_instance Pointer to SNTP instance */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_process Main SNTP processing function */ -/* tx_thread_sleep Sleep for specified time */ -/* tx_mutex_get Get the SNTP mutex */ -/* tx_mutex_put Release the SNTP mutex */ -/* tx_thread_preemption_change Change thread preemption */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_thread_entry(ULONG sntp_instance) -{ - -NX_SNTP_CLIENT *client_ptr; -UINT status; -UINT current_preemption; - - - /* Setup the SNTP pointer. */ - client_ptr = (NX_SNTP_CLIENT *) sntp_instance; - - /* Enter while loop. */ - do - { - - /* Loop for obtaining the SNTP mutex. */ - do - { - - /* Get the SNTP mutex. */ - status = tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - } while (status != TX_SUCCESS); - - /* Perform periodic tasks for the SNTP Client. */ - _nx_sntp_client_process(client_ptr); - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Disable preemption for critical section. */ - tx_thread_preemption_change(tx_thread_identify(), 0, ¤t_preemption); - - /* Indicate the SNTP Client process is idle. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_TRUE; - - /* Sleep for timer interval. */ - tx_thread_sleep(NX_SNTP_CLIENT_SLEEP_INTERVAL); - - /* Clear flag to indicate SNTP thread is not in a position to be stopped. */ - client_ptr -> nx_sntp_client_sleep_flag = NX_FALSE; - - /* Restore original preemption. */ - tx_thread_preemption_change(tx_thread_identify(), current_preemption, ¤t_preemption); - - - } while (1); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_receive_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the socket receive callback for the SNTP Client */ -/* UDP socket. It sets a flag for the SNTP Client thread to know there*/ -/* is a packet waiting to be processed. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to Client UDP socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Sets a receive event */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr) -{ - NX_PARAMETER_NOT_USED(socket_ptr); - - /* Wakeup all threads that are attempting to perform a receive or that had their select satisfied. */ - tx_event_flags_set(&nx_sntp_client_events, NX_SNTP_CLIENT_RECEIVE_EVENT, TX_OR); - - receive_timerticks = tx_time_get(); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called periodically by the SNTP client thread, and */ -/* depending on the CLient mode (unicast or broadcast) calls the */ -/* unicast or broadcast process function. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to the SNTP client */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_process_unicast Process unicast tasks */ -/* _nx_sntp_client_process_broadcast Process broadcast tasks */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr) -{ - - - /* Is the client using unicast or unicast to receive updates? */ - if (client_ptr -> nx_sntp_client_protocol_mode == UNICAST_MODE) - { - /* Call the unicast process function. */ - _nx_sntp_client_process_unicast(client_ptr); - } - else - { - - /* Call the broadcast process function. */ - _nx_sntp_client_process_broadcast(client_ptr); - } - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_process_time_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function applies the server time data to client local time taking*/ -/* into account the round trip time. Time updates are checked for a max */ -/* time offset set by the Client max_time_adjustment parameter. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_INVALID_SERVER_UPDATE_TIME No time of server update recorded*/ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* memcpy Copy data to area of memory */ -/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ -/* Add msec to NTP time fraction field*/ -/* _nx_sntp_client_utility_get_msec_diff */ -/* Compute time difference in msecs */ -/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ -/* Add time in msecs to an NTP time */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_run_broadcast Listen and process broadcast updates*/ -/* _nx_sntp_client_process_update_packet */ -/* Process update SNTP packets */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr) -{ - -UINT status; -UINT ignore_max_adjustment_limit; -ULONG elapsed_msecs_difference; -UINT adjustment; -NX_SNTP_TIME local_time; - - - /* Copy the received time update to the update time just received from the server. */ - memcpy(&client_ptr -> nx_sntp_server_update_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); - - /* Check if the client is configured for round trip time calculation. */ - if (NX_SNTP_CLIENT_RTT_REQUIRED == NX_TRUE) - { - - /* Compute roundtrip delay. */ - _nx_sntp_client_calculate_roundtrip(&(client_ptr -> nx_sntp_client_roundtrip_time_msec)); - - /* Has the client computed a valid round trip time? */ - if (client_ptr -> nx_sntp_client_roundtrip_time_msec) - { - - /* Yes, Add 1/2 round trip to server's reported time. */ - status =_nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_current_server_time_message.transmit_time), - ((client_ptr -> nx_sntp_client_roundtrip_time_msec) / 2)); - - if (status != NX_SUCCESS) - { - - /* Cannot use this time update. */ - return status; - } - } - } - - /* Is this the first update? */ - if (client_ptr -> nx_sntp_client_first_update_pending == NX_TRUE) - { - /* Check Client configuration if we ignore max adjustment limit on first update. */ - ignore_max_adjustment_limit = NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP; - } - else - ignore_max_adjustment_limit = NX_FALSE; - - /* If not ignoring the max adjustment, deal with time difference between client and server. */ - if (ignore_max_adjustment_limit == NX_FALSE) - { - UINT pos_diff = NX_TRUE; - - /* Compute difference of server update packet minus the client's local time. It is reasonable - to assume that the Client time is 'behind' the server time because it is updated by the - server time. */ - local_time.seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds + - client_ptr -> nx_sntp_client_local_ntp_time_elapsed; - local_time.fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; - status = _nx_sntp_client_utility_get_msec_diff(&local_time, - &(client_ptr -> nx_sntp_server_update_time), - &elapsed_msecs_difference, &pos_diff); - - - /* Note that a positive difference vs negative difference is not an error. */ - if (status != NX_SUCCESS) - { - - /* Cannot use this time update. */ - return status; - } - - /* Is the difference less than the client's minimum adjustment? */ - if (elapsed_msecs_difference > NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT) - { - - /* The adjustment is larger than the Client's minimum adjustment. */ - - /* Set the local clock to the server time only if 1)we are ignoring the maximum adjustment on startup, - or 2) the difference is within the Client's max time adjustment. */ - if (elapsed_msecs_difference > NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT) - { - /* Cannot use this time update. */ - return NX_SNTP_INVALID_TIME; - } - } - } - - /* Ok to update client local time. */ - memcpy(&client_ptr -> nx_sntp_client_local_ntp_time, &client_ptr -> nx_sntp_current_server_time_message.transmit_time, sizeof(NX_SNTP_TIME)); - client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0; - - /* Apply a correction to server's time for internal SNTP Client delays e.g. periodic task intervals. */ - adjustment = ((process_timerticks - receive_timerticks) * 1000) / NX_IP_PERIODIC_RATE; - - status = _nx_sntp_client_utility_add_msecs_to_ntp_time(&(client_ptr -> nx_sntp_client_local_ntp_time), (LONG)adjustment); - - /* Done processing time update. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_calculate_roundtrip PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes roundtrip based on the elapsed time from */ -/* sending the unicast request to receiving the SNTP response. */ -/* */ -/* INPUT */ -/* */ -/* roundtrip_time round trip time computation */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Valid time computations result */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_process_update_packet */ -/* Process server update packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time) -{ - -ULONG x; - - - /* Initialize invalid results. */ - *roundtrip_time = 0; - - /* Compute the roundtrip as the time the packet left the SNTP Client - to the time it received a response from the SNTP server. */ - - /* Check for wrapped timer value. */ - if (send_timerticks > receive_timerticks) - { - /* The time has wrapped. */ - x = 0xFFFFFFFF - send_timerticks; - *roundtrip_time = (LONG)(receive_timerticks + x); - } - else - { - *roundtrip_time = (LONG)(receive_timerticks - send_timerticks); - } - - /* Convert to milliseconds. */ - *roundtrip_time = (LONG)((ULONG)(*roundtrip_time) * NX_SNTP_MILLISECONDS_PER_TICK); - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_get_local_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get local time service.*/ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Pointer to SNTP seconds */ -/* fraction Local time fraction component */ -/* buffer Pointer for time in string format */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_get_local_time Get local time service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer) -{ - -UINT status; - - - /* Check input pointer parameters. */ - if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL)) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_sntp_client_get_local_time(client_ptr, seconds, fraction, buffer); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_get_local_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the current SNTP Client local time and */ -/* returns the data in seconds and fractions, and if a non zero */ -/* buffer pointer is supplied, a string containing the data in ASCII. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Pointer to SNTP seconds */ -/* fraction Local time fraction component */ -/* buffer Pointer for time in string format */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* _nx_sntp_client_get_local_time_extended */ -/* Get local time service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer) -{ - -UINT status; - - status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, NX_MAX_STRING_LENGTH); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_get_local_time_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get extended local */ -/* time service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Pointer to SNTP seconds */ -/* fraction Local time fraction component */ -/* buffer Pointer for time in string format */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_get_local_time_extended */ -/* Get extended local time service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size) -{ - -UINT status; - - - /* Check input pointer parameters. */ - if ((client_ptr == NX_NULL) || (seconds == NX_NULL) || (fraction == NX_NULL)) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check if this function is called from the appropriate thread. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual service. */ - status = _nx_sntp_client_get_local_time_extended(client_ptr, seconds, fraction, buffer, buffer_size); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_get_local_time_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the current SNTP Client local time and */ -/* returns the data in seconds and fractions, and if a non zero */ -/* buffer pointer is supplied, a string containing the data in ASCII. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Pointer to SNTP seconds */ -/* fraction Local time fraction component */ -/* buffer Pointer for time in string format */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_fraction_to_usecs */ -/* Convert NTP fraction to usecs */ -/* _nx_sntp_client_number_to_ascii Converts number to ascii text */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size) -{ - -ULONG usecs; -UINT offset = 0; -UINT length = 0; - - *seconds = client_ptr -> nx_sntp_client_local_ntp_time.seconds; - *fraction = client_ptr -> nx_sntp_client_local_ntp_time.fraction; - - if (buffer != NX_NULL) - { - - /* Convert SNTP fraction component into microseconds. */ - _nx_sntp_client_utility_fraction_to_usecs(client_ptr -> nx_sntp_client_local_ntp_time.fraction, &usecs); - - /* Decrease length for terminal zero. */ - buffer_size--; - - /* Create a string with just the time. */ - /* Format: "Time: %lu.%06lu sec.\r\n" */ - if (buffer_size < 6) - { - return(NX_SIZE_ERROR); - } - buffer[offset++] = 'T'; - buffer[offset++] = 'i'; - buffer[offset++] = 'm'; - buffer[offset++] = 'e'; - buffer[offset++] = ':'; - buffer[offset++] = ' '; - length = _nx_sntp_client_number_to_ascii(&buffer[offset], buffer_size - offset, - client_ptr->nx_sntp_client_local_ntp_time.seconds); - if (length == 0) - { - return(NX_SIZE_ERROR); - } - offset += length; - if ((buffer_size - offset) < 14) - { - return(NX_SIZE_ERROR); - } - buffer[offset++] = '.'; - length = _nx_sntp_client_number_to_ascii(&buffer[offset], 6, usecs); - if (length == 0) - { - return(NX_SIZE_ERROR); - } - - if (length < 6) - { - - /* Append zeroes. */ - memmove(&buffer[offset + (6 - length)], &buffer[offset], length); - memset(&buffer[offset], '0', (6 - length)); - } - buffer[offset++] = ' '; - buffer[offset++] = 's'; - buffer[offset++] = 'e'; - buffer[offset++] = 'c'; - buffer[offset++] = '.'; - buffer[offset++] = '\r'; - buffer[offset++] = '\n'; - buffer[offset] = '\0'; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_convert_time_to_UCHAR PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts time from the ULONG seconds and msecs in the */ -/* NX_SNTP_TIME data to the 32 bit UCHAR seconds and fraction fields in*/ -/* the NTP time message. The caller specifies which time stamp in the */ -/* NTP time message (transmit,receive, origination, or reference clock)*/ -/* and that field is converted over. */ -/* */ -/* INPUT */ -/* */ -/* time_ptr Pointer to NX_SNTP_TIME time */ -/* time_message_ptr Pointer to NTP (UCHAR) time */ -/* which_stamp Which time stamp to convert */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_PARAM_ERROR Invalid time stamp requested */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memset Clear specified area of memory */ -/* memcpy Copy data to specified area of memory*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_send_unicast_request */ -/* Create a time request and transmit it*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time_ptr, - NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp) -{ - -ULONG *buffer; - - /* Copy the buffer to the requested time stamp field. */ - switch (which_stamp) - { - - case REFERENCE_TIME: - buffer = time_message_ptr -> reference_clock_update_time_stamp; - break; - - case ORIGINATE_TIME: - buffer = time_message_ptr -> originate_time_stamp; - break; - - case RECEIVE_TIME: - buffer = time_message_ptr -> receive_time_stamp; - break; - - case TRANSMIT_TIME: - buffer = time_message_ptr -> transmit_time_stamp; - break; - - default: - /* Invalid time stamp. Return as error. */ - return NX_SNTP_PARAM_ERROR; - } - - /* Copy NX_SNTP_TIME seconds and fraction to the buffer. */ - *(buffer) = time_ptr -> seconds; - *(buffer + 1) = time_ptr -> fraction; - - /* Return successful completion. */ - return NX_SUCCESS; -} - -/* The conventional civil timescale used in most parts of the world is based on Coordinated Universal Time (UTC), - which replaced Greenwich Mean Time (GMT) many years ago. UTC is based on International Atomic Time (TAI), - which is derived from hundreds of cesium oscillators in the national standards laboratories of many regions. - Deviations of UTC from TAI are implemented in the form of leap seconds, which occur at intervals from a - few months to serveral years. */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_convert_seconds_to_date PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes the month, day, and time in an NTP time based */ -/* on the known number of seconds at 1/1/1999 since 1/1/1900 (the NTP */ -/* time epoch) and the current NTP time. The caller must indicated the */ -/* year of the NTP time to convert to simplify the computation. The data*/ -/* is written to an NX_SNTP_DATE_TIME object from which the call can */ -/* extract date and time data, or call the NetX SNTP API to display the */ -/* data/time string. */ -/* */ -/* INPUT */ -/* */ -/* current_NTP_time_ptr Pointer to NTP time */ -/* current_year Year in the NTP time data */ -/* current_date_time_ptr Pointer to date time object */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting time */ -/* NX_SNTP_UNABLE_TO_CONVERT_DATETIME Insufficient data for converting */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_convert_fraction_to_msecs */ -/* Converts the 32 bit fraction field*/ -/* in an NTP time to milliseconds */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year, - NX_SNTP_DATE_TIME *current_date_time_ptr) -{ - - /* Check if there is a base number of seconds set. */ -#if (NTP_SECONDS_AT_01011999 == 0) - - /* No, so we cannot convert time into months and years. */ - return NX_SNTP_UNABLE_TO_CONVERT_DATETIME; -#else - -UINT seconds_diff; -UINT years_diff; -UINT leapyears_diff; -UINT leaps; -UINT seconds_into_currentyear; -UINT seconds_into_currentmonth; -UINT seconds_into_currentday; -UINT seconds_into_currenthour; - - memset(current_date_time_ptr, 0, sizeof(NX_SNTP_DATE_TIME)); - - do - { - - current_date_time_ptr -> year = current_year; - - seconds_diff = current_NTP_time_ptr -> seconds - NTP_SECONDS_AT_01011999; - - years_diff = current_year - 1999; - - /* Figure out number of leap years since 1999 not including the current year. */ - leapyears_diff = (current_year - 1 - 1996) >> 2; - - /* Determine if this is a leap year. */ - leaps = (current_year - 1996) & 3; - - /* Check if this is a leap year. */ - if (leaps == 0 ) - { - /* It is! */ - current_date_time_ptr -> leap_year = NX_TRUE; - } - else - { - - /* Not a leap year. Clear the leap year flag. */ - current_date_time_ptr -> leap_year = NX_FALSE; - } - - /* Compute number of seconds into the current year e.g. as of 01/01 at midnite by subtracting - the total number of seconds since 1/1/1999 up to the end of the previous year. Remember to compute - the leapyear seconds at a different rate. */ - seconds_into_currentyear = seconds_diff - ((years_diff - leapyears_diff) * SECONDS_PER_NONLEAPYEAR) - - (leapyears_diff * SECONDS_PER_LEAPYEAR); - - current_year++; - - }while(seconds_into_currentyear > SECONDS_PER_NONLEAPYEAR); - - /* Initialize month to January till we find out what the month is. */ - current_date_time_ptr -> month = JANUARY; - - while (1) - { - - /* Does the number of seconds goes past January? */ - if (seconds_into_currentyear >= SEC_IN_JAN) - { - - /* Yes, reset month to Feb and subtract seconds in January. */ - current_date_time_ptr -> month = FEBRUARY; - seconds_into_currentyear -= SEC_IN_JAN; - } - /* No, we're done going month to month. */ - else break; - - /* Handle February differently because it is a leap month. */ - if (current_date_time_ptr -> leap_year) - { - - /* This is a leap year so Feb has 29 days. */ - if (seconds_into_currentyear >= SEC_IN_LEAPFEB) - { - current_date_time_ptr -> month = MARCH; - seconds_into_currentyear -= SEC_IN_LEAPFEB; - } - else break; - - } - else - { - /* Not a leap year, Feb has the usual 28 days. */ - if (seconds_into_currentyear >= SEC_IN_NONLEAPFEB) - { - current_date_time_ptr -> month = MARCH; - seconds_into_currentyear -= SEC_IN_NONLEAPFEB; - } - else break; - - } - - /* Repeat for each month for the rest of the year. */ - - if (seconds_into_currentyear >= SEC_IN_MAR) - { - current_date_time_ptr -> month = APRIL; - seconds_into_currentyear -= SEC_IN_MAR; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_APR) - { - current_date_time_ptr -> month = MAY; - seconds_into_currentyear -= SEC_IN_APR; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_MAY) - { - current_date_time_ptr -> month = JUNE; - seconds_into_currentyear -= SEC_IN_MAY; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_JUN) - { - current_date_time_ptr -> month = JULY; - seconds_into_currentyear -= SEC_IN_JUN; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_JUL) - { - current_date_time_ptr -> month = AUGUST; - seconds_into_currentyear -= SEC_IN_JUL; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_AUG) - { - current_date_time_ptr -> month = SEPTEMBER; - seconds_into_currentyear -= SEC_IN_AUG; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_SEP) - { - current_date_time_ptr -> month = OCTOBER; - seconds_into_currentyear -= SEC_IN_SEP; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_OCT) - { - current_date_time_ptr -> month = NOVEMBER; - seconds_into_currentyear -= SEC_IN_OCT; - } - else break; - - if (seconds_into_currentyear >= SEC_IN_NOV) - { - current_date_time_ptr -> month = DECEMBER; - seconds_into_currentyear -= SEC_IN_NOV; - } - else break; - - /* We should not have more than the seconds in december or there is an error. */ - if (seconds_into_currentyear > SEC_IN_DEC) - { - - /* Return the error status. */ - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - else break; - } - - /* Time is now in the current month. */ - seconds_into_currentmonth = seconds_into_currentyear; - - /* Compute how many complete days the time goes into the current month and - add one for the current day. */ - current_date_time_ptr -> day = seconds_into_currentmonth/SECONDS_PER_DAY + 1; - - /* Compute the number of seconds into the current day. */ - seconds_into_currentday = seconds_into_currentmonth % SECONDS_PER_DAY; - - /* Compute the number of complete hours into the current day we are. */ - current_date_time_ptr -> hour = seconds_into_currentday/SECONDS_PER_HOUR; - - /* Compute the number of seconds into the current hour. */ - seconds_into_currenthour = seconds_into_currentday % SECONDS_PER_HOUR; - - /* Break this down into minutes. */ - current_date_time_ptr -> minute = seconds_into_currenthour/SECONDS_PER_MINUTE; - - /* Finally the remainder is the seconds. */ - current_date_time_ptr -> second = seconds_into_currenthour % SECONDS_PER_MINUTE; - - /* Convert time fraction field into milliseconds. */ - _nx_sntp_client_utility_convert_fraction_to_msecs((ULONG *)(&(current_date_time_ptr -> millisecond)), current_NTP_time_ptr); - - return NX_SUCCESS; -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_utility_display_date_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking services on the display date */ -/* time service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* buffer Pointer to string buffer */ -/* length Size of the string buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_SNTP_PARAM_ERROR Invalid non pointer input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_display_date_time */ -/* Actual display date/time service */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length) -{ - -UINT status; - - - /* Check for invalid pointer input. */ - if ((client_ptr == NX_NULL) || (buffer == NX_NULL)) - { - - /* Return pointer error. */ - return NX_PTR_ERROR; - } - - /* Check for invalid parameter input. */ - if (length == 0) - { - - /* Return parameter error. */ - return NX_SNTP_PARAM_ERROR; - } - - /* Call the actual display time service. */ - status = _nx_sntp_client_utility_display_date_time(client_ptr, buffer, length); - - /* Return completion status. */ - return status; -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_request_unicast_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the service that */ -/* forwards a unicast request from the SNTP Client application. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* wait_option Time to wait for response (ticks) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if (client_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - status = _nx_sntp_client_request_unicast_time(client_ptr, wait_option); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_request_unicast_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends a unicast request regardless if the SNTP Client */ -/* is configured for unicast or broadcast mode. After sending the */ -/* request, the function waits for the specified time for a response. */ -/* */ -/* If received, the SNTP Server response is processed as it normally is*/ -/* for valid SNTP data, and applied to the SNTP Client's notion of time*/ -/* "local time". */ -/* */ -/* This will not interfere with subsequent unicast requests in unicast */ -/* mode, or the processing of periodic updates in broadcast mode. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* wait_option Time to wait for response (ticks) */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid pointer input */ -/* status Actual completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option) -{ - -UINT status; - - - /* Make sure the client is started. */ - if (!client_ptr -> nx_sntp_client_started) - { - return NX_SNTP_CLIENT_NOT_STARTED; - } - - /* Create and send a unicast request. */ - status = _nx_sntp_client_send_unicast_request(client_ptr); - - if (status != NX_SUCCESS) - { - return status; - } - - /* Wait to receive a response. */ - status = _nx_sntp_client_receive_time_update(client_ptr, wait_option); - - /* If we got a valid SNTP packet, process the data. */ - if (status == NX_SUCCESS) - { - - /* Process the server update packet and apply to local time if valid. */ - status = _nx_sntp_client_process_update_packet(client_ptr); - } - - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - /* Return completion status. */ - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_display_date_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts an NTP time data into a month-date-year time, */ -/* including seconds and second fraction string. It is intended as a */ -/* human readable representation of NTP time. The caller must supply a */ -/* pointer to a buffer large enough (40 chars is enough) to hold the */ -/* string and define the NX_SNTP_CURRENT_YEAR parameter, usually as the */ -/* current year. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* buffer Pointer to string buffer */ -/* length Size of the string buffer */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_INVALID_DATETIME_BUFFER Buffer not large enough */ -/* NX_SNTP_ERROR_CONVERTING_DATETIME Internal error converting NTP time*/ -/* status Convert seconds completion status */ -/* */ -/* CALLS */ -/* _nx_sntp_client_utility_convert_seconds_to_date */ -/* Converts seconds to year, month */ -/* _nx_sntp_client_number_to_ascii Converts number to ascii text */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length) -{ - -UINT status; -UINT offset; -UINT return_length; -NX_SNTP_DATE_TIME DisplayTime; -const CHAR *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aud", "Sep", "Oct", "Nov", "Dec"}; - - -#ifndef NX_SNTP_CURRENT_YEAR - return NX_SNTP_ERROR_CONVERTING_DATETIME; -#else - - /* Verify the client has set a local time. */ - if (client_ptr -> nx_sntp_client_local_ntp_time.seconds == 0) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - - status = _nx_sntp_client_utility_convert_seconds_to_date(&(client_ptr -> nx_sntp_client_local_ntp_time), NX_SNTP_CURRENT_YEAR, &DisplayTime); - if (status != NX_SUCCESS) - { - return status; - } - - /* Check if we have a long enough buffer. */ - if (length < 5) - { - - /* Return the error status. */ - return NX_SNTP_INVALID_DATETIME_BUFFER; - } - - /* Decrease length for terminal zero. */ - length--; - - /* Substitute numeric month to name of the month. */ - if ((DisplayTime.month < JANUARY) || (DisplayTime.month > DECEMBER)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - buffer[0] = months[DisplayTime.month - JANUARY][0]; - buffer[1] = months[DisplayTime.month - JANUARY][1]; - buffer[2] = months[DisplayTime.month - JANUARY][2]; - buffer[3] = ' '; - offset = 4; - - /* Write in the rest of the data as numeric from the Date Time objext. */ - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.day); - if ((return_length == 0) || ((length - offset) < 2)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = ','; - buffer[offset++] = ' '; - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.year); - if ((return_length == 0) || ((length - offset) < 1)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = ' '; - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.hour); - if ((return_length == 0) || ((length - offset) < 1)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = ':'; - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.minute); - if ((return_length == 0) || ((length - offset) < 1)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = ':'; - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.second); - if ((return_length == 0) || ((length - offset) < 1)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = '.'; - return_length = _nx_sntp_client_number_to_ascii(&buffer[offset], length - offset, DisplayTime.millisecond); - if ((return_length == 0) || ((length - offset) < 5)) - { - return NX_SNTP_ERROR_CONVERTING_DATETIME; - } - offset += return_length; - buffer[offset++] = ' '; - buffer[offset++] = 'U'; - buffer[offset++] = 'T'; - buffer[offset++] = 'C'; - buffer[offset++] = ' '; - buffer[offset] = '\0'; - -#endif - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_add_msecs_to_ntp_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds msecs (not necessarily a positive value and not */ -/* limited to less than a second) to an NTP time value. Msecs cannot be */ -/* added directly to the fraction field in the NTP time field because */ -/* this field is represented in fixed point notation. Arithmetic */ -/* overflow and loss of sign errors as a result of adding numbers are */ -/* handled as errors. */ -/* */ -/* INPUT */ -/* */ -/* timeA_ptr Pointer to NTP time operand */ -/* msecs_to_add Time (msecs) to add */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_OVERFLOW_ERROR Overflow result adding numbers */ -/* NX_SNTP_INVALID_TIME An invalid result (e.g. negative */ -/* time) from adding numbers */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_process_time_data Apply server time to local time */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add) -{ - -UINT status; -ULONG timeA_usec; -LONG seconds; -LONG usecs; - - - /* Separate msecs_to_add into seconds and milliseconds. */ - seconds = msecs_to_add / 1000; - usecs = (msecs_to_add % 1000) * 1000; - - /* Are we adding a positive number? */ - if (msecs_to_add > 0) - { - /* Yes; check for overflow before trying to add seconds to the TimeA operand. */ - status = _nx_sntp_client_utility_addition_overflow_check(timeA_ptr -> seconds, (ULONG)seconds); - - /* Check for error (overflow). */ - if (status != NX_SUCCESS) - { - - /* Return the error condition. */ - return status; - } - } - /* Check if a negative number larger than the timeA operand is being added (creates negative time!)*/ - else if (timeA_ptr -> seconds < (ULONG)abs(seconds)) - { - - /* Yes; return the error condition. */ - return NX_SNTP_INVALID_TIME; - } - - /* Ok to add seconds to the NTP time seconds. */ - timeA_ptr -> seconds += (ULONG)seconds; - - /* Next get the usecs from the timeA operand (always positive and < 1000000). */ - _nx_sntp_client_utility_fraction_to_usecs(timeA_ptr -> fraction, &timeA_usec); - - /* In case usecs is < 0, we might have to perform a carry. */ - if ((usecs + (LONG)timeA_usec) < 0) - { - /* Perform a carry by subtracting a second from timeA seconds...*/ - timeA_ptr -> seconds--; - - /* And adding it to the usecs of timeA. */ - timeA_usec += 1000000; - } - - /* OK to add the usecs up. */ - usecs += (LONG)timeA_usec; - - /* Check for a positive carry over into seconds. */ - if (usecs >= 1000000) - { - /* Yes there's a carry; check for possibility of overflow - before adding carry (unlikely for another 30 years). */ - if (timeA_ptr -> seconds == 0xFFFFFFFF) - { - - return NX_SNTP_OVERFLOW_ERROR; - } - - /* OK to increment the seconds. */ - timeA_ptr -> seconds++; - - /* Set milliseconds to remainder. */ - usecs = usecs % 1000000; - } - - /* Convert usecs to the fixed point notation fraction and store in TimeA fraction. */ - status = _nx_sntp_client_utility_usecs_to_fraction((ULONG)usecs, &(timeA_ptr ->fraction)); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_receiving_updates PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the get SNTP get receive */ -/* status service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP client instance */ -/* receive_status Pointer to server status */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid input status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_receiving_updates */ -/* Actual get server status service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status) -{ - -UINT status; - - /* Check for the validity of input parameter. */ - if ((client_ptr == NX_NULL) || (receive_status == NX_NULL)) - { - - /* Return error status. */ - return(NX_PTR_ERROR); - } - - status = _nx_sntp_client_receiving_updates(client_ptr, receive_status); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_receiving_updates PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the status of the Client SNTP server. If the */ -/* client has not received a valid update within the NX_SNTP_CLIENT_MAX_*/ -/* _TIME_LAPSE interval or if the number of invalid updates received by */ -/* the client exceeds the NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT limit, */ -/* the status is set to NX_FALSE. If the Client has not yet received */ -/* its first valid update from the current SNTP server, status is set to*/ -/* false. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP client instance */ -/* receive_status Pointer to receive_status */ -/* NX_FALSE: not receiving updates */ -/* NX_TRUE: receiving valid updates */ -/* */ -/* OUTPUT */ -/* */ -/* NX_PTR_ERROR Invalid input status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_mutex_get Get the SNTP mutex */ -/* tx_mutex_put Release the SNTP mutex */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *receive_status) -{ - - - /* Get the SNTP mutex. */ - tx_mutex_get(&(client_ptr -> nx_sntp_client_mutex), TX_WAIT_FOREVER); - - /* Verify the client's SNTP server is valid, and the Client has received at least one valid udpate from it. */ - *receive_status = ((client_ptr -> nx_sntp_valid_server_status == NX_TRUE) && (client_ptr -> nx_sntp_client_first_update_pending == NX_FALSE)); - - /* Release the SNTP mutex. */ - tx_mutex_put(&(client_ptr -> nx_sntp_client_mutex)); - - /* Return completion status. */ - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_set_local_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the set client local time */ -/* service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Local time seconds component */ -/* fraction Local time fraction component */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_set_local_time Actual set client local time service*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction) -{ - -UINT status; - - - /* Check for invalid input. */ - if (client_ptr == NX_NULL) - { - return NX_PTR_ERROR; - } - - /* Call the actual service. */ - status = _nx_sntp_client_set_local_time(client_ptr, seconds, fraction); - - /* Return completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_set_local_time PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function takes the seconds and fraction input from the caller */ -/* (or more accurately the independent time clock source, and applies it*/ -/* to the SNTP client local time. */ -/* */ -/* In between SNTP server updates, it is expected that the SNTP Client */ -/* host application will update the SNTP client local time from the */ -/* independent time source (e.g. real time clock on board) and then */ -/* use the SNTP Server time updates to correct the local time for drifts*/ -/* from the correct time. */ -/* */ -/* It can also set the SNTP Client's base time before starting up the */ -/* SNTP Client. If the host application cannot obtain a base time, the */ -/* SNTP Client will take the first SNTP update as the absolute time. If */ -/* the host application does have a real time clock or independent time */ -/* keeper, the SNTP client can set a large enough max adjustment that */ -/* any Server time udpate will be accepted to the SNTP Client. This */ -/* leaves the SNTP Client completely dependent on the network and SNTP */ -/* Server, plus it is vulnerable to rogue SNTP packets. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to SNTP Client */ -/* seconds Local time seconds component */ -/* fraction Local time fraction component */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction) -{ - - - client_ptr -> nx_sntp_client_local_ntp_time.seconds = seconds; - client_ptr -> nx_sntp_client_local_ntp_time.fraction = fraction; - client_ptr -> nx_sntp_client_local_ntp_time_elapsed = 0; - - /* Return completion status. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_set_time_update_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for the set time update */ -/* callback service. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* time_update_cb Pointer to callback when Client */ -/* receives an SNTP update */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_set_time_update_notify */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, - VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)) -{ - -UINT status; - - - /* Check for valid input. */ - if ((client_ptr == NX_NULL) || (time_update_cb == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_sntp_client_set_time_update_notify(client_ptr, time_update_cb); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_set_time_update_notify PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the application of a valid SNTP time update. */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to Client struct */ -/* time_update_cb Pointer to callback when Client */ -/* receives an SNTP update */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, - VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)) -{ - - - client_ptr -> nx_sntp_client_time_update_notify = time_update_cb; - - return NX_SUCCESS; -} - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_get_msec_diff PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes the difference in milliseconds between two */ -/* NTP times, receiving an NTP packet, and transmitting it back. */ -/* The logic calculates the difference in the seconds component and */ -/* converts it to milliseconds. It converts the fraction to useconds */ -/* and calculates that difference. Useconds are rounded to the nearest */ -/* millisecond. This logic assumes the transmit time occurs after */ -/* receive time. */ -/* */ -/* The net difference is the difference in milliseconds from the */ -/* fractions added to (or subtracted from) the difference in */ -/* milliseconds from the seconds component. */ -/* */ -/* Note that the conversion of useconds to milliseconds may result */ -/* in the two times' difference to be zero, when they are actually */ -/* different by useconds. */ -/* */ -/* INPUT */ -/* */ -/* timeReceived_ptr NTP time of received message */ -/* timeTransmit_ptr NTP time of transmitted message */ -/* total_difference_msecs Millseconds of difference in time */ -/* pos_diff True if Transmit Time >= */ -/* Receive Time */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Valid transmit/receive times */ -/* NX_SNTP_OVERFLOW_ERROR Overflow result */ -/* NX_SNTP_INVALID_TIME Transmit time seconds > timeTransmit_ptr -> seconds) - { - - /* Use a temporary variable to store the difference in the seconds. */ - temp = timeReceived_ptr -> seconds - timeTransmit_ptr -> seconds; - *pos_diff = NX_FALSE; - } - else - { - - /* Reverse the operand to get the absolute difference in the seconds. */ - temp = timeTransmit_ptr -> seconds -timeReceived_ptr -> seconds; - *pos_diff = NX_TRUE; - } - - /* Check for overflow when converting seconds to milliseconds - (0x3E8 = 1000). */ - if (temp > (0xFFFFFFFF / 0x3E8)) - { - - /* Return error status. */ - return NX_SNTP_OVERFLOW_ERROR; - } - - /* Convert to msecs. */ - seconds_difference_in_msecs = temp * 1000; - - /* Convert the Received time fraction to usecs and msecs. */ - _nx_sntp_client_utility_fraction_to_usecs(timeReceived_ptr -> fraction, &usecsReceived); - - msecsReceived = usecsReceived / 1000; - - if (usecsReceived % 1000 >= 500) - msecsReceived++; - - /* Convert the Transmit Time fraction to usecs and msecs. */ - _nx_sntp_client_utility_fraction_to_usecs(timeTransmit_ptr -> fraction, &usecsTransmit); - - msecsTransmit = usecsTransmit / 1000; - - if (usecsTransmit % 1000 >= 500) - msecsTransmit++; - - /* Get the difference of the two time stamps' fraction in milliseconds. */ - if (timeReceived_ptr -> seconds == timeTransmit_ptr -> seconds) - { - - /* Determine the absolute difference in the millisecond component. */ - if (usecsTransmit >= usecsReceived) - { - - *total_difference_msecs = msecsTransmit - msecsReceived; - } - else - { - - /* Transmit time usecs < Received time usecs. */ - *pos_diff = NX_FALSE; - *total_difference_msecs = msecsReceived - msecsTransmit; - } - } - else - { - - /* Consider the case where the transmit time seconds is greater. */ - if (timeTransmit_ptr -> seconds > timeReceived_ptr -> seconds) - { - - if ( usecsTransmit >= usecsReceived) - { - - /* This will add to the total milliseconds' difference. */ - *total_difference_msecs = seconds_difference_in_msecs + (msecsTransmit - msecsReceived); - } - else /* (usecsReceived > usecsTransmit) */ - { - - /* This will subtract from the total milliseconds' difference . */ - *total_difference_msecs = seconds_difference_in_msecs - (msecsReceived - msecsTransmit); - } - } - - /* Consider the case where the transmit time seconds is less. */ - else - { - - if (usecsReceived >= usecsTransmit) - { - - /* This will add to the total milliseconds' difference. */ - *total_difference_msecs = seconds_difference_in_msecs + (msecsReceived - msecsTransmit); - } - else /* (usecsTransmit > usecsReceived) */ - { - - /* This will subtract from the total milliseconds' difference . */ - *total_difference_msecs = seconds_difference_in_msecs - (msecsTransmit - msecsReceived); - } - } - } - - /* Return successful completion status. */ - return NX_SUCCESS; - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_is_zero_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function tests each byte (UCHAR) of data to be non zero. The */ -/* return value indicates if the entire data is zero. */ -/* */ -/* INPUT */ -/* */ -/* data Pointer to first byte of data */ -/* size Number of bytes in data */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TRUE Each byte of data is zero */ -/* NX_FALSE At least one byte is non zero */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_apply_sanity_checks Checks SNTP server reply validity*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size) -{ - -UINT i; -UINT is_zero; - - - /* Initialize local variables. */ - i = 0; - is_zero = NX_TRUE; - - while(i < size) - { - - if (*data != 0x0) - { - - is_zero = NX_FALSE; - break; - } - - data += sizeof(UCHAR); - i++; - } - - return is_zero; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_convert_fraction_to_msecs PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the fraction in an NTP time to milliseconds. */ -/* */ -/* INPUT */ -/* */ -/* milliseconds Pointer to milliseconds converted */ -/* time_ptr Pointer to an NTP time */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_fraction_to_usecs */ -/* Convert fraction to usecs */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_utility_display_NTP_time */ -/* Display NTP time in seconds */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr) -{ - -ULONG usecs; - - - /* Convert to usecs first. */ - _nx_sntp_client_utility_fraction_to_usecs(time_ptr ->fraction, &usecs); - - /* Then convert to milliseconds. */ - *milliseconds = usecs / 1000; - - /* Round up if greater than 500 usecs left over*/ - if (usecs % 1000 >= 500) - { - - (*milliseconds)++; - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_utility_usecs_to_fraction PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the utility to convert */ -/* microseconds to fraction. */ -/* */ -/* INPUT */ -/* */ -/* usecs Microseconds to convert */ -/* fraction Pointer to converted fraction */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_INVALID_TIME Invalid SNTP data input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_usecs_to_fraction */ -/* Actual usecs conversion service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction) -{ - -UINT status; - - - if ((usecs == 0) || (fraction == NX_NULL)) - { - - return NX_SNTP_INVALID_TIME; - } - - status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_usecs_to_fraction PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts microseconds to a time stamp fraction. It is */ -/* primarily an intermediary function used in the process of converting */ -/* millliseconds to fixed point time fraction data. */ -/* */ -/* This conversion scheme is limited to microseconds less than 1000000. */ -/* */ -/* INPUT */ -/* */ -/* usecs Microseconds to convert */ -/* fraction Fraction to converted fraction */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_OVERFLOW_ERROR Overflow error status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_utility_msecs_to_fraction */ -/* Convert milliseconds to fixed point*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction) -{ - -ULONG _frac = usecs * 3962; - - - *fraction = (usecs * 4294) + (_frac >> 12); - - if((_frac & 4095) >= 2048) - *fraction = *fraction + 1; - - /* Successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_utility_msecs_to_fraction PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the utility to convert */ -/* milliseconds to fraction. */ -/* */ -/* INPUT */ -/* */ -/* msecs Milliseconds to convert */ -/* fraction Pointer to converted fraction */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_INVALID_TIME Invalid SNTP data input */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_msecs_to_fraction */ -/* Actual msecs conversion service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction) -{ - -UINT status; - - - if ((msecs == 0) || (fraction == NX_NULL)) - { - - return NX_SNTP_INVALID_TIME; - } - - status = _nx_sntp_client_utility_msecs_to_fraction(msecs, fraction); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_msecs_to_fraction PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts milliseconds to fixed point notation used in */ -/* the NTP time fraction field. This will not accept msecs >= 1000 */ -/* because that number cannot be represented in an NTP time fraction. */ -/* */ -/* INPUT */ -/* */ -/* msecs Milliseconds to convert */ -/* fraction Pointer to converted fraction */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_SNTP_OVERFLOW_ERROR Overflow result */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_usecs_to_fraction */ -/* Convert usecs to fixed point */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ -/* Add msecs to an NTP time data */ -/* _nx_sntp_client_utility_add_NTPtime */ -/* Add two NTP time fields */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction) -{ - -UINT status; -ULONG usecs; - - - /* Check for possible overflow. */ - if (msecs > 1000) - { - - /* Return error condition. */ - return NX_SNTP_OVERFLOW_ERROR; - } - - /* Convert msecs to usecs first. */ - usecs = msecs * 1000; - - /* Convert usecs to fraction. */ - status = _nx_sntp_client_utility_usecs_to_fraction(usecs, fraction); - - /* Check for error. */ - if (status != NX_SUCCESS) - { - - /* Return the error status. */ - return status; - } - - /* Successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_sntp_client_utility_fraction_to_usecs PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking on the utility to convert */ -/* fraction to microseconds. */ -/* */ -/* INPUT */ -/* */ -/* fraction Fraction to convert */ -/* usecs Pointer to converted microseconds */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_sntp_client_utility_fraction_to_usecs */ -/* Actual usecs conversion service */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs) -{ - -UINT status; - - - if (usecs == NX_NULL) - { - return NX_SNTP_INVALID_TIME; - } - - status = _nx_sntp_client_utility_fraction_to_usecs(fraction, usecs); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_fraction_to_usecs PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a time stamp fraction to microseconds. It is */ -/* primarily an intermediary function used in the process of converting */ -/* fixed point time fraction data to msecs. */ -/* */ -/* INPUT */ -/* */ -/* fraction Fraction to convert to usecs */ -/* usecs Pointer to ucsecs from fraction */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_get_local_time_extended */ -/* Get extended local time */ -/* _nx_sntp_client_utility_convert_fraction_to_msecs */ -/* Convert time fraction to msecs */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs) -{ - -ULONG value, segment; -int i; - - value = 0; - - for(i = 2; i < 32; i+=6) - { - segment = (fraction >> i) & 0x3F; - - if((value & 0x3F) >= 32) - value = (value >> 6) + segment * 15625 + 1; - else - value = (value >> 6) + segment * 15625; - } - *usecs = value; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_convert_refID_KOD_code PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the reference ID field in a NTP time message */ -/* data to a known Kiss of Death reference_id. */ -/* */ -/* Note the Kiss of Death reference_id list is subject to change. This */ -/* is current as of 4/01/2007. */ -/* */ -/* INPUT */ -/* */ -/* reference_id Pointer to the reference ID to convert */ -/* code_id Pointer to converted code */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Copy data to specified area of memory */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code (e.g. the Client kiss of death handler callback) */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id) -{ - -/* This is the internal list of Kiss of Death codes and their meaning. */ - - - /* Compare the reference_id to each known reference_id and if it matches return the reference_id ID. */ - if (!memcmp(reference_id, ANYCAST, 4)) - { - *code_id = NX_SNTP_KOD_ANYCAST; - } - else if (!memcmp(reference_id, AUTH_FAIL, 4)) - { - *code_id = NX_SNTP_KOD_AUTH_FAIL; - } - else if (!memcmp(reference_id, AUTOKEY_FAIL, 4)) - { - *code_id = NX_SNTP_KOD_AUTOKEY_FAIL; - } - else if (!memcmp(reference_id, BROADCAST, 4)) - { - *code_id = NX_SNTP_KOD_BROADCAST; - } - else if (!memcmp(reference_id, CRYP_FAIL, 4)) - { - *code_id = NX_SNTP_KOD_CRYP_FAIL; - } - else if (!memcmp(reference_id, DENY, 4)) - { - *code_id = NX_SNTP_KOD_DENY; - } - else if (!memcmp(reference_id, DROP, 4)) - { - *code_id = NX_SNTP_KOD_DROP; - } - else if (!memcmp(reference_id, DENY_POLICY, 4)) - { - *code_id = NX_SNTP_KOD_DENY_POLICY; - } - else if (!memcmp(reference_id, NOT_INIT, 4)) - { - *code_id = NX_SNTP_KOD_NOT_INIT; - } - else if (!memcmp(reference_id, MANYCAST, 4)) - { - *code_id = NX_SNTP_KOD_MANYCAST; - } - else if (!memcmp(reference_id, NO_KEY, 4)) - { - *code_id = NX_SNTP_KOD_NO_KEY; - } - else if (!memcmp(reference_id, RATE, 4)) - { - *code_id = NX_SNTP_KOD_RATE; - } - else if (!memcmp(reference_id, RMOT, 4)) - { - *code_id = NX_SNTP_KOD_RMOT; - } - else if (!memcmp(reference_id, STEP, 4)) - { - *code_id = NX_SNTP_KOD_STEP; - } - else - { - /* Set reference_id ID to generic KOD 'other' reference_id. */ - *code_id = NX_SNTP_KISS_OF_DEATH_PACKET; - } - - /* Return successful completion. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_utility_addition_overflow_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs a simple platform independent check for */ -/* overflow when adding two operands. */ -/* */ -/* INPUT */ -/* */ -/* temp1 First addition operand */ -/* temp2 Second addition operand */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SNTP_OVERFLOW_ERROR Overflow result adding time */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_utility_add_msecs_to_ntp_time */ -/* Add msecs to an NTP time */ -/* _nx_sntp_client_utility_add_NTPtime */ -/* Add two NTP times */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2) -{ - -ULONG sum_lower_16, sum_upper_16; -UINT carry; - - - carry = 0; - - /* Add the lower 16 bits. */ - sum_lower_16 = (temp1 & NX_LOWER_16_MASK) + (temp2 & NX_LOWER_16_MASK); - - /* Check for carry. */ - if (sum_lower_16 & NX_CARRY_BIT) - { - - /* Use variable to add the carry to the upper 16 bits.*/ - carry = 1; - } - - /* Add the upper 16 bits. */ - sum_upper_16 = (temp1 >> NX_SHIFT_BY_16) + (temp2 >> NX_SHIFT_BY_16) + carry; - - /* Check for carry. */ - if (sum_upper_16 & NX_CARRY_BIT) - { - - /* This indicates an overflow. Return as an error. */ - return NX_SNTP_OVERFLOW_ERROR; - } - - /* Ok to add operands!*/ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_sntp_client_number_to_ascii PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number to ascii text. */ -/* */ -/* INPUT */ -/* */ -/* buffer_ptr Pointer to output string buffer */ -/* buffer_size Size of output buffer */ -/* number Number to convert to ASCII */ -/* */ -/* OUTPUT */ -/* */ -/* size Size of converted string */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_sntp_client_utility_display_date_time */ -/* Convert an NTP time */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_sntp_client_number_to_ascii(CHAR *buffer_ptr, UINT buffer_size, UINT number) -{ - -UINT i; -UINT digit; -UINT size; - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < buffer_size) - { - - /* Shift the current digits over one. */ - for (i = size; i != 0; i--) - { - - /* Move each digit over one place. */ - buffer_ptr[i] = buffer_ptr[i - 1]; - } - - /* Compute the next decimal digit. */ - digit = (number % 10); - - /* Update the input number. */ - number = (number / 10); - - /* Store the new digit in ASCII form. */ - if (digit < 10) - { - buffer_ptr[0] = (CHAR)(digit + '0'); - } - else - { - buffer_ptr[0] = (CHAR)((digit - 10) + 'a'); - } - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - return(0); - } - - /* Return size to caller. */ - return(size); -} \ No newline at end of file diff --git a/protocol_handlers/sntp/nxd_sntp_client.h b/protocol_handlers/sntp/nxd_sntp_client.h deleted file mode 100644 index 64612a65..00000000 --- a/protocol_handlers/sntp/nxd_sntp_client.h +++ /dev/null @@ -1,781 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX SNTP Client Component */ -/** */ -/** Simple Network Time Protocol (SNTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_sntp_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Simple Network Time Protocol (SNTP) */ -/* Client component, including all data types and external references. */ -/* It is assumed that tx_api.h, tx_port.h, nx_api.h, and nx_port.h, */ -/* have already been included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_SNTP_CLIENT_H -#define NXD_SNTP_CLIENT_H - -#include "nx_ip.h" - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - - -#define NXD_SNTP_ID 0x534E5460UL - - -/* Conversion between seconds and timer ticks. This must equal the - NetX timer tick to seconds ratio. */ - -#define NX_SNTP_MILLISECONDS_PER_TICK (1000 / NX_IP_PERIODIC_RATE) - -/* Set minimum and maximum Client unicast poll period (in seconds) for requesting - time data. RFC 4330 polling range is from 16 - 131072 seconds. - Note that the RFC 4330 strongly recommends polling intervals of at least - one minute to unnecessary reduce demand on public time servers. */ - -#define NX_SNTP_CLIENT_MIN_UNICAST_POLL_INTERVAL 64 -#define NX_SNTP_CLIENT_MAX_UNICAST_POLL_INTERVAL 131072 - -/* Define Client request types. Note that this does not limit the - NetX SNTP Client from using MANYCAST or MULTICAST discovery options. */ - -#define BROADCAST_MODE 1 -#define UNICAST_MODE 2 - -#define NX_SNTP_CLIENT_RECEIVE_EVENT ((ULONG) 0x00000001) /* Event flag to signal a receive packet event */ - -/* Define the minimum size of the packet NTP/SNTP time message - (e.g. without authentication data). */ - -#define NX_SNTP_TIME_MESSAGE_MIN_SIZE 48 - - -/* Define the maximum size of the packet NTP/SNTP time message (includes 20 bytes for - optional authentication data). */ - -#define NX_SNTP_TIME_MESSAGE_MAX_SIZE 68 - -/* Define the largest IP4 size for ip address e.g. xxx.xxx.xxx.xxx */ - -#define NX_SNTP_CLIENT_MAX_IP_ADDRESS_SIZE 15 - - - -/* Define fields in the NTP message format. */ - -#define REFERENCE_TIME 0 -#define ORIGINATE_TIME 1 -#define RECEIVE_TIME 2 -#define TRANSMIT_TIME 3 - -/* Define masks for stratum levels. */ - -#define STRATUM_KISS_OF_DEATH 0x00 -#define STRATUM_PRIMARY 0x01 -#define STRATUM_SECONDARY 0x0E /* 2 - 15 */ -#define STRATUM_RESERVED 0xF0 /* 16 - 255*/ - - -/* Kiss of death strings (see Codes below). Applicable when stratum = 0 - - Code Meaning - -------------------------------------------------------------- */ - - -#define ANYCAST "ACST" /* The association belongs to an anycast server. */ -#define AUTH_FAIL "AUTH" /* Server authentication failed. */ -#define AUTOKEY_FAIL "AUTO" /* Autokey sequence failed. */ -#define BROADCAST "BCST" /* The association belongs to a broadcast server. */ -#define CRYP_FAIL "CRYP" /* Cryptographic authentication or identification failed. */ -#define DENY "DENY" /* Access denied by remote server. */ -#define DROP "DROP" /* Lost peer in symmetric mode. */ -#define DENY_POLICY "RSTR" /* Access denied due to local policy. */ -#define NOT_INIT "INIT" /* The association has not yet synchronized for the first time. */ -#define MANYCAST "MCST" /* The association belongs to a manycast server. */ -#define NO_KEY "NKEY" /* No key found. Either the key was never installed or is not trusted. */ -#define RATE "RATE" /* Rate exceeded. The server temporarily denied access; client exceeded rate threshold. */ -#define RMOT "RMOT" /* Somebody is tinkering with association from remote host running ntpdc. OK unless they've stolen your keys. */ -#define STEP "STEP" /* A step change in system time has occurred, but association has not yet resynchronized. */ - -/* Define Kiss of Death error codes. Note: there should be a 1 : 1 correspondence of - KOD strings to KOD error codes! */ - -#define NX_SNTP_KISS_OF_DEATH_PACKET 0xF00 - -#define NX_SNTP_KOD_ANYCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x01) -#define NX_SNTP_KOD_AUTH_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x02) -#define NX_SNTP_KOD_AUTOKEY_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x03) -#define NX_SNTP_KOD_BROADCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x04) -#define NX_SNTP_KOD_CRYP_FAIL (NX_SNTP_KISS_OF_DEATH_PACKET | 0x05) -#define NX_SNTP_KOD_DENY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x06) -#define NX_SNTP_KOD_DROP (NX_SNTP_KISS_OF_DEATH_PACKET | 0x07) -#define NX_SNTP_KOD_DENY_POLICY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x08) -#define NX_SNTP_KOD_NOT_INIT (NX_SNTP_KISS_OF_DEATH_PACKET | 0x09) -#define NX_SNTP_KOD_MANYCAST (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0A) -#define NX_SNTP_KOD_NO_KEY (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0B) -#define NX_SNTP_KOD_RATE (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0C) -#define NX_SNTP_KOD_RMOT (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0D) -#define NX_SNTP_KOD_STEP (NX_SNTP_KISS_OF_DEATH_PACKET | 0x0E) - -/* Define SNTP protocol modes. SNTP is limited to primarily Client, server and broadcast modes. */ - -#define PROTOCOL_MODE_RESERVED 0 -#define PROTOCOL_MODE_SYMM_ACTIVE 1 -#define PROTOCOL_MODE_SYMM_PASSIVE 2 -#define PROTOCOL_MODE_CLIENT 3 -#define PROTOCOL_MODE_SERVER_UNICAST 4 -#define PROTOCOL_MODE_SERVER_BROADCAST 5 -#define PROTOCOL_MODE_NTP_CNTL_MSG 6 -#define PROTOCOL_MODE_PRIVATE 7 - - -/* NX SNTP Client configurable options. */ - - - -/* Set the NetX SNTP client thread stack size . */ - -#ifndef NX_SNTP_CLIENT_THREAD_STACK_SIZE -#define NX_SNTP_CLIENT_THREAD_STACK_SIZE 2048 -#endif - - -/* Set the client thread time slice. */ - -#ifndef NX_SNTP_CLIENT_THREAD_TIME_SLICE -#define NX_SNTP_CLIENT_THREAD_TIME_SLICE TX_NO_TIME_SLICE -#endif - - - -#ifndef NX_SNTP_CLIENT_THREAD_PRIORITY -#define NX_SNTP_CLIENT_THREAD_PRIORITY 2 -#endif - - -/* Set NetX SNTP client thread preemption threshold. */ - -#ifndef NX_SNTP_CLIENT_PREEMPTION_THRESHOLD -#define NX_SNTP_CLIENT_PREEMPTION_THRESHOLD NX_SNTP_CLIENT_THREAD_PRIORITY -#endif - - - -/* Configure the NetX SNTP client network parameters */ - -/* Set Client UDP socket name. */ - -#ifndef NX_SNTP_CLIENT_UDP_SOCKET_NAME -#define NX_SNTP_CLIENT_UDP_SOCKET_NAME "SNTP Client socket" -#endif - - -/* Set port for client to bind UDP socket. */ - -#ifndef NX_SNTP_CLIENT_UDP_PORT -#define NX_SNTP_CLIENT_UDP_PORT 123 -#endif - -/* Set port for client to connect to SNTP server. */ - -#ifndef NX_SNTP_SERVER_UDP_PORT -#define NX_SNTP_SERVER_UDP_PORT 123 -#endif - -/* Set Time to Live (TTL) value for transmitted UDP packets, including manycast and - multicast transmissions. The default TTL for windows operating system time - server is used. */ - -#ifndef NX_SNTP_CLIENT_TIME_TO_LIVE -#define NX_SNTP_CLIENT_TIME_TO_LIVE NX_IP_TIME_TO_LIVE -#endif - - -/* Set maximum queue depth for client socket.*/ - -#ifndef NX_SNTP_CLIENT_MAX_QUEUE_DEPTH -#define NX_SNTP_CLIENT_MAX_QUEUE_DEPTH 5 -#endif - - -/* Set the time out (timer ticks) for packet allocation from the client packet pool. */ - -#ifndef NX_SNTP_CLIENT_PACKET_TIMEOUT -#define NX_SNTP_CLIENT_PACKET_TIMEOUT (1 * NX_IP_PERIODIC_RATE) -#endif - - -/* Set the NTP/SNTP version of this NTP Client. */ - -#ifndef NX_SNTP_CLIENT_NTP_VERSION -#define NX_SNTP_CLIENT_NTP_VERSION 3 -#endif - - -/* Set minimum NTP/SNTP version the Client will accept from its time server. */ - -#ifndef NX_SNTP_CLIENT_MIN_NTP_VERSION -#define NX_SNTP_CLIENT_MIN_NTP_VERSION 3 -#endif - - - -/* Define the minimum (numerically highest) stratum the Client will - accept for a time server. Valid range is 1 - 15. */ - -#ifndef NX_SNTP_CLIENT_MIN_SERVER_STRATUM -#define NX_SNTP_CLIENT_MIN_SERVER_STRATUM 2 -#endif - - -/* Define minimum time difference (msec) between server and client time - the Client requires to change its local time. */ - -#ifndef NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT -#define NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT 10 -#endif - - -/* Define maximum time update (msec) the Client will make to its local time - per update. */ - -#ifndef NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT -#define NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT 180000 -#endif - - -/* Determine if the Client should ignore the maximum time adjustment on startup. If the - host application has a pretty accurate notion of time, this can be set to false. If not - the SNTP Client may be unable to apply the first (any) updates. */ - -#ifndef NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP -#define NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP NX_TRUE -#endif - - -/* Determine if the Client should create a random delay before starting SNTP polling. */ - -#ifndef NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP -#define NX_SNTP_CLIENT_RANDOMIZE_ON_STARTUP NX_FALSE -#endif - - -/* Set the maximum time lapse (in seconds) without a time update that can be tolerated by - the Client (application). This should be determined by application time sensitivity. - For unicast operation, the max lapse could be set to three successive poll requests - without an update. Here we set it to 2 hour based on the RFC recommendation to limit - traffic congestion. */ - -#ifndef NX_SNTP_CLIENT_MAX_TIME_LAPSE -#define NX_SNTP_CLIENT_MAX_TIME_LAPSE 7200 -#endif - - -/* Define a time out (seconds) for the SNTP Client timer. */ - -#ifndef NX_SNTP_UPDATE_TIMEOUT_INTERVAL -#define NX_SNTP_UPDATE_TIMEOUT_INTERVAL 1 -#endif - -/* Define the SNTP Client task sleep interval in timer ticks when - the SNTP CLient thread is idle. */ - -#ifndef NX_SNTP_CLIENT_SLEEP_INTERVAL -#define NX_SNTP_CLIENT_SLEEP_INTERVAL 1 -#endif - - -/* Set the unicast poll interval (in seconds) for Client time update requests. RFC 4330 - recommends a minimum polling interval of once per hour to minimize traffic congestion. */ - -#ifndef NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL -#define NX_SNTP_CLIENT_UNICAST_POLL_INTERVAL 3600 -#endif - - -/* Set the Client exponential back off rate for extending Client poll interval. - To effectively disable, set to 1. */ - -#ifndef NX_SNTP_CLIENT_EXP_BACKOFF_RATE -#define NX_SNTP_CLIENT_EXP_BACKOFF_RATE 2 -#endif - -/* Determine if the Client requires round trip calculation of SNTP messages. */ - -#ifndef NX_SNTP_CLIENT_RTT_REQUIRED -#define NX_SNTP_CLIENT_RTT_REQUIRED NX_FALSE -#endif - - -/* Define the upper limit of server clock dispersion (usec) the Client - will accept. To disable this check, set this parameter to 0x0. */ - -#ifndef NX_SNTP_CLIENT_MAX_ROOT_DISPERSION -#define NX_SNTP_CLIENT_MAX_ROOT_DISPERSION 50000 -#endif - - -/* Set the limit on consecutive bad updates from server before Client - switches to alternate server. */ - -#ifndef NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT -#define NX_SNTP_CLIENT_INVALID_UPDATE_LIMIT 3 -#endif - -/* Set size of SNTP data in bytes, not including IP and UDP header fields or authentication. */ -#define NX_SNTP_CLIENT_PACKET_DATA_SIZE 48 - -/* To display date in year/month/date format, set the current year (same year as in NTP time being evaluated) e.g 2015. - Otherwise set to zero. */ -#ifndef NX_SNTP_CURRENT_YEAR -#define NX_SNTP_CURRENT_YEAR 2015 -#endif /* NX_SNTP_CURRENT_YEAR */ - - -/* Define status levels for SNTP update processing */ - -#define UPDATE_STATUS_CONTINUE 1 -#define UPDATE_STATUS_BREAK 2 -#define UPDATE_STATUS_ERROR 3 -#define UPDATE_STATUS_SUCCESS 4 - - -/* Define the number of seconds from 01-01-1990 00:00:00 to 01-01-1999 00:00:00 (last occurrance - of a leap second) to be able to define time in year, month, date. If zero, - no date time is displayed. */ -#ifndef NTP_SECONDS_AT_01011999 -#define NTP_SECONDS_AT_01011999 0xBA368E80 -#endif /* NTP_SECONDS_AT_01011999 */ - -/* Define which epoch time is relative on the host system. */ - -#define UNIX_EPOCH 1 -#define NTP_EPOCH 2 - - - -/* Enumerate months*/ - -#define JANUARY 1 -#define FEBRUARY 2 -#define MARCH 3 -#define APRIL 4 -#define MAY 5 -#define JUNE 6 -#define JULY 7 -#define AUGUST 8 -#define SEPTEMBER 9 -#define OCTOBER 10 -#define NOVEMBER 11 -#define DECEMBER 12 - - -/* Compute seconds per month for convenience computating date and time. */ - -#define SEC_IN_JAN (31 * SECONDS_PER_DAY) -#define SEC_IN_LEAPFEB (29 * SECONDS_PER_DAY) -#define SEC_IN_NONLEAPFEB (28 * SECONDS_PER_DAY) -#define SEC_IN_MAR (31 * SECONDS_PER_DAY) -#define SEC_IN_APR (30 * SECONDS_PER_DAY) -#define SEC_IN_MAY (31 * SECONDS_PER_DAY) -#define SEC_IN_JUN (30 * SECONDS_PER_DAY) -#define SEC_IN_JUL (31 * SECONDS_PER_DAY) -#define SEC_IN_AUG (31 * SECONDS_PER_DAY) -#define SEC_IN_SEP (30 * SECONDS_PER_DAY) -#define SEC_IN_OCT (31 * SECONDS_PER_DAY) -#define SEC_IN_NOV (30 * SECONDS_PER_DAY) -#define SEC_IN_DEC (31 * SECONDS_PER_DAY) - -/* Compute seconds per year, month,day for convenience computating date and time. */ - -#define SECONDS_PER_LEAPYEAR (86400 * 366) -#define SECONDS_PER_NONLEAPYEAR (86400 * 365) -#define SECONDS_PER_DAY 86400 -#define SECONDS_PER_HOUR 3600 -#define SECONDS_PER_MINUTE 60 - - -/* Internal SNTP error processing codes. */ - -#define NX_SNTP_ERROR_CONSTANT 0xD00 - - -/* Client side errors. */ -#define NX_SNTP_CLIENT_NOT_INITIALIZED (NX_SNTP_ERROR_CONSTANT | 0x01) /* Client not properly initialized to receive time data. */ -#define NX_SNTP_OVER_LIMIT_ON_SERVERS (NX_SNTP_ERROR_CONSTANT | 0x02) /* Cannot accept server because client list has reached max # servers. */ -#define NX_SNTP_INVALID_DOMAIN (NX_SNTP_ERROR_CONSTANT | 0x03) /* Invalid domain such as bad IP format or empty string. Applicable to broadcast mode. */ -#define NX_SNTP_NO_AVAILABLE_SERVERS (NX_SNTP_ERROR_CONSTANT | 0x04) /* Client has no available time servers to contact. */ -#define NX_SNTP_INVALID_LOCAL_TIME (NX_SNTP_ERROR_CONSTANT | 0x05) /* Client local time has not been set or is invalid. */ -#define NX_SNTP_OUT_OF_DOMAIN_SERVER (NX_SNTP_ERROR_CONSTANT | 0x06) /* Broadcast server does not belong to client broadcast domain. */ -#define NX_SNTP_INVALID_DATETIME_BUFFER (NX_SNTP_ERROR_CONSTANT | 0x07) /* Insufficient or invalid buffer for writing human readable time date string. */ -#define NX_SNTP_ERROR_CONVERTING_DATETIME (NX_SNTP_ERROR_CONSTANT | 0x08) /* An internal error has occurred converting NTP time to mm-dd-yy time format. */ -#define NX_SNTP_UNABLE_TO_CONVERT_DATETIME (NX_SNTP_ERROR_CONSTANT | 0x09) /* An internal error has occurred converting NTP time to mm-dd-yy time format. */ -#define NX_SNTP_INVALID_SERVER_ADDRESS (NX_SNTP_ERROR_CONSTANT | 0x0A) /* Invalid server type e.g. IPv4 or IPv6 incompatible. */ -#define NX_SNTP_CLIENT_NOT_STARTED (NX_SNTP_ERROR_CONSTANT | 0x0B) /* SNTP Client task is not running */ -#define NX_SNTP_CLIENT_ALREADY_STARTED (NX_SNTP_ERROR_CONSTANT | 0x0C) /* SNTP Client task is already running */ -#define NX_SNTP_PARAM_ERROR (NX_SNTP_ERROR_CONSTANT | 0x0D) /* Invalid non pointer parameter. */ - - /* Server side errors */ -#define NX_SNTP_SERVER_NOT_AVAILABLE (NX_SNTP_ERROR_CONSTANT | 0x10) /* Client will not get any time update service from current server. */ -#define NX_SNTP_NO_UNICAST_FROM_SERVER (NX_SNTP_ERROR_CONSTANT | 0x11) /* Client did not receive a valid unicast response from server. */ -#define NX_SNTP_SERVER_CLOCK_NOT_SYNC (NX_SNTP_ERROR_CONSTANT | 0x12) /* Server clock not synchronized. */ -#define NX_SNTP_KOD_SERVER_NOT_AVAILABLE (NX_SNTP_ERROR_CONSTANT | 0x13) /* Server sent a KOD packet indicating service temporarily not available. */ -#define NX_SNTP_KOD_REMOVE_SERVER (NX_SNTP_ERROR_CONSTANT | 0x14) /* Server sent a KOD packet indicating service is not available to client (ever). */ -#define NX_SNTP_SERVER_AUTH_FAIL (NX_SNTP_ERROR_CONSTANT | 0x15) /* Server rejects Client packet on basis of missing or invalid authorization data. */ - -/* Bad packet and time update errors */ -#define NX_SNTP_INVALID_TIME_PACKET (NX_SNTP_ERROR_CONSTANT | 0x20) /* Invalid packet (length or data incorrect). */ -#define NX_SNTP_INVALID_NTP_VERSION (NX_SNTP_ERROR_CONSTANT | 0x21) /* Server NTP/SNTP version not incompatible with client. */ -#define NX_SNTP_INVALID_SERVER_MODE (NX_SNTP_ERROR_CONSTANT | 0x22) /* Server association invalid (out of protocol with client). */ -#define NX_SNTP_INVALID_SERVER_PORT (NX_SNTP_ERROR_CONSTANT | 0x23) /* Server port does not match what the client expects. */ -#define NX_SNTP_INVALID_IP_ADDRESS (NX_SNTP_ERROR_CONSTANT | 0x24) /* Server IP address does not match what the client expects. */ -#define NX_SNTP_INVALID_SERVER_STRATUM (NX_SNTP_ERROR_CONSTANT | 0x25) /* Server stratum is invalid or below client stratum. */ -#define NX_SNTP_BAD_SERVER_ROOT_DISPERSION (NX_SNTP_ERROR_CONSTANT | 0x26) /* Server root dispersion (clock precision) is too high or invalid value (0) reported. */ -#define NX_SNTP_OVER_INVALID_LIMIT (NX_SNTP_ERROR_CONSTANT | 0x27) /* Client over the limit on consecutive server updates with bad data received. */ -#define NX_SNTP_DUPE_SERVER_PACKET (NX_SNTP_ERROR_CONSTANT | 0x28) /* Client has received duplicate packets from server. */ -#define NX_SNTP_INVALID_TIMESTAMP (NX_SNTP_ERROR_CONSTANT | 0x29) /* Server time packet has one or more invalid time stamps in update message. */ -#define NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD (NX_SNTP_ERROR_CONSTANT | 0x2A) /* Packet payload not large enough for SNTP message. */ -#define NX_SNTP_INVALID_SNTP_PACKET (NX_SNTP_ERROR_CONSTANT | 0x2B) /* Server IP version does not match what the client expects. */ - -/* Arithmetic errors or invalid results */ -#define NX_SNTP_INVALID_TIME (NX_SNTP_ERROR_CONSTANT | 0x30) /* Invalid time resulting from arithmetic operation. */ -#define NX_SNTP_INVALID_RTT_TIME (NX_SNTP_ERROR_CONSTANT | 0x31) /* Round trip time correction to server time yields invalid time (e.g. <0). */ -#define NX_SNTP_OVERFLOW_ERROR (NX_SNTP_ERROR_CONSTANT | 0x32) /* Overflow error resulting from multiplying/adding two 32 bit (timestamp) numbers. */ -#define NX_SNTP_SIGN_ERROR (NX_SNTP_ERROR_CONSTANT | 0x33) /* Loss of sign error resulting from multiplying/adding two 32 bit (timestamp) numbers. */ - -/* Time out errors */ -#define NX_SNTP_TIMED_OUT_ON_SERVER (NX_SNTP_ERROR_CONSTANT | 0x44) /* Client did not receive update from the current server within specified timeout. */ -#define NX_SNTP_MAX_TIME_LAPSE_EXCEEDED (NX_SNTP_ERROR_CONSTANT | 0x45) /* Client has not received update from any server within the max allowed time lapse. */ - - - -/* Define the Netx Date Time structure. */ - - typedef struct NX_SNTP_DATE_TIME_STRUCT - { - UINT year; - UINT month; - UINT day; - UINT hour; - UINT minute; - UINT second; - UINT millisecond; /* This is the fraction part of the NTP time data. */ - UINT time_zone; /* NTP time is represented in Coordinated Universal Time (UTC). */ - UINT leap_year; /* Indicates if current time is in a leap year. */ - - } NX_SNTP_DATE_TIME; - - -/* Define the Netx SNTP Time structure. */ - - typedef struct NX_SNTP_TIME_STRUCT - { - ULONG seconds; /* Seconds, in the 32 bit field of an NTP time data. */ - ULONG fraction; /* Fraction of a second, in the 32 bit fraction field of an NTP time data. */ - - } NX_SNTP_TIME; - - -/* Define the NetX SNTP Time Message structure. The Client only uses the flags field and the transmit_time_stamp field - in time requests it sends to its time server. */ - - typedef struct NX_SNTP_TIME_MESSAGE_STRUCT - { - /* These are represented as 8 bit data fields in the time message format. */ - UINT flags; /* Flag containing host's NTP version, mode and leap indicator. */ - UINT peer_clock_stratum; /* Level of precision in the NTP network. Applicable only in server NTP messages. */ - UINT peer_poll_interval; /* Frequency at which an NTP host polls its NTP peer. Applicable only in server NTP messages. */ - UINT peer_clock_precision; /* Precision of the NTP server clock. Applicable only in server NTP messages. */ - - /* These are represented as 32 bit data fields in the time message format*/ - ULONG root_delay; /* Round trip time from NTP Server to primary reference source. Applicable only in server NTP messages. */ - ULONG clock_dispersion; /* Server reference clock type (but if stratum is zero, indicates server status when not able to send time updates. */ - UCHAR reference_clock_id[4]; /* Maximum error in server clock based to the clock frequency tolerance. Applicable only in server NTP messages. */ - - /* These are represented as 64 bit data fields in the time message format*/ - ULONG reference_clock_update_time_stamp[2]; /* Time at which the server clock was last set or corrected in a server time message. */ - ULONG originate_time_stamp[2]; /* Time at which the Client update request left the Client in a server time message. */ - ULONG receive_time_stamp[2]; /* Time at which the server received the Client request in a server time message. */ - ULONG transmit_time_stamp[2]; /* Time at which the server transmitted its reply to the Client in a server time message (or the time client request was sent in the client request message). */ - - /* Optional authenticator fields. */ - UCHAR KeyIdentifier[4]; /* Key Identifier and Message Digest fields contain the... */ - UCHAR MessageDigest[16]; /* ...message authentication code (MAC) information defined. */ - - /* These fields are used internally for 'convert' UCHAR data in NX_SNTP_TIME data e.g. seconds and fractions. */ - NX_SNTP_TIME reference_clock_update_time; /* Time at which the server clock was last set or corrected in a server time message. */ - NX_SNTP_TIME originate_time; /* Time at which the Client update request left the Client in a server time message. */ - NX_SNTP_TIME receive_time; /* Time at which the server received the Client request in a server time message. */ - NX_SNTP_TIME transmit_time; /* Time at which the server transmitted its reply to the Client in a server time message (or the time client request was sent in the client request message). */ - - } NX_SNTP_TIME_MESSAGE; - - -/* Define the SNTP client structure. */ - - typedef struct NX_SNTP_CLIENT_STRUCT - { - ULONG nx_sntp_client_id; /* SNTP ID for identifying the client service task. */ - NX_IP *nx_sntp_client_ip_ptr; /* Pointer to the Client IP instance. */ - UINT nx_sntp_client_interface_index; /* Index to SNTP network interface */ - NX_PACKET_POOL *nx_sntp_client_packet_pool_ptr; /* Pointer to the Client packet pool. */ - UINT nx_sntp_client_sleep_flag; /* The flag indicating the SNTP Client thread is sleeping */ - UINT nx_sntp_client_started; /* Flag indicating the SNTP Client task is running */ - TX_THREAD nx_sntp_client_thread; /* The SNTP Client processing thread */ - TX_MUTEX nx_sntp_client_mutex; /* The SNTP Client mutex for protecting access */ - UCHAR nx_sntp_client_thread_stack[NX_SNTP_CLIENT_THREAD_STACK_SIZE]; /* Stack size for SNTP client thread */ - NXD_ADDRESS nx_sntp_server_ip_address; /* Client's current time server IP address. */ - NX_UDP_SOCKET nx_sntp_client_udp_socket; /* Client UDP socket for sending and receiving time updates. */ - UINT nx_sntp_client_first_update_pending; /* First SNTP update not yet received with current server */ - UINT nx_sntp_client_time_start_wait; /* Initial time at start of receiving broadcast SNTP updates */ - UINT nx_sntp_client_sent_initial_unicast; /* Status on initial unicast transmittal for clients in broadcast mode */ - UINT nx_sntp_client_invalid_time_updates; /* Number of invalid SNTP messages received */ - UINT nx_sntp_valid_server_status; /* Server status; if receiving valid updates, status is TRUE */ - UINT nx_sntp_client_protocol_mode; /* Mode of operation, either unicast or broadcast */ - UINT nx_sntp_client_broadcast_initialized; /* Client task is ready to receive broadcast time data. */ - NXD_ADDRESS nx_sntp_broadcast_time_server; /* Client's broadcast SNTP server */ - NXD_ADDRESS nx_sntp_multicast_server_address; /* IP address Client should listen on to receive broadcasts from a multicast server. */ - UINT nx_sntp_client_unicast_initialized; /* Client task is ready to receive unicast time data. */ - NXD_ADDRESS nx_sntp_unicast_time_server; /* Client's unicast time server. */ - ULONG nx_sntp_client_unicast_poll_interval; /* Unicast interval at which client is polling the time server. */ - UINT nx_sntp_client_backoff_count; /* Count of times the back off rate has been applied to the poll interval */ - TX_TIMER nx_sntp_update_timer; /* SNTP update timer; expires when no data received for specified time lapse. */ - ULONG nx_sntp_update_time_remaining; /* Time (in seconds) remaining that the Client task can continue running without receiving a valid update. */ - LONG nx_sntp_client_roundtrip_time_msec; /* Round trip time (msec) for a packet to travel to server and back to client. Does not include server processing time. */ - ULONG nx_sntp_client_local_ntp_time_elapsed; /* Seconds elapsed since local time is updated last time. */ - NX_SNTP_TIME_MESSAGE nx_sntp_current_server_time_message; /* Time update which the Client has just received from its server. */ - NX_SNTP_TIME_MESSAGE nx_sntp_current_time_message_request; /* Client request to send to its time server. */ - NX_SNTP_TIME_MESSAGE nx_sntp_previous_server_time_message; /* Previous valid time update received from the Client time server. */ - NX_SNTP_TIME nx_sntp_client_local_ntp_time; /* Client's notion of local time. */ - NX_SNTP_TIME nx_sntp_server_update_time; /* Time (based on client local time) when the server update was received in response to the current request. */ - UINT (*apply_custom_sanity_checks)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, NX_SNTP_TIME_MESSAGE *client_time_msg_ptr, NX_SNTP_TIME_MESSAGE *server_time_msg_ptr); - /* Pointer to callback service for performing additional sanity checks on received time data. */ - UINT (*leap_second_handler)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, UINT indicator); - /* Pointer to callback service for handling an impending leap second. */ - UINT (*kiss_of_death_handler)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, UINT code); - /* Pointer to callback service for handling kiss of death packets received from server. */ - VOID (*random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand); - /* Pointer to callback service for random number generator. */ - - VOID (*nx_sntp_client_time_update_notify)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time); - - } NX_SNTP_CLIENT; - - -#ifndef NX_SNTP_SOURCE_CODE - -/* Define the system API mappings based on the error checking selected by the user. */ - - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - - -#ifdef NX_SNTP_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_sntp_client_create _nx_sntp_client_create -#define nx_sntp_client_delete _nx_sntp_client_delete -#define nx_sntp_client_get_local_time _nx_sntp_client_get_local_time -#define nx_sntp_client_get_local_time_extended _nx_sntp_client_get_local_time_extended -#define nxd_sntp_client_initialize_broadcast _nxd_sntp_client_initialize_broadcast -#define nxd_sntp_client_initialize_unicast _nxd_sntp_client_initialize_unicast -#define nx_sntp_client_initialize_broadcast _nx_sntp_client_initialize_broadcast -#define nx_sntp_client_initialize_unicast _nx_sntp_client_initialize_unicast -#define nx_sntp_client_receiving_updates _nx_sntp_client_receiving_updates -#define nx_sntp_client_run_broadcast _nx_sntp_client_run_broadcast -#define nx_sntp_client_run_unicast _nx_sntp_client_run_unicast -#define nx_sntp_client_set_local_time _nx_sntp_client_set_local_time -#define nx_sntp_client_stop _nx_sntp_client_stop -#define nx_sntp_client_utility_msecs_to_fraction _nx_sntp_client_utility_msecs_to_fraction -#define nx_sntp_client_utility_usecs_to_fraction _nx_sntp_client_utility_usecs_to_fraction -#define nx_sntp_client_utility_fraction_to_usecs _nx_sntp_client_utility_fraction_to_usecs -#define nx_sntp_client_utility_display_date_time _nx_sntp_client_utility_display_date_time -#define nx_sntp_client_request_unicast_time _nx_sntp_client_request_unicast_time -#define nx_sntp_client_set_time_update_notify _nx_sntp_client_set_time_update_notify - -#else - -/* Services with error checking. */ - -#define nx_sntp_client_create _nxe_sntp_client_create -#define nx_sntp_client_delete _nxe_sntp_client_delete -#define nx_sntp_client_get_local_time _nxe_sntp_client_get_local_time -#define nx_sntp_client_get_local_time_extended _nxe_sntp_client_get_local_time_extended -#define nxd_sntp_client_initialize_broadcast _nxde_sntp_client_initialize_broadcast -#define nxd_sntp_client_initialize_unicast _nxde_sntp_client_initialize_unicast -#define nx_sntp_client_initialize_broadcast _nxe_sntp_client_initialize_broadcast -#define nx_sntp_client_initialize_unicast _nxe_sntp_client_initialize_unicast -#define nx_sntp_client_receiving_updates _nxe_sntp_client_receiving_updates -#define nx_sntp_client_run_broadcast _nxe_sntp_client_run_broadcast -#define nx_sntp_client_run_unicast _nxe_sntp_client_run_unicast -#define nx_sntp_client_set_local_time _nxe_sntp_client_set_local_time -#define nx_sntp_client_stop _nxe_sntp_client_stop -#define nx_sntp_client_utility_msecs_to_fraction _nxe_sntp_client_utility_msecs_to_fraction -#define nx_sntp_client_utility_usecs_to_fraction _nxe_sntp_client_utility_usecs_to_fraction -#define nx_sntp_client_utility_fraction_to_usecs _nxe_sntp_client_utility_fraction_to_usecs -#define nx_sntp_client_utility_display_date_time _nxe_sntp_client_utility_display_date_time -#define nx_sntp_client_request_unicast_time _nxe_sntp_client_request_unicast_time -#define nx_sntp_client_set_time_update_notify _nxe_sntp_client_set_time_update_notify - -#endif /* NX_SNTP_DISABLE_ERROR_CHECKING */ - - -/* Define the prototypes accessible to the application software. */ - -UINT nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, - UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), - UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), - VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); -UINT nx_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); -UINT nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); -UINT nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); -UINT nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); -UINT nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); -UINT nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); -UINT nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); -UINT nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); -UINT nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); -UINT nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); -UINT nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); -UINT nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); -UINT nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); -UINT nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); -UINT nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); -UINT nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); -UINT nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); -UINT nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); - -#else /* NX_SNTP_SOURCE_CODE */ - - -/* SNTP source code is being compiled, do not perform any API mapping. */ - -UINT _nx_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, - UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), - UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), - VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); -UINT _nxe_sntp_client_create(NX_SNTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT iface_index, NX_PACKET_POOL *packet_pool_ptr, - UINT (*leap_second_handler)(NX_SNTP_CLIENT *client_ptr, UINT indicator), - UINT (*kiss_of_death_handler)(NX_SNTP_CLIENT *client_ptr, UINT code), - VOID (random_number_generator)(struct NX_SNTP_CLIENT_STRUCT *client_ptr, ULONG *rand)); -UINT _nx_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); -UINT _nxe_sntp_client_delete (NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); -UINT _nxe_sntp_client_get_local_time(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer); -UINT _nx_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); -UINT _nxe_sntp_client_get_local_time_extended(NX_SNTP_CLIENT *client_ptr, ULONG *seconds, ULONG *fraction, CHAR *buffer, UINT buffer_size); -UINT _nxde_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); -UINT _nxd_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *multicast_server_address, NXD_ADDRESS *broadcast_time_server); -UINT _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); -UINT _nxe_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_time_server); -UINT _nxde_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); -UINT _nxd_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, NXD_ADDRESS *unicast_time_server); -UINT _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); -UINT _nxe_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG unicast_time_server); -UINT _nx_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); -UINT _nxe_sntp_client_receiving_updates(NX_SNTP_CLIENT *client_ptr, UINT *server_status); -UINT _nx_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); -UINT _nxe_sntp_client_run_broadcast(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); -UINT _nxe_sntp_client_run_unicast(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); -UINT _nxe_sntp_client_set_local_time(NX_SNTP_CLIENT *client_ptr, ULONG seconds, ULONG fraction); -UINT _nx_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); -UINT _nxe_sntp_client_stop(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); -UINT _nxe_sntp_client_utility_msecs_to_fraction(ULONG msecs, ULONG *fraction); -UINT _nx_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); -UINT _nxe_sntp_client_utility_usecs_to_fraction(ULONG usecs, ULONG *fraction); -UINT _nx_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); -UINT _nxe_sntp_client_utility_fraction_to_usecs(ULONG fraction, ULONG *usecs); -UINT _nx_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); -UINT _nxe_sntp_client_utility_display_date_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer, UINT length); -UINT _nxe_sntp_client_utility_display_NTP_time(NX_SNTP_CLIENT *client_ptr, CHAR *buffer); -UINT _nx_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); -UINT _nxe_sntp_client_request_unicast_time(NX_SNTP_CLIENT *client_ptr, UINT wait_option); -UINT _nx_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); -UINT _nxe_sntp_client_set_time_update_notify(NX_SNTP_CLIENT *client_ptr, VOID (time_update_cb)(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time)); - -/* Define internal SNTP Client functions. */ - -UINT _nx_sntp_client_apply_sanity_checks(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_calculate_roundtrip(LONG *roundtrip_time); -UINT _nx_sntp_client_check_server_clock_dispersion(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_create_time_request_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_SNTP_TIME_MESSAGE *time_message_ptr); -UINT _nx_sntp_client_duplicate_update_check(NX_SNTP_TIME_MESSAGE *timeA_msg_ptr, NX_SNTP_TIME_MESSAGE *timeB_msg_ptr, UINT *is_a_dupe); -UINT _nx_sntp_client_extract_time_message_from_packet(NX_SNTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); -VOID _nx_sntp_client_process(NX_SNTP_CLIENT *client_ptr); -VOID _nx_sntp_client_process_broadcast(NX_SNTP_CLIENT *client_ptr); -VOID _nx_sntp_client_process_unicast(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_process_time_data(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_process_update_packet(NX_SNTP_CLIENT *client_ptr); -VOID _nx_sntp_client_receive_notify(NX_UDP_SOCKET *socket_ptr); -UINT _nx_sntp_client_receive_time_update(NX_SNTP_CLIENT *client_ptr, ULONG timeout); -UINT _nx_sntp_client_reset_current_time_message(NX_SNTP_CLIENT *client_ptr); -UINT _nx_sntp_client_send_unicast_request(NX_SNTP_CLIENT *client_ptr); -VOID _nx_sntp_client_thread_entry(ULONG sntp_instance); -VOID _nx_sntp_client_update_timeout_entry(ULONG info); -UINT _nx_sntp_client_utility_add_msecs_to_ntp_time(NX_SNTP_TIME *timeA_ptr, LONG msecs_to_add); -UINT _nx_sntp_client_utility_convert_fraction_to_msecs(ULONG *milliseconds, NX_SNTP_TIME *time_ptr); -UINT _nx_sntp_client_utility_convert_seconds_to_date(NX_SNTP_TIME *current_NTP_time_ptr, UINT current_year, NX_SNTP_DATE_TIME *current_date_time_ptr); -UINT _nx_sntp_client_utility_convert_refID_KOD_code(UCHAR *reference_id, UINT *code_id); -UINT _nx_sntp_client_utility_get_msec_diff(NX_SNTP_TIME *timeA_ptr, NX_SNTP_TIME *timeB_ptr, ULONG *total_difference_msecs, UINT *pos_diff); -UINT _nx_sntp_client_utility_addition_overflow_check(ULONG temp1, ULONG temp2); -UINT _nx_sntp_client_utility_convert_time_to_UCHAR(NX_SNTP_TIME *time, NX_SNTP_TIME_MESSAGE *time_message_ptr, UINT which_stamp); -UINT _nx_sntp_client_utility_is_zero_data(UCHAR *data, UINT size); - - - -#endif /* NX_SNTP_SOURCE_CODE */ - -/* If a C++ compiler is being used....*/ -#ifdef __cplusplus -} -#endif - - -#endif /* NXD_SNTP_CLIENT_H */ diff --git a/protocol_handlers/telnet/nxd_telnet_client.c b/protocol_handlers/telnet/nxd_telnet_client.c deleted file mode 100644 index c85a76c2..00000000 --- a/protocol_handlers/telnet/nxd_telnet_client.c +++ /dev/null @@ -1,961 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** TELNET Client Protocol */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_TELNET_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_telnet_client.h" - - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_telnet_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client connect call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* server_ip TELNET server IPv6 address */ -/* server_port Server TCP port (usually 23) */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxde_telnet_client_connect Actual client connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, - UINT server_port, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (!server_ip_address)) - { - return(NX_PTR_ERROR); - } - - /* Check for invalid non pointer input. */ - if (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) - { - return NX_TELNET_INVALID_PARAMETER; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client connect function. */ - status = _nxd_telnet_client_connect(client_ptr, server_ip_address, server_port, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_telnet_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a previously created TELNET instance with */ -/* the TCP port at the specified address. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* server_ip_address TELNET server address */ -/* server_port Server TCP port (usually 23) */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nxd_tcp_client_socket_connect Connect to TELNET server */ -/* nx_tcp_client_socket_bind Bind client socket to port */ -/* nx_tcp_client_socket_unbind Unbind client socket from port*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, NXD_ADDRESS *server_ip_address, - UINT server_port, ULONG wait_option) - -{ - -UINT status; - - - /* Determine if the client is still in a not connected state. */ - if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state != NX_TCP_CLOSED) - { - - /* Already connected, return an error. */ - return(NX_TELNET_NOT_DISCONNECTED); - } - - /* Bind the client control socket. */ - status = nx_tcp_client_socket_bind(&(client_ptr -> nx_telnet_client_socket), NX_ANY_PORT, wait_option); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Unable to bind socket to port. */ - return(status); - } - - /* Connect the socket to the TELNET server using the 'duo' (support IPv4 and IPv6 addresses types) - tcp connect service. */ - status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_telnet_client_socket), - server_ip_address, server_port, wait_option); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Unbind the socket. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_telnet_client_socket)); - - /* Unable to connect socket to server TELNET control port. */ - return(status); - } - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client connect call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* server_ip TELNET server IP address */ -/* server_port Server TCP port (usually 23) */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_telnet_client_connect Actual client connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip, UINT server_port, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid server IP address. */ - if (server_ip == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client connect function. */ - status = _nx_telnet_client_connect(client_ptr, server_ip, server_port, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(server_ip); - NX_PARAMETER_NOT_USED(server_port); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts the IPv4 address to a NetX Duo NXD_ADDRESS */ -/* data and forwarded to the NetX Duo Telnet connect function, */ -/* nxd_telnet_client_connect to connect a previously created TELNET */ -/* instance with the TCP port at the specified IPv4 address. */ -/* */ -/* This serves primarily as a wrapper function for backward */ -/* compatibility with NetX Telnet applications. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* server_ip_address TELNET server IPv4 address */ -/* server_port Server TCP port (usually 23) */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nxd_tcp_client_socket_connect Connect to TELNET server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, - UINT server_port, ULONG wait_option) -{ -#ifndef NX_DISABLE_IPV4 -NXD_ADDRESS server_ipduo_address; - - /* Construct an IP address structure, and fill in IPv4 address information. */ - server_ipduo_address.nxd_ip_version = NX_IP_VERSION_V4; - server_ipduo_address.nxd_ip_address.v4 = server_ip_address; - - /* Invoke the real connection call. */ - return (_nxd_telnet_client_connect(client_ptr, &server_ipduo_address, server_port, wait_option)); -#else - NX_PARAMETER_NOT_USED(client_ptr); - NX_PARAMETER_NOT_USED(server_ip_address); - NX_PARAMETER_NOT_USED(server_port); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* client_name Name of this TELNET client */ -/* ip_ptr Pointer to IP instance */ -/* window_size Size of TCP receive window */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id == NX_TELNET_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Call actual client create function. */ - status = _nx_telnet_client_create(client_ptr, client_name, ip_ptr, window_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an TELNET client instance. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* client_name Name of this TELNET client */ -/* ip_ptr Pointer to IP instance */ -/* window_size Size of TCP receive window */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size) -{ - -UINT status; - - - /* Clear the client TELNET control block. */ - memset((void *) client_ptr, 0, sizeof(NX_TELNET_CLIENT)); - - /* Create the TCP control socket. */ - status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_telnet_client_socket), client_name, - NX_TELNET_TOS, NX_TELNET_FRAGMENT_OPTION, NX_TELNET_TIME_TO_LIVE, window_size, - NX_NULL, NX_NULL); - - /* Check for an error. */ - if (status) - { - - /* Return an error. */ - return(NX_TELNET_ERROR); - } - - /* Save off the remaining information. */ - - /* Save the client name. */ - client_ptr -> nx_telnet_client_name = client_name; - - /* Save the IP pointer. */ - client_ptr -> nx_telnet_client_ip_ptr = ip_ptr; - - /* Set the TELNET client id. */ - client_ptr -> nx_telnet_client_id = NX_TELNET_CLIENT_ID; - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_client_delete Actual client delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_delete(NX_TELNET_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nx_telnet_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created TELNET client instance. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_delete Delete TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr) -{ - - /* Determine if the client is still in an established state. */ - if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state == NX_TCP_ESTABLISHED) - { - - /* Still connected, return an error. */ - return(NX_TELNET_NOT_DISCONNECTED); - } - - /* Delete the socket. */ - nx_tcp_socket_delete(&(client_ptr -> nx_telnet_client_socket)); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client disconnect. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_client_disconnect Actual client disconnect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client disconnect function. */ - status = _nx_telnet_client_disconnect(client_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function disconnects a previously established TELNET */ -/* connection. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_client_socket_unbind Unbind a socket */ -/* nx_tcp_socket_disconnect Disconnect a socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option) -{ - - - /* Determine if the client is still in an established state. */ - if (client_ptr -> nx_telnet_client_socket.nx_tcp_socket_state != NX_TCP_ESTABLISHED) - { - - /* Not connected, return an error. */ - return(NX_TELNET_NOT_CONNECTED); - } - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_telnet_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_telnet_client_socket)); - - /* Return success to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client packet */ -/* receive call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* packet_ptr Destination for packet ptr */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_client_packet_receive Actual client packet receive */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client packet receive function. */ - status = _nx_telnet_client_packet_receive(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_packet_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client packet */ -/* receive call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* packet_ptr Destination for packet ptr */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_receive Receive TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - /* Attempt to receive a packet from the TCP socket. */ - status = nx_tcp_socket_receive(&(client_ptr -> nx_telnet_client_socket), packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_client_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client packet */ -/* send call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* packet_ptr Pointer to packet to send */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_client_packet_send Actual client packet send */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_telnet_client_id != NX_TELNET_CLIENT_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client packet send function. */ - status = _nx_telnet_client_packet_send(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_client_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET client packet */ -/* send call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to TELNET client */ -/* packet_ptr Pointer to packet to send */ -/* wait_option Specifies how long to wait */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_send Send TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - - /* Attempt to send a packet on the TCP socket. */ - status = nx_tcp_socket_send(&(client_ptr -> nx_telnet_client_socket), packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} diff --git a/protocol_handlers/telnet/nxd_telnet_client.h b/protocol_handlers/telnet/nxd_telnet_client.h deleted file mode 100644 index 6a4390bd..00000000 --- a/protocol_handlers/telnet/nxd_telnet_client.h +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** TELNET Client Protocol */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_telnet_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Duo TELNET Protocol for Clients, */ -/* including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_TELNET_CLIENT_H -#define NXD_TELNET_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the TELNET ID. */ - -#define NX_TELNET_CLIENT_ID 0x54454C4DUL - - - -/* Define TELNET TCP socket create options. */ - -#ifndef NX_TELNET_TOS -#define NX_TELNET_TOS NX_IP_NORMAL -#endif - -#ifndef NX_TELNET_FRAGMENT_OPTION -#define NX_TELNET_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - - -#ifndef NX_TELNET_TIME_TO_LIVE -#define NX_TELNET_TIME_TO_LIVE 0x80 -#endif - - -/* Define the TELNET Server TCP port number. */ -#ifndef NX_TELNET_SERVER_PORT -#define NX_TELNET_SERVER_PORT 23 /* Default Port for TELNET server */ -#endif - -/* Define return code constants. */ - -#define NX_TELNET_ERROR 0xF0 /* TELNET internal error */ -#define NX_TELNET_TIMEOUT 0xF1 /* TELNET timeout occurred */ -#define NX_TELNET_FAILED 0xF2 /* TELNET error */ -#define NX_TELNET_NOT_CONNECTED 0xF3 /* TELNET not connected error */ -#define NX_TELNET_NOT_DISCONNECTED 0xF4 /* TELNET not disconnected error */ -#define NX_TELNET_INVALID_PARAMETER 0xF5 /* Invalid non pointer input to Telnet function */ - - -/* Define the TELNET Client structure. */ - -typedef struct NX_TELNET_CLIENT_STRUCT -{ - ULONG nx_telnet_client_id; /* TELNET Client ID */ - CHAR *nx_telnet_client_name; /* Name of this TELNET client */ - NX_IP *nx_telnet_client_ip_ptr; /* Pointer to associated IP structure */ - NX_TCP_SOCKET nx_telnet_client_socket; /* Client TELNET socket */ -} NX_TELNET_CLIENT; - - -#ifndef NX_TELNET_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nxd_telnet_client_connect _nxd_telnet_client_connect -#define nx_telnet_client_connect _nx_telnet_client_connect -#define nx_telnet_client_create _nx_telnet_client_create -#define nx_telnet_client_delete _nx_telnet_client_delete -#define nx_telnet_client_disconnect _nx_telnet_client_disconnect -#define nx_telnet_client_packet_receive _nx_telnet_client_packet_receive -#define nx_telnet_client_packet_send _nx_telnet_client_packet_send - -#else - -/* Services with error checking. */ - -#define nxd_telnet_client_connect _nxde_telnet_client_connect -#define nx_telnet_client_connect _nxe_telnet_client_connect -#define nx_telnet_client_create _nxe_telnet_client_create -#define nx_telnet_client_delete _nxe_telnet_client_delete -#define nx_telnet_client_disconnect _nxe_telnet_client_disconnect -#define nx_telnet_client_packet_receive _nxe_telnet_client_packet_receive -#define nx_telnet_client_packet_send _nxe_telnet_client_packet_send -#define nx_telnet_server_create _nxe_telnet_server_create - -#endif - -/* Define the prototypes accessible to the application software. */ -UINT nxd_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); -UINT nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); -UINT nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); -UINT nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); -UINT nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); -UINT nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); - - -#else - -/* TELNET source code is being compiled, do not perform any API mapping. */ -UINT _nxde_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); -UINT _nxd_telnet_client_connect(NX_TELNET_CLIENT *my_client, NXD_ADDRESS *server_ip_address, UINT server_port, ULONG wait_option); - -UINT _nxe_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); -UINT _nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG server_ip_address, UINT server_port, ULONG wait_option); -UINT _nxe_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); -UINT _nx_telnet_client_create(NX_TELNET_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, ULONG window_size); -UINT _nxe_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); -UINT _nx_telnet_client_delete(NX_TELNET_CLIENT *client_ptr); -UINT _nxe_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); -UINT _nx_telnet_client_disconnect(NX_TELNET_CLIENT *client_ptr, ULONG wait_option); -UINT _nxe_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_telnet_client_packet_receive(NX_TELNET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_telnet_client_packet_send(NX_TELNET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); - - -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_TELNET_CLIENT_H */ diff --git a/protocol_handlers/telnet/nxd_telnet_server.c b/protocol_handlers/telnet/nxd_telnet_server.c deleted file mode 100644 index 22cc65f4..00000000 --- a/protocol_handlers/telnet/nxd_telnet_server.c +++ /dev/null @@ -1,2565 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** TELNET Protocol (TELNET) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_TELNET_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_telnet_server.h" -#include "stdio.h" -#include "string.h" - - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* server_name Name of TELNET server */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* new_connection Pointer to user's new */ -/* connection function */ -/* receive_data Pointer to user's receive */ -/* data function */ -/* connection_end Pointer to user's end of */ -/* connection function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), - void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), - void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id == NX_TELNET_SERVER_ID) || - (stack_ptr == NX_NULL) || (new_connection == NX_NULL) || (receive_data == NX_NULL) || (connection_end == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server create function. */ - status = _nx_telnet_server_create(server_ptr, server_name, ip_ptr, stack_ptr, stack_size, new_connection, receive_data, connection_end); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a TELNET server on the specified IP. In doing */ -/* so this function creates a TCP socket for subsequent TELNET */ -/* transfers and a thread for the TELNET server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* server_name Name of TELNET server */ -/* ip_ptr Pointer to IP instance */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* new_connection Pointer to user's new */ -/* connection function */ -/* receive_data Pointer to user's receive */ -/* data function */ -/* connection_end Pointer to user's end of */ -/* connection function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create sockets */ -/* nx_tcp_socket_delete Delete sockets */ -/* nx_tcp_socket_receive_notify Register receive notify */ -/* callback */ -/* tx_event_flags_create Create event flags */ -/* tx_event_flags_delete Delete event flags */ -/* tx_thread_create Create TELNET server thread */ -/* tx_thread_delete Delete TELNET server thread */ -/* tx_timer_create Create TELNET server timer */ -/* tx_timer_delete Delete TELNET server timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), - void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), - void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)) -{ - -UINT i; -UINT status; - - /* Clear the TELNET server structure. */ - memset((void *) server_ptr, 0, sizeof(NX_TELNET_SERVER)); - - /* Create the TELNET Server thread. */ - status = tx_thread_create(&(server_ptr -> nx_telnet_server_thread), "TELNET Server Thread", - _nx_telnet_server_thread_entry, (ULONG) server_ptr, stack_ptr, - stack_size, NX_TELNET_SERVER_PRIORITY, NX_TELNET_SERVER_PRIORITY, - TX_NO_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred creating the thread. */ - if (status != TX_SUCCESS) - { - - /* Error creating the server thread. */ - return(status); - } - - /* Create the ThreadX event flags. These will be used to driver the TELNET server thread. */ - status = tx_event_flags_create(&(server_ptr -> nx_telnet_server_event_flags), "TELNET Server Thread Events"); - - /* Determine if an error occurred creating the event flags. */ - if (status != TX_SUCCESS) - { - - /* Delete the server thread. */ - tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); - - /* Error creating the server event flags. */ - return(status); - } - - /* Create the ThreadX activity timeout timer. This will be used to periodically check to see if - a client connection has gone silent and needs to be terminated. */ - status = tx_timer_create(&(server_ptr -> nx_telnet_server_timer), "TELNET Server Timer", - _nx_telnet_server_timeout, (ULONG) server_ptr, - (NX_IP_PERIODIC_RATE * NX_TELNET_TIMEOUT_PERIOD), - (NX_IP_PERIODIC_RATE * NX_TELNET_TIMEOUT_PERIOD), TX_NO_ACTIVATE); - - /* Determine if an error occurred creating the timer. */ - if (status != TX_SUCCESS) - { - - /* Delete the server thread. */ - tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); - - /* Delete the server event flags. */ - tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); - - /* Error creating the server timer. */ - return(status); - } - - /* Loop to create all the TELNET client sockets. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Setup the logical index for this client request structure. */ - server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_connection = i; - - /* Create an TELNET client socket. */ - status += nx_tcp_socket_create(ip_ptr, &(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket), "TELNET Server Control Socket", - NX_TELNET_TOS, NX_TELNET_FRAGMENT_OPTION, NX_TELNET_TIME_TO_LIVE, NX_TELNET_SERVER_WINDOW_SIZE, NX_NULL, _nx_telnet_server_disconnect_present); - - /* If no error is present, register the receive notify function. */ - if (status == NX_SUCCESS) - { - - /* Register the receive function. */ - nx_tcp_socket_receive_notify(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket), - _nx_telnet_server_data_present); - } - - /* Make sure each socket points to the TELNET server. */ - server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket.nx_tcp_socket_reserved_ptr = server_ptr; - } - - /* Determine if an error has occurred. */ - if (status != NX_SUCCESS) - { - - /* Loop to delete any created sockets. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Delete the TELNET socket. */ - nx_tcp_socket_delete(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket)); - } - - /* Delete the server thread. */ - tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); - - /* Delete the timer. */ - tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); - - /* Return the NetX error. */ - return(status); - } - - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - -#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL - - /* Create the packet pool for negotiating telnet options, and check the status */ - status = nx_packet_pool_create(&(server_ptr -> nx_telnet_server_packet_pool), "Telnet Server Options", - NX_TELNET_SERVER_PACKET_PAYLOAD, &server_ptr -> nx_telnet_server_pool_area, - NX_TELNET_SERVER_PACKET_POOL_SIZE); - - /* Determine if it was successful. */ - if (status != NX_SUCCESS) - { - /* Loop to delete any created sockets. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Delete the TELNET socket. */ - nx_tcp_socket_delete(&(server_ptr -> nx_telnet_server_client_list[i].nx_telnet_client_request_socket)); - } - - /* Delete the server thread. */ - tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); - - /* Delete the timer. */ - tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); - - /* No, return error status. */ - return(status); - } - - server_ptr -> nx_telnet_server_packet_pool_ptr = &(server_ptr -> nx_telnet_server_packet_pool); -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - - /* Save the Server name. */ - server_ptr -> nx_telnet_server_name = server_name; - - /* Save the IP pointer address. */ - server_ptr -> nx_telnet_server_ip_ptr = ip_ptr; - - /* Save the user-supplied new connection and receive data functions. */ - server_ptr -> nx_telnet_new_connection = new_connection; - server_ptr -> nx_telnet_receive_data = receive_data; - server_ptr -> nx_telnet_connection_end = connection_end; - - /* Set the server ID to indicate the TELNET server thread is ready. */ - server_ptr -> nx_telnet_server_id = NX_TELNET_SERVER_ID; - - server_ptr -> nx_telnet_server_open_connections = 0; - - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_delete Actual server delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_delete(NX_TELNET_SERVER *server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_telnet_server_delete(server_ptr); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created TELNET server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_unaccept Unaccept server socket */ -/* nx_tcp_server_socket_unlisten Unlisten on server */ -/* nx_tcp_socket_delete Delete socket */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* tx_event_flags_delete Delete event flags */ -/* tx_thread_delete Delete thread */ -/* tx_thread_suspend Suspend thread */ -/* tx_thread_terminate Terminate thread */ -/* tx_timer_deactivate Deactivate timer */ -/* tx_timer_delete Delete timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr) -{ - -UINT i; -NX_TELNET_CLIENT_REQUEST *client_request_ptr; - - - /* Clear the server ID to indicate the TELNET server is no longer ready. */ - server_ptr -> nx_telnet_server_id = 0; - - /* Suspend the TELNET server thread. */ - tx_thread_suspend(&(server_ptr -> nx_telnet_server_thread)); - - /* Terminate server thread. */ - tx_thread_terminate(&(server_ptr -> nx_telnet_server_thread)); - - /* Delete server thread. */ - tx_thread_delete(&(server_ptr -> nx_telnet_server_thread)); - - /* Delete the event flag group. */ - tx_event_flags_delete(&(server_ptr -> nx_telnet_server_event_flags)); - - /* Deactivate and delete timer. */ - tx_timer_deactivate(&(server_ptr -> nx_telnet_server_timer)); - tx_timer_delete(&(server_ptr -> nx_telnet_server_timer)); - - /* If the Telnet Server is configured to send options and the packet - pool is created by the internally (by the Telnet server task) - we need to delete it. */ -#ifndef NX_TELNET_SERVER_OPTION_DISABLE -#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL - nx_packet_pool_delete(&server_ptr -> nx_telnet_server_packet_pool); -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - - /* Walk through the server structure to close and delete any open sockets. */ - i = 0; - client_request_ptr = &(server_ptr -> nx_telnet_server_client_list[0]); - while (i < NX_TELNET_MAX_CLIENTS) - { - - /* Disconnect the socket. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); - - /* Unaccept the socket. */ - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_telnet_client_request_socket)); - - /* Delete the socket. */ - nx_tcp_socket_delete(&(client_request_ptr -> nx_telnet_client_request_socket)); - - /* Increment the pointer into the client request list. */ - client_request_ptr++; - i++; - } - - /* Unlisten on the TELNET port. */ - nx_tcp_server_socket_unlisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server disconnect */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* logical_connection Logical connection entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_disconnect Actual server disconnect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for a valid logical connection. */ - if (logical_connection >= NX_TELNET_MAX_CLIENTS) - return(NX_OPTION_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server disconnect function. */ - status = _nx_telnet_server_disconnect(server_ptr, logical_connection); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes server disconnect requests made by the */ -/* application receive data callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* logical_connection Logical connection entry */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_relisten Relisten on Telnet port */ -/* nx_tcp_server_socket_unaccept Socket unaccept */ -/* nx_tcp_socket_disconnect Socket disconnect */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection) -{ - -UINT i; -UINT status; -NX_TELNET_CLIENT_REQUEST *client_ptr; - - /* Set a pointer to the indicated client connection. */ - client_ptr = &(server_ptr -> nx_telnet_server_client_list[logical_connection]); - - /* Determine if the connection is alive. */ - if (client_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state >= NX_TCP_ESTABLISHED) - { - - /* Disconnect the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); - - /* Call the application's end connection callback routine. */ - if (server_ptr -> nx_telnet_connection_end) - { - - /* Yes, there is a connection end callback routine - call it! */ - (server_ptr -> nx_telnet_connection_end)(server_ptr, client_ptr -> nx_telnet_client_request_connection); - } - - /* Unaccept this socket. */ - nx_tcp_server_socket_unaccept(&(client_ptr -> nx_telnet_client_request_socket)); - - /* Update number of current open connections. */ - if (server_ptr -> nx_telnet_server_open_connections > 0) - server_ptr -> nx_telnet_server_open_connections--; - - /* Clear the client request activity timeout. */ - client_ptr -> nx_telnet_client_request_activity_timeout = 0; - } - else - { - - /* Error, disconnecting an unconnected socket. */ - return(NX_TELNET_NOT_CONNECTED); - } - - /* Now look for a socket that is closed to relisten on. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Set a pointer to client request structure. */ - client_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket is closed. */ - if (client_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - /* Relisten on this socket. */ - status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, - &(client_ptr -> nx_telnet_client_request_socket)); - /* Check for bad status. */ - if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - - /* Increment the error count and keep trying. */ - server_ptr -> nx_telnet_server_relisten_errors++; - continue; - } - - /* Break out of loop. */ - break; - } - } - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server packet send */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* logical_connection Logical connection entry */ -/* packet_ptr Packet pointer to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_packet_send Actual server packet send call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for a valid logical connection. */ - if (logical_connection >= NX_TELNET_MAX_CLIENTS) - return(NX_OPTION_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server packet send function. */ - status = _nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes packet send requests made from the */ -/* application's receive data callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* logical_connection Logical connection entry */ -/* packet_ptr Packet pointer to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_send Send packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; -NX_TELNET_CLIENT_REQUEST *client_ptr; - - - /* Derive the pointer to the appropriate client connection. */ - client_ptr = &(server_ptr -> nx_telnet_server_client_list[logical_connection]); - - /* Send the packet to the client. */ - status = nx_tcp_socket_send(&(client_ptr -> nx_telnet_client_request_socket), packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status) - { - - /* Map to a generic error. */ - status = NX_TELNET_FAILED; - } - - /* Return to caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_start Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_start(NX_TELNET_SERVER *server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Call actual server start function. */ - status = _nx_telnet_server_start(server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts a previously created TELNET server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_TELNET_NO_PACKET_POOL Telnet server packet pool not */ -/* set yet */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_listen Listen of TELNET clients */ -/* tx_thread_resume Resume TELNET server thread */ -/* tx_timer_activate Activate TELNET server timer */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_start(NX_TELNET_SERVER *server_ptr) -{ - -UINT status; -ULONG events; - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - - /* Check for Telnet server packet pool we'll need to send options. */ - if (server_ptr -> nx_telnet_server_packet_pool_ptr == NX_NULL) - { - - /* The Telnet server packet pool is not set. */ - return NX_TELNET_NO_PACKET_POOL; - } -#endif - - /* Start listening on the TELNET socket. */ - status = nx_tcp_server_socket_listen(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, - &(server_ptr -> nx_telnet_server_client_list[0].nx_telnet_client_request_socket), - NX_TELNET_MAX_CLIENTS, _nx_telnet_server_connection_present); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(status); - } - - /* Activate TELNET server timer. */ - tx_timer_activate(&(server_ptr -> nx_telnet_server_timer)); - - /* Clear stop event. */ - tx_event_flags_get(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_STOP_EVENT, TX_OR_CLEAR, &events, TX_NO_WAIT); - - /* Start the TELNET server thread. */ - tx_thread_resume(&(server_ptr -> nx_telnet_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_stop Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_stop(NX_TELNET_SERVER *server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_telnet_server_id != NX_TELNET_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_telnet_server_stop(server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops a previously started TELNET server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* tx_timer_deactivate Deactivate TELNET server timer*/ -/* nx_tcp_server_socket_unaccept Unaccept server socket */ -/* nx_tcp_server_socket_unlisten Unlisten on server */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr) -{ -UINT i; -NX_TELNET_CLIENT_REQUEST *client_request_ptr; - - /* Deactivate TELNET server timer. */ - tx_timer_deactivate(&(server_ptr -> nx_telnet_server_timer)); - - /* Suspend the TELNET server thread. */ - tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_STOP_EVENT, TX_OR); - - /* Walk through the server structure to close and delete any open sockets. */ - i = 0; - client_request_ptr = &(server_ptr -> nx_telnet_server_client_list[0]); - while (i < NX_TELNET_MAX_CLIENTS) - { - - /* Disconnect the socket. */ - nx_tcp_socket_disconnect(&(client_request_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); - - /* Unaccept the socket. */ - nx_tcp_server_socket_unaccept(&(client_request_ptr -> nx_telnet_client_request_socket)); - - /* Reset client request. */ - client_request_ptr -> nx_telnet_client_request_activity_timeout = 0; - - /* Increment the pointer into the client request list. */ - client_request_ptr++; - i++; - } - - /* Unlisten on the TELNET port. */ - nx_tcp_server_socket_unlisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_get_open_connection_count PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server get open */ -/* connection count service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* current_connections Pointer to # open connections */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_get_open_connection_count */ -/* Actual server get count call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (current_connections == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_telnet_server_get_open_connection_count(server_ptr, current_connections); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_get_open_connection_count PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the number of currently open connections. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* current_connections Pointer to # open connections */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections) -{ - - /* Retrieve server's record of open connections. */ - *current_connections = server_ptr -> nx_telnet_server_open_connections; - - /* Return completion status. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry of the TELNET server. All basic */ -/* processing is initiated by this function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* telnet_server Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_connect_process Process connection */ -/* _nx_telnet_server_data_process Process received data */ -/* _nx_telnet_server_disconnect_process Process disconnection */ -/* _nx_telnet_server_timeout_processing Process activity timeout */ -/* tx_event_flags_get Get TELNET event(s) */ -/* tx_thread_suspend Suspend TELNET thread */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_thread_entry(ULONG telnet_server) -{ - -NX_TELNET_SERVER *server_ptr; -UINT status; -ULONG events; - - - /* Setup the server pointer. */ - server_ptr = (NX_TELNET_SERVER *) telnet_server; - - /* Loop to process TELNET Server requests. */ - while(1) - { - - /* Wait for an TELNET client activity. */ - status = tx_event_flags_get(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_ANY_EVENT, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Check the return status. */ - if (status) - { - - /* If an error occurs, simply continue the loop. */ - continue; - } - - /* Check whether service is started. */ - if (events & NX_TELNET_STOP_EVENT) - { - - /* Suspend thread here. */ - tx_thread_suspend(&server_ptr -> nx_telnet_server_thread); - continue; - } - - /* Otherwise, an event is present. Process according to the event. */ - - /* Check for a client connection event. */ - if (events & NX_TELNET_SERVER_CONNECT) - { - - /* Call the connect processing. */ - _nx_telnet_server_connect_process(server_ptr); - } - - /* Check for a TELNET client write data event. */ - if (events & NX_TELNET_SERVER_DATA) - { - - /* Call processing to handle server data. */ - _nx_telnet_server_data_process(server_ptr); - } - - /* Check for a client disconnect event. */ - if (events & NX_TELNET_SERVER_DISCONNECT) - { - - /* Call the disconnect processing. */ - _nx_telnet_server_disconnect_process(server_ptr); - } - - /* Check for a client activity timeout event. */ - if (events & NX_TELNET_SERVER_ACTIVITY_TIMEOUT) - { - - /* Call the activity timeout processing. */ - _nx_telnet_server_timeout_processing(server_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_connect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all TELNET client connections received. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_accept Accept connection on socket */ -/* nx_tcp_server_socket_relisten Relisten for connection */ -/* nx_tcp_server_socket_unaccept Unaccept connection */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_thread_entry TELNET server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_connect_process(NX_TELNET_SERVER *server_ptr) -{ - -UINT i; -UINT status; -NX_TELNET_CLIENT_REQUEST *client_req_ptr; - - - /* One of the client request sockets is in the process of connection. */ - - /* Search the connections to see which one. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket was the one that is in being connected. */ - if ((client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state > NX_TCP_CLOSED) && - (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state < NX_TCP_ESTABLISHED) && - (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_connect_port)) - { - - /* Yes, we have found the socket being connected. */ - - /* Increment the number of connection requests. */ - server_ptr -> nx_telnet_server_connection_requests++; - - /* Attempt to accept on this socket. */ - status = nx_tcp_server_socket_accept(&(client_req_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); - - /* Determine if it is successful. */ - if (status) - { - - /* Not successful, simply unaccept on this socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); - } - else - { - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_telnet_client_request_activity_timeout = NX_TELNET_ACTIVITY_TIMEOUT; - - /* Update number of current open connections. */ - server_ptr -> nx_telnet_server_open_connections++; - - /* Call the application's new connection callback routine. */ - if (server_ptr -> nx_telnet_new_connection) - { - /* Yes, there is a new connection callback routine - call it! */ - (server_ptr -> nx_telnet_new_connection)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); - } - - /* Disable remote echo by default. */ - if(server_ptr -> nx_telnet_set_echo) - server_ptr -> nx_telnet_set_echo(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, NX_FALSE); - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - - /* Yes, send out server echo option requests. */ - status = _nx_telnet_server_send_option_requests(server_ptr, client_req_ptr); - if(status != NX_SUCCESS) - return; -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - - } - } - } - - /* Now look for a socket that is closed to relisten on. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Set a pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket is closed. */ - if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - /* Relisten on this socket. */ - status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, - &(client_req_ptr -> nx_telnet_client_request_socket)); - /* Check for bad status. */ - if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - - /* Increment the error count and keep trying. */ - server_ptr -> nx_telnet_server_relisten_errors++; - continue; - } - - /* Break out of loop. */ - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_connection_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all TELNET client connections received on */ -/* the socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Socket event occurred */ -/* port Port the connection occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port) -{ - -NX_TELNET_SERVER *server_ptr; - - NX_PARAMETER_NOT_USED(port); - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the connect event flag. */ - tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_CONNECT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_disconnect_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function handles all TELNET client disconnections received on */ -/* the socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_disconnect_present(NX_TCP_SOCKET *socket_ptr) -{ - -NX_TELNET_SERVER *server_ptr; - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the disconnect event flag. */ - tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_DISCONNECT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_disconnect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes all TELNET client disconnections received */ -/* on the socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_relisten Relisten on Telnet port */ -/* nx_tcp_server_socket_unaccept Unaccept connection */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_thread_entry TELNET server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_disconnect_process(NX_TELNET_SERVER *server_ptr) -{ - -UINT i; -UINT status; -NX_TELNET_CLIENT_REQUEST *client_req_ptr; -UINT reset_client_request; - - - /* Now look for a socket that has a disconnect state. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - reset_client_request = NX_FALSE; - - /* Setup pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Has the socket received a RST packet? If so NetX will put it in a CLOSED or LISTEN state - and the socket activity timeout has not been reset yet. */ - if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state < NX_TCP_SYN_SENT) - { - - if (client_req_ptr -> nx_telnet_client_request_activity_timeout > 0) - { - - reset_client_request = NX_TRUE; - } - } - else - { - - /* Now see if this socket has entered a disconnect state. */ - while (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state > NX_TCP_ESTABLISHED) - { - - /* Yes, a disconnect is present, which signals an end of session for TELNET request. */ - - /* First, cleanup this socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_telnet_client_request_socket), NX_TELNET_SERVER_TIMEOUT); - - reset_client_request = NX_TRUE; - } - } - - /* If this connection is closed, update the telnet data and notify the application of a disconnect. */ - if (reset_client_request == NX_TRUE) - { - - /* Unaccept this socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_telnet_client_request_activity_timeout = 0; - - /* Update number of current open connections. */ - if (server_ptr -> nx_telnet_server_open_connections > 0) - server_ptr -> nx_telnet_server_open_connections--; - - /* Call the application's end connection callback routine. */ - if (server_ptr -> nx_telnet_connection_end) - { - - /* Yes, there is a connection end callback routine - call it! */ - (server_ptr -> nx_telnet_connection_end)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); - } - } - } - - /* Now look for a socket that is closed to relisten on. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket is closed. */ - if (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - /* Relisten on this socket. */ - status = nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, - &(client_req_ptr -> nx_telnet_client_request_socket)); - /* Check for bad status. */ - if ((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - - /* Increment the error count and keep trying. */ - server_ptr -> nx_telnet_server_relisten_errors++; - continue; - } - - /* Break out of loop. */ - break; - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_data_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function notifies the TELNET server thread of data received */ -/* from a client on the socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Socket event occurred */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_data_present(NX_TCP_SOCKET *socket_ptr) -{ - -NX_TELNET_SERVER *server_ptr; - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_DATA, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_data_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes all TELNET client data packets received on */ -/* the request socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive from socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_thread_entry TELNET server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_data_process(NX_TELNET_SERVER *server_ptr) -{ - -UINT i; -UINT status; -NX_PACKET *packet_ptr; -NX_TELNET_CLIENT_REQUEST *client_req_ptr; -#ifndef NX_TELNET_SERVER_OPTION_DISABLE -UCHAR data_char; -UINT offset; -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - - /* Now look for a socket that has receive data. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Setup pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket has data. If so, process all of it now! */ - while (client_req_ptr -> nx_telnet_client_request_socket.nx_tcp_socket_receive_queue_count) - { - - /* Reset the client request activity timeout. */ - client_req_ptr -> nx_telnet_client_request_activity_timeout = NX_TELNET_ACTIVITY_TIMEOUT; - - /* Attempt to read a packet from this socket. */ - status = nx_tcp_socket_receive(&(client_req_ptr -> nx_telnet_client_request_socket), &packet_ptr, NX_NO_WAIT); - - /* Check for not data present. */ - if (status != NX_SUCCESS) - { - - /* Break to look at the next socket. */ - break; - } - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - - /* If the first byte of the packet data is the telnet "IAC" code, - this is a telnet option packet. */ - if (*packet_ptr -> nx_packet_prepend_ptr == NX_TELNET_IAC) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - if (packet_ptr -> nx_packet_next) - { - - /* Chained packet is not supported. */ - nx_packet_release(packet_ptr); - break; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* We will use an offset to mark the beginning of each telnet option, if there is more - than one, in the packet payload. */ - offset = 0; - - /* Validate the packet length. */ - if (packet_ptr -> nx_packet_length == 1) - { - nx_packet_release(packet_ptr); - break; - } - - /* Set the work pointer to just past the telnet IAC tag. */ - data_char = *(packet_ptr -> nx_packet_prepend_ptr + 1); - - /* Verify the next byte is a valid Telnet option code. */ - if ((data_char >= NX_TELNET_WILL) && (data_char <= NX_TELNET_DONT)) - { - - /* Process the entire packet for telnet options, ensuring we don't go off the end of the payload. */ - while((offset < packet_ptr -> nx_packet_length) && (*(packet_ptr -> nx_packet_prepend_ptr + offset) == NX_TELNET_IAC)) - { - - /* Process this telnet option. The offset will be updated to the location - of the next option (if there is one) on return of this function. */ - _nx_telnet_server_process_option(server_ptr, packet_ptr, &offset, client_req_ptr); - } - } - - /* Are there any data left? */ - if ((offset < packet_ptr -> nx_packet_length) && (server_ptr -> nx_telnet_receive_data)) - { - - /* Yes. Adjust packet. */ - packet_ptr -> nx_packet_prepend_ptr += offset; - packet_ptr -> nx_packet_length -= offset; - - /* Yes, there is a process data callback routine - call it! */ - (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); - } - else - { - - /* We're done with this packet. */ - nx_packet_release(packet_ptr); - } - - /* Check if the echo negotiation is successful. */ - if((client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success == NX_TRUE) && - (client_req_ptr -> nx_telnet_client_agree_server_will_echo_success == NX_TRUE)) - { - - /* Enable remote echo. */ - if(server_ptr -> nx_telnet_set_echo) - server_ptr -> nx_telnet_set_echo(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, NX_TRUE); - } - } - - /* It's not an option packet. */ - else - { - - /* Check server receive callback. */ - if (server_ptr -> nx_telnet_receive_data) - { - - /* Yes, there is a process data callback routine - call it! */ - (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); - } - else - { - - /* Error, no application callback routine. */ - - /* Release the packet and continue the loop. */ - nx_packet_release(packet_ptr); - } - } -#else - if (*packet_ptr -> nx_packet_prepend_ptr == NX_TELNET_IAC) - { - nx_packet_release(packet_ptr); - } - /* Call the server receive callback. */ - else if (server_ptr -> nx_telnet_receive_data) - { - - /* Yes, there is a process data callback routine - call it! */ - (server_ptr -> nx_telnet_receive_data)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr); - } - else - { - - /* Error, no application callback routine. */ - - /* Release the packet and continue the loop. */ - nx_packet_release(packet_ptr); - } - -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the periodic timer for this TELNET server. Its */ -/* duty is to inform the TELNET server that it is time to check for */ -/* activity timeouts. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* telnet_server_address TELNET server's address */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX ThreadX timer callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_timeout(ULONG telnet_server_address) -{ - -NX_TELNET_SERVER *server_ptr; - - /* Pickup server pointer. */ - server_ptr = (NX_TELNET_SERVER *) telnet_server_address; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_telnet_server_event_flags), NX_TELNET_SERVER_ACTIVITY_TIMEOUT, TX_OR); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_timeout_processing PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reviews all the active TELNET client connections and */ -/* looks for an activity timeout. If a connection has not had any */ -/* activity within NX_TELNET_ACTIVITY_TIMEOUT seconds, the connection */ -/* is deleted and its resources are made available to a new connection.*/ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_relisten Relisten for another connect */ -/* nx_tcp_server_socket_unaccept Unaccept server connection */ -/* nx_tcp_socket_disconnect Disconnect socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_thread_entry TELNET server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_timeout_processing(NX_TELNET_SERVER *server_ptr) -{ - -UINT i; -NX_TELNET_CLIENT_REQUEST *client_req_ptr; - - - /* Now look through all the sockets. */ - for (i = 0; i < NX_TELNET_MAX_CLIENTS; i++) - { - - /* Set a pointer to client request structure. */ - client_req_ptr = &(server_ptr -> nx_telnet_server_client_list[i]); - - /* Now see if this socket has an activity timeout active. */ - if (client_req_ptr -> nx_telnet_client_request_activity_timeout) - { - - /* Decrement the activity timeout for this client request. */ - if (client_req_ptr -> nx_telnet_client_request_activity_timeout > NX_TELNET_TIMEOUT_PERIOD) - client_req_ptr -> nx_telnet_client_request_activity_timeout = client_req_ptr -> nx_telnet_client_request_activity_timeout - NX_TELNET_TIMEOUT_PERIOD; - else - client_req_ptr -> nx_telnet_client_request_activity_timeout = 0; - - /* Determine if this entry has exceeded the activity timeout. */ - if (client_req_ptr -> nx_telnet_client_request_activity_timeout == 0) - { - - /* Yes, the activity timeout has been exceeded. Tear down and clean up the - entire client request structure. */ - - /* Increment the activity timeout counter. */ - server_ptr -> nx_telnet_server_activity_timeouts++; - - /* Now disconnect the command socket. */ - nx_tcp_socket_disconnect(&(client_req_ptr -> nx_telnet_client_request_socket), NX_NO_WAIT); - - /* Unaccept the server socket. */ - nx_tcp_server_socket_unaccept(&(client_req_ptr -> nx_telnet_client_request_socket)); - - /* Relisten on this socket. This will probably fail, but it is needed just in case all available - clients were in use at the time of the last relisten. */ - nx_tcp_server_socket_relisten(server_ptr -> nx_telnet_server_ip_ptr, NX_TELNET_SERVER_PORT, - &(client_req_ptr -> nx_telnet_client_request_socket)); - - /* Update number of current open connections. */ - if (server_ptr -> nx_telnet_server_open_connections > 0) - server_ptr -> nx_telnet_server_open_connections--; - - /* Call the application's end connection callback routine. */ - if (server_ptr -> nx_telnet_connection_end) - { - - /* Yes, there is a connection end callback routine - call it! */ - (server_ptr -> nx_telnet_connection_end)(server_ptr, client_req_ptr -> nx_telnet_client_request_connection); - } - } - } - } -} - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - -#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TELNET server create packet */ -/* pool call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* pool_ptr Pointer to telnet packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nx_telnet_server_packet_pool_set Actual set packet pool call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -UINT _nxe_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr) -{ - -UINT status; - - /* Check for invalid pointer input. */ - if ((server_ptr == NX_NULL) || (pool_ptr == NX_NULL)) - { - return NX_PTR_ERROR; - } - - /* Actual set packet pool service. */ - status = _nx_telnet_server_packet_pool_set(server_ptr, pool_ptr); - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_telnet_server_packet_pool_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the Telnet Server packet pool to the packet pool */ -/* created outside the Telnet Server domain. This permits the packet */ -/* pool memory to be in a different location from the Telnet Server. */ -/* */ -/* The Telnet Server only uses this packet pool for sending Telnet */ -/* options (requires NX_TELNET_SERVER_OPTION_DISABLE not be defined). */ -/* */ -/* Note: This will overwrite an existing Telnet Server packet pool if */ -/* one was previously set. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* pool_ptr Pointer to telnet packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Telnet server packet pool */ -/* successfully set */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr) -{ - - - server_ptr -> nx_telnet_server_packet_pool_ptr = pool_ptr; - - return NX_SUCCESS; -} - -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_create_option_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates option packet for specified type and id. */ -/* */ -/* INPUT */ -/* */ -/* option_message_type Option type */ -/* option_id Option_id */ -/* stream Output buffer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_send_option_requests Send telnet option */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_telnet_server_create_option_packet(UCHAR option_message_type, UCHAR option_id, UCHAR *stream) -{ - - *(stream++) = NX_TELNET_IAC; - *(stream++) = option_message_type; - *stream = option_id; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_send_option_requests PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called if 1) the server is configured to send out */ -/* options without waiting to receive client option requests, or 2)after*/ -/* receiving a client's initial option requests. This will send out */ -/* those option requests the server did not receive from the client */ -/* based on the server session option list. */ -/* */ -/* This function obtains mutex protection on the client session record */ -/* to update the record with options sent out from the server. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to telnet server */ -/* client_req_ptr Pointer to client record */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet from pool */ -/* nx_packet_release Release packet back to pool */ -/* nx_packet_data_append Append data to packet payload */ -/* _nx_telnet_server_create_option_packet */ -/* Create telnet option message */ -/* _nx_telnet_server_packet_send Send telnet option to client */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_data_process Top level telnet packet handler*/ -/* _nx_telnet_server_connect_process Telnet connection handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_telnet_server_send_option_requests(NX_TELNET_SERVER *server_ptr, NX_TELNET_CLIENT_REQUEST *client_req_ptr) -{ -UINT status; -NX_PACKET *packet_ptr; -UINT option_length; -UINT packet_available; -UCHAR option_stream[9]; - - status = NX_SUCCESS; - - /* Indicate packet not available, nor needing to be released. */ - packet_available = NX_FALSE; - - /* Allocate a packet for replies to send to this telnet client. */ - status = nx_packet_allocate(server_ptr -> nx_telnet_server_packet_pool_ptr, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT); - - if (status != NX_SUCCESS) - return status; - - /* Now a packet is available, and if not used should be released. */ - packet_available = NX_TRUE; - - /* Initialize option data to zero bytes. */ - option_length = 0; - - client_req_ptr -> nx_telnet_client_agree_server_will_echo_success = NX_FALSE; - client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success = NX_FALSE; - - /* Yes, create will echo request (3 bytes). */ - _nx_telnet_server_create_option_packet(NX_TELNET_WILL, NX_TELNET_ECHO, &option_stream[0]); - - /* Yes, create dont echo request (3 bytes). */ - _nx_telnet_server_create_option_packet(NX_TELNET_DONT, NX_TELNET_ECHO, &option_stream[3]); - - /* Yes, create will SGA request (3 bytes). */ - _nx_telnet_server_create_option_packet(NX_TELNET_WILL, NX_TELNET_SGA, &option_stream[6]); - - /* Update the the packet payload for number of bytes for a telnet option request. */ - option_length = 9; - - /* Add to the packet payload. */ - status = nx_packet_data_append(packet_ptr, option_stream, 9, server_ptr -> nx_telnet_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if (status) - { - nx_packet_release(packet_ptr); - return(status); - } - - /* Check if we have a packet started, but not sent yet. */ - if (option_length > 0) - { - - /* Send the telnet packet out to the client. */ - status = _nx_telnet_server_packet_send(server_ptr, client_req_ptr -> nx_telnet_client_request_connection, packet_ptr, 100); - - /* If errors sending, we need to release the packet. */ - if (status != NX_SUCCESS) - { - nx_packet_release(packet_ptr); - return status; - } - - /* Indicate we need another packet, just sent out the last one. */ - packet_available = NX_FALSE; - } - - /* Check for unused packet (needs to be released). */ - if (packet_available == NX_TRUE) - { - - /* Release the packet we did not use. */ - nx_packet_release(packet_ptr); - } - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_telnet_server_process_option PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function examines the telnet option in the current packet and */ -/* determines if it is a new client request, an option with */ -/* subnegotiation data for the server, or a response to a previously */ -/* sent server telnet option request to the client. It then forwards */ -/* the telnet option information to the appropriate telnet processor. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TELNET server */ -/* packet_ptr Packet with telnet option */ -/* offset Option offset in packet */ -/* client_req_ptr Telnet client sending packet */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TELNET_SESSION_OPTIONS_FULL Session option list is fill */ -/* NX_SUCCESS Option successfully processed */ -/* */ -/* CALLS */ -/* _nx_telnet_server_update_server_session_attributes */ -/* Updates server telnet features*/ -/* _nx_telnet_server_update_client_session_attributes */ -/* Updates client telnet features*/ -/* _nx_telnet_server_process_new_option Add new option to session list*/ -/* _nx_telnet_server_respond_to_pending_option */ -/* Send server reply to option */ -/* _nx_telnet_server_process_subnegotiation_data */ -/* Process received option specs */ -/* _nx_telnet_server_validate_option_change */ -/* Determine if option is dupe */ -/* Process received option specs */ -/* CALLED BY */ -/* */ -/* _nx_telnet_server_data_process Top level incoming telnet */ -/* packet handler */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -VOID _nx_telnet_server_process_option(NX_TELNET_SERVER *server_ptr, NX_PACKET *packet_ptr, UINT *offset, - NX_TELNET_CLIENT_REQUEST *client_req_ptr) -{ -UCHAR data_char; -UCHAR *work_ptr; - - NX_PARAMETER_NOT_USED(server_ptr); - - /* Set the work pointer to see what option received. */ - work_ptr = (UCHAR *)(packet_ptr -> nx_packet_prepend_ptr + (*offset) + 2); - - /* This option isn't complete, just move to the end of the packet. */ - if (work_ptr >= packet_ptr -> nx_packet_append_ptr) - { - *offset = packet_ptr -> nx_packet_length; - return; - } - - data_char = *work_ptr; - - /* If it is a echo option. */ - if(data_char == NX_TELNET_ECHO) - { - - /* Check whether the client replies with echo negotiation of the local echo disabled. */ - work_ptr--; - data_char = *work_ptr; - if(data_char == NX_TELNET_DO) - { - - /* Server will echo what received from the telnet connection. */ - client_req_ptr -> nx_telnet_client_agree_server_will_echo_success = NX_TRUE; - - /* Move the offset to past the option. */ - (*offset)+=3; - } - else - { - - /* Move the offset to past the option. */ - (*offset)+=3; - } - } - - /* If it is a SGA option. */ - else if(data_char == NX_TELNET_SGA) - { - - /* Check whether the client replies with SGA negotiation. */ - work_ptr--; - data_char = *work_ptr; - if(data_char == NX_TELNET_DO) - { - - /* Server will enable SGA option. */ - client_req_ptr -> nx_telnet_client_agree_server_will_SGA_success = NX_TRUE; - - /* Move the offset to past the option. */ - (*offset)+=3; - } - else - { - /* Move the offset to past the option. */ - (*offset)+=3; - return; - } - } - - /* We have not implemented this option, just return. */ - else - { - - /* See next three bytes. */ - (*offset)+=3; - return; - } -} -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ diff --git a/protocol_handlers/telnet/nxd_telnet_server.h b/protocol_handlers/telnet/nxd_telnet_server.h deleted file mode 100644 index 6b8723c7..00000000 --- a/protocol_handlers/telnet/nxd_telnet_server.h +++ /dev/null @@ -1,354 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** TELNET Server Protocol (TELNET Server) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_telnet_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Duo TELNET Protocol (TELNET) component, */ -/* including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_TELNET_SERVER_H -#define NXD_TELNET_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the Server TELNET ID. */ - -#define NX_TELNET_SERVER_ID 0x54454C4EUL - -/* Defined, option negotiation is disabled. -#define NX_TELNET_SERVER_OPTION_DISABLE -*/ - - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - -/* If NX_TELNET_SERVER_OPTION_DISABLE is not defined, and Telnet Server - needs a packet pool, this option lets the application create the packet - pool instead of the Telnet Server. -#define NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -*/ - -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - -/* Define the maximum number of clients the TELNET Server can accommodate. */ - -#ifndef NX_TELNET_MAX_CLIENTS -#define NX_TELNET_MAX_CLIENTS 4 -#endif - - -/* Define TELNET TCP socket create options. */ - -#ifndef NX_TELNET_TOS -#define NX_TELNET_TOS NX_IP_NORMAL -#endif - -#ifndef NX_TELNET_FRAGMENT_OPTION -#define NX_TELNET_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_TELNET_SERVER_WINDOW_SIZE -#define NX_TELNET_SERVER_WINDOW_SIZE 2048 -#endif - -#ifndef NX_TELNET_TIME_TO_LIVE -#define NX_TELNET_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_TELNET_SERVER_TIMEOUT -#define NX_TELNET_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_TELNET_SERVER_PRIORITY -#define NX_TELNET_SERVER_PRIORITY 16 -#endif - -#ifndef NX_TELNET_ACTIVITY_TIMEOUT -#define NX_TELNET_ACTIVITY_TIMEOUT 600 /* Seconds allowed with no activity */ -#endif - -#ifndef NX_TELNET_TIMEOUT_PERIOD -#define NX_TELNET_TIMEOUT_PERIOD 60 /* Number of seconds to check */ -#endif - - -/* Define TELNET commands that are optionally included in the TELNET data. The application is responsible for - recognizing and responding to the commands in accordance with the specification. The TELNET option command - requires three bytes, as follows: - - IAC, COMMAND, OPTION ID - -*/ - -/* Define byte indicating TELNET command follows. */ - -#define NX_TELNET_IAC 255 /* TELNET Command byte - two consecutive -> 255 data */ - -/* Define TELNET Negotiation Commands - Immediately follows IAC. */ - -#define NX_TELNET_WILL 251 /* TELNET WILL - Sender wants to enable the option */ -#define NX_TELNET_WONT 252 /* TELNET WONT - Sender wants to disable the option */ -#define NX_TELNET_DO 253 /* TELNET DO - Sender wants receiver to enable option */ -#define NX_TELNET_DONT 254 /* TELNET DONT - Sender wants receiver to disable option*/ - - -/* Define the Telnet Server packet payload. */ - -#ifndef NX_TELNET_SERVER_PACKET_PAYLOAD -#define NX_TELNET_SERVER_PACKET_PAYLOAD 300 -#endif - -/* Define the size of the Telnet Server packet pool. This will allow room for about - 5-6 packets of 300 byte payload. */ - -#ifndef NX_TELNET_SERVER_PACKET_POOL_SIZE -#define NX_TELNET_SERVER_PACKET_POOL_SIZE 2048 -#endif - - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - -/* Define TELNET Option IDs. */ -#define NX_TELNET_ECHO 1 /* TELNET ECHO Option */ -#define NX_TELNET_SGA 3 /* TELNET SGA Option */ -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - -/* Define Server thread events. */ - -#define NX_TELNET_SERVER_CONNECT 0x01 /* TELNET connection is present */ -#define NX_TELNET_SERVER_DISCONNECT 0x02 /* TELNET disconnection is present */ -#define NX_TELNET_SERVER_DATA 0x04 /* TELNET receive data is present */ -#define NX_TELNET_SERVER_ACTIVITY_TIMEOUT 0x08 /* TELNET activity timeout check */ -#define NX_TELNET_STOP_EVENT 0x10 /* TELNET stop service */ -#define NX_TELNET_ANY_EVENT 0xFF /* Any TELNET event */ - - -/* Define return code constants. */ - -#define NX_TELNET_ERROR 0xF0 /* TELNET internal error */ -#define NX_TELNET_TIMEOUT 0xF1 /* TELNET timeout occurred */ -#define NX_TELNET_FAILED 0xF2 /* TELNET error */ -#define NX_TELNET_NOT_CONNECTED 0xF3 /* TELNET not connected error */ -#define NX_TELNET_NOT_DISCONNECTED 0xF4 /* TELNET not disconnected error */ -#define NX_TELNET_INVALID_PARAMETER 0xF5 /* Invalid non pointer input to Telnet function */ -#define NX_TELNET_NO_PACKET_POOL 0xF6 /* Telnet server packet pool not set */ - -/* Define the TELNET Server TCP port numbers. */ - -#ifndef NX_TELNET_SERVER_PORT -#define NX_TELNET_SERVER_PORT 23 /* Default Port for TELNET server */ -#endif - - -/* Define the per client request structure for the TELNET Server data structure. */ - -typedef struct NX_TELNET_CLIENT_REQUEST_STRUCT -{ - UINT nx_telnet_client_request_connection; /* Logical connection number */ - ULONG nx_telnet_client_request_activity_timeout; /* Timeout for client activity */ - ULONG nx_telnet_client_request_total_bytes; /* Total bytes read or written */ - NX_TCP_SOCKET nx_telnet_client_request_socket; /* Client request socket */ -#ifndef NX_TELNET_SERVER_OPTION_DISABLE - USHORT nx_telnet_client_agree_server_will_echo_success; /* True if server will echo negotiation success */ - USHORT nx_telnet_client_agree_server_will_SGA_success; /* True if server will SGA negotiation success */ -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - -} NX_TELNET_CLIENT_REQUEST; - - -/* Define the TELNET Server data structure. */ - -typedef struct NX_TELNET_SERVER_STRUCT -{ - ULONG nx_telnet_server_id; /* TELNET Server ID */ - CHAR *nx_telnet_server_name; /* Name of this TELNET server */ - NX_IP *nx_telnet_server_ip_ptr; /* Pointer to associated IP structure */ - ULONG nx_telnet_server_connection_requests; /* Number of connection requests */ - ULONG nx_telnet_server_disconnection_requests; /* Number of disconnection requests */ - ULONG nx_telnet_server_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_telnet_server_total_bytes_received; /* Number of total bytes received */ - ULONG nx_telnet_server_relisten_errors; /* Number of relisten errors */ - ULONG nx_telnet_server_activity_timeouts; /* Number of activity timeouts */ - ULONG nx_telnet_server_open_connections; /* Number of currently open connections */ - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE -#ifndef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL - UCHAR nx_telnet_server_pool_area[NX_TELNET_SERVER_PACKET_POOL_SIZE]; - NX_PACKET_POOL nx_telnet_server_packet_pool; /* Server TCP packet pool - for telnet option messages */ -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ - NX_PACKET_POOL *nx_telnet_server_packet_pool_ptr; /* Pointer to packet pool */ -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ - NX_TELNET_CLIENT_REQUEST /* TELNET client request array */ - nx_telnet_server_client_list[NX_TELNET_MAX_CLIENTS]; - TX_EVENT_FLAGS_GROUP - nx_telnet_server_event_flags; /* TELNET server thread events */ - TX_TIMER nx_telnet_server_timer; /* TELNET server activity timeout timer */ - TX_THREAD nx_telnet_server_thread; /* TELNET server thread */ - void (*nx_telnet_new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection); - void (*nx_telnet_receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr); - void (*nx_telnet_connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection); - void (*nx_telnet_set_echo)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, UINT echo_flag); -} NX_TELNET_SERVER; - -#ifndef NX_TELNET_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_telnet_server_create _nx_telnet_server_create -#define nx_telnet_server_delete _nx_telnet_server_delete -#define nx_telnet_server_disconnect _nx_telnet_server_disconnect -#define nx_telnet_server_packet_send _nx_telnet_server_packet_send -#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -#define nx_telnet_server_packet_pool_set _nx_telnet_server_packet_pool_set -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -#define nx_telnet_server_start _nx_telnet_server_start -#define nx_telnet_server_stop _nx_telnet_server_stop -#define nx_telnet_server_get_open_connection_count _nx_telnet_server_get_open_connection_count - -#else - -/* Services with error checking. */ - -#define nx_telnet_server_create _nxe_telnet_server_create -#define nx_telnet_server_delete _nxe_telnet_server_delete -#define nx_telnet_server_disconnect _nxe_telnet_server_disconnect -#define nx_telnet_server_packet_send _nxe_telnet_server_packet_send -#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -#define nx_telnet_server_packet_pool_set _nxe_telnet_server_packet_pool_set -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -#define nx_telnet_server_start _nxe_telnet_server_start -#define nx_telnet_server_stop _nxe_telnet_server_stop -#define nx_telnet_server_get_open_connection_count _nxe_telnet_server_get_open_connection_count - -#endif - -/* Define the prototypes accessible to the application software. */ - -UINT nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), - void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), - void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); -UINT nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr); -UINT nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); -UINT nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); -#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -UINT nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -UINT nx_telnet_server_start(NX_TELNET_SERVER *server_ptr); -UINT nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr); -UINT nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); - - -#else - -/* TELNET source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), - void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), - void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); -UINT _nx_telnet_server_create(NX_TELNET_SERVER *server_ptr, CHAR *server_name, NX_IP *ip_ptr, VOID *stack_ptr, ULONG stack_size, - void (*new_connection)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection), - void (*receive_data)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection, NX_PACKET *packet_ptr), - void (*connection_end)(struct NX_TELNET_SERVER_STRUCT *telnet_server_ptr, UINT logical_connection)); -UINT _nxe_telnet_server_delete(NX_TELNET_SERVER *server_ptr); -UINT _nx_telnet_server_delete(NX_TELNET_SERVER *server_ptr); -UINT _nxe_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); -UINT _nx_telnet_server_disconnect(NX_TELNET_SERVER *server_ptr, UINT logical_connection); -UINT _nxe_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_telnet_server_packet_send(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr, ULONG wait_option); -#ifdef NX_TELNET_SERVER_USER_CREATE_PACKET_POOL -UINT _nxe_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); -UINT _nx_telnet_server_packet_pool_set(NX_TELNET_SERVER *server_ptr, NX_PACKET_POOL *pool_ptr); -#endif /* NX_TELNET_SERVER_USER_CREATE_PACKET_POOL */ -UINT _nxe_telnet_server_start(NX_TELNET_SERVER *server_ptr); -UINT _nx_telnet_server_start(NX_TELNET_SERVER *server_ptr); -UINT _nxe_telnet_server_stop(NX_TELNET_SERVER *server_ptr); -UINT _nx_telnet_server_stop(NX_TELNET_SERVER *server_ptr); -UINT _nxe_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); -UINT _nx_telnet_server_get_open_connection_count(NX_TELNET_SERVER *server_ptr, UINT *current_connections); - -/* Define internal TELNET functions. */ - -VOID _nx_telnet_server_thread_entry(ULONG telnet_server); -VOID _nx_telnet_server_connect_process(NX_TELNET_SERVER *server_ptr); -VOID _nx_telnet_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); -VOID _nx_telnet_server_disconnect_present(NX_TCP_SOCKET *socket_ptr); -VOID _nx_telnet_server_disconnect_process(NX_TELNET_SERVER *server_ptr); -VOID _nx_telnet_server_data_present(NX_TCP_SOCKET *socket_ptr); -VOID _nx_telnet_server_data_process(NX_TELNET_SERVER *server_ptr); -VOID _nx_telnet_server_timeout(ULONG telnet_server_address); -VOID _nx_telnet_server_timeout_processing(NX_TELNET_SERVER *server_ptr); - -#ifndef NX_TELNET_SERVER_OPTION_DISABLE -UINT _nx_telnet_server_send_option_requests(NX_TELNET_SERVER *server_ptr, NX_TELNET_CLIENT_REQUEST *client_req_ptr); -VOID _nx_telnet_server_process_option(NX_TELNET_SERVER *server_ptr, NX_PACKET *packet_ptr, UINT *offset, NX_TELNET_CLIENT_REQUEST *client_request_ptr); -VOID _nx_telnet_server_create_option_packet(UCHAR option_message_type, UCHAR option_id, UCHAR *stream); -#endif /* NX_TELNET_SERVER_OPTION_DISABLE */ -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_TELNET_SERVER_H */ diff --git a/protocol_handlers/tftp/nxd_tftp_client.c b/protocol_handlers/tftp/nxd_tftp_client.c deleted file mode 100644 index c5a23a4c..00000000 --- a/protocol_handlers/tftp/nxd_tftp_client.c +++ /dev/null @@ -1,2396 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Trivial File Transfer Protocol (TFTP) Client */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_TFTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_ipv6.h" -#include "nxd_tftp_client.h" - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP client create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* tftp_client_name Name of TFTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id == NXD_TFTP_CLIENT_ID) || - (pool_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Call actual client create function. */ - status = _nxd_tftp_client_create(tftp_client_ptr, tftp_client_name, ip_ptr, pool_ptr, ip_type); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a TFTP client on the specified IP. In doing */ -/* so this function creates an UDP socket for subsequent TFTP */ -/* transfers. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* tftp_client_name Name of TFTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to TFTP pool */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_bind Bind the UDP socket */ -/* nx_udp_socket_create Create a UDP socket */ -/* nx_udp_socket_delete Delete the UDP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type) -{ - -UINT status; - - - /* Clear the TFTP server structure. */ - memset((void *) tftp_client_ptr, 0, sizeof(NX_TFTP_CLIENT)); - - /* Setup the TFTP client data structure. */ - - /* Save the TFTP client name. */ - tftp_client_ptr -> nx_tftp_client_name = tftp_client_name; - - /* Save the TFTP IP pointer. */ - tftp_client_ptr -> nx_tftp_client_ip_ptr = ip_ptr; - - /* Save the TFTP packet pool pointer. */ - tftp_client_ptr -> nx_tftp_client_packet_pool_ptr = pool_ptr; - - /* Initialize the server port number. This can change after the open request. */ - tftp_client_ptr -> nx_tftp_client_server_port = NX_TFTP_SERVER_PORT; - - /* Setup the current state to not open. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_NOT_OPEN; - - /* Default the client network interface to the primary interface. */ - tftp_client_ptr -> nx_tftp_client_interface_index = 0; - - /* Create the UDP socket. */ - status = nx_udp_socket_create(ip_ptr, &(tftp_client_ptr -> nx_tftp_client_socket), tftp_client_name, - NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH); - - /* Determine if an error occurred. */ - if (status) - { - - /* Yes, return error code. */ - return(status); - } - - /* Now, bind the socket to a port number. */ - - /* Let NetX decide which port. */ - status = nx_udp_socket_bind(&(tftp_client_ptr -> nx_tftp_client_socket), NX_TFTP_SOURCE_PORT, NX_WAIT_FOREVER); - - /* Determine if an error occurred. */ - if (status) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_client_ptr -> nx_tftp_client_socket)); - - /* Yes, return error code. */ - return(status); - } - - /* Otherwise, all is okay. Set the TFTP ID to indicate success. */ - tftp_client_ptr -> nx_tftp_client_id = NXD_TFTP_CLIENT_ID; - - NX_PARAMETER_NOT_USED(ip_type); - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_delete Actual client delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nxd_tftp_client_delete(tftp_client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a TFTP client on the specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind the UDP socket */ -/* nx_udp_socket_delete Delete the UDP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr) -{ - - /* Unbind the TFTP client UDP socket. */ - nx_udp_socket_unbind(&(tftp_client_ptr -> nx_tftp_client_socket)); - - /* Delete the TFTP client UDP socket. */ - nx_udp_socket_delete(&(tftp_client_ptr -> nx_tftp_client_socket)); - - /* Clear the TFTP client ID. */ - tftp_client_ptr -> nx_tftp_client_id = 0; - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP client set interface */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* if_index Interface for tftp messages */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_INTERFACE Invalid interface index input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_set_interface Actual set interface call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index) -{ - -UINT status; - - /* Check for invalid input pointer input. */ - if (tftp_client_ptr == NX_NULL) - return(NX_PTR_ERROR); - - /* Verify a valid index as been supplied. */ - if (if_index >= NX_MAX_PHYSICAL_INTERFACES) - { - return NX_TFTP_INVALID_INTERFACE; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nxd_tftp_client_set_interface(tftp_client_ptr, if_index); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_set_interface PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the physical interface which the TFTP client */ -/* sends and receives TFTP packets. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* if_index Interface for tftp messages */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* NX_INVALID_INTERFACE Invalid interface index input */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_unbind Unbind the UDP socket */ -/* nx_udp_socket_delete Delete the UDP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index) -{ - - - /* Set the TFTP client interface index. */ - tftp_client_ptr -> nx_tftp_client_interface_index = if_index; - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_error_info_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP error information */ -/* get call. */ -/* */ -/* Note: error_string pointer points to string generated by internal */ -/* logic and it is always NULL-terminated. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* error_code Pointer to destination for */ -/* error code */ -/* error_string Pointer to destination for */ -/* the error string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_error_info_get Actual get error info call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || - (error_code == NX_NULL) || (error_string == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client error information get function. */ - status = _nxd_tftp_client_error_info_get(tftp_client_ptr, error_code, error_string); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_error_info_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function picks up the error code and error string for the */ -/* specified TFTP client instance. */ -/* */ -/* Note: error_string pointer points to string generated by internal */ -/* logic and it is always NULL-terminated. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* error_code Pointer to destination for */ -/* error code */ -/* error_string Pointer to destination for */ -/* the error string */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string) -{ - - /* Return the error code and the error string. */ - *error_code = tftp_client_ptr -> nx_tftp_client_error_code; - *error_string = &(tftp_client_ptr -> nx_tftp_client_error_string[0]); - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_file_close PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP file close call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_file_close Actual client file close */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file close function. */ - status = _nxd_tftp_client_file_close(tftp_client_ptr, ip_type); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_file_close PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function closes the previously opened TFTP file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion status */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet for 0-length */ -/* data packet */ -/* nxd_udp_socket_send Send UDP data packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type) -{ - -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT status; - - - /* Determine if the file is still open for writing. */ - if (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_WRITE_OPEN) - { - - /* Allocate a new packet for the final data message. */ - if (ip_type == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &packet_ptr, NX_IPv4_UDP_PACKET, NX_NO_WAIT); - } - else - { - status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &packet_ptr, NX_IPv6_UDP_PACKET, NX_NO_WAIT); - } - - /* Determine if an error occurred trying to allocate a packet. */ - if (status != NX_SUCCESS) - { - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Return error condition. */ - return(status); - } - - if (4u > ((ULONG)(packet_ptr -> nx_packet_data_end) - (ULONG)(packet_ptr -> nx_packet_append_ptr))) - { - /* Return the unsent packet to the packet pool. */ - nx_packet_release(packet_ptr); - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - return(NX_SIZE_ERROR); - } - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now, build the TFTP 0-data length message. */ - - /* Setup a pointer to the packet payload. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Initial byte is always zero. */ - *buffer_ptr++ = 0; - - /* Set the ACK code. */ - *buffer_ptr++ = NX_TFTP_CODE_DATA; - - /* Put the block number in. */ - *buffer_ptr++ = (UCHAR) ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8)); - *buffer_ptr = (UCHAR) ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF)); - - /* Adjust the packet pointers and length. */ - packet_ptr -> nx_packet_length = 4; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr + 4; - - /* Send the 0-length data packet out. */ - status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, - &tftp_client_ptr -> nx_tftp_client_server_ip, - tftp_client_ptr -> nx_tftp_client_server_port); - - /* Determine if an error occurred trying to sending the packet. */ - if (status) - { - - /* Return the unsent packet to the packet pool. */ - nx_packet_release(packet_ptr); - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Return error condition. */ - return(status); - } - } - - /* Indicate the client is finished with the file. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_FINISHED; - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_tftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP file open call. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* file_name Pointer to file name */ -/* server_ip_address IP address of TFTP server */ -/* open_type Open for read or write */ -/* wait_option Timeout for the open request */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_IP_ADDRESS_ERROR Invalid address supplied */ -/* NX_OPTION_ERROR Invalid TFTP option supplied */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_client_file_open Actual client file open */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option) -{ - -#ifndef NX_DISABLE_IPV4 -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid server IP address. */ - if (server_ip_address == 0) - return(NX_IP_ADDRESS_ERROR); - - /* Check for illegal open option type. */ - if ((open_type != NX_TFTP_OPEN_FOR_READ) && (open_type != NX_TFTP_OPEN_FOR_WRITE)) - return(NX_OPTION_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file open function. */ - status = _nx_tftp_client_file_open(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option); - - /* Return completion status. */ - return(status); -#else - NX_PARAMETER_NOT_USED(tftp_client_ptr); - NX_PARAMETER_NOT_USED(file_name); - NX_PARAMETER_NOT_USED(server_ip_address); - NX_PARAMETER_NOT_USED(open_type); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens a TFTP file. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* file_name Pointer to file name */ -/* tftp_server_address IP address of TFTP server */ -/* open_type Open for read or write */ -/* wait_option Timeout for the open request */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_client_file_open_internal Actual open service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option) -{ -#ifndef NX_DISABLE_IPV4 -UINT status; - - -NXD_ADDRESS server_address; - - /* Create the IPv4 address block. Set the version to IPv4. */ - server_address.nxd_ip_version = NX_IP_VERSION_V4; - server_address.nxd_ip_address.v4 = server_ip_address; - - /* Call the actual file open service. */ - status = _nx_tftp_client_file_open_internal(tftp_client_ptr, file_name, &server_address, open_type, wait_option, NX_IP_VERSION_V4); - - - /* Return the completion status. */ - return status; -#else - NX_PARAMETER_NOT_USED(tftp_client_ptr); - NX_PARAMETER_NOT_USED(file_name); - NX_PARAMETER_NOT_USED(server_ip_address); - NX_PARAMETER_NOT_USED(open_type); - NX_PARAMETER_NOT_USED(wait_option); - - return(NX_NOT_SUPPORTED); -#endif /* NX_DISABLE_IPV4 */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP file open call. */ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* file_name Pointer to file name */ -/* server_ip_address IP address of TFTP server */ -/* open_type Open for read or write */ -/* wait_option Timeout for the open request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* NX_IP_ADDRESS_ERROR Invalid address supplied */ -/* NX_OPTION_ERROR Invalid TFTP option supplied */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_file_open Actual client file open */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for an invalid server IP address. */ - if (!server_ip_address) - return(NX_IP_ADDRESS_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for illegal open option type. */ - if ((open_type != NX_TFTP_OPEN_FOR_READ) && (open_type != NX_TFTP_OPEN_FOR_WRITE)) - return(NX_OPTION_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file open function. */ - status = _nxd_tftp_client_file_open(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option, ip_type); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_file_open PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens a TFTP file received over IPv4 or IPv6 networks.*/ -/* */ -/* Note: The string length of file_name is limited by the packet */ -/* payload size. */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* file_name Pointer to file name */ -/* tftp_server_address IP address of TFTP server */ -/* open_type Open for read or write */ -/* wait_option Timeout for the open request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ -/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ -/* NX_TFTP_NOT_CLOSED TFTP client file already open */ -/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_client_file_open_internal Actual open service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Call the actual file open service. */ - status = _nx_tftp_client_file_open_internal(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option, ip_type); - - /* Return the completion status. */ - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_client_file_open_internal PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens a TFTP file received. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* file_name Pointer to file name */ -/* tftp_server_address IP address of TFTP server */ -/* open_type Open for read or write */ -/* wait_option Timeout for the open request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ -/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ -/* NX_TFTP_NOT_CLOSED TFTP client file already open */ -/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet for TFTP */ -/* request or data */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_receive Receive UDP data packet */ -/* nxd_udp_socket_send Send UDP data packet */ -/* nxd_udp_source_extract Extract IP and port from msg */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tftp_client_file_open_internal(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type) - -{ - -UINT status; -UINT i; -NXD_ADDRESS ip_address; - -UINT port; -UCHAR *buffer_ptr; -NX_PACKET *packet_ptr; -UINT matching = NX_FALSE; - - - /* Determine if the TFTP instance is already open. */ - if ((tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_OPEN) || - (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_WRITE_OPEN)) - { - - /* This instance is already open, return an error. */ - return(NX_TFTP_NOT_CLOSED); - } - - /* Enter the open state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_OPEN; - - /* Save the server's IP address. */ - - if (ip_type == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - return NX_TFTP_INVALID_IP_VERSION; -#else - COPY_NXD_ADDRESS(server_ip_address, &tftp_client_ptr -> nx_tftp_client_server_ip); -#endif - } - else - { - -#ifndef NX_DISABLE_IPV4 - /* If not IPv6, assume the client IP request is using IPv4 if not explicitly specified. */ - tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_version = ip_type; - tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4 = server_ip_address -> nxd_ip_address.v4; -#else - return NX_TFTP_INVALID_IP_VERSION; -#endif /* NX_DISABLE_IPV4 */ - } - - /* Initialize the server port number. This can change after the open request. */ - tftp_client_ptr -> nx_tftp_client_server_port = NX_TFTP_SERVER_PORT; - - /* Clear the error code. */ - tftp_client_ptr -> nx_tftp_client_error_code = 0; - - /* Specify that the first block. */ - tftp_client_ptr -> nx_tftp_client_block_number = 1; - - /* Allocate a packet for initial open request message. Determine whether we are sending - IPv4 or IPv6 packets. */ - - if (ip_type == NX_IP_VERSION_V4) - { - - status = nx_packet_allocate((tftp_client_ptr -> nx_tftp_client_ip_ptr) -> nx_ip_default_packet_pool, - &packet_ptr, NX_IPv4_UDP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate((tftp_client_ptr -> nx_tftp_client_ip_ptr) -> nx_ip_default_packet_pool, - &packet_ptr, NX_IPv6_UDP_PACKET, wait_option); - } - - /* Determine if an error occurred trying to allocate a packet. */ - if (status != NX_SUCCESS) - { - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Return error condition. */ - return(status); - } - - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Now, build the TFTP open request. */ - - /* Setup a pointer to the packet payload. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Initial byte is always zero. */ - *buffer_ptr++ = 0; - - /* Determine the type of open requested. */ - if (open_type == NX_TFTP_OPEN_FOR_READ) - *buffer_ptr++ = NX_TFTP_CODE_READ; - else - *buffer_ptr++ = NX_TFTP_CODE_WRITE; - - /* Now place the file name in the buffer. */ - i = 0; - while (file_name[i] && (ULONG)(packet_ptr -> nx_packet_data_end - buffer_ptr) > 7u) - { - - /* Store character of file name into request. */ - *buffer_ptr++ = (UCHAR) file_name[i]; - i++; - } - - /* Place a NULL after the file name. */ - *buffer_ptr++ = NX_NULL; - - /* Now place the mode string. */ - *buffer_ptr++ = (UCHAR) 'O'; - *buffer_ptr++ = (UCHAR) 'C'; - *buffer_ptr++ = (UCHAR) 'T'; - *buffer_ptr++ = (UCHAR) 'E'; - *buffer_ptr++ = (UCHAR) 'T'; - - /* Place a NULL after the mode. */ - *buffer_ptr++ = NX_NULL; - - /* Adjust the packet length and the append pointer. */ - packet_ptr -> nx_packet_append_ptr = buffer_ptr; - packet_ptr -> nx_packet_length = (ULONG)(buffer_ptr - packet_ptr -> nx_packet_prepend_ptr); - - /* Now send the open request to the TFTP server. */ - status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, - server_ip_address, tftp_client_ptr -> nx_tftp_client_server_port); - - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - nx_packet_release(packet_ptr); - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Return error condition. */ - return(status); - } - - /* Determine if the TFTP file was open for writing. */ - if (open_type == NX_TFTP_OPEN_FOR_WRITE) - { - - /* Change to the open for writing state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_WRITE_OPEN; - - /* Open for write request is present. We now need to wait for the ACK of block number 0 - from the server. */ - status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), &packet_ptr, wait_option); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Return error condition. */ - return(status); - } - - /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ - if (packet_ptr -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_INVALID_PACKET); - } - - /* Extract the source IP and port numbers. */ - status = nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - - /* Check for an invalid server IP address. */ - -#ifndef NX_DISABLE_IPV4 - if ((ip_type == NX_IP_VERSION_V4)&& - (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4)) - { - - matching = NX_TRUE; - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (ip_type == NX_IP_VERSION_V6) - { - - if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) - { - - matching = NX_TRUE; - } - } - else -#endif - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_TFTP_INVALID_IP_VERSION; - } - - /* Do we have a match? */ - if (!matching) - { - /* No, invalid IP address! */ - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_INVALID_SERVER_ADDRESS); - } - - /* Save the source port since the server can change its port. */ - tftp_client_ptr -> nx_tftp_client_server_port = port; - - /* Check for valid server ACK. */ - - /* Setup a pointer to the packet payload. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Check for valid ACK message. */ - if ((buffer_ptr[0] != 0) || (buffer_ptr[1] != NX_TFTP_CODE_ACK) || - (buffer_ptr[2] != 0) || (buffer_ptr[3] != 0) || - (packet_ptr -> nx_packet_length != 4)) - { - - UINT code; - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Get the error status from the server message. */ - buffer_ptr++; - code = *(buffer_ptr); - - /* If this is a server error, save it to the TFTP client. */ - if (code == NX_TFTP_CODE_ERROR) - { - - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code = ((UINT) (*buffer_ptr)) << 8; - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); - buffer_ptr++; - - /* Loop to save error message to TFTP Client. */ - tftp_client_ptr -> nx_tftp_client_error_string[sizeof(tftp_client_ptr -> nx_tftp_client_error_string) - 1] = NX_NULL; - for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++) - { - - /* Store desired file name. */ - tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; - - /* Check for NULL character. */ - if (tftp_client_ptr -> nx_tftp_client_error_string[i] == NX_NULL) - { - break; - } - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_CODE_ERROR); - } - /* Unknown code, not an error or an ACK. */ - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_NO_ACK_RECEIVED); - } - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - } - - /* Otherwise, return success! */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_file_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP file read call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* packet_ptr Pointer to destination for */ -/* return packet pointer */ -/* wait_option Timeout for the read request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_file_read Actual client file read */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file read function. */ - status = _nxd_tftp_client_file_read(tftp_client_ptr, packet_ptr, wait_option, ip_type); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_file_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function reads a buffer from a previously opened TFTP file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* packet_ptr Pointer to destination for */ -/* return packet pointer */ -/* wait_option Timeout for the read request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_TFTP_CLIENT_NOT_OPEN Requested file not open */ -/* NX_TFTP_INVALID_SERVER_ADDRESS Reply from unknown Server */ -/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ -/* NX_TFTP_END_OF_FILE No more data in file */ -/* NX_TFTP_INVALID_BLOCK_NUMBER Mismatching block number in */ -/* received TFTP packet */ -/* NX_TFTP_CODE_ERROR Unknown TFTP code received */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet for ACK packet*/ -/* nx_packet_release Release packet */ -/* nx_udp_socket_receive Receive UDP data packet */ -/* nxd_udp_socket_send Send TFTP ACK packet */ -/* nxd_udp_source_extract Extract IP and port from msg */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UCHAR *buffer_ptr; -UINT status; -NXD_ADDRESS ip_address; -UINT port; -UINT i; -USHORT block_number; -UCHAR code; -NX_PACKET *ack_packet; -UINT matching = NX_FALSE; -UCHAR resend_ACK_packet = NX_FALSE; - - - /* Determine if we are still in an open state. */ - if (tftp_client_ptr -> nx_tftp_client_state != NX_TFTP_STATE_OPEN) - { - - /* This instance is not open, return an error. */ - if (tftp_client_ptr -> nx_tftp_client_state == NX_TFTP_STATE_END_OF_FILE) - return(NX_TFTP_END_OF_FILE); - else - return(NX_TFTP_NOT_OPEN); - } - - /* Read the next block of the file. */ - status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, wait_option); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Check for the type of error. */ - if (status != NX_NO_PACKET) - { - - /* Serious error, enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - } - - /* Return error condition. */ - return(status); - } - - /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ - if ((*packet_ptr) -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - /* Return. */ - return(NX_INVALID_PACKET); - } - - /* At this point, we have a block of the file from the server. */ - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(*packet_ptr, &ip_address, &port); - - /* Check for an invalid server IP address. */ - -#ifndef NX_DISABLE_IPV4 - if (ip_type == NX_IP_VERSION_V4) - { - - if (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4) - { - matching = NX_TRUE; - } - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (ip_type == NX_IP_VERSION_V6) - { - if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) - { - - matching = NX_TRUE; - } - } - else -#endif - { - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - return NX_TFTP_INVALID_IP_VERSION; - } - - /* Do we have a match? */ - if (matching == NX_FALSE) - { - - /* No, Invalid IP address! */ - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Return error condition. */ - return(NX_TFTP_INVALID_SERVER_ADDRESS); - } - - /* Save the source port since the server can change its port. */ - tftp_client_ptr -> nx_tftp_client_server_port = port; - - /* Setup a pointer to the buffer. */ - buffer_ptr = (*packet_ptr) -> nx_packet_prepend_ptr; - - /* Pickup the type of packet. */ - buffer_ptr++; - code = *buffer_ptr; - - /* Is a data packet present? */ - if (code == NX_TFTP_CODE_DATA) - { - - /* Yes, a data packet is present. */ - - /* Pickup the block number. */ - buffer_ptr++; - block_number = (USHORT)((*buffer_ptr) << 8); - buffer_ptr++; - block_number = (USHORT)(block_number | (*buffer_ptr)); - - /* Check if the server didn't receive last TFTP ACK. */ - if ((USHORT)(tftp_client_ptr -> nx_tftp_client_block_number - 1) == block_number) - { - - /* The Server will resend previous packet till it times out. - set a flag to indicate we need to resend the ACK packet to - prevent this. */ - resend_ACK_packet = NX_TRUE; - } - /* Is there a block number match (greater than 1) ? */ - else if (tftp_client_ptr -> nx_tftp_client_block_number != block_number) - { - - /* Block numbers don't match. Invalid packet or old data packet. Discard it. */ - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Return error condition. */ - return(NX_TFTP_INVALID_BLOCK_NUMBER); - } - - /* Valid block number, end ACK back to server. */ - - /* Allocate a new packet for the ACK message. Determine whether we are sending - IPv4 or IPv6 packets. */ - - if (ip_type == NX_IP_VERSION_V4) - { - - status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &ack_packet, NX_IPv4_UDP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &ack_packet, NX_IPv6_UDP_PACKET, wait_option); - } - - /* Determine if an error occurred trying to allocate a packet. */ - if (status != NX_SUCCESS) - { - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the data packet. */ - nx_packet_release(*packet_ptr); - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Return error condition. */ - return(status); - } - - if (4u > ((ULONG)(ack_packet -> nx_packet_data_end) - (ULONG)(ack_packet -> nx_packet_append_ptr))) - { - nx_packet_release(*packet_ptr); - - nx_packet_release(ack_packet); - return(NX_SIZE_ERROR); - } - - ack_packet -> nx_packet_append_ptr = ack_packet -> nx_packet_prepend_ptr; - - /* Valid block number, we need to send an ACK back to server. So now - build the TFTP ACK message. */ - - /* Setup a pointer to the packet payload. */ - buffer_ptr = ack_packet -> nx_packet_prepend_ptr; - - /* Initial byte is always zero. */ - *buffer_ptr++ = 0; - - /* Set the ACK code. */ - *buffer_ptr++ = NX_TFTP_CODE_ACK; - - /* Put the block number in. */ - *buffer_ptr++ = (UCHAR) (block_number >> 8); - *buffer_ptr = (UCHAR) (block_number & 0xFF); - - /* Adjust the ACK packet pointers and length. */ - ack_packet -> nx_packet_length = 4; - ack_packet -> nx_packet_append_ptr = ack_packet -> nx_packet_append_ptr + 4; - - /* Send the ACK packet out. */ - status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), ack_packet, - &tftp_client_ptr -> nx_tftp_client_server_ip, - tftp_client_ptr -> nx_tftp_client_server_port); - - /* Check error status. */ - if (status != NX_SUCCESS) - { - nx_packet_release(*packet_ptr); - - nx_packet_release(ack_packet); - return status; - } - - /* If we received a duplicate data packet, release it here. */ - if (resend_ACK_packet == NX_TRUE) - { - - /* ACK for previous packet sent, so we can release this duplicate packet. */ - nx_packet_release(*packet_ptr); - - /* Set packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Do not handle as an error. Indicate the TFTP Client is still downloading a file. */ - return NX_TFTP_INVALID_BLOCK_NUMBER; - } - - /* Adjust the packet to position past the TFTP header. */ - (*packet_ptr) -> nx_packet_length = (*packet_ptr) -> nx_packet_length - 4; - (*packet_ptr) -> nx_packet_prepend_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + 4; - - /* Check for end of file condition. Anything less than 512 bytes signals an end of file. */ - if ((*packet_ptr) -> nx_packet_length < NX_TFTP_FILE_TRANSFER_MAX) - { - - /* End of file is present. */ - - /* Mark the state as end of file. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_END_OF_FILE; - - - /* Return EOF condition. */ - return(NX_TFTP_END_OF_FILE); - - } - else - { - - /* More packets are still required. Increment the block number. */ - tftp_client_ptr -> nx_tftp_client_block_number++; - } - - /* Return a successful status. */ - return(NX_SUCCESS); - } - else if (code == NX_TFTP_CODE_ERROR) - { - - /* Error code received. */ - - /* Change the state to error. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Save the error code and message. */ - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code = (((UINT) (*buffer_ptr)) << 8); - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); - buffer_ptr++; - - /* Loop to save error message. */ - for (i = 0; (i < (sizeof(tftp_client_ptr -> nx_tftp_client_error_string) -1)) && (*buffer_ptr); i++) - { - - /* Store desired file name. */ - tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; - } - - /* Set NULL terminator. */ - tftp_client_ptr -> nx_tftp_client_error_string[i] = NX_NULL; - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - /* Return a failed status. */ - return(NX_TFTP_CODE_ERROR); - } - /* This could be an ack from the previous file write. Just ignore it. */ - else if (code == NX_TFTP_CODE_ACK) - { - - /* Release the data packet. */ - nx_packet_release(*packet_ptr); - - /* Not an error. */ - return NX_SUCCESS; - } - else - { - - /* Change the state to error. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the packet. */ - nx_packet_release(*packet_ptr); - - /* Return a failed status. */ - return(NX_TFTP_FAILED); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_file_write PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP file write call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* packet_ptr Pointer to packet */ -/* wait_option Timeout for the write request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_client_file_write Actual client file write */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NXD_TFTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client file write function. */ - status = _nxd_tftp_client_file_write(tftp_client_ptr, packet_ptr, wait_option, ip_type); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_file_write PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function writes a buffer to a previously opened TFTP file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_client_ptr Pointer to TFTP client */ -/* packet_ptr Pointer to packet */ -/* wait_option Timeout for the write request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_TFTP_INVALID_IP_VERSION Unsupported IP protocol */ -/* NX_TFTP_NO_ACK_RECEIVED ACK not received from Server */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_receive Receive UDP data packet */ -/* nxd_udp_socket_send Send TFTP ACK packet */ -/* nxd_udp_source_extract Extract IP and port */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UCHAR *buffer_ptr; -UINT status; -ULONG length; -NXD_ADDRESS ip_address; -UINT port; -UINT matching = NX_FALSE; - - - /* Determine if we are still in an open state. */ - if (tftp_client_ptr -> nx_tftp_client_state != NX_TFTP_STATE_WRITE_OPEN) - { - - /* This instance is not open, return an error. */ - return(NX_TFTP_NOT_OPEN); - } - - /* Save the length of the TFTP write data. */ - length = packet_ptr -> nx_packet_length; - - /* Place the TFTP information in front of the data packet. */ - packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - 4; - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + 4; - - /* Setup a pointer to the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Set the TFTP data code. */ - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_DATA; - - /* Set the block number. */ - *buffer_ptr++ = (UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8); - *buffer_ptr++ = (UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF); - - /* Send the data packet out. */ - status = nxd_udp_socket_send(&(tftp_client_ptr -> nx_tftp_client_socket), packet_ptr, - &tftp_client_ptr -> nx_tftp_client_server_ip, tftp_client_ptr -> nx_tftp_client_server_port); - - /* Determine if an error occurred trying to send the packet. */ - if (status) - { - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the data packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(status); - } - - /* We now need to wait for the ACK for this write request. */ - status = nx_udp_socket_receive(&(tftp_client_ptr -> nx_tftp_client_socket), &packet_ptr, wait_option); - - /* Check the return status. */ - if (status) - { - - /* Return error code, the application may rebuild another packet and try again. */ - - /* Return error condition. */ - return(NX_TFTP_TIMEOUT); - } - - /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ - if (packet_ptr -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return(NX_INVALID_PACKET); - } - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - /* Check for an invalid server IP address. */ - -#ifndef NX_DISABLE_IPV4 - if (ip_type == NX_IP_VERSION_V4) - { - - if (ip_address.nxd_ip_address.v4 == tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v4) - { - matching = NX_TRUE; - } - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (ip_type == NX_IP_VERSION_V6) - { - if (CHECK_IPV6_ADDRESSES_SAME(&ip_address.nxd_ip_address.v6[0], &tftp_client_ptr -> nx_tftp_client_server_ip.nxd_ip_address.v6[0])) - { - - matching = NX_TRUE; - } - } - else -#endif - { - /* Release the packet. */ - nx_packet_release(packet_ptr); - - return NX_TFTP_INVALID_IP_VERSION; - } - - /* Do we have a match? */ - if (!matching) - { - - /* No, Invalid IP address! */ - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_INVALID_SERVER_ADDRESS); - } - - /* Setup a pointer to the buffer. */ - buffer_ptr = (packet_ptr) -> nx_packet_prepend_ptr; - - /* Check for valid ACK message. */ - if ((buffer_ptr[0] != 0) || (buffer_ptr[1] != NX_TFTP_CODE_ACK) || - (buffer_ptr[2] != ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number >> 8))) || - (buffer_ptr[3] != ((UCHAR) (tftp_client_ptr -> nx_tftp_client_block_number & 0xFF))) || - (packet_ptr -> nx_packet_length != 4)) - { - - UINT code; - - /* Enter error state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_ERROR; - - /* Get the error status from the server message. */ - buffer_ptr++; - code = *(buffer_ptr); - - /* Check if this is a error reported by the server. If so save it to - the TFTP Client. */ - if (code == NX_TFTP_CODE_ERROR) - { - UINT i; - - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code = ((UINT) (*buffer_ptr)) << 8; - buffer_ptr++; - tftp_client_ptr -> nx_tftp_client_error_code |= (UINT) (*buffer_ptr); - buffer_ptr++; - - /* Loop to save error message. */ - for (i = 0; (i < (sizeof(tftp_client_ptr -> nx_tftp_client_error_string) -1)) && (*buffer_ptr); i++) - { - - /* Store desired file name. */ - tftp_client_ptr -> nx_tftp_client_error_string[i] = (CHAR) *buffer_ptr++; - } - - /* Set NULL terminator. */ - tftp_client_ptr -> nx_tftp_client_error_string[i] = NX_NULL; - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_CODE_ERROR); - } - /* Unknown code, not an error or an ACK. */ - else - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return error condition. */ - return(NX_TFTP_NO_ACK_RECEIVED); - } - } - - /* At this point, everything is okay. */ - - /* Release the ACK packet. */ - nx_packet_release(packet_ptr); - - /* Check the length to see if we have the end of the file. */ - if (length < NX_TFTP_FILE_TRANSFER_MAX) - { - - /* Yes, this is the last packet. */ - - /* Enter into the finished state. */ - tftp_client_ptr -> nx_tftp_client_state = NX_TFTP_STATE_FINISHED; - } - else - { - - /* More blocks to transfer still, increment the block number. */ - tftp_client_ptr -> nx_tftp_client_block_number++; - } - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_client_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP packet allocate call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* pool_ptr Pointer to packet pool */ -/* packet_ptr Pointer to destination for */ -/* pointer of newly allocated */ -/* packet */ -/* wait_option Timeout for the request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_INVALID_PARAMETERS Invalid non pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp _client_file_write Actual client file write */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((pool_ptr == NX_NULL) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for valid IP version*/ - if ((ip_type != NX_IP_VERSION_V4) && (ip_type != NX_IP_VERSION_V6)) - { - return NX_INVALID_PARAMETERS; - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client packet allocate function. */ - status = _nxd_tftp_client_packet_allocate(pool_ptr, packet_ptr, wait_option, ip_type); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_client_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a packet with extra room for the TFTP */ -/* control information. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* pool_ptr Pointer to packet pool */ -/* packet_ptr Pointer to destination for */ -/* pointer of newly allocated */ -/* packet */ -/* wait_option Timeout for the request */ -/* ip_type IP type */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type) -{ - -UINT status; - - - /* Allocate a new packet. Determine whether we are sending IPv4 or IPv6 packets. */ - if (ip_type == NX_IP_VERSION_V4) - { - - status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv4_UDP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate(pool_ptr, packet_ptr, NX_IPv6_UDP_PACKET, wait_option); - } - - /* Determine if an error is present. */ - if (status) - { - - /* Return the error code from the allocate routine. */ - return(status); - } - - (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr; - - /* Successful packet allocation. Adjust the prepend and append pointers forward to - accommodate the TFTP header. */ - (*packet_ptr) -> nx_packet_prepend_ptr += 4; - (*packet_ptr) -> nx_packet_append_ptr += 4; - - /* Return success to the caller. */ - return(NX_SUCCESS); -} - diff --git a/protocol_handlers/tftp/nxd_tftp_client.h b/protocol_handlers/tftp/nxd_tftp_client.h deleted file mode 100644 index 96e46b6c..00000000 --- a/protocol_handlers/tftp/nxd_tftp_client.h +++ /dev/null @@ -1,313 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Trivial File Transfer Protocol (TFTP) Client */ -/** */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_tftp_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ -/* Client component, including all data types and external references */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_TFTP_CLIENT_H -#define NXD_TFTP_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the NetX TFTP CLIENT ID. */ - -#define NXD_TFTP_CLIENT_ID 0x54465460UL - - -/* Define TFTP maximum error string. */ - -#ifndef NX_TFTP_ERROR_STRING_MAX -#define NX_TFTP_ERROR_STRING_MAX 64 /* Maximum error sting size */ -#endif - -/* Define TFTP UDP socket create options. */ - -#ifndef NX_TFTP_TYPE_OF_SERVICE -#define NX_TFTP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_TFTP_FRAGMENT_OPTION -#define NX_TFTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_TFTP_TIME_TO_LIVE -#define NX_TFTP_TIME_TO_LIVE 0x80 -#endif - - -/* If the host application wishes to specify a source port, define it here. The default is to let - NetX choose the TFTP Client source port. */ -#ifndef NX_TFTP_SOURCE_PORT -#define NX_TFTP_SOURCE_PORT NX_ANY_PORT -#endif - -#define NX_TFTP_QUEUE_DEPTH 5 - -#define NX_TFTP_FILE_TRANSFER_MAX 512 /* 512 byte maximum file transfer */ - - -/* Define open types. */ - -#define NX_TFTP_OPEN_FOR_READ 0x01 /* TFTP open for reading */ -#define NX_TFTP_OPEN_FOR_WRITE 0x02 /* TFTP open for writing */ - - -/* Define TFTP message codes. */ - -#define NX_TFTP_CODE_READ 0x01 /* TFTP read file request */ -#define NX_TFTP_CODE_WRITE 0x02 /* TFTP write file request */ -#define NX_TFTP_CODE_DATA 0x03 /* TFTP data packet */ -#define NX_TFTP_CODE_ACK 0x04 /* TFTP command/data acknowledgement */ -#define NX_TFTP_CODE_ERROR 0x05 /* TFTP error message */ - - -/* Define TFTP error code constants. */ - -#define NX_TFTP_ERROR_NOT_DEFINED 0x00 /* TFTP not defined error code, see error string */ -#define NX_TFTP_ERROR_FILE_NOT_FOUND 0x01 /* TFTP file not found error code */ -#define NX_TFTP_ERROR_ACCESS_VIOLATION 0x02 /* TFTP file access violation error code */ -#define NX_TFTP_ERROR_DISK_FULL 0x03 /* TFTP disk full error code */ -#define NX_TFTP_ERROR_ILLEGAL_OPERATION 0x04 /* TFTP illegal operation error code */ -#define NX_TFTP_CODE_ERROR 0x05 /* TFTP client request received error code from server */ -#define NX_TFTP_ERROR_FILE_EXISTS 0x06 /* TFTP file already exists error code */ -#define NX_TFTP_ERROR_NO_SUCH_USER 0x07 /* TFTP no such user error code */ -#define NX_TFTP_INVALID_SERVER_ADDRESS 0x08 /* Invalid TFTP server IP extracted from received packet*/ -#define NX_TFTP_NO_ACK_RECEIVED 0x09 /* Did not receive TFTP server ACK response */ -#define NX_TFTP_INVALID_BLOCK_NUMBER 0x0A /* Invalid block number received from Server response */ -#define NX_TFTP_INVALID_INTERFACE 0x0B /* Invalid interface for TFTP Client */ - /* (or multihome not supported) */ -#define NX_TFTP_INVALID_IP_VERSION 0x0C /* Invalid or unsupported IP version specified */ - - -/* Define offsets into the TFTP message buffer. */ - -#define NX_TFTP_CODE_OFFSET 0 /* Offset to TFTP code in buffer */ -#define NX_TFTP_FILENAME_OFFSET 2 /* Offset to TFTP filename in message */ -#define NX_TFTP_BLOCK_NUMBER_OFFSET 2 /* Offset to TFTP block number in buffer */ -#define NX_TFTP_DATA_OFFSET 4 /* Offset to TFTP data in buffer */ -#define NX_TFTP_ERROR_CODE_OFFSET 2 /* Offset to TFTP error code */ -#define NX_TFTP_ERROR_STRING_OFFSET 4 /* Offset to TFPT error string */ - - -/* Define return code constants. */ - -#define NX_TFTP_ERROR 0xC0 /* TFTP internal error */ -#define NX_TFTP_TIMEOUT 0xC1 /* TFTP timeout occurred */ -#define NX_TFTP_FAILED 0xC2 /* TFTP error */ -#define NX_TFTP_NOT_OPEN 0xC3 /* TFTP not opened error */ -#define NX_TFTP_NOT_CLOSED 0xC4 /* TFTP not closed error */ -#define NX_TFTP_END_OF_FILE 0xC5 /* TFTP end of file error */ -#define NX_TFTP_POOL_ERROR 0xC6 /* TFTP packet pool size error - less than 560 bytes */ - - -/* Define TFTP connection states. */ - -#define NX_TFTP_STATE_NOT_OPEN 0 /* TFTP connection not open */ -#define NX_TFTP_STATE_OPEN 1 /* TFTP connection open */ -#define NX_TFTP_STATE_WRITE_OPEN 2 /* TFTP connection open for writing */ -#define NX_TFTP_STATE_END_OF_FILE 3 /* TFTP connection at end of file */ -#define NX_TFTP_STATE_ERROR 4 /* TFTP error condition */ -#define NX_TFTP_STATE_FINISHED 5 /* TFTP finished writing condition */ - - -/* Define the TFTP Server UDP port number */ - -#define NX_TFTP_SERVER_PORT 69 /* Port for TFTP server */ - - -/* Define the basic TFTP Client data structure. */ - -typedef struct NX_TFTP_CLIENT_STRUCT -{ - ULONG nx_tftp_client_id; /* TFTP Client ID */ - CHAR *nx_tftp_client_name; /* Name of this TFTP client */ - UINT nx_tftp_client_interface_index; /* Index specifying network interface */ - NX_IP *nx_tftp_client_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_tftp_client_packet_pool_ptr; /* Pointer to TFTP client packet pool */ - NXD_ADDRESS nx_tftp_client_server_ip; /* Server's IP address */ - UINT nx_tftp_client_server_port; /* Server's port number (69 originally) */ - UINT nx_tftp_client_state; /* State of TFTP client */ - USHORT nx_tftp_client_block_number; /* Block number in file transfer */ - USHORT nx_tftp_client_reserved; /* Reserved for future use */ - UINT nx_tftp_client_error_code; /* Error code received */ - CHAR nx_tftp_client_error_string[NX_TFTP_ERROR_STRING_MAX + 1]; - NX_UDP_SOCKET nx_tftp_client_socket; /* TFTP Socket */ - -} NX_TFTP_CLIENT; - - - -#ifndef NX_TFTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/******************* Services without error checking. ***********************/ - -/* NetX (IPv4 supported only) services */ -#define nx_tftp_client_file_open _nx_tftp_client_file_open - -/* For NetX applications, map the NetX TFTP service to the NetX Duo TFTP service. */ -#define nx_tftp_client_create(a,b,c,d) _nxd_tftp_client_create(a,b,c,d,NX_IP_VERSION_V4) -#define nx_tftp_client_packet_allocate(a,b,c) _nxd_tftp_client_packet_allocate(a,b,c, NX_IP_VERSION_V4) -#define nx_tftp_client_delete _nxd_tftp_client_delete -#define nx_tftp_client_error_info_get _nxd_tftp_client_error_info_get -#define nx_tftp_client_file_close(a) _nxd_tftp_client_file_close(a, NX_IP_VERSION_V4) -#define nx_tftp_client_file_read(a,b,c) _nxd_tftp_client_file_read(a,b,c,NX_IP_VERSION_V4) -#define nx_tftp_client_file_write(a,b,c) _nxd_tftp_client_file_write(a,b,c,NX_IP_VERSION_V4) -#define nx_tftp_client_set_interface _nxd_tftp_client_set_interface - -/* NetX Duo TFTP (IPv4 and IPv6 supported) services. */ -#define nxd_tftp_client_create _nxd_tftp_client_create -#define nxd_tftp_client_delete _nxd_tftp_client_delete -#define nxd_tftp_client_file_open _nxd_tftp_client_file_open -#define nxd_tftp_client_error_info_get _nxd_tftp_client_error_info_get -#define nxd_tftp_client_file_close _nxd_tftp_client_file_close -#define nxd_tftp_client_file_read _nxd_tftp_client_file_read -#define nxd_tftp_client_file_write _nxd_tftp_client_file_write -#define nxd_tftp_client_packet_allocate _nxd_tftp_client_packet_allocate -#define nxd_tftp_client_set_interface _nxd_tftp_client_set_interface - -#else - -/*************** Services with error checking. ******************/ - -/* NetX (IPv4 supported only) services */ -#define nx_tftp_client_file_open _nxe_tftp_client_file_open - -/* For NetX TFTP applications, map the NetX TFTP service to the equivalent NetX Duo TFTP service. */ -#define nx_tftp_client_create(a,b,c,d) _nxde_tftp_client_create(a,b,c,d,NX_IP_VERSION_V4) -#define nx_tftp_client_packet_allocate(a,b,c) _nxde_tftp_client_packet_allocate(a,b,c,NX_IP_VERSION_V4) -#define nx_tftp_client_delete _nxde_tftp_client_delete -#define nx_tftp_client_error_info_get _nxde_tftp_client_error_info_get -#define nx_tftp_client_file_close(a) _nxde_tftp_client_file_close(a, NX_IP_VERSION_V4) -#define nx_tftp_client_file_read(a,b,c) _nxde_tftp_client_file_read(a,b,c,NX_IP_VERSION_V4) -#define nx_tftp_client_file_write(a,b,c) _nxde_tftp_client_file_write(a,b,c,NX_IP_VERSION_V4) -#define nx_tftp_client_set_interface _nxde_tftp_client_set_interface - -/* NetX Duo (IPv4 and IPv6 supported) services. */ -#define nxd_tftp_client_create _nxde_tftp_client_create -#define nxd_tftp_client_delete _nxde_tftp_client_delete -#define nxd_tftp_client_file_open _nxde_tftp_client_file_open -#define nxd_tftp_client_error_info_get _nxde_tftp_client_error_info_get -#define nxd_tftp_client_file_close _nxde_tftp_client_file_close -#define nxd_tftp_client_file_read _nxde_tftp_client_file_read -#define nxd_tftp_client_file_write _nxde_tftp_client_file_write -#define nxd_tftp_client_packet_allocate _nxde_tftp_client_packet_allocate -#define nxd_tftp_client_set_interface _nxde_tftp_client_set_interface - - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); - -UINT nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); -UINT nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); -UINT nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); -UINT nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); -UINT nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); -UINT nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); -UINT nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftpv6_client_ptr, UINT if_index); - -#else - -/* TFTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); -UINT _nx_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, ULONG server_ip_address, UINT open_type, ULONG wait_option); - -UINT _nxde_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); -UINT _nxd_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, UINT ip_type); -UINT _nxde_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); -UINT _nxd_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); -UINT _nxde_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); -UINT _nxd_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); -UINT _nxde_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); -UINT _nxd_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr, UINT ip_type); -UINT _nxde_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); -UINT _nxd_tftp_client_file_open(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); -UINT _nxde_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxd_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxde_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxd_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxde_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxd_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option, UINT ip_type); -UINT _nxde_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index); -UINT _nxd_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index); - - - -#endif /* NX_TFTP_SOURCE_CODE */ - -/* Internal functions. */ -UINT _nx_tftp_client_file_open_internal(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *file_name, NXD_ADDRESS *server_ip_address, UINT open_type, ULONG wait_option, UINT ip_type); - - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_TFTP_CLIENT_H */ diff --git a/protocol_handlers/tftp/nxd_tftp_server.c b/protocol_handlers/tftp/nxd_tftp_server.c deleted file mode 100644 index ba066fee..00000000 --- a/protocol_handlers/tftp/nxd_tftp_server.c +++ /dev/null @@ -1,2855 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** Trivial File Transfer Protocol (TFTP) Server */ -/** */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_TFTP_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nxd_tftp_server.h" -#ifdef FEATURE_NX_IPV6 -#include "nx_ipv6.h" -#endif - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* tftp_server_name Name of TFTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* NX_TFTP_POOL_ERROR Invalid packet size for TFTP */ -/* server packet pool */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, - FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id == NXD_TFTP_SERVER_ID) || - (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL)) - { - - return(NX_PTR_ERROR); - } - - /* Pickup a packet from the supplied packet pool. */ - packet_ptr = pool_ptr -> nx_packet_pool_available_list; - - /* Determine if the packet payload is large enough (must include 512 bytes plus packet headers). */ - if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_TFTP_PACKET_SIZE) - { - - return(NX_TFTP_POOL_ERROR); - } - - /* Call actual server create function. */ - status = _nxd_tftp_server_create(tftp_server_ptr, tftp_server_name, ip_ptr, media_ptr, stack_ptr, stack_size, pool_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a TFTP server on the specified IP. In doing */ -/* so this function creates an UDP socket for subsequent TFTP */ -/* transfers and a thread for the TFTP server. */ -/* */ -/* If NX_TFTP_SERVER_RETRANSMIT_ENABLE is enabled, it also creates */ -/* a timer for retransmitting TFTP server packets up to a maximum */ -/* number of retries before terminating the connection. */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* tftpvserver_name Name of TFTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* */ -/* OUTPUT */ -/* */ -/* status Actual cmpletion status */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* nx_udp_socket_bind Bind the TFTP server socket */ -/* nx_udp_socket_create Create TFTP server socket */ -/* nx_udp_socket_delete Delete TFTP server socket */ -/* nx_udp_socket_unbind Unbind TFTP server socket */ -/* tx_thread_create Create TFTP server thread */ -/* tx_timer_create Create retransmit timer */ -/* nx_udp_socket_receive_notify Set a receive callback */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, - FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr) -{ - -UINT status; - - - /* Clear the TFTP server structure. */ - memset((void *) tftp_server_ptr, 0, sizeof(NX_TFTP_SERVER)); - - /* Create the server's UDP socket. */ - status = nx_udp_socket_create(ip_ptr, &(tftp_server_ptr -> nx_tftp_server_socket), tftp_server_name, - NX_TFTP_TYPE_OF_SERVICE, NX_TFTP_FRAGMENT_OPTION, NX_TFTP_TIME_TO_LIVE, NX_TFTP_QUEUE_DEPTH); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, return error code. */ - return(status); - } - - /* Register the receive function. */ - nx_udp_socket_receive_notify(&(tftp_server_ptr -> nx_tftp_server_socket), _nx_tftp_server_data_present); - - /* Make sure the socket points to the TFTP server. */ - tftp_server_ptr -> nx_tftp_server_socket.nx_udp_socket_reserved_ptr = tftp_server_ptr; - - /* Now, bind the socket to a the well known TFTP UDP port number. */ - status = nx_udp_socket_bind(&(tftp_server_ptr -> nx_tftp_server_socket), NX_TFTP_SERVER_PORT, NX_NO_WAIT); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Yes, return error code. */ - return(status); - } - - /* Now create the TFTP Server thread. */ - status = tx_thread_create(&(tftp_server_ptr -> nx_tftp_server_thread), "TFTP Server Thread", _nx_tftp_server_thread_entry, - (ULONG) tftp_server_ptr, stack_ptr, stack_size, NX_TFTP_SERVER_PRIORITY, NX_TFTP_SERVER_PRIORITY, - NX_TFTP_SERVER_TIME_SLICE, TX_DONT_START); - - /* Determine if an error occurred creating the thread. */ - if (status != NX_SUCCESS) - { - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Yes, return error code. */ - return(status); - } - - /* Create the ThreadX event flags. These will be used to drive the TFTP server thread. */ - status = tx_event_flags_create(&(tftp_server_ptr -> nx_tftp_server_event_flags), "TFTP Server Thread Events"); - - /* Determine if an error occurred creating the event flags. */ - if (status != TX_SUCCESS) - { - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the server thread. */ - tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Error creating the server event flags. */ - return(status); - } - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - /* Create the ThreadX retransmit timeout timer. This will be used to retransmit TFTP server - packets if the Client has not responded or sends a duplicate (old) ACK or data packet. */ - status = tx_timer_create(&(tftp_server_ptr -> nx_tftp_server_timer), "TFTP Server Timer", - _nx_tftp_server_timer_entry, (ULONG) tftp_server_ptr, - (NX_TFTP_SERVER_TIMEOUT_PERIOD), - (NX_TFTP_SERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE); - - if (status != NX_SUCCESS) - { - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the event flags. */ - tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags)); - - /* Delete the server thread. */ - tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Yes, return error code. */ - return(status); - } -#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ - - /* Save the Server name. */ - tftp_server_ptr -> nx_tftp_server_name = tftp_server_name; - - /* Save the IP pointer address. */ - tftp_server_ptr -> nx_tftp_server_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - tftp_server_ptr -> nx_tftp_server_packet_pool_ptr = pool_ptr; - - /* Save the media pointer address. */ - tftp_server_ptr -> nx_tftp_server_media_ptr = media_ptr; - - /* Clear the error code and error string. */ - tftp_server_ptr -> nx_tftp_server_error_code = 0; - tftp_server_ptr -> nx_tftp_server_error_string[0] = NX_NULL; - - /* Set the server ID to indicate the TFTP server thread is ready. */ - tftp_server_ptr -> nx_tftp_server_id = NXD_TFTP_SERVER_ID; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP server delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_server_delete Actual server delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nxd_tftp_server_delete(tftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created TFTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* status Actual completion status */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close File close */ -/* nx_udp_socket_delete Delete TFTP server socket */ -/* nx_udp_socket_unbind Unbind TFTP server socket */ -/* tx_thread_delete Delete TFTP server thread */ -/* tx_thread_suspend Suspend TFTP server thread */ -/* tx_thread_terminate Terminate TFTP server */ -/* thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr) -{ - -UINT i; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; - - - /* Clear the server ID to indicate the TFTP server is no longer ready. */ - tftp_server_ptr -> nx_tftp_server_id = 0; - - /* Unbind the UDP socket. */ - nx_udp_socket_unbind(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Delete the UDP socket. */ - nx_udp_socket_delete(&(tftp_server_ptr -> nx_tftp_server_socket)); - - /* Suspend the TFTP server thread. */ - tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Terminate server thread. */ - tx_thread_terminate(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Delete the server flag group. */ - tx_event_flags_delete(&(tftp_server_ptr -> nx_tftp_server_event_flags)); - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - tx_timer_delete(&(tftp_server_ptr -> nx_tftp_server_timer)); -#endif - - - /* Delete server thread. */ - tx_thread_delete(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Walk through the server structure to close any remaining open files. */ - i = 0; - - client_request_ptr = &(tftp_server_ptr -> nx_tftp_server_client_list[0]); - - while (i < NX_TFTP_MAX_CLIENTS) - { - - /* Is this entry in use? */ - - /* First determine which IP address type. */ - if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* This is an IPv4 client. Is this slot empty? */ - if ((client_request_ptr -> nx_tftp_client_request_port != 0) && - (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4) != 0) - { - - /* No, need to close the file on this client! */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - } -#endif /* NX_DISABLE_IPV4 */ - } - else if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifdef FEATURE_NX_IPV6 - /* This is an IPv6 Client. Is this slot empty? */ - if ((client_request_ptr -> nx_tftp_client_request_port != 0) && - (!CHECK_UNSPECIFIED_ADDRESS(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0]))) - { - - /* No, need to close the file on this client!*/ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - } -#endif /* FEATURE_NX_IPV6 */ - } - - /* Increment the pointer into the client request list. */ - client_request_ptr++; - i++; - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP server start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_server_start Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Call actual server start function. */ - status = _nxd_tftp_server_start(tftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts a previously created TFTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_resume Resume TFTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr) -{ - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - /* Activate TFTP server timer. */ - tx_timer_activate(&(tftp_server_ptr -> nx_tftp_server_timer)); -#endif - - /* Start the TFTP server thread. */ - tx_thread_resume(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxde_tftp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the TFTP server stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* NX_PTR_ERROR Invalid pointer input */ -/* */ -/* CALLS */ -/* */ -/* _nxd_tftp_server_stop Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxde_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((tftp_server_ptr == NX_NULL) || (tftp_server_ptr -> nx_tftp_server_id != NXD_TFTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nxd_tftp_server_stop(tftp_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxd_tftp_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops a previously started TFTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Successful completion */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Suspend TFTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr) -{ - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - /* Deactivate TFTP server timer. */ - tx_timer_deactivate(&(tftp_server_ptr -> nx_tftp_server_timer)); -#endif - - /* Suspend the TFTP server thread. */ - tx_thread_suspend(&(tftp_server_ptr -> nx_tftp_server_thread)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_data_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is notified by NetX of receive events generated by */ -/* TFTP Clients connecting or sending data. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Socket receiving data */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX TCP socket callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr) -{ - -NX_TFTP_SERVER *server_ptr; - - /* Pickup server pointer. This is setup in the reserved field of the TCP socket. */ - server_ptr = (NX_TFTP_SERVER *)(socket_ptr -> nx_udp_socket_reserved_ptr); - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_RECEIVE_EVENT, TX_OR); -} - - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_timer_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function captures timer events used to determine if the Client */ -/* retransmit timer has expired. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* ULONG Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set events for server thread */ -/* */ -/* CALLED BY */ -/* */ -/* NetX NetX connect callback */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address) -{ - -NX_TFTP_SERVER *server_ptr; - - /* Pickup server pointer. */ - server_ptr = (NX_TFTP_SERVER *) tftp_server_address; - - /* Set the data event flag. */ - tx_event_flags_set(&(server_ptr -> nx_tftp_server_event_flags), NX_TFTP_SERVER_TIMER_EVENT, TX_OR); - - return; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_timer_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks all the active TFTP client connections */ -/* for their retransmission timeout. If expired, the Server retransmits*/ -/* the data or ACK up to a maximum number of retries */ -/* (NX_TFTP_SERVER_MAX_RETRIES) and then terminates the connection and */ -/* closes any open files. The client request is cleared and available */ -/* for the next client request */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close session file. */ -/* fx_file_delete Delete the file */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP server task function */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr) -{ - -UINT i; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; - - - /* Now look through all the sockets. */ - for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++) - { - - /* Set a pointer to client request structure. */ - client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]); - - /* Check if this request has a retransmit timeout pending. */ - if (client_request_ptr -> nx_tftp_client_retransmit_timeout ) - { - - /* Update reatransmit timeout. */ - if (client_request_ptr -> nx_tftp_client_retransmit_timeout >= NX_TFTP_SERVER_TIMEOUT_PERIOD) - { - - client_request_ptr -> nx_tftp_client_retransmit_timeout -= NX_TFTP_SERVER_TIMEOUT_PERIOD; - } - else - { - - client_request_ptr -> nx_tftp_client_retransmit_timeout = 0; - } - - /* Has the retransmit timeout expired? */ - if (client_request_ptr -> nx_tftp_client_retransmit_timeout == 0) - { - - /* Yes, retransmit unless we have hit the max retry limit. */ - if (client_request_ptr -> nx_tftp_client_retransmit_retries < NX_TFTP_SERVER_MAX_RETRIES) - { - - - /* Update the Client request retransmit timeout and number of retries. */ - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; - client_request_ptr -> nx_tftp_client_retransmit_retries++; - - /* Determine which type of request this is. */ - if (client_request_ptr -> nx_tftp_client_request_open_type == NX_TFTP_STATE_WRITE_OPEN) - { - - /* Retransmit the ACK. */ - _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_TRUE); - } - else - { - - /* Retransmit the file data. */ - _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_TRUE); - } - } - else - { - - /* The session has timed out. Send error and close. */ - _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address, - client_request_ptr -> nx_tftp_client_request_port, - NX_TFTP_SESSION_TIMED_OUT, "NetX TFTP Server: Session timed out"); - - /* Error, close the file and delete the client request. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - } - } - } - } -} -#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the entry of the TFTP server. All basic */ -/* processing is initiated by this function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tftp_server Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_get Get the TFTP events */ -/* _nx_tftp_server_process_received_data Process received packet */ -/* _nx_tftp_server_timer_process Process TFTP timer */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_thread_entry(ULONG tftp_server) -{ - -NX_TFTP_SERVER *server_ptr; -UINT status; -ULONG events; - - - /* Setup the server pointer. */ - server_ptr = (NX_TFTP_SERVER *) tftp_server; - - /* Loop to process TFTP Server requests. */ - while(1) - { - - /* Wait for TFTP events. */ - status = tx_event_flags_get(&(server_ptr -> nx_tftp_server_event_flags), NX_SERVER_TFTP_ANY_EVENT, - TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Check the return status. */ - if (status) - { - - /* If an error occurs, simply continue the loop. */ - continue; - } - - /* Otherwise, an event is present. Process according to the event. */ - - /* Check for a client receive event. */ - if (events & NX_TFTP_SERVER_RECEIVE_EVENT) - { - - /* Call the data received handler. */ - _nx_tftp_server_process_received_data(server_ptr); - } - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - /* Check for a timer event. */ - if (events & NX_TFTP_SERVER_TIMER_EVENT) - { - /* Call the timer timeout handler. */ - _nx_tftp_server_timer_process(server_ptr); - } -#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE*/ - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_process_received_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called when the TFTP server is notified of a */ -/* receive event. It parses the TFTP Client message and calls the */ -/* appropriate handler for read and write requests, client errors, or */ -/* ACKing data sent by the server. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_server_ack_process Process ACK from previous read*/ -/* _nx_tftp_server_data_process Write data packet to file */ -/* _nx_tftp_server_error_process Process error packet */ -/* _nx_tftp_server_open_for_read_process Open file for reading */ -/* _nx_tftp_server_open_for_write_process Open for writing */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_receive Receive next TFTP packet */ -/* */ -/* CALLED BY */ -/* */ -/* nx_tftp_server_thread_entry TFTP thread task function */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr) -{ - -UINT status; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UCHAR request_code; - - - /* Wait for a request on the TFTP UDP well known port 69. */ - status = nx_udp_socket_receive(&(server_ptr -> nx_tftp_server_socket), &packet_ptr, NX_NO_WAIT); - - /* Check the return status. */ - if (status) - { - - /* If an error occurs, simply return to caller. */ - return; - } - - /* Check for valid packet length (The minimum TFTP header size is ACK packet, four bytes). */ - if (packet_ptr -> nx_packet_length < 4) - { - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Return. */ - return; - } - - /* Otherwise, we have received a packet successfully. */ - - /* Setup a pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Pickup up the request code. First one must be zero. */ - request_code = *buffer_ptr++; - - /* If not zero, abort. */ - if (request_code) - { - - nx_packet_release(packet_ptr); - - return; - } - - /* Now get the actual request code. */ - request_code = *buffer_ptr++; - - /* Process relative to the TFTP request code. */ - switch (request_code) - { - - case NX_TFTP_CODE_READ: - - /* Process an open for read request. */ - _nx_tftp_server_open_for_read_process(server_ptr, packet_ptr); - - /* Increment the number of open for read requests. */ - server_ptr -> nx_tftp_server_open_for_read_requests++; - break; - - case NX_TFTP_CODE_WRITE: - - /* Process an open for write request. */ - _nx_tftp_server_open_for_write_process(server_ptr, packet_ptr); - - /* Increment the number of open for write requests. */ - server_ptr -> nx_tftp_server_open_for_write_requests++; - break; - - case NX_TFTP_CODE_DATA: - - /* Process a data request. */ - _nx_tftp_server_data_process(server_ptr, packet_ptr); - - /* Increment the number of data block write requests. */ - server_ptr -> nx_tftp_server_data_blocks_received++; - break; - - case NX_TFTP_CODE_ACK: - - /* Process an ack response. */ - _nx_tftp_server_ack_process(server_ptr, packet_ptr); - - /* Increment the number of acks for previous data blocks sent. */ - server_ptr -> nx_tftp_server_acks_received++; - break; - - case NX_TFTP_CODE_ERROR: - - /* Process an error request. */ - _nx_tftp_server_error_process(server_ptr, packet_ptr); - - /* Increment the number of errors received. */ - server_ptr -> nx_tftp_server_errors_received++; - break; - - default: - - /* Increment the number of unknown codes received. */ - server_ptr -> nx_tftp_server_unknown_commands++; - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_open_for_read_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens the specified file for reading, and returns */ -/* the first block of the file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* packet_ptr Pointer to TFTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_directory_information_get Get information about file */ -/* fx_file_close Close file on EOF or error */ -/* fx_file_open Open file for reading */ -/* fx_file_read Read block from file */ -/* _nx_tftp_server_find_client_request Find client entry */ -/* _nx_tftp_server_send_error Send error message */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_send Send TFTP data packet */ -/* nx_udp_source_extract Extract IP and port */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP Server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ -NXD_ADDRESS ip_address; -ULONG file_size; -ULONG actual_size; -UINT port; -UCHAR *buffer_ptr; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; -NX_PACKET *new_packet = NX_NULL; -UINT status; - - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - /* First, try to find a matching exiting entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); - - /* See if we need to find a new entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Yes, find a free entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL); - } - else - { - - /* This is a dupe request. Ignore it. */ - nx_packet_release(packet_ptr); - return; - } - - /* Determine if there was a free entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Increment the maximum clients errors. */ - server_ptr -> nx_tftp_server_clients_exceeded_errors++; - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients"); - - /* No more clients can be serviced, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Initialize the client request structure. */ -#ifndef NX_DISABLE_IPV4 - if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - - client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4; - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) - { - COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address)); - } - else -#endif - { - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; - } - - - client_request_ptr -> nx_tftp_client_request_port = port; - client_request_ptr -> nx_tftp_client_request_block_number = 1; - client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_OPEN; - client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - /* Reset the retransmission timeout and retries for the client request. */ - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; - client_request_ptr -> nx_tftp_client_retransmit_retries = 0; -#else - - /* Clear the count of ACK retransmits from the other side. */ - client_request_ptr -> nx_tftp_client_request_retransmits = 0; - -#endif - - /* Setup a pointer to the file name. */ - buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); - - if (packet_ptr -> nx_packet_length < 4) - { - nx_packet_release(packet_ptr); - return; - } - - /* Check if the packet buffer ends with NULL. */ - if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1)) - { - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the file size. */ - status = fx_directory_information_get(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr, NX_NULL, &file_size, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL); - - /* Check the return status. */ - if (status != FX_SUCCESS) - { - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Not Found"); - - /* Unable to find the file size, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Attempt to open the file. */ - status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr ->nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_READ); - - /* Check the return status. */ - if (status != FX_SUCCESS) - { - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed"); - - /* Unable to open the file, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* The file has been opened successfully, now try to read up to 512 bytes. */ - - /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ - if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); - } - else if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); - } - else - status = NX_TFTP_INVALID_ADDRESS_TYPE; - /* Check for successful packet allocation. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Unable to allocate net packet, release the original. */ - nx_packet_release(packet_ptr); - return; - } - - if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) - { - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - nx_packet_release(new_packet); - return; - } - - client_request_ptr -> nx_tftp_client_file_size = file_size; - - /* Read data when length of file is larger then 0. */ - if(file_size) - { - - /* Attempt to read the requested file. */ - status = fx_file_read(&(client_request_ptr ->nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4, NX_TFTP_FILE_TRANSFER_MAX, &actual_size); - - /* Check for successful file read. */ - if ((status != NX_SUCCESS) || - ((file_size > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != NX_TFTP_FILE_TRANSFER_MAX)) || - ((file_size < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != file_size))) - { - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error"); - - /* Unable to read the file, close it and release the packet. */ - fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); - - nx_packet_release(packet_ptr); - return; - } - } - else - { - - actual_size = 0; - } - - /* Increment the number of total bytes sent. */ - server_ptr -> nx_tftp_server_total_bytes_sent += actual_size; - - /* Setup the client request structure. */ - client_request_ptr -> nx_tftp_client_request_remaining_bytes = file_size - actual_size; - - /* Determine if the file size is evenly divisible by our TFTP transfer size. */ - if (file_size % NX_TFTP_FILE_TRANSFER_MAX) - { - - /* Not an exact fit, ensure the exact fit flag is clear. */ - client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; - } - else if (file_size > 0) - { - - /* Yes, the file size happens to be evenly divisible by the TFTP transfer size. In this - case, we need to send a zero-length data packet at the end of file to let the other side - know we are at the end. */ - client_request_ptr -> nx_tftp_client_request_exact_fit = NX_TRUE; - } - - /* Move the TFTP data code and block number into the payload before sending it to the client. */ - buffer_ptr = new_packet -> nx_packet_prepend_ptr; - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_DATA; - *buffer_ptr++ = 0; - *buffer_ptr++ = 1; /* First block number of file. */ - - /* Setup the packet pointers appropriately. */ - new_packet -> nx_packet_length = actual_size + 4; - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length; - - /* Send the data packet out. */ - status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port); - - /* Release packet if send fails. */ - if (status) - { - nx_packet_release(new_packet); - } - - /* Release the original packet. */ - nx_packet_release(packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_open_for_write_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function opens the specified file for writing, and returns */ -/* an ACK for block 0 to let the client know everything is good. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* packet_ptr Pointer to TFTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_create Create file, if necessary */ -/* fx_file_close Close file on EOF or error */ -/* fx_file_open Open file for reading */ -/* fx_file_write Write block to file */ -/* _nx_tftp_server_find_client_request Find client entry */ -/* _nx_tftp_server_send_error Send error message */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_send Send TFTP data packet */ -/* nx_udp_source_extract Extract IP and port */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP Server thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ -NXD_ADDRESS ip_address; -UINT port; -UCHAR *buffer_ptr; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; -NX_PACKET *new_packet; -UINT status; - - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - /* First, try to find a matching exiting entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); - - /* See if we need to find a new entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Find a free entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, 0, NX_NULL); - } - else - { - - /* This is a dupe request. Ignore it. */ - nx_packet_release(packet_ptr); - return; - } - - /* Determine if there was a free entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Increment the maximum clients errors. */ - server_ptr -> nx_tftp_server_clients_exceeded_errors++; - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: Too Many Clients"); - - /* No more clients can be serviced, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Setup a pointer to the file name. */ - buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); - - if (packet_ptr -> nx_packet_length < 4) - { - nx_packet_release(packet_ptr); - return; - } - - /* Check if the packet buffer ends with NULL. */ - if (*(UCHAR *)(packet_ptr -> nx_packet_append_ptr - 1)) - { - nx_packet_release(packet_ptr); - return; - } - - /* Perform a file create. This will fail if the file is already present, which we don't care about at this point. */ - fx_file_delete(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr); - fx_file_create(server_ptr -> nx_tftp_server_media_ptr, (CHAR *) buffer_ptr); - - /* Attempt to open the file. */ - status = fx_file_open(server_ptr -> nx_tftp_server_media_ptr, &(client_request_ptr -> nx_tftp_client_request_file), (CHAR *) buffer_ptr, FX_OPEN_FOR_WRITE); - - /* Check for file is open errors. */ - if (status != NX_SUCCESS) - { - - /* This is an actual file open error. Send an error to the client. */ - if (status == FX_ACCESS_ERROR) - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ACCESS_VIOLATION, "NetX TFTP Server: File Access Error"); - else - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_FILE_NOT_FOUND, "NetX TFTP Server: File Open Failed"); - - /* Unable to open the file, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Now, attempt to build an ACK response to let the client know it can start writing. */ - - /* Allocate packet for the ACK packet. Determine whether we are sending IP packets. */ - if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); - } - else - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); - } - - /* Check for successful packet allocation. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Close the file. */ - fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); - - /* Unable to allocate net packet, release the original. */ - nx_packet_release(packet_ptr); - return; - } - - if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) - { - nx_packet_release(new_packet); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; - } - - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; - - /* Setup the client request structure. */ -#ifndef NX_DISABLE_IPV4 - if (ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - - client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_version = NX_IP_VERSION_V4; - client_request_ptr ->nx_tftp_client_request_ip_address.nxd_ip_address.v4 = ip_address.nxd_ip_address.v4; - } - else -#endif /* NX_DISABLE_IPV4 */ -#ifdef FEATURE_NX_IPV6 - if (ip_address.nxd_ip_version == NX_IP_VERSION_V6) - { - COPY_NXD_ADDRESS(&ip_address, &(client_request_ptr ->nx_tftp_client_request_ip_address)); - } - else -#endif - { - - /* Close the file. */ - fx_file_close(&(client_request_ptr ->nx_tftp_client_request_file)); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; - } - - - client_request_ptr -> nx_tftp_client_request_port = port; - client_request_ptr -> nx_tftp_client_request_block_number = 1; - client_request_ptr -> nx_tftp_client_request_open_type = NX_TFTP_STATE_WRITE_OPEN; - client_request_ptr -> nx_tftp_client_request_remaining_bytes = 0; - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - /* Reset retransmission timeouts and retries on current client request. */ - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; - client_request_ptr -> nx_tftp_client_retransmit_retries = 0; - -#else - - /* Clear the count of data retransmits from the other side. */ - client_request_ptr -> nx_tftp_client_request_retransmits = 0; -#endif - - /* Create the ACK packet. */ - buffer_ptr = new_packet -> nx_packet_prepend_ptr; - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_ACK; - *buffer_ptr++ = 0; - *buffer_ptr++ = 0; /* 0, just to signal server is ready. */ - - /* Setup the packet pointers appropriately. */ - new_packet -> nx_packet_length = 4; - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4; - - /* Send the data packet out. */ - status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &ip_address, port); - - /* Release packet if send fails. */ - if (status) - { - nx_packet_release(new_packet); - } - - /* Release the original packet. */ - nx_packet_release(packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_data_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function takes the supplied data packet and writes it to the */ -/* previously opened file. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* packet_ptr Pointer to TFTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file on EOF or error */ -/* fx_file_write Write block to file */ -/* _nx_tftp_server_find_client_request Find client entry */ -/* _nx_tftp_server_send_error Send error message */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_copy Copy packet */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_send Send TFTP ACK packet */ -/* nx_udp_source_extract Extract IP and port */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP Server thread loop */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -NXD_ADDRESS ip_address; -UINT port; -USHORT block_number; -UCHAR *buffer_ptr; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; -UINT status; - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - /* Find the matching entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); - - - /* Determine if there was a matching entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Increment the unknown clients errors. */ - server_ptr -> nx_tftp_server_unknown_clients_errors++; - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection"); - - /* No more clients can be serviced, release the packet. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Setup a pointer to the block number. */ - buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); - - if (packet_ptr -> nx_packet_length < 4) - { - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the block number. */ - block_number = (USHORT)(*buffer_ptr++); - block_number = (USHORT)((block_number << 8) | (*buffer_ptr)); - - /* Determine if this block number matches the current client block number. */ - if (client_request_ptr -> nx_tftp_client_request_block_number != block_number) - { - - /* No, it does not. */ - - /* Check if it matches our previous ACK e.g. it could be a retransmit from the other side. */ - if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1)) - { - -#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - /* It does. Update how many we have received. */ - client_request_ptr -> nx_tftp_client_request_retransmits++; - - /* Decide if we should close the client request. */ - if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS) - { - - /* Not yet. Just drop the packet for now. */ - nx_packet_release(packet_ptr); - - return; - } - /* Else handle as an error. */ -#else - nx_packet_release(packet_ptr); - - /* (Let the retransmit timeout handler retransmit our ACK to the client.) */ - return; -#endif - } - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number"); - - /* Error, close the file, release the packet and delete the client request. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return; - } - - /* At this point we have a valid packet. */ - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - /* Reset the retransmit retry counter and retransmit timeout. */ - client_request_ptr -> nx_tftp_client_retransmit_retries = 0; - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; -#else - - /* Clear the count of retransmits from the other side. */ - client_request_ptr -> nx_tftp_client_request_retransmits = 0; -#endif - - /* Determine if there is anything to write. */ - if (packet_ptr -> nx_packet_length > 4) - { - - /* At this point, we need to write the next block of the file. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Determine if the current packet is chained. */ - if (packet_ptr -> nx_packet_next) - { - - NX_PACKET *temp_ptr; - - - /* Yes, the packet is chained. We have to copy the receive packet into a packet with the - a payload of at least 560 bytes so the write request can be supplied with just the - payload pointer. */ - status = nx_packet_copy(packet_ptr, &temp_ptr, server_ptr -> nx_tftp_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Check for successful packet copy. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Unable to allocate net packet, release the original. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - nx_packet_release(packet_ptr); - - memset(client_request_ptr,0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return; - } - - /* Successful packet copy. Release the original packet and reassign the packet pointer variable. */ - nx_packet_release(packet_ptr); - packet_ptr = temp_ptr; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Attempt to write the block to the file. */ - status = fx_file_write(&(client_request_ptr -> nx_tftp_client_request_file), packet_ptr -> nx_packet_prepend_ptr+4, - packet_ptr -> nx_packet_length - 4); - - /* Check for successful file write. */ - if (status != NX_SUCCESS) - { - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Write Error"); - - /* Unable to write the file, close it and release the packet. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - nx_packet_release(packet_ptr); - - return; - } - } - - /* Check the last packet. */ - if (packet_ptr -> nx_packet_length - 4 < NX_TFTP_FILE_TRANSFER_MAX) - { - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - } - - status = _nx_tftp_server_send_ack(server_ptr, client_request_ptr, NX_FALSE); - - if (status == NX_SUCCESS) - { - - /* Increment the number of total bytes received. */ - server_ptr -> nx_tftp_server_total_bytes_received += (packet_ptr -> nx_packet_length - 4); - - /* Determine if this was the last write. */ - if ((packet_ptr -> nx_packet_length - 4) < NX_TFTP_FILE_TRANSFER_MAX) - { - - /* No, nothing left to write. Close the file, release the packet and delete - the client request. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - } - } - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_ack_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an ACK to the previous file read */ -/* operation and prepares the next data packet to send if necessary. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* packet_ptr Pointer to TFTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* fx_file_close Close file on EOF or error */ -/* fx_file_read Read block from file */ -/* _nx_tftp_server_find_client_request Find client entry */ -/* _nx_tftp_server_send_error Send error message */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_copy Copy packet */ -/* nx_packet_release Release packet */ -/* nx_udp_socket_send Send TFTP data packet */ -/* nx_udp_source_extract Extract IP and port */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP Server thread */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -NXD_ADDRESS ip_address; -UINT port; -USHORT block_number; -UCHAR *buffer_ptr; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; - - - /* Extract the source IP and port numbers. */ - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - - /* Find a matching entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); - - /* Determine if there was a matching entry. */ - if (client_request_ptr == NX_NULL) - { - - /* Increment the unknown clients errors. */ - server_ptr -> nx_tftp_server_unknown_clients_errors++; - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_NO_SUCH_USER, "NetX TFTP Server: Unknown connection"); - - /* No more clients can be serviced, release the packet. */ - nx_packet_release(packet_ptr); - return; - } - - /* Setup a pointer to the block number. */ - buffer_ptr = (UCHAR *) (packet_ptr -> nx_packet_prepend_ptr + 2); - - if (packet_ptr -> nx_packet_length < 4) - { - nx_packet_release(packet_ptr); - return; - } - - /* Pickup the block number. */ - block_number = (USHORT)(*buffer_ptr++); - block_number = (USHORT)((block_number << 8) | (*buffer_ptr)); - - /* Determine if this block number matches the request. */ - if (client_request_ptr -> nx_tftp_client_request_block_number != block_number) - { - - /* Check if this is a retransmitted ACK e.g. our previous data packet was dropped our - delayed. */ - if (client_request_ptr -> nx_tftp_client_request_block_number == (USHORT)(block_number + 1)) - { - -#ifndef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - /* It does. Update how many we have received. */ - client_request_ptr -> nx_tftp_client_request_retransmits++; - - /* Decide if we should close the client request. */ - if (client_request_ptr -> nx_tftp_client_request_retransmits <= NX_TFTP_MAX_CLIENT_RETRANSMITS) - { - - /* Not yet. Just drop the packet for now. */ - nx_packet_release(packet_ptr); - - return; - } - - /* Else handle as an error. */ -#else - nx_packet_release(packet_ptr); - - /* (Let the retransmit timeout handler retransmit our data to the client.) */ - return; -#endif - } - - /* Send an error to the client. */ - _nx_tftp_server_send_error(server_ptr, &ip_address, port, NX_TFTP_ERROR_ILLEGAL_OPERATION, "NetX TFTP Server: Bad block number"); - - /* Error, close the file, release the packet and delete the client request. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - nx_packet_release(packet_ptr); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return; - } - - /* The block number matches, see if there is anything left to send. */ - if ((client_request_ptr -> nx_tftp_client_request_remaining_bytes == 0) && - (client_request_ptr -> nx_tftp_client_request_exact_fit == NX_FALSE)) - { - - /* No, nothing left to send. Close the file, release the packet and delete - the client request. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - nx_packet_release(packet_ptr); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return; - } - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - /* We have a valid ACK. Reset the retransmit retry counter and retransmit timeout. */ - client_request_ptr -> nx_tftp_client_retransmit_retries = 0; - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; -#endif - - /* At this point, we need to send the next block of the file. */ - _nx_tftp_server_send_data(server_ptr, client_request_ptr, NX_FALSE); - - /* Release the original packet. */ - nx_packet_release(packet_ptr); - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_send_data PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a data packet based on the last ACK received */ -/* and sends it out. This will also retransmit a data packet if */ -/* specified. On error it will close the file and the client request. */ -/* It does not update the Client request e.g. block number. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* client_request_ptr Pointer to Client request */ -/* retransmit Indicate if retransmiting a */ -/* previously sent ACK */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_server_close_client_request Terminate a client request */ -/* _nx_tftp_server_send_error Send error status to Client */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_udp_socket_send Send TFTP data packet */ -/* fx_file_seek Set location in file */ -/* fx_file_read Read from set location in file*/ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_timer_process TFTP timeout event */ -/* _nx_tftp_server_ack_process Process a received ACK */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit) -{ - -UINT status; -ULONG actual_size = 0; -NX_PACKET *new_packet; -UCHAR *buffer_ptr; - - - /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ - if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); - } - else - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); - } - - - /* Check for successful packet allocation. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Unable to allocate net packet, release the original. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return status; - } - - if (4u + NX_TFTP_FILE_TRANSFER_MAX > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) - { - nx_packet_release(new_packet); - return(NX_SIZE_ERROR); - } - - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; - - /* Determine if there are more bytes to read. */ - if (client_request_ptr -> nx_tftp_client_request_remaining_bytes) - { - - status = NX_SUCCESS; - - /* Are we retransmitting? */ - if (retransmit) - { - - /* Yes, figure out where to reset the file pointer to the previous - file read so we can retrieve the previous data we sent. */ - UINT index = client_request_ptr -> nx_tftp_client_file_size - - client_request_ptr -> nx_tftp_client_request_remaining_bytes - - client_request_ptr -> nx_tftp_client_previous_write_size; - - status = fx_file_seek(&(client_request_ptr -> nx_tftp_client_request_file), index); - } - - /* Are we still ok to do a file read? */ - if (status == NX_SUCCESS) - { - - /* Yes. Attempt to read the requested file. */ - UINT status_read = fx_file_read(&(client_request_ptr -> nx_tftp_client_request_file), new_packet -> nx_packet_prepend_ptr+4, - NX_TFTP_FILE_TRANSFER_MAX, &actual_size); - - /* Check for successful file read. */ - if ((status_read != NX_SUCCESS) || - ((client_request_ptr -> nx_tftp_client_request_remaining_bytes > NX_TFTP_FILE_TRANSFER_MAX) && (actual_size < NX_TFTP_FILE_TRANSFER_MAX)) || - ((client_request_ptr -> nx_tftp_client_request_remaining_bytes < NX_TFTP_FILE_TRANSFER_MAX) && (actual_size != client_request_ptr -> nx_tftp_client_request_remaining_bytes))) - { - - /* Update our 'status' variable with the result from file read. */ - status = status_read; - } - } - - /* Are we ok to transmit more data? */ - if (status != NX_SUCCESS) - { - - /* No, send an error back to the client. */ - _nx_tftp_server_send_error(server_ptr, &client_request_ptr -> nx_tftp_client_request_ip_address, - client_request_ptr -> nx_tftp_client_request_port, - NX_TFTP_ERROR_NOT_DEFINED, "NetX TFTP Server: File Read Error"); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - /* Unable to read the file, close it and release the packet. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - nx_packet_release(new_packet); - - return status; - } - } - else - { - - /* Clear the exact fit flag since the only way we can be here is if the TFTP transfer size - evenly divided into the file size and we need to send a zero length data buffer to signal - the end of the file. */ - client_request_ptr -> nx_tftp_client_request_exact_fit = NX_FALSE; - - /* Set the actual size to zero for exact fit case. */ - actual_size = 0; - } - - /* Increment the number of total bytes sent. */ - server_ptr -> nx_tftp_server_total_bytes_sent += actual_size; - - /* Is this new data being sent (not a retransmit)? */ - if (retransmit == NX_FALSE) - { - - /* Yes, so advance the block number and number of bytes of the file sent. */ - client_request_ptr -> nx_tftp_client_request_block_number++; - - client_request_ptr -> nx_tftp_client_request_remaining_bytes -= actual_size; - } - - client_request_ptr -> nx_tftp_client_previous_write_size = actual_size; - - /* Move the TFTP data code and block number into the payload before sending it to the client. */ - buffer_ptr = new_packet -> nx_packet_prepend_ptr; - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_DATA; - *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number >> 8); - *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF); - - /* Setup the packet pointers appropriately. */ - new_packet -> nx_packet_length = actual_size + 4; - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + new_packet -> nx_packet_length; - - /* Send the data packet out. */ - status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address, - client_request_ptr -> nx_tftp_client_request_port); - - /* Release packet if send fails. */ - if (status) - { - nx_packet_release(new_packet); - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_send_ack PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates an ACK packet based on the last block of data */ -/* received, and sends it out. This will also retransmit an ACK if */ -/* specified. On error it will close the file and the client request. */ -/* It does not update the Client request e.g. block number. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* client_request_ptr Pointer to Client request */ -/* retransmit Indicate if retransmiting a */ -/* previously sent ACK */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tftp_server_close_client_request Terminate a client request */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_udp_socket_send Send TFTP data packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_timer_process TFTP timeout event */ -/* _nx_tftp_server_data_process Process a received packet */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit) -{ - -UINT status; -UCHAR *buffer_ptr; -NX_PACKET *new_packet; - - - /* Allocate packet for the ACK. Determine whether we are sending IP packets. */ - if (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); - } - else - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); - } - - /* Check for successful packet allocation. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Unable to allocate net packet, release the original. */ - fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); - - memset(client_request_ptr, 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - return status; - } - - if (4u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) - { - nx_packet_release(new_packet); - return(NX_SIZE_ERROR); - } - - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; - - /* Now build the ACK message to the client. */ - buffer_ptr = new_packet -> nx_packet_prepend_ptr; - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_ACK; - - /* If we are retransmitting, send the block number of the previous ACK. */ - if (retransmit) - { - - *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) >> 8); - *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number - 1) & 0xFF); - } - else - { - - *buffer_ptr++ = (UCHAR) ((client_request_ptr -> nx_tftp_client_request_block_number) >> 8); - *buffer_ptr++ = (UCHAR) (client_request_ptr -> nx_tftp_client_request_block_number & 0xFF); - } - - /* Setup the packet pointers appropriately. */ - new_packet -> nx_packet_length = 4; - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr + 4; - - /* Send the ACK packet out. */ - status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, &client_request_ptr -> nx_tftp_client_request_ip_address, - client_request_ptr -> nx_tftp_client_request_port); - - /* Release packet if send fails. */ - if (status) - { - nx_packet_release(new_packet); - } - - /* Is this ACK for new data received (e.g. not a retransmit)? */ - if (retransmit == NX_FALSE) - { - - /* Yes, so increase the block number. */ - client_request_ptr -> nx_tftp_client_request_block_number++; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_error_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an error sent by a client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* packet_ptr Pointer to TFTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_thread_entry TFTP Server thread task */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -UINT i; -UCHAR *buffer_ptr; -UINT port; -NXD_ADDRESS ip_address; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; - - - /* Pickup a pointer to the error code in the buffer. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr + 2; - - if (packet_ptr -> nx_packet_length < 4) - { - nx_packet_release(packet_ptr); - return; - } - - /* Set the error code in the server control block. */ - server_ptr -> nx_tftp_server_error_code = (((UINT) (*buffer_ptr)) << 8); - buffer_ptr++; - server_ptr -> nx_tftp_server_error_code |= ((UINT) (*buffer_ptr) & 0xFF); - buffer_ptr++; - - /* Loop to save error message. */ - server_ptr -> nx_tftp_server_error_string[sizeof(server_ptr -> nx_tftp_server_error_string) - 1] = NX_NULL; - for (i = 0; i < NX_TFTP_ERROR_STRING_MAX; i++) - { - - /* Store desired file name. */ - server_ptr -> nx_tftp_server_error_string[i] = (CHAR) *buffer_ptr++; - - /* Check for NULL character. */ - if (server_ptr -> nx_tftp_server_error_string[i] == NX_NULL) - break; - - /* Check for packet buffer boundary. */ - if (buffer_ptr >= packet_ptr -> nx_packet_append_ptr) - break; - } - - /* Extract the source IP and port numbers. */ - - nxd_udp_source_extract(packet_ptr, &ip_address, &port); - - /* First, try to find a matching existing entry in the client request structure. */ - client_request_ptr = _nx_tftp_server_find_client_request(server_ptr, port, &ip_address); - - /* Reset the retransmit timeout on the client request. */ - if (client_request_ptr) - { -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - - client_request_ptr -> nx_tftp_client_retransmit_timeout = NX_TFTP_SERVER_RETRANSMIT_TIMEOUT; - client_request_ptr -> nx_tftp_client_retransmit_retries = 0; -#else - - client_request_ptr -> nx_tftp_client_request_retransmits = 0; - -#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_find_client_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function attempts to find the specified IP and port number in */ -/* the client request array of this TFTP server instance. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* port Client port number */ -/* ip_address Client IP address */ -/* */ -/* OUTPUT */ -/* */ -/* NX_TFTP_CLIENT_REQUEST * NULL if not found */ -/* Non null if match found */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_ack_process ACK processing */ -/* _nx_tftp_server_data_process Data packet processing */ -/* _nx_tftp_server_open_for_write_process Open for write processing */ -/* _nx_tftp_server_open_for_read_process Open for read processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, NXD_ADDRESS *ip_address) -{ - -UINT i; -NX_TFTP_CLIENT_REQUEST *client_request_ptr; - - /* First, find a free entry in the client request structure. */ - i = 0; - for (i = 0; i < NX_TFTP_MAX_CLIENTS; i++) - { - client_request_ptr = &(server_ptr -> nx_tftp_server_client_list[i]); - - /* First check if we are adding an address. If the caller sends in a blank - address and port, we are. */ - if (port == 0) - { - - /* We are adding an address. Now check if this slot is empty. */ - - if (client_request_ptr -> nx_tftp_client_request_port == 0) - { - - /* If there is no port number, this is an empty slot. But let's clear the slot anyway. */ - memset(&(server_ptr -> nx_tftp_server_client_list[i]), 0, sizeof(NX_TFTP_CLIENT_REQUEST)); - - break; - } - } - /* This is a valid address. Does it match the current entry? */ - else - { - /* Check if it is an IPv4 or IPv6 packet. */ - if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - -#ifndef NX_DISABLE_IPV4 - /* This is an IPv4 request packet. */ - if ((client_request_ptr -> nx_tftp_client_request_port == port) && - (client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v4 == ip_address -> nxd_ip_address.v4)) - { - - /* Yes, they match! */ - break; - } -#else - return NX_NULL; -#endif /* NX_DISABLE_IPV4 */ - } - else if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6) - { - -#ifndef FEATURE_NX_IPV6 - return NX_NULL; -#else - /* This is an IPv6 request packet. */ - if ((client_request_ptr -> nx_tftp_client_request_port == port) && - (CHECK_IPV6_ADDRESSES_SAME(&client_request_ptr -> nx_tftp_client_request_ip_address.nxd_ip_address.v6[0], &ip_address -> nxd_ip_address.v6[0]))) - { - - /* Yes, they match! */ - break; - } -#endif - } - } - } - - /* Determine if a match was found. */ - if (i < NX_TFTP_MAX_CLIENTS) - { - /* Return a pointer to the matching client request. */ - return(&(server_ptr -> nx_tftp_server_client_list[i])); - } - else - { - /* Return a NULL pointer indicating no match found. */ - return((NX_TFTP_CLIENT_REQUEST *)NX_NULL); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tftp_server_send_error PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function send a TFTP error message to the client specified */ -/* by the port and IP address. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to TFTP server */ -/* ip_address Client IP address */ -/* port Client port number */ -/* error TFTP error code */ -/* error_message Error string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_allocate Allocate error packet */ -/* nx_udp_socket_send Send TFPT error packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tftp_server_ack_process ACK processing */ -/* _nx_tftp_server_data_process Data packet processing */ -/* _nx_tftp_server_open_for_write_process Open for write processing */ -/* _nx_tftp_server_open_for_read_process Open for read processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, NXD_ADDRESS *ip_address, UINT port, UINT error, CHAR *error_message) -{ - -UINT status; -UCHAR *buffer_ptr; -NX_PACKET *new_packet; - - - /* Allocate packet for the read packet. Determine whether we are sending IP packets. */ - if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv4_UDP_PACKET, NX_WAIT_FOREVER); - } - else - { - status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_IPv6_UDP_PACKET, NX_WAIT_FOREVER); - } - - /* Check for successful packet allocation. */ - if (status != NX_SUCCESS) - { - - /* Increment the number of server allocation errors. */ - server_ptr -> nx_tftp_server_allocation_errors++; - - /* Unable to allocate packet for error message, just return! */ - return; - } - - if (6u > ((ULONG)(new_packet -> nx_packet_data_end) - (ULONG)(new_packet -> nx_packet_append_ptr))) - { - nx_packet_release(new_packet); - return; - } - - new_packet -> nx_packet_append_ptr = new_packet -> nx_packet_prepend_ptr; - - /* Move the TFTP error code and message into the payload before sending it to the client. */ - buffer_ptr = new_packet -> nx_packet_prepend_ptr; - *buffer_ptr++ = 0; - *buffer_ptr++ = NX_TFTP_CODE_ERROR; - *buffer_ptr++ = 0; - *buffer_ptr++ = (UCHAR) (error & 0xFF); - - /* Loop to copy the error message into the buffer. */ - do - { - - /* Copy a byte of the error message into the buffer. */ - *buffer_ptr = (UCHAR) *error_message; - - /* Determine if a NULL is present. */ - if (*buffer_ptr == NX_NULL) - { - - /* Yes, we are at the end of the string end the loop. */ - break; - } - - /* Move both pointers to the next character. */ - buffer_ptr++; - error_message++; - } while (buffer_ptr < (new_packet -> nx_packet_data_end - 1)); - - /* Ensure a NULL is in the last position! */ - *buffer_ptr++ = NX_NULL; - - /* Setup the packet pointers appropriately. */ - new_packet -> nx_packet_length = (ULONG)(buffer_ptr - new_packet -> nx_packet_prepend_ptr); - new_packet -> nx_packet_append_ptr = buffer_ptr; - - /* Send the data packet out. */ - status = nxd_udp_socket_send(&(server_ptr -> nx_tftp_server_socket), new_packet, ip_address, port); - - /* Release packet if send fails. */ - if (status) - { - nx_packet_release(new_packet); - } -} diff --git a/protocol_handlers/tftp/nxd_tftp_server.h b/protocol_handlers/tftp/nxd_tftp_server.h deleted file mode 100644 index c34fcc7b..00000000 --- a/protocol_handlers/tftp/nxd_tftp_server.h +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Duo Component */ -/** */ -/** Trivial File Transfer Protocol (TFTP) Server */ -/** */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nxd_tftp_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ -/* Server for NetX Duo. It supports IPv4 and IPv6 networks. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_TFTP_SERVER_H -#define NXD_TFTP_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the TFTP ID. */ - -#define NXD_TFTP_SERVER_ID 0x54465461UL - -#ifndef NX_TFTP_NO_FILEX -#include "fx_api.h" -#else -#include "filex_stub.h" -#endif - -/* Define TFTP maximum error string. */ - -#ifndef NX_TFTP_ERROR_STRING_MAX -#define NX_TFTP_ERROR_STRING_MAX 64 /* Maximum error sting size */ -#endif - - -/* Define the maximum number of clients the TFTP Server can accommodate. */ - -#ifndef NX_TFTP_MAX_CLIENTS -#define NX_TFTP_MAX_CLIENTS 10 -#endif - - -/* Define TFTP UDP socket create options. */ - -#ifndef NX_TFTP_TYPE_OF_SERVICE -#define NX_TFTP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_TFTP_FRAGMENT_OPTION -#define NX_TFTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_TFTP_TIME_TO_LIVE -#define NX_TFTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_PHYSICAL_TRAILER -#define NX_PHYSICAL_TRAILER 4 -#endif - -#ifndef NX_TFTP_SERVER_PRIORITY -#define NX_TFTP_SERVER_PRIORITY 16 -#endif - -#ifndef NX_TFTP_SERVER_TIME_SLICE -#define NX_TFTP_SERVER_TIME_SLICE 2 -#endif - - -/* To enable a retransmission on client requests (e.g. resend - ACK and data packets, as well apply a timeout on a Client request), - define this option. -#define NX_TFTP_SERVER_RETRANSMIT_ENABLE -*/ - - -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - -/* Define the timer expiration for updating time remaining on a TFTP Client - request activity timeout (in timer ticks). */ -#ifndef NX_TFTP_SERVER_TIMEOUT_PERIOD -#define NX_TFTP_SERVER_TIMEOUT_PERIOD 20 -#endif - -/* Define the interval before retransmitting an ACK or data packet (in timer ticks). */ -#ifndef NX_TFTP_SERVER_RETRANSMIT_TIMEOUT -#define NX_TFTP_SERVER_RETRANSMIT_TIMEOUT 200 -#endif - -/* Define the max number of retries retransmitting a data packet or ACK if no response or a previous - (duplicate) ACK or data packet, respectively, is received. */ -#ifndef NX_TFTP_SERVER_MAX_RETRIES -#define NX_TFTP_SERVER_MAX_RETRIES 5 -#endif - -#else - -/* Define the number of instances TFTP server receives a duplicate data or an ACK packet - without sending an error message. This does not utilize the retransmission timeout - and is available only if NX_TFTP_SERVER_RETRANSMIT_ENABLE is not defined. */ - -#ifndef NX_TFTP_MAX_CLIENT_RETRANSMITS -#define NX_TFTP_MAX_CLIENT_RETRANSMITS 2 -#endif - -#endif /* NX_TFTP_SERVER_RETRANSMIT_ENABLE */ - - -#define NX_TFTP_QUEUE_DEPTH 5 - -#define NX_TFTP_FILE_TRANSFER_MAX 512 /* 512 byte maximum file transfer */ - - -/* Derive the maximum TFTP packet size, including Ethernet, IP and UDP headers, and - accounting for potential physical driver needs at the end of the packet. */ - -#define NX_TFTP_PACKET_SIZE (NX_UDP_PACKET + NX_TFTP_FILE_TRANSFER_MAX + NX_PHYSICAL_TRAILER) - - -/* Define open types. */ - -#define NX_TFTP_OPEN_FOR_READ 0x01 /* TFTP open for reading */ -#define NX_TFTP_OPEN_FOR_WRITE 0x02 /* TFTP open for writing */ - - -/* Define TFTP message codes. */ - -#define NX_TFTP_CODE_READ 0x01 /* TFTP read file request */ -#define NX_TFTP_CODE_WRITE 0x02 /* TFTP write file request */ -#define NX_TFTP_CODE_DATA 0x03 /* TFTP data packet */ -#define NX_TFTP_CODE_ACK 0x04 /* TFTP command/data acknowledgement */ -#define NX_TFTP_CODE_ERROR 0x05 /* TFTP error message */ - - -/* Define TFTP error code constants. */ - -#define NX_TFTP_ERROR_NOT_DEFINED 0x00 /* TFTP not defined error code, see error string */ -#define NX_TFTP_ERROR_FILE_NOT_FOUND 0x01 /* TFTP file not found error code */ -#define NX_TFTP_ERROR_ACCESS_VIOLATION 0x02 /* TFTP file access violation error code */ -#define NX_TFTP_ERROR_DISK_FULL 0x03 /* TFTP disk full error code */ -#define NX_TFTP_ERROR_ILLEGAL_OPERATION 0x04 /* TFTP illegal operation error code */ -#define NX_TFTP_CODE_ERROR 0x05 /* TFTP client request received error code from server */ -#define NX_TFTP_ERROR_FILE_EXISTS 0x06 /* TFTP file already exists error code */ -#define NX_TFTP_ERROR_NO_SUCH_USER 0x07 /* TFTP no such user error code */ -#define NX_INVALID_TFTP_SERVER_ADDRESS 0x08 /* Invalid TFTP server IP extraced from received packet */ -#define NX_TFTP_NO_ACK_RECEIVED 0x09 /* Did not receive TFTP server ACK response */ -#define NX_TFTP_INVALID_BLOCK_NUMBER 0x0A /* Invalid block number received from Server response */ -#define NX_TFTP_INVALID_ADDRESS_TYPE 0x0B /* Invalid IP version associated with client data */ -#define NX_TFTP_SESSION_TIMED_OUT 0x0C /* No response from client or retransmissions limit hit */ - - -/* Define offsets into the TFTP message buffer. */ - -#define NX_TFTP_CODE_OFFSET 0 /* Offset to TFTP code in buffer */ -#define NX_TFTP_FILENAME_OFFSET 2 /* Offset to TFTP filename in message */ -#define NX_TFTP_BLOCK_NUMBER_OFFSET 2 /* Offset to TFTP block number in buffer */ -#define NX_TFTP_DATA_OFFSET 4 /* Offset to TFTP data in buffer */ -#define NX_TFTP_ERROR_CODE_OFFSET 2 /* Offset to TFTP error code */ -#define NX_TFTP_ERROR_STRING_OFFSET 4 /* Offset to TFPT error string */ - - -/* Define return code constants. */ - -#define NX_TFTP_ERROR 0xC0 /* TFTP internal error */ -#define NX_TFTP_TIMEOUT 0xC1 /* TFTP timeout occurred */ -#define NX_TFTP_FAILED 0xC2 /* TFTP error */ -#define NX_TFTP_NOT_OPEN 0xC3 /* TFTP not opened error */ -#define NX_TFTP_NOT_CLOSED 0xC4 /* TFTP not closed error */ -#define NX_TFTP_END_OF_FILE 0xC5 /* TFTP end of file error */ -#define NX_TFTP_POOL_ERROR 0xC6 /* TFTP packet pool size error - less than 560 bytes */ - - -/* Define TFTP connection states. */ - -#define NX_TFTP_STATE_NOT_OPEN 0 /* TFTP connection not open */ -#define NX_TFTP_STATE_OPEN 1 /* TFTP connection open */ -#define NX_TFTP_STATE_WRITE_OPEN 2 /* TFTP connection open for writing */ -#define NX_TFTP_STATE_END_OF_FILE 3 /* TFTP connection at end of file */ -#define NX_TFTP_STATE_ERROR 4 /* TFTP error condition */ -#define NX_TFTP_STATE_FINISHED 5 /* TFTP finished writing condition */ - - -/* Define TFTP Server events. */ - -#define NX_TFTP_SERVER_RECEIVE_EVENT 0x01 /* TFTP received Client packet */ -#define NX_TFTP_SERVER_TIMER_EVENT 0x02 /* TFTP timer event */ -#define NX_SERVER_TFTP_ANY_EVENT 0x0F /* Any event */ - -/* Define the TFTP Server UDP port number */ - -#define NX_TFTP_SERVER_PORT 69 - -/* Define the per client request structure for the TFTP Server data structure. */ - -typedef struct NX_TFTP_CLIENT_REQUEST_STRUCT -{ - UINT nx_tftp_client_request_port; /* Port of client request */ - NXD_ADDRESS nx_tftp_client_request_ip_address; /* IP address of client */ - USHORT nx_tftp_client_request_block_number; /* Block number of file transfer */ - USHORT nx_tftp_client_request_reserved; /* Reserved for future use */ - UINT nx_tftp_client_request_open_type; /* Open type of client request */ - ULONG nx_tftp_client_request_remaining_bytes; /* Remaining bytes to send */ - UINT nx_tftp_client_request_exact_fit; /* Exact fit flag */ - ULONG nx_tftp_client_request_last_activity_time; /* Time of last activity */ - FX_FILE nx_tftp_client_request_file; /* File control block */ - ULONG nx_tftp_client_file_size; /* Size of file in bytes */ - ULONG nx_tftp_client_previous_write_size; /* Size of data in last data packet */ -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - UINT nx_tftp_client_retransmit_timeout; /* Time between retransmits from server */ - UINT nx_tftp_client_retransmit_retries; /* Number of retries on current data,ACK*/ -#else - UINT nx_tftp_client_request_retransmits; /* Number of retransmits from client */ -#endif -} NX_TFTP_CLIENT_REQUEST; - - -/* Define the TFTP Server data structure. */ - -typedef struct NX_TFTP_SERVER_STRUCT -{ - ULONG nx_tftp_server_id; /* TFTP Server ID */ - CHAR *nx_tftp_server_name; /* Name of this TFTP client */ - NX_IP *nx_tftp_server_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_tftp_server_packet_pool_ptr; /* Pointer to TFTP server packet pool */ - FX_MEDIA *nx_tftp_server_media_ptr; /* Pointer to media control block */ - ULONG nx_tftp_server_open_for_write_requests; /* Number of open for write requests */ - ULONG nx_tftp_server_open_for_read_requests; /* Number of open for read requests */ - ULONG nx_tftp_server_acks_received; /* Number of ACKs received */ - ULONG nx_tftp_server_data_blocks_received; /* Number of data blocks received */ - ULONG nx_tftp_server_errors_received; /* Number of errors received */ - ULONG nx_tftp_server_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_tftp_server_total_bytes_received; /* Number of total bytes received */ - ULONG nx_tftp_server_unknown_commands; /* Number of unknown commands received */ - ULONG nx_tftp_server_allocation_errors; /* Number of allocation errors */ - ULONG nx_tftp_server_clients_exceeded_errors; /* Number of maximum clients errors */ - ULONG nx_tftp_server_unknown_clients_errors; /* Number of unknown clients errors */ - UINT nx_tftp_server_error_code; /* Last error code received */ - CHAR nx_tftp_server_error_string[NX_TFTP_ERROR_STRING_MAX + 1]; - NX_TFTP_CLIENT_REQUEST /* TFTP client request array */ - nx_tftp_server_client_list[NX_TFTP_MAX_CLIENTS]; - NX_UDP_SOCKET nx_tftp_server_socket; /* TFTP Server UDP socket */ - TX_THREAD nx_tftp_server_thread; /* TFTP server thread */ - TX_EVENT_FLAGS_GROUP - nx_tftp_server_event_flags; /* TFTP server thread events */ -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE - TX_TIMER nx_tftp_server_timer; /* TFTP server activity timeout timer */ -#endif -} NX_TFTP_SERVER; - - -#ifndef NX_TFTP_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -/* NetX TFTP services mapped to NetX Duo TFTP services */ -#define nx_tftp_server_create _nxd_tftp_server_create -#define nx_tftp_server_delete _nxd_tftp_server_delete -#define nx_tftp_server_start _nxd_tftp_server_start -#define nx_tftp_server_stop _nxd_tftp_server_stop - -/* NetX Duo (IPv4 and IPv6 supported) TFTP services */ -#define nxd_tftp_server_create _nxd_tftp_server_create -#define nxd_tftp_server_delete _nxd_tftp_server_delete -#define nxd_tftp_server_start _nxd_tftp_server_start -#define nxd_tftp_server_stop _nxd_tftp_server_stop - -#else - -/* Services with error checking. */ - -/* NetX TFTP services mapped to NetX Duo TFTP services with error checking*/ -#define nx_tftp_server_create _nxde_tftp_server_create -#define nx_tftp_server_delete _nxde_tftp_server_delete -#define nx_tftp_server_start _nxde_tftp_server_start -#define nx_tftp_server_stop _nxde_tftp_server_stop - -/* NetX Duo (IPv4 and IPv6 supported) TFTP services with error checking */ -#define nxd_tftp_server_create _nxde_tftp_server_create -#define nxd_tftp_server_delete _nxde_tftp_server_delete -#define nxd_tftp_server_start _nxde_tftp_server_start -#define nxd_tftp_server_stop _nxde_tftp_server_stop - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - -UINT nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); -UINT nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); -UINT nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); -UINT nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); - -#else - -/* TFTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxde_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); -UINT _nxd_tftp_server_create(NX_TFTP_SERVER *tftp_server_ptr, CHAR *tftp_server_name, NX_IP *ip_ptr, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr); -UINT _nxde_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); -UINT _nxd_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); -UINT _nxde_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); -UINT _nxd_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); -UINT _nxde_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); -UINT _nxd_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); - -#endif /* NX_TFTP_SOURCE_CODE */ - -/* Internal TFTP server functions */ - -void _nx_tftp_server_thread_entry(ULONG tftp_server); -void _nx_tftp_server_open_for_read_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -void _nx_tftp_server_open_for_write_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -VOID _nx_tftp_server_data_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -VOID _nx_tftp_server_ack_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -VOID _nx_tftp_server_error_process(NX_TFTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -NX_TFTP_CLIENT_REQUEST * _nx_tftp_server_find_client_request(NX_TFTP_SERVER *server_ptr, UINT port, NXD_ADDRESS *ip_address); -VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, NXD_ADDRESS *ip_address, UINT port, UINT error, CHAR *error_message); -VOID _nx_tftp_server_data_present(NX_UDP_SOCKET *socket_ptr); -VOID _nx_tftp_server_process_received_data(NX_TFTP_SERVER *server_ptr); -UINT _nx_tftp_server_send_data(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit); -UINT _nx_tftp_server_send_ack(NX_TFTP_SERVER *server_ptr, NX_TFTP_CLIENT_REQUEST *client_request_ptr, UINT retransmit); -#ifdef NX_TFTP_SERVER_RETRANSMIT_ENABLE -VOID _nx_tftp_server_timer_process(NX_TFTP_SERVER *server_ptr); -VOID _nx_tftp_server_timer_entry(ULONG tftp_server_address); -#endif -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_TFTP_SERVER_H */ diff --git a/protocol_handlers/web/nx_tcpserver.c b/protocol_handlers/web/nx_tcpserver.c deleted file mode 100644 index 09e51630..00000000 --- a/protocol_handlers/web/nx_tcpserver.c +++ /dev/null @@ -1,1426 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Multiple TCP Socket/TLS Session support module */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_TCPSERVER_SOURCE_CODE - -#include "nx_api.h" -#include "nx_tcpserver.h" - - -/* Define internal function prototypes. */ -static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr); -static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr); -static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port); -static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr); -static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr); -static VOID _nx_tcpserver_timeout(ULONG tcpserver_address); -static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr); -static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr); -static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr); -static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr); -static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address); - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_session_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function allocates a free socket (and TLS session, if */ -/* TLS is enabled) for an incoming client request. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to server structure */ -/* session_pptr Pointer to allocated socket */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_relisten */ -/* _nx_tcpserver_start */ -/* _nx_tcpserver_connect_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr) -{ -UINT i; -NX_TCP_SOCKET *socket_ptr; - - /* Reset. */ - *session_pptr = NX_NULL; - - /* Loop to find unused session. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - - /* Skip the listen session. */ - if(&server_ptr -> nx_tcpserver_sessions[i] == server_ptr -> nx_tcpserver_listen_session) - continue; - - socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); - - /* A closed or listening socket is available. */ - if((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) && - (socket_ptr -> nx_tcp_socket_bound_next == NX_NULL) && - (socket_ptr -> nx_tcp_socket_bind_in_progress == NX_NULL)) - { - - /* Reset expiration to zero. */ - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0; - - /* Return the socket. */ - *session_pptr = &server_ptr -> nx_tcpserver_sessions[i]; - return NX_SUCCESS; - } - } - - return NX_TCPSERVER_FAIL; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_relisten PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked whenever a connection is closed */ -/* to re-enable listening on that closed socket/session. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to server structure */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tcpserver_session_allocate Allocate socket for listening */ -/* nx_tcp_server_socket_relisten Re-listen on free socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_connect_process */ -/* _nx_tcpserver_disconnect_process */ -/* _nx_tcpserver_timeout_process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr) -{ -UINT status; -NX_TCP_SESSION *session_ptr; - - /* Is any socket listening? */ - if(server_ptr -> nx_tcpserver_listen_session == NX_NULL) - { - - /* Get a socket to listen. */ - status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); - if(status) - { - return NX_TCPSERVER_FAIL; - } - - status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, - server_ptr -> nx_tcpserver_listen_port, - &session_ptr -> nx_tcp_session_socket); - if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - printf("%d, %d\n", status, __LINE__); - return NX_TCPSERVER_FAIL; - } - - /* Store listen socket. */ - server_ptr -> nx_tcpserver_listen_session = session_ptr; - } - else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, - server_ptr -> nx_tcpserver_listen_port, - &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); - if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - printf("%d, %d\n", status, __LINE__); - return NX_TCPSERVER_FAIL; - } - } - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* nx_tcpserver_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a socket server instance to handle multiple */ -/* incoming TCP or TLS client connections. The server utilizes an */ -/* internal thread and manages a queue of TCP sockets (and TLS */ -/* sessions if enabled) that are used to handle incoming requests. */ -/* The callback routines are used to handle individual requests. Each */ -/* socket (and TLS session) receives identical state so that each */ -/* incoming request is handled consistently. */ -/* */ -/* The number of available sockets and TLS sessions is determined by */ -/* the size of the sessions buffer and can be found by dividing the */ -/* buffer size by the size of the NX_TCP_SESSION structure. */ -/* */ -/* INPUT */ -/* */ -/* ip_ptr IP instance for this server */ -/* server_ptr Pointer to server structure */ -/* name Name string for this server */ -/* type_of_service Type of service for TCP */ -/* sockets */ -/* fragment Flag to enable IP fragmenting */ -/* time_to_live Time to live value for socket */ -/* window_size Size of socket's receive */ -/* window */ -/* new_connection Callback invoked for new */ -/* client connections */ -/* receive_data Callback invoked when data is */ -/* received from the client */ -/* connection_end Callback invoked when a */ -/* connection is closed */ -/* connection_timeout Callback invoked when a */ -/* connection times out */ -/* timeout Timeout value for all sockets */ -/* stack_ptr Stack buffer for internal */ -/* server thread */ -/* stack_size Size of thread stack buffer */ -/* sessions_buffer Buffer for per-session data */ -/* buffer_size Size of per-session buffer, */ -/* determines session number */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_create Create server thread */ -/* tx_event_flags_create Create thread event flags */ -/* tx_timer_create Create timeout timer */ -/* nx_tcp_socket_create Create TCP sockets */ -/* nx_tcp_socket_receive_notify Set TCP notification callback */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, - ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, - VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - ULONG timeout, VOID *stack_ptr, UINT stack_size, - VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option) -{ -UINT i; -UINT status; - - /* Initialize server struct. */ - server_ptr -> nx_tcpserver_ip = ip_ptr; - server_ptr -> nx_tcpserver_sessions = sessions_buffer; - server_ptr -> nx_tcpserver_sessions_count = buffer_size / sizeof(NX_TCP_SESSION); - server_ptr -> nx_tcpserver_listen_port = 0; - server_ptr -> nx_tcpserver_listen_session = NX_NULL; - server_ptr -> nx_tcpserver_new_connection = new_connection; - server_ptr -> nx_tcpserver_receive_data = receive_data; - server_ptr -> nx_tcpserver_connection_end = connection_end; - server_ptr -> nx_tcpserver_connection_timeout = connection_timeout; - server_ptr -> nx_tcpserver_timeout = timeout; - server_ptr -> nx_tcpserver_accept_wait_option = accept_wait_option; - - /* Create the tcpserver thread. */ - status = tx_thread_create(&server_ptr -> nx_tcpserver_thread, "TCPSERVER Thread", - _nx_tcpserver_thread_entry, (ULONG)server_ptr, stack_ptr, - stack_size, thread_priority, thread_priority, - TX_NO_TIME_SLICE, TX_DONT_START); - - /* Create the tcpserver event flags. */ - status += tx_event_flags_create(&server_ptr -> nx_tcpserver_event_flags, "TCPSERVER Events"); - - /* Create the timeout timer. */ - status += tx_timer_create(&server_ptr -> nx_tcpserver_timer, "TCPSERVER Timer", - _nx_tcpserver_timeout, (ULONG)server_ptr, - (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD), - (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE); - - /* Initialize buffer. */ - memset(sessions_buffer, 0, buffer_size); - - /* Initialize TCP sockets. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - status += nx_tcp_socket_create(ip_ptr, &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, name, type_of_service, fragment, time_to_live, - window_size, NX_NULL, _nx_tcpserver_disconnect_present); - - status += nx_tcp_socket_receive_notify(&server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, _nx_tcpserver_data_present); - - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket.nx_tcp_socket_reserved_ptr = server_ptr; - } - - return status; -} - - -#ifdef NX_TCPSERVER_ENABLE_TLS - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_tls_setup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function configures a previously created NetX socket server */ -/* instance to use TLS. The parameters are used to configure all the */ -/* TLS sessions in the server with identical state so that each */ -/* incoming TLS client experiences consistent behavior. The number of */ -/* TLS sessions and TCP sockets is determined by the size of the */ -/* sessions buffer passed into nx_tcpserver_create. */ -/* */ -/* The cryptographic routine table (ciphersuite table) is shared */ -/* between all TLS sessions as it just contains function pointers. */ -/* */ -/* The metadata buffer and packet reassembly buffer are divided */ -/* equally between all TLS sessions. If the buffer size is not evenly */ -/* divisible by the number of sessions the remainder will be unused. */ -/* */ -/* The passed-in identity certificate is used by all sessions. During */ -/* TLS operation the server identity certificate is only read from so */ -/* copies are not needed for each session. */ -/* */ -/* The trusted certificates are added to the trusted store for each */ -/* TLS session in the server. This is used for client certificate */ -/* verification which is enabled if remote certificates are provided. */ -/* */ -/* The remote certificate array and buffer is shared by default */ -/* between all TLS sessions. This does mean that some sessions may */ -/* block during certificate validation. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to control block */ -/* crypto_table TLS cryptographic routines */ -/* metadata_buffer Cryptographic metadata buffer */ -/* metadata_size Size of metadata buffer */ -/* packet_buffer TLS packet buffer */ -/* packet_size Size of packet buffer */ -/* identity_certificate TLS server certificate */ -/* trusted_certificates TLS trusted certificates */ -/* trusted_certs_num Number of trusted certs */ -/* remote_certificates Remote certificates array */ -/* remote_certs_num Number of remote certificates */ -/* remote_certificate_buffer Buffer for remote certs */ -/* remote_cert_buffer_size Size of remote cert buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_create Create TLS Session */ -/* */ -/* nx_secure_tls_session_packet_buffer_set */ -/* Set TLS packet buffer */ -/* */ -/* nx_secure_tls_local_certificate_add */ -/* Add local TLS identity cert */ -/* */ -/* nx_secure_tls_session_client_verify_enable */ -/* Enable client cert verify */ -/* */ -/* nx_secure_tls_trusted_certificate_add Add a trusted TLS cert */ -/* */ -/* nx_secure_tls_remote_certificate_allocate */ -/* Allocate space for incoming */ -/* client certificates */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -/* Setup TLS state per server session. */ -UINT _nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size) -{ -NX_SECURE_TLS_SESSION *tls_session; -ULONG session_metadata_size; -UCHAR *session_metadata; -UCHAR *session_cert_buffer; -UINT session_cert_buffer_size = 0; -UINT session_pkt_buffer_size; -UINT num_sessions; -UINT i; -UINT cert_count; -UINT status; - - /* Get the number of sessions in the TCP server. */ - num_sessions = server_ptr -> nx_tcpserver_sessions_count; - - /* Get our per-session packet buffer size. */ - session_pkt_buffer_size = packet_buffer_size / num_sessions; - - /* Get our per-session metadata. */ - session_metadata = metadata_buffer; - session_metadata_size = metadata_size / num_sessions; - - /* It's OK to have zero remote certs allocated. */ - if(remote_certs_num > 0) - { - /* Divide the remote certificate buffer size by the total number of - remote certificates to get per-certificate size. */ - session_cert_buffer_size = remote_cert_buffer_size / remote_certs_num; - } - - /* Loop through all sessions, initialize each one. */ - for(i = 0; i < num_sessions; ++i) - { - /* This server instance is using TLS so mark as such. */ - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_using_tls = NX_TRUE; - - /* Setup per-session data. Get the session from the server structure, then initialize it. */ - tls_session = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session); - status = nx_secure_tls_session_create(tls_session, crypto_table, session_metadata, session_metadata_size); - - if(status != NX_SUCCESS) - { - return(status); - } - - /* Allocate space for packet reassembly. */ - status = nx_secure_tls_session_packet_buffer_set(tls_session, &packet_buffer[i * session_pkt_buffer_size], - session_pkt_buffer_size); - - if(status != NX_SUCCESS) - { - return(status); - } - - /* Add identity certificate. */ - status = nx_secure_tls_local_certificate_add(tls_session, identity_certificate); - - if(status != NX_SUCCESS) - { - return(status); - } - - /* See if remote certificates are provided. */ - if(remote_certs_num > 0) - { - /* We have remote certificates to allocate so enable client certificate authentication. */ - nx_secure_tls_session_client_verify_enable(tls_session); - - /* Add trusted certificates to each TLS session. */ - for(cert_count = 0; cert_count < trusted_certs_num; ++cert_count) - { - status = nx_secure_tls_trusted_certificate_add(tls_session, trusted_certificates[cert_count]); - - if(status != NX_SUCCESS) - { - return(status); - } - } - - /* Allocate remote certificates (if remote_certs_num > 0). The remote certificate - buffers are shared between all TLS Sessions. This is possible since they are only - needed for the certificate verification process and are freed immediately after. */ - session_cert_buffer = remote_certificate_buffer; - - for(cert_count = 0; cert_count < remote_certs_num; ++cert_count) - { - /* Allocate a remote certificate from the provided array. */ - status = nx_secure_tls_remote_certificate_allocate(tls_session, remote_certificates[i], - session_cert_buffer, session_cert_buffer_size); - - if(status != NX_SUCCESS) - { - return(status); - } - - /* Now get the next certificate and its buffer. */ - session_cert_buffer += session_cert_buffer_size; - } - } - - /* Advance metadata buffer. */ - session_metadata = &session_metadata[session_metadata_size]; - } - return(NX_SUCCESS); -} -#endif - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called by an application to start a socket server */ -/* that was previously created and configured. This routine starts the */ -/* internal server thread and timer. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to server structure */ -/* port Port for server to listen on */ -/* listen_queue_size Maximum number of TCP */ -/* connections queued */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_tcpserver_session_allocate Allocate socket for listening */ -/* nx_tcp_server_socket_listen Listen on free TCP socket */ -/* tx_timer_activate Start timeout timer */ -/* tx_thread_resume Start server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size) -{ -UINT status; -NX_TCP_SESSION *session_ptr; - - /* Check whether listen is done. */ - if(server_ptr -> nx_tcpserver_listen_port) - return NX_TCPSERVER_FAIL; - - /* Get a socket to listen. */ - status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); - if(status) - return status; - - /* Listen on port. */ - status = nx_tcp_server_socket_listen(server_ptr -> nx_tcpserver_ip, port, &session_ptr -> nx_tcp_session_socket, listen_queue_size, _nx_tcpserver_connect_present); - if(status) - return status; - - /* Store socket and port. */ - server_ptr -> nx_tcpserver_listen_session = session_ptr; - server_ptr -> nx_tcpserver_listen_port = port; - - /* Activate timer. */ - tx_timer_activate(&server_ptr -> nx_tcpserver_timer); - - /* Start thread. */ - tx_thread_resume(&server_ptr -> nx_tcpserver_thread); - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_connect_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is used for the TCP listen callback passed */ -/* into nx_tcp_server_socket_listen and is used to determine when an */ -/* incoming request has been received and is ready for processing. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to TCP socket */ -/* port Port of incoming request */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set thread event flag */ -/* */ -/* CALLED BY */ -/* */ -/* TCP stack */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port) -{ -NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - - NX_PARAMETER_NOT_USED(port); - - /* Set the connect event flag. */ - tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_CONNECT, TX_OR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_data_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is used for the TCP receive callback passed */ -/* into nx_tcp_socket_receive_notify and is used to determine when */ -/* data has been received and is ready for processing. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to TCP socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set thread event flag */ -/* */ -/* CALLED BY */ -/* */ -/* TCP stack */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr) -{ -NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the data event flag. */ - tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DATA, TX_OR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_disconnect_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is used for the TCP disconnect callback */ -/* passed into nx_tcp_socket_create and is used to determine when */ -/* a socket has been disconnected. */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to TCP socket */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set thread event flag */ -/* */ -/* CALLED BY */ -/* */ -/* TCP stack */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr) -{ -NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr; - - /* Set the disconnect event flag. */ - tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DISCONNECT, TX_OR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked whenever the internal timeout */ -/* timer expires, and is passed into tx_timer_create as the callback. */ -/* */ -/* INPUT */ -/* */ -/* tcpserver_address Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* tx_event_flags_set Set thread event flag */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_timeout(ULONG tcpserver_address) -{ -NX_TCPSERVER *server_ptr = (NX_TCPSERVER *)tcpserver_address; - - /* Set the timeout event flag. */ - tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_TIMEOUT, TX_OR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_connect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked by the server thread whenever an */ -/* incoming connection request is received. It establishes the TCP */ -/* connection and if TLS is enabled, it begins the TLS handshake. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_tcpserver_session_allocate Get socket for listening */ -/* nx_tcp_server_socket_relisten Relisten on existing socket */ -/* nx_tcp_server_socket_accept Accept incoming TCP request */ -/* nx_secure_tls_session_start Start TLS handshake */ -/* nx_tcp_server_socket_unaccept Clear accepted socket */ -/* _nx_tcpserver_relisten Re-listen on all sockets */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr) -{ -UINT status; -NX_TCP_SESSION *session_ptr = NX_NULL; - - /* Is any socket listening? */ - if(server_ptr -> nx_tcpserver_listen_session == NX_NULL) - { - - /* No. Check whether listen is done. */ - if(server_ptr -> nx_tcpserver_listen_port == 0) - { - return; - } - - /* Get a socket to listen. */ - status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr); - if(status) - { - return; - } - - status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, - server_ptr -> nx_tcpserver_listen_port, - &session_ptr -> nx_tcp_session_socket); - if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - return; - } - - /* Store listen socket. */ - server_ptr -> nx_tcpserver_listen_session = session_ptr; - } - else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - - status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip, - server_ptr -> nx_tcpserver_listen_port, - &session_ptr -> nx_tcp_session_socket); - if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING)) - { - return; - } - } - - /* Accept connection. */ - status = nx_tcp_server_socket_accept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, server_ptr -> nx_tcpserver_accept_wait_option); - - if(status == NX_SUCCESS) - { - - /* Set default expiration. */ - server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout; - -#ifdef NX_TCPSERVER_ENABLE_TLS - /* If TLS, start the TLS handshake. */ - if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_using_tls == NX_TRUE) - { - status = nx_secure_tls_session_start(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_tls_session, - &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, NX_WAIT_FOREVER); - - if(status != NX_SUCCESS) - { - nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); - } - } - - if (status == NX_SUCCESS) -#endif - { - if(server_ptr -> nx_tcpserver_new_connection) - { - - /* Invoke new connection callback. */ - server_ptr -> nx_tcpserver_new_connection(server_ptr, server_ptr -> nx_tcpserver_listen_session); - } - - /* Clear listen socket. */ - server_ptr -> nx_tcpserver_listen_session = NX_NULL; - } - } - else - { - nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket); - } - - /* Relisten */ - _nx_tcpserver_relisten(server_ptr); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_data_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked by the server thread whenever */ -/* data is received from the remote client. If the application passes */ -/* a receive callback to _nx_tcpserver_create, it will be invoked here.*/ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcpserver_receive_data Callback to process data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr) -{ -UINT i; -NX_TCP_SOCKET *socket_ptr; - - /* Do nothing if callback is not set. */ - if(server_ptr -> nx_tcpserver_receive_data == NX_NULL) - { - return; - } - - /* Initialize TCP sockets. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); - - if(socket_ptr -> nx_tcp_socket_receive_queue_count) - { - - /* Reset default expiration. */ - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout; - - /* Invoke receive data callback. */ - server_ptr -> nx_tcpserver_receive_data(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); - - /* Relisten */ - _nx_tcpserver_relisten(server_ptr); - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_disconnect_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked by the server thread whenever */ -/* a socket is disconnected. If the application passes a disconnect */ -/* callback to _nx_tcpserver_create, it will be invoked here. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcpserver_connection_end Callback for disconnections */ -/* _nx_tcpserver_relisten Re-listen on free sockets */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr) -{ -UINT i; -NX_TCP_SOCKET *socket_ptr; - - /* Do nothing if callback is not set. */ - if(server_ptr -> nx_tcpserver_connection_end == NX_NULL) - { - return; - } - - /* Initialize TCP sockets. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket); - - if((socket_ptr -> nx_tcp_socket_state > NX_TCP_ESTABLISHED) || - ((socket_ptr -> nx_tcp_socket_state < NX_TCP_SYN_SENT) && - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration)) - { - - /* Invoke disconnect callback. */ - server_ptr -> nx_tcpserver_connection_end(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); - - /* Reset epiration of session. */ - server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0; - - /* Relisten */ - _nx_tcpserver_relisten(server_ptr); - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_timeout_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is invoked by the server thread whenever */ -/* a timeout event is encountered (triggered by the timeout timer). */ -/* If the application passes a disconnect callback to */ -/* _nx_tcpserver_create, it will be invoked here. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* nx_tcpserver_connection_timeout Callback to process timeout */ -/* _nx_tcpserver_relisten Re-listen on free sockets */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_tcpserver_thread_entry */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr) -{ -UINT i; -NX_TCP_SESSION *session_ptr; - - /* Do nothing if callback is not set. */ - if(server_ptr -> nx_tcpserver_connection_timeout == NX_NULL) - { - return; - } - - /* Initialize TCP sockets. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - session_ptr = &server_ptr -> nx_tcpserver_sessions[i]; - - /* Skip socket that is not used. */ - if(session_ptr -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED) - { - continue; - } - - /* Skip socket that is already timeout. */ - if(session_ptr -> nx_tcp_session_expiration == 0) - { - continue; - } - - /* Is the session timeout? */ - if(session_ptr -> nx_tcp_session_expiration > NX_TCPSERVER_TIMEOUT_PERIOD) - session_ptr -> nx_tcp_session_expiration -= NX_TCPSERVER_TIMEOUT_PERIOD; - else - { - - session_ptr -> nx_tcp_session_expiration = 0; - - /* Invoke timeout callback. */ - server_ptr -> nx_tcpserver_connection_timeout(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]); - - /* Relisten */ - _nx_tcpserver_relisten(server_ptr); - } - } -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_thread_entry PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is the entry point for the socket server */ -/* thread. It continually loops, checking the event flags and */ -/* dispatching processing when events are encountered. */ -/* */ -/* INPUT */ -/* */ -/* tcpserver_address Pointer to socket server */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_tcpserver_connect_process Process new connection */ -/* _nx_tcpserver_data_process Process received data */ -/* _nx_tcpserver_disconnect_process Process disconnection event */ -/* _nx_tcpserver_timeout_process Process server timeout */ -/* */ -/* CALLED BY */ -/* */ -/* ThreadX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address) -{ -ULONG events; -UINT status; -NX_TCPSERVER *server_ptr = (NX_TCPSERVER *)tcpserver_address; - - - /* Loop to process events. */ - while(1) - { - status = tx_event_flags_get(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_ANY_EVENT, TX_OR_CLEAR, &events, TX_WAIT_FOREVER); - - /* Check the return status. */ - if(status) - { - - /* If an error occurs, simply continue the loop. */ - continue; - } - - /* Otherwise, an event is present. Process according to the event. */ - - /* Check for a connect event. */ - if(events & NX_TCPSERVER_CONNECT) - { - - /* Call the connect processing. */ - _nx_tcpserver_connect_process(server_ptr); - } - - - /* Check for a data event. */ - if(events & NX_TCPSERVER_DATA) - { - - /* Call the receive data processing. */ - _nx_tcpserver_data_process(server_ptr); - } - - - /* Check for a disconnect event. */ - if(events & NX_TCPSERVER_DISCONNECT) - { - - /* Call the disconnect processing. */ - _nx_tcpserver_disconnect_process(server_ptr); - } - - - /* Check for a timeout event. */ - if(events & NX_TCPSERVER_TIMEOUT) - { - - /* Call the disconnect processing. */ - _nx_tcpserver_timeout_process(server_ptr); - } - - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called by an application to stop a currently */ -/* running socket server. It shuts down the server thread and stops */ -/* listening on all internal TCP sockets. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to server structure */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_suspend Stop server thread */ -/* tx_timer_deactivate Stop server timeout timer */ -/* nx_tcp_server_socket_unlisten Stop listening on TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tcpserver_stop(NX_TCPSERVER *server_ptr) -{ -UINT status; - - /* Check whether listen is done. */ - if(server_ptr -> nx_tcpserver_listen_port == 0) - return NX_TCPSERVER_FAIL; - - /* Suspend thread. */ - tx_thread_suspend(&server_ptr -> nx_tcpserver_thread); - - /* Deactivate timer. */ - tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer); - - /* Unlisten. */ - status = nx_tcp_server_socket_unlisten(server_ptr -> nx_tcpserver_ip, server_ptr -> nx_tcpserver_listen_port); - - if(status == NX_SUCCESS) - { - - /* Clear. */ - server_ptr -> nx_tcpserver_listen_port = 0; - server_ptr -> nx_tcpserver_listen_session = NX_NULL; - } - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_tcpserver_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is called by an application to clean up a previously */ -/* created socket server. It cleans up the server thread and closes */ -/* deletes all internal TCP sockets and TLS sessions. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to server structure */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* tx_thread_terminate Stop server thread */ -/* tx_thread_delete Stop server timeout timer */ -/* tx_event_flags_delete Delete server event flags */ -/* tx_timer_deactivate Deactivate timeout timer */ -/* tx_timer_delete Delete timeout timer */ -/* nx_tcp_socket_disconnect Disconnect TCP sockets */ -/* nx_tcp_server_socket_unaccept Stop listening on TCP sockets */ -/* nx_tcp_socket_delete Delete TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_tcpserver_delete(NX_TCPSERVER *server_ptr) -{ -UINT i; -NX_TCP_SOCKET *socket_ptr; - - /* Terminate server thread. */ - tx_thread_terminate(&server_ptr -> nx_tcpserver_thread); - - /* Delete server thread. */ - tx_thread_delete(&server_ptr -> nx_tcpserver_thread); - - /* Delete the event flag group */ - tx_event_flags_delete(&server_ptr -> nx_tcpserver_event_flags); - - /* Deactivate and delete timer. */ - tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer); - tx_timer_delete(&server_ptr -> nx_tcpserver_timer); - - /* Delete all opened sockets. */ - for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++) - { - - /* Get socket pointer. */ - socket_ptr = &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket; - - /* Disconnect the socket. */ - nx_tcp_socket_disconnect(socket_ptr, NX_NO_WAIT); - - /* unaccept the socket. */ - nx_tcp_server_socket_unaccept(socket_ptr); - - /* Delete the socket. */ - nx_tcp_socket_delete(socket_ptr); - } - - /* Return successful compeletion. */ - return NX_SUCCESS; -} diff --git a/protocol_handlers/web/nx_tcpserver.h b/protocol_handlers/web/nx_tcpserver.h deleted file mode 100644 index 234a0d62..00000000 --- a/protocol_handlers/web/nx_tcpserver.h +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Multiple TCP Socket/TLS Session support module */ -/** */ -/**************************************************************************/ - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_tcpserver.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX TCP Server module component, */ -/* including all data types and external references. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_TCPSERVER_H -#define NX_TCPSERVER_H - -#include "tx_api.h" -#include "nx_api.h" -#ifdef NX_WEB_HTTPS_ENABLE - -/* Enable TLS for the TCPServer module to support HTTPS */ -#ifndef NX_TCPSERVER_ENABLE_TLS -#define NX_TCPSERVER_ENABLE_TLS -#endif - -#include "nx_secure_tls_api.h" -#endif /* NX_WEB_HTTPS_ENABLE */ - -#ifndef NX_TCPSERVER_ACCEPT_WAIT -#define NX_TCPSERVER_ACCEPT_WAIT 1 -#endif /* NX_TCPSERVER_ACCEPT_WAIT */ - -#ifndef NX_TCPSERVER_DISCONNECT_WAIT -#define NX_TCPSERVER_DISCONNECT_WAIT 1 -#endif /* NX_TCPSERVER_DISCONNECT_WAIT */ - -#ifndef NX_TCPSERVER_PRIORITY -#define NX_TCPSERVER_PRIORITY 4 -#endif /* NX_TCPSERVER_PRIORITY */ - -#ifndef NX_TCPSERVER_TIMEOUT_PERIOD -#define NX_TCPSERVER_TIMEOUT_PERIOD 1 -#endif /* NX_TCPSERVER_TIMEOUT_PERIOD */ - -/* Define thread events. */ -#define NX_TCPSERVER_CONNECT 0x00000001 -#define NX_TCPSERVER_DATA 0x00000002 -#define NX_TCPSERVER_DISCONNECT 0x00000004 -#define NX_TCPSERVER_TIMEOUT 0x00000008 -#define NX_TCPSERVER_ANY_EVENT 0xFFFFFFFF - -/* ERROR code */ -#define NX_TCPSERVER_FAIL 0x01 - -/* TCP Server session structure - contains individual - TCP sockets and TLS sessions. */ -typedef struct NX_TCP_SESSION_STRUCT -{ - /* TCP socket used for this session. */ - NX_TCP_SOCKET nx_tcp_session_socket; - - /* Expiration timeout for this socket. */ - ULONG nx_tcp_session_expiration; - - /* Reserved value for passing data to/from individual sessions. */ - ULONG nx_tcp_session_reserved; - -#ifdef NX_TCPSERVER_ENABLE_TLS - /* Flag set to NX_TRUE if using TLS. */ - UINT nx_tcp_session_using_tls; - - /* If TLS is enabled, we also have a TLS session to maintain. */ - NX_SECURE_TLS_SESSION nx_tcp_session_tls_session; -#endif - -} NX_TCP_SESSION; - -/* TCPSERVER structure */ -typedef struct NX_TCPSERVER_STRUCT -{ - NX_IP *nx_tcpserver_ip; - NX_TCP_SESSION *nx_tcpserver_sessions; - UINT nx_tcpserver_sessions_count; - UINT nx_tcpserver_listen_port; - NX_TCP_SESSION *nx_tcpserver_listen_session; - TX_THREAD nx_tcpserver_thread; - TX_TIMER nx_tcpserver_timer; - TX_EVENT_FLAGS_GROUP nx_tcpserver_event_flags; - ULONG nx_tcpserver_timeout; - ULONG nx_tcpserver_accept_wait_option; - VOID (*nx_tcpserver_new_connection)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); - VOID (*nx_tcpserver_receive_data)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); - VOID (*nx_tcpserver_connection_end)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); - VOID (*nx_tcpserver_connection_timeout)(struct NX_TCPSERVER_STRUCT *server_ptr, NX_TCP_SESSION *session_ptr); - ULONG nx_tcpserver_reserved; -} NX_TCPSERVER; - - -#ifndef NX_TCPSERVER_SOURCE_CODE - -/* APIs */ -#define nx_tcpserver_create _nx_tcpserver_create -#define nx_tcpserver_start _nx_tcpserver_start -#define nx_tcpserver_stop _nx_tcpserver_stop -#define nx_tcpserver_delete _nx_tcpserver_delete -#ifdef NX_TCPSERVER_ENABLE_TLS -#define nx_tcpserver_tls_setup _nx_tcpserver_tls_setup -#endif - -#ifdef NX_TCPSERVER_ENABLE_TLS -UINT nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, - UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size); -#endif - -UINT nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, - ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, - VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - ULONG timeout, VOID *stack_ptr, UINT stack_size, - VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option); - - -UINT nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size); - -UINT nx_tcpserver_stop(NX_TCPSERVER *server_ptr); - -UINT nx_tcpserver_delete(NX_TCPSERVER *server_ptr); - -#else - -#ifdef NX_TCPSERVER_ENABLE_TLS -UINT _nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, - UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size); -#endif - -UINT _nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name, - ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, - VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr), - ULONG timeout, VOID *stack_ptr, UINT stack_size, - VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option); - - -UINT _nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size); - -UINT _nx_tcpserver_stop(NX_TCPSERVER *server_ptr); - -UINT _nx_tcpserver_delete(NX_TCPSERVER *server_ptr); - -#endif - -#endif /* NX_TCPSERVER_H */ diff --git a/protocol_handlers/web/nx_web_http_client.c b/protocol_handlers/web/nx_web_http_client.c deleted file mode 100644 index 860501b3..00000000 --- a/protocol_handlers/web/nx_web_http_client.c +++ /dev/null @@ -1,8505 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Web Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) and */ -/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_WEB_HTTP_CLIENT_SOURCE_CODE - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_ipv6.h" - -#include "nx_web_http_client.h" - -#include "stdio.h" -#include "string.h" - - -/* Define global HTTPS variables and strings. */ - - -/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing - into this array yields the base64 representation of the 6bit number. */ - -CHAR _nx_web_http_client_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* Define status maps. */ -static NX_WEB_HTTP_CLIENT_STATUS_MAP _nx_web_http_client_status_maps[] = -{ - {"200", NX_SUCCESS}, - {"100", NX_WEB_HTTP_STATUS_CODE_CONTINUE}, - {"101", NX_WEB_HTTP_STATUS_CODE_SWITCHING_PROTOCOLS}, - {"201", NX_WEB_HTTP_STATUS_CODE_CREATED}, - {"202", NX_WEB_HTTP_STATUS_CODE_ACCEPTED}, - {"203", NX_WEB_HTTP_STATUS_CODE_NON_AUTH_INFO}, - {"204", NX_WEB_HTTP_STATUS_CODE_NO_CONTENT}, - {"205", NX_WEB_HTTP_STATUS_CODE_RESET_CONTENT}, - {"206", NX_WEB_HTTP_STATUS_CODE_PARTIAL_CONTENT}, - {"300", NX_WEB_HTTP_STATUS_CODE_MULTIPLE_CHOICES}, - {"301", NX_WEB_HTTP_STATUS_CODE_MOVED_PERMANETLY}, - {"302", NX_WEB_HTTP_STATUS_CODE_FOUND}, - {"303", NX_WEB_HTTP_STATUS_CODE_SEE_OTHER}, - {"304", NX_WEB_HTTP_STATUS_CODE_NOT_MODIFIED}, - {"305", NX_WEB_HTTP_STATUS_CODE_USE_PROXY}, - {"307", NX_WEB_HTTP_STATUS_CODE_TEMPORARY_REDIRECT}, - {"400", NX_WEB_HTTP_STATUS_CODE_BAD_REQUEST}, - {"401", NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED}, - {"402", NX_WEB_HTTP_STATUS_CODE_PAYMENT_REQUIRED}, - {"403", NX_WEB_HTTP_STATUS_CODE_FORBIDDEN}, - {"404", NX_WEB_HTTP_STATUS_CODE_NOT_FOUND}, - {"405", NX_WEB_HTTP_STATUS_CODE_METHOD_NOT_ALLOWED}, - {"406", NX_WEB_HTTP_STATUS_CODE_NOT_ACCEPTABLE}, - {"407", NX_WEB_HTTP_STATUS_CODE_PROXY_AUTH_REQUIRED}, - {"408", NX_WEB_HTTP_STATUS_CODE_REQUEST_TIMEOUT}, - {"409", NX_WEB_HTTP_STATUS_CODE_CONFLICT}, - {"410", NX_WEB_HTTP_STATUS_CODE_GONE}, - {"411", NX_WEB_HTTP_STATUS_CODE_LENGTH_REQUIRED}, - {"412", NX_WEB_HTTP_STATUS_CODE_PRECONDITION_FAILED}, - {"413", NX_WEB_HTTP_STATUS_CODE_ENTITY_TOO_LARGE}, - {"414", NX_WEB_HTTP_STATUS_CODE_URL_TOO_LARGE}, - {"415", NX_WEB_HTTP_STATUS_CODE_UNSUPPORTED_MEDIA}, - {"416", NX_WEB_HTTP_STATUS_CODE_RANGE_NOT_SATISFY}, - {"417", NX_WEB_HTTP_STATUS_CODE_EXPECTATION_FAILED}, - {"500", NX_WEB_HTTP_STATUS_CODE_INTERNAL_ERROR}, - {"501", NX_WEB_HTTP_STATUS_CODE_NOT_IMPLEMENTED}, - {"502", NX_WEB_HTTP_STATUS_CODE_BAD_GATEWAY}, - {"503", NX_WEB_HTTP_STATUS_CODE_SERVICE_UNAVAILABLE}, - {"504", NX_WEB_HTTP_STATUS_CODE_GATEWAY_TIMEOUT}, - {"505", NX_WEB_HTTP_STATUS_CODE_VERSION_ERROR}, -}; - -static UINT _nx_web_http_client_status_maps_size = sizeof(_nx_web_http_client_status_maps)/sizeof(NX_WEB_HTTP_CLIENT_STATUS_MAP); - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* client_name Name of HTTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* window_size Size of HTTP client rx window */ -/* http_client_size Size of HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_create Actual client create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size) -{ - -NX_PACKET *packet_ptr; -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id == NX_WEB_HTTP_CLIENT_ID) || - (pool_ptr == NX_NULL) || (http_client_size != sizeof(NX_WEB_HTTP_CLIENT))) - return(NX_PTR_ERROR); - - /* Pickup a packet from the supplied packet pool. */ - packet_ptr = pool_ptr -> nx_packet_pool_available_list; - - /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ - if ((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) < NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE) - return(NX_WEB_HTTP_POOL_ERROR); - - /* Call actual client create function. */ - status = _nx_web_http_client_create(client_ptr, client_name, ip_ptr, pool_ptr, window_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a HTTP client on the specified IP. In doing */ -/* so this function creates an TCP socket for subsequent HTTP */ -/* transfers. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* client_name Name of HTTP client */ -/* ip_ptr Pointer to IP instance */ -/* pool_ptr Pointer to packet pool */ -/* window_size Size of HTTP client rx window */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create HTTP client socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size) -{ - -UINT status; - - - /* Clear the HTTP Client structure. */ - memset((void *) client_ptr, 0, sizeof(NX_WEB_HTTP_CLIENT)); - - /* Create the Client's TCP socket. */ - status = nx_tcp_socket_create(ip_ptr, &(client_ptr -> nx_web_http_client_socket), client_name, - NX_WEB_HTTP_TYPE_OF_SERVICE, NX_WEB_HTTP_FRAGMENT_OPTION, NX_WEB_HTTP_TIME_TO_LIVE, - window_size, NX_NULL, NX_NULL); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, return error code. */ - return(status); - } - - /* Save the Client name. */ - client_ptr -> nx_web_http_client_name = client_name; - - /* Save the IP pointer address. */ - client_ptr -> nx_web_http_client_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - client_ptr -> nx_web_http_client_packet_pool_ptr = pool_ptr; - - /* Set the client state to ready to indicate a get or put operation can be done. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - - /* Set the current method to "NONE". */ - client_ptr -> nx_web_http_client_method = NX_WEB_HTTP_METHOD_NONE; - - /* Set the Client ID to indicate the HTTP client thread is ready. */ - client_ptr -> nx_web_http_client_id = NX_WEB_HTTP_CLIENT_ID; - - /* Set the default port the client connects to the HTTP server on (80). */ - client_ptr -> nx_web_http_client_connect_port = NX_WEB_HTTP_SERVER_PORT; - - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete Actual client delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual client delete function. */ - status = _nx_web_http_client_delete(client_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created HTTP client on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_delete Delete the HTTP client socket */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr) -{ - -#ifdef NX_WEB_HTTPS_ENABLE - - /* End TLS session if using HTTPS. */ - if (client_ptr->nx_web_http_client_is_https) - { - nx_secure_tls_session_end(&(client_ptr -> nx_web_http_client_tls_session), NX_WAIT_FOREVER); - nx_secure_tls_session_delete(&(client_ptr -> nx_web_http_client_tls_session)); - } -#endif - - /* Disconnect and unbind the socket. */ - nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), NX_WEB_HTTP_CLIENT_TIMEOUT); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); - - /* Delete the TCP socket. */ - nx_tcp_socket_delete(&(client_ptr -> nx_web_http_client_socket)); - - /* Clear the client ID to indicate the HTTP client is no longer ready. */ - client_ptr -> nx_web_http_client_id = 0; - - /* Release request packet. */ - if (client_ptr -> nx_web_http_client_request_packet_ptr) - { - nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); - client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; - } - - /* Release response packet. */ - if (client_ptr -> nx_web_http_client_response_packet) - { - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - } - - /* Clear out the entire structure in case it is used again. */ - memset(client_ptr, 0, sizeof(NX_WEB_HTTP_CLIENT)); - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_content_type_header_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is used to add the Content-Type HTTP header */ -/* to an outgoing request. It determines the resource type from the */ -/* resource string and then adds the complete header to the current */ -/* HTTP request packet allocated in the control block. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* resource Server resource name */ -/* wait_option Timeout for called functions */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_type_get Get resource content type */ -/* _nx_web_http_client_request_header_add */ -/* Add header to request packet */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_content_type_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *resource, ULONG wait_option) -{ -UINT j; -CHAR string1[20]; - - /* Now build the content-type entry. */ - j = _nx_web_http_client_type_get(resource, string1); - _nx_web_http_client_request_header_add(client_ptr, "Content-Type", 12, string1, j, wait_option); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_content_length_header_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This internal function is used to add the Content-Length HTTP */ -/* header to an outgoing request. It converts the passed-in length */ -/* value to an HTTP string and then adds the complete header to the */ -/* current HTTP request packet allocated in the control block. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* total_bytes Content length value */ -/* wait_option Timeout for called functions */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_number_convert Convert length to string */ -/* _nx_web_http_client_request_header_add */ -/* Add header to request packet */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_content_length_header_add(NX_WEB_HTTP_CLIENT *client_ptr, ULONG total_bytes, ULONG wait_option) -{ -UINT j; -CHAR string1[20]; - - /* Now build the content-length entry. */ - j = _nx_web_http_client_number_convert(total_bytes, string1); - _nx_web_http_client_request_header_add(client_ptr, "Content-Length", 14, string1, j, wait_option); - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo client get start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_start Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, CHAR *host, CHAR *username, CHAR *password, - ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_web_http_client_get_start(client_ptr, server_ip, server_port, resource, - host, username, password, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_get_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. The response is processed by calling */ -/* nx_web_http_client_response_body_get. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_start_extended */ -/* Actual client get start call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, CHAR *host, - CHAR *username, CHAR *password, ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_get_start_extended(client_ptr, server_ip, server_port, resource, - temp_resource_length, host, temp_host_length, username, - temp_username_length, password, temp_password_length, - wait_option)); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo client get start */ -/* call with string length. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_start_extended */ -/* Actual client get start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_web_http_client_get_start_extended(client_ptr, server_ip, server_port, resource, - resource_length, host, host_length, username, - username_length, password, password_length, - wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_get_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. The response is processed by calling */ -/* nx_web_http_client_response_body_get. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ - -UINT status; - - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_GET, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the GET state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; - - return(status); -} - -#ifdef NX_WEB_HTTPS_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_get_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure GET request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_secure_start Actual GET request processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_web_http_client_get_secure_start(client_ptr, server_ip, server_port, resource, - host, username, password, tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_get_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. This version of the function also requires a TLS setup */ -/* callback as the request is sent over TLS-secured HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_secure_start_extended */ -/* Actual GET request processing */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_get_secure_start_extended(client_ptr, server_ip, server_port, - resource, temp_resource_length, host, - temp_host_length, username, - temp_username_length, password, - temp_password_length, tls_setup, - wait_option)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_get_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure GET request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_get_secure_start_extended */ -/* Actual GET request processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET start routine. */ - status = _nx_web_http_client_get_secure_start_extended(client_ptr, server_ip, server_port, - resource, resource_length, host, - host_length, username, username_length, - password, password_length, tls_setup, - wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_get_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application GET request. The specified */ -/* resource (URL) is requested from the HTTP Server at the specified */ -/* IP address. This version of the function also requires a TLS setup */ -/* callback as the request is sent over TLS-secured HTTPS. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_secure_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ - -UINT status; - - /* Use default HTTPS port. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_GET, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the GET state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; - - return(status); -} - -#endif /* NX_WEB_HTTPS_ENABLE */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_get_server_response PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the initial response from the remote */ -/* server. The body of the response is retrieved by the application */ -/* by calling the GET response body API. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_receive Receive packet */ -/* nx_packet_data_append Put data into return packet */ -/* nx_packet_copy Copy packet data */ -/* nx_packet_release Release processed packets */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_get_server_response(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -NX_PACKET *head_packet_ptr; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; -UINT status; -NX_PACKET *work_ptr; -UINT crlf_found = 0; -NX_PACKET *tmp_ptr; - - - /* Default the return packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Wait for a response from server. */ - status = _nx_web_http_client_receive(client_ptr, &head_packet_ptr, wait_option); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Return an error condition. */ - return(status); - } - - crlf_found = 0; - work_ptr = head_packet_ptr; - - /* Build a pointer to the buffer area. */ - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - - do - { - - /* See if there is a blank line present in the buffer. */ - /* Search the buffer for a cr/lf pair. */ - while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) - { - if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) - { - - /* Found CR. */ - crlf_found++; - } - else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) - { - - /* Found LF. */ - crlf_found++; - } - else - { - - /* Reset the CRLF marker. */ - crlf_found = 0; - } - - if (crlf_found == 4) - { - - /* Yes, we have found the end of the HTTP response header. */ - - /* Set the return packet pointer. */ - *packet_ptr = head_packet_ptr; - - /* Return a successful completion. */ - return(NX_SUCCESS); - } - - /* Move the buffer pointer up. */ - buffer_ptr++; - } - - /* Determine if the packet has already overflowed into another packet. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - - if (work_ptr -> nx_packet_next != NX_NULL) - { - - /* Get the next packet in the chain. */ - work_ptr = work_ptr -> nx_packet_next; - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - } - else -#endif - { - /* Receive another packet from the HTTP server port. */ - status = _nx_web_http_client_receive(client_ptr, &new_packet_ptr, wait_option); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Release the current head packet. */ - nx_packet_release(head_packet_ptr); - - /* Return an error condition. */ - return(status); - } - - /* Successfully received another packet. Its contents now need to be placed in the head packet. */ - tmp_ptr = new_packet_ptr; - -#ifndef NX_DISABLE_PACKET_CHAIN - while (tmp_ptr) - { -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Copy the contents of the current packet into the head packet. */ - status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, - (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), - client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, an error is present. */ - - /* Release both packets. */ - nx_packet_release(head_packet_ptr); - nx_packet_release(new_packet_ptr); - - /* Return an error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - tmp_ptr = tmp_ptr -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Release the new packet. */ - nx_packet_release(new_packet_ptr); - } - - } while (status == NX_SUCCESS); - - /* Release the packet. */ - nx_packet_release(head_packet_ptr); - - return(NX_WEB_HTTP_ERROR); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_response_body_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client get packet call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Destination for packet pointer*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_response_body_get Actual client get packet call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual GET packet routine. */ - status = _nx_web_http_client_response_body_get(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_response_body_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets a data packet associated with the resource */ -/* specified by the previous GET start request. It can be called */ -/* repeatedly to get all of the packets for larger resources. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Destination for packet pointer*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_receive Receive a resource data packet*/ -/* _nx_web_http_client_get_server_response */ -/* Get server response header */ -/* _nx_web_http_client_content_length_get */ -/* Get Content Length value */ -/* _nx_web_http_client_process_header_fields */ -/* Process HTTP header fields */ -/* _nx_web_http_client_error_exit Close HTTP(S) session */ -/* _nx_web_http_client_response_chunked_get */ -/* Get chunked response packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option) -{ - -UINT status = NX_SUCCESS; -UINT length = 0, offset = 0; -NX_PACKET *response_packet_ptr = NX_NULL; -CHAR *buffer_ptr; -UINT i = 0; -UINT status_code = NX_SUCCESS; - - - /* Check if the request packet is sent out. */ - if ((client_ptr -> nx_web_http_client_state < NX_WEB_HTTP_CLIENT_STATE_GET) || - (client_ptr -> nx_web_http_client_state > NX_WEB_HTTP_CLIENT_STATE_DELETE)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Default the return packet to NULL. */ - *packet_pptr = NX_NULL; - - /* Check for a response from the Server. */ - if (!(client_ptr -> nx_web_http_client_response_header_received)) - { - - /* Pickup the response from the Server. */ - status = _nx_web_http_client_get_server_response(client_ptr, &response_packet_ptr, wait_option); - - /* Validate the response packet length. */ - if (status == NX_SUCCESS) - { - if (response_packet_ptr -> nx_packet_append_ptr - response_packet_ptr -> nx_packet_prepend_ptr < 12) - { - status = NX_WEB_HTTP_ERROR; - } - } - - /* Check for error processing received packet. */ - if (status != NX_SUCCESS) - { - - if (status != NX_NO_PACKET) - { - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Reenter the READY state. */ - client_ptr->nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - } - - return(status); - } - - /* Setup pointer to server response. */ - buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine which status code is reveived. */ - for (i = 0; i < _nx_web_http_client_status_maps_size; i++) - { - if ((buffer_ptr[9] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[0]) && - (buffer_ptr[10] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[1]) && - (buffer_ptr[11] == _nx_web_http_client_status_maps[i].nx_web_http_client_status_string[2])) - { - status_code = _nx_web_http_client_status_maps[i].nx_web_http_client_status_code; - break; - } - } - - /* Check the status code. */ - if (i == _nx_web_http_client_status_maps_size) - { - - /* Received an unknown status code. */ - status = NX_WEB_HTTP_REQUEST_UNSUCCESSFUL_CODE; - } - else if (buffer_ptr[9] != '2') - { - - /* Received an error status code. */ - status = status_code; - } - /* Determine if the request was successful. */ - else - { - - /* Pickup the content length if it exists. */ - length = _nx_web_http_client_content_length_get(client_ptr, response_packet_ptr); - - /* Pickup the content offset and process other headers. */ - offset = _nx_web_http_client_process_header_fields(client_ptr, response_packet_ptr); - - /* Determine if the packet is valid. */ - if (!offset || - (response_packet_ptr -> nx_packet_length < offset) || - ((response_packet_ptr -> nx_packet_length > (offset + length)) && - (!client_ptr -> nx_web_http_client_response_chunked))) - { - - /* Bad packet length. */ - status = NX_WEB_HTTP_BAD_PACKET_LENGTH; - } - else - { - - /* Set the flag of response header received. */ - client_ptr -> nx_web_http_client_response_header_received = NX_TRUE; - - /* Store the total number of bytes to receive. - For HEAD request, just process the response header. */ - if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_HEAD) - { - client_ptr -> nx_web_http_client_total_receive_bytes = length; - } - else - { - client_ptr -> nx_web_http_client_total_receive_bytes = 0; - } - client_ptr -> nx_web_http_client_actual_bytes_received = 0; - - /* Adjust the pointers to skip over the response header. */ - response_packet_ptr -> nx_packet_prepend_ptr = response_packet_ptr -> nx_packet_prepend_ptr + offset; - - /* Reduce the length. */ - response_packet_ptr -> nx_packet_length = response_packet_ptr -> nx_packet_length - offset; - - /* Set for processing chunked response. */ - if (client_ptr -> nx_web_http_client_response_chunked) - { - client_ptr -> nx_web_http_client_response_packet = response_packet_ptr; - client_ptr -> nx_web_http_client_chunked_response_remaining_size = response_packet_ptr -> nx_packet_length; - } - } - } - } - else if (!client_ptr -> nx_web_http_client_response_chunked) - { - - /* Pickup the response from the Server. */ - status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, wait_option); - - /* Check for error processing received packet. */ - if (status != NX_SUCCESS) - { - - if (status != NX_NO_PACKET) - { - - /* Clear the flag of response header received. */ - client_ptr->nx_web_http_client_response_header_received = NX_FALSE; - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Reenter the READY state. */ - client_ptr->nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - } - - return(status); - } - - if (response_packet_ptr -> nx_packet_length > (client_ptr -> nx_web_http_client_total_receive_bytes - client_ptr -> nx_web_http_client_actual_bytes_received)) - { - - /* Bad packet length. */ - status = NX_WEB_HTTP_BAD_PACKET_LENGTH; - } - } - - if (status == NX_SUCCESS) - { - if (client_ptr -> nx_web_http_client_response_chunked) - { - - /* Process the chunked response. */ - status = _nx_web_http_client_response_chunked_get(client_ptr, &response_packet_ptr, wait_option); - - if (status == NX_NO_PACKET) - { - return(status); - } - } - else - { - - /* Adjust the actual received bytes. */ - client_ptr -> nx_web_http_client_actual_bytes_received = client_ptr -> nx_web_http_client_actual_bytes_received + - response_packet_ptr -> nx_packet_length; - - /* Determine if the GET packet operation is complete. */ - if (client_ptr -> nx_web_http_client_total_receive_bytes == client_ptr -> nx_web_http_client_actual_bytes_received) - { - - /* Yes, we are finished. */ - status = NX_WEB_HTTP_GET_DONE; - } - } - - /* Move the packet pointer into the return pointer. */ - *packet_pptr = response_packet_ptr; - } - - if (status != NX_SUCCESS) - { - - /* Error, break down the connection and return to the caller. */ - if ((status != NX_WEB_HTTP_GET_DONE) && response_packet_ptr) - { - - /* Release the invalid HTTP packet. */ - nx_packet_release(response_packet_ptr); - } - - if (client_ptr -> nx_web_http_client_response_chunked) - { - - /* If the response is chunked, reset the chunk info. */ - if (status != NX_WEB_HTTP_GET_DONE) - { - - /* If status is NX_WEB_HTTP_GET_DONE, return this packet. */ - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - } - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; - client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; - } - - /* Clear the flag of response header received. */ - client_ptr -> nx_web_http_client_response_header_received = NX_FALSE; - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - if ((status != NX_WEB_HTTP_GET_DONE) || !(client_ptr -> nx_web_http_client_keep_alive)) -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - { - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - } - - /* Reenter the READY state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - } - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_response_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the next data in byte. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* data Returned data */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_receive Receive another packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_response_read(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR *data, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; - - /* If there is no remaining data. */ - while (client_ptr -> nx_web_http_client_chunked_response_remaining_size == 0) - { - - /* Release the previous received packet. */ - if (client_ptr -> nx_web_http_client_response_packet) - { - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - } - - /* Receive another packet. */ - status = _nx_web_http_client_receive(client_ptr, &(client_ptr -> nx_web_http_client_response_packet), wait_option); - if (status) - { - return(status); - } - - /* Update the packet pointer, data pointer and remaining size. */ - (*current_packet_pptr) = client_ptr -> nx_web_http_client_response_packet; - (*current_data_pptr) = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; - client_ptr -> nx_web_http_client_chunked_response_remaining_size = client_ptr -> nx_web_http_client_response_packet -> nx_packet_length; - } - - /* Process the packet chain. */ - if ((*current_data_pptr) == (*current_packet_pptr) -> nx_packet_append_ptr) - { -#ifndef NX_DISABLE_PACKET_CHAIN - if ((*current_packet_pptr) -> nx_packet_next == NX_NULL) - { - return(NX_INVALID_PACKET); - } - - (*current_packet_pptr) = (*current_packet_pptr) -> nx_packet_next; - (*current_data_pptr) = (*current_packet_pptr) -> nx_packet_prepend_ptr; - - /* Release the processed packet in the packet chain. */ - if (client_ptr -> nx_web_http_client_response_packet) - { - client_ptr -> nx_web_http_client_response_packet -> nx_packet_next = NX_NULL; - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - client_ptr -> nx_web_http_client_response_packet = (*current_packet_pptr); - } -#else - return(NX_INVALID_PACKET); -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Set the returned data. */ - *data = *(*current_data_pptr); - - /* Update the data pointer and remaining size. */ - (*current_data_pptr)++; - client_ptr -> nx_web_http_client_chunked_response_remaining_size--; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_response_byte_expect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if next byte is the expected data. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* data Expected data */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Compare result */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_response_read Get next data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_response_byte_expect(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR data, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; -UCHAR tmp; - - /* Get next data. */ - status = _nx_web_http_client_response_read(client_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); - - if (status) - { - return(status); - } - - /* Return the compare result. */ - if (tmp != data) - { - return(NX_NOT_FOUND); - } - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_chunked_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the chunk size of the response packet chunk. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* chunk_size Returned chunk size */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_chunked_size_get Get chunk size */ -/* _nx_web_http_client_response_byte_expect */ -/* Check if next byte is expected*/ -/* nx_packet_release Release packet */ -/* nx_packet_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_chunked_size_get(NX_WEB_HTTP_CLIENT *client_ptr, UINT *chunk_size, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; -UINT size = 0; -UCHAR tmp; -UINT chunk_extension = 0; - - if (client_ptr -> nx_web_http_client_actual_bytes_received < client_ptr -> nx_web_http_client_total_receive_bytes) - { - - /* If there are bytes need to receive, set the size need to receive as chunk size. */ - *chunk_size = client_ptr -> nx_web_http_client_total_receive_bytes - client_ptr -> nx_web_http_client_actual_bytes_received; - } - else - { - - /* Get the chunk size. */ - while (1) - { - - /* Read next byte from request packet. */ - status = _nx_web_http_client_response_read(client_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); - if (status) - { - return(status); - } - - /* Skip the chunk extension. */ - if (chunk_extension && (tmp != '\r')) - { - continue; - } - - /* Calculate the size. */ - if ((tmp >= 'a') && (tmp <= 'f')) - { - size = (size << 4) + 10 + (UINT)(tmp - 'a'); - } - else if ((tmp >= 'A') && (tmp <= 'F')) - { - size = (size << 4) + 10 + (UINT)(tmp - 'A'); - } - else if ((tmp >= '0') && (tmp <= '9')) - { - size = (size << 4) + (UINT)(tmp - '0'); - } - else if (tmp == '\r') - { - - /* Find the end of chunk header. */ - break; - } - else if (tmp == ';') - { - - /* Find chunk extension. */ - chunk_extension = 1; - } - else - { - return(NX_NOT_FOUND); - } - } - - /* Expect '\n'. */ - status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, current_packet_pptr, current_data_pptr); - if (status) - { - return(status); - } - - *chunk_size = size; - } - - /* If there is no remaining data, receive another packet. */ - while (client_ptr -> nx_web_http_client_chunked_response_remaining_size == 0) - { - if (client_ptr -> nx_web_http_client_response_packet) - { - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - } - - status = _nx_web_http_client_receive(client_ptr, &(client_ptr -> nx_web_http_client_response_packet), wait_option); - if (status) - { - return(status); - } - - /* Update the current request packet, data pointer and remaining size. */ - (*current_packet_pptr) = client_ptr -> nx_web_http_client_response_packet; - (*current_data_pptr) = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; - client_ptr -> nx_web_http_client_chunked_response_remaining_size = client_ptr -> nx_web_http_client_response_packet -> nx_packet_length; - } - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_response_chunked_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the chunk data from chunked response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_pptr Pointer to the packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_chunked_size_get Get chunk size */ -/* _nx_web_http_client_response_byte_expect */ -/* Check if next byte is expected*/ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_response_chunked_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option) -{ -UINT status; -UINT chunk_size = 0, length = 0, temp_size = 0; -UINT remaining_size = 0; -NX_PACKET *packet_ptr; -NX_PACKET *current_packet_ptr = NX_NULL; -UCHAR *current_data_ptr = NX_NULL; - - /* Set pointer for processing packet data. */ - current_packet_ptr = client_ptr -> nx_web_http_client_response_packet; - - if (current_packet_ptr) - { - - /* Set current data pointer. */ - current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; - } - - /* Get chunk size. */ - status = _nx_web_http_client_chunked_size_get(client_ptr, &chunk_size, wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - /* Check if it's the end. */ - if (chunk_size == 0) - { - - /* Read CRLF. */ - status = _nx_web_http_client_response_byte_expect(client_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - /* Return an empty packet. */ - client_ptr -> nx_web_http_client_response_packet -> nx_packet_append_ptr = client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr; - client_ptr -> nx_web_http_client_response_packet -> nx_packet_length = 0; - *packet_pptr = client_ptr -> nx_web_http_client_response_packet; - - return(NX_WEB_HTTP_GET_DONE); - } - - /* Set the return packet. */ - *packet_pptr = client_ptr -> nx_web_http_client_response_packet; - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - packet_ptr = *packet_pptr; - packet_ptr -> nx_packet_prepend_ptr = current_data_ptr; - remaining_size = client_ptr -> nx_web_http_client_chunked_response_remaining_size; - - /* Process the chunk data. */ - if (chunk_size <= remaining_size) - { - - /* One or more chunk in the remaining data. */ - temp_size = chunk_size; - - /* Check if the chunk data is all in this packet. */ - while (temp_size > (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr)) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - if (current_packet_ptr -> nx_packet_next == NX_NULL) - { - return(NX_INVALID_PACKET); - } - - temp_size -= (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); - current_packet_ptr = current_packet_ptr -> nx_packet_next; - current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; -#else - return(NX_INVALID_PACKET); -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Skip the chunk data. */ - current_data_ptr += temp_size; - client_ptr -> nx_web_http_client_chunked_response_remaining_size -= chunk_size; - length = chunk_size; - - /* Read CRLF. */ - status = _nx_web_http_client_response_byte_expect(client_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - status = _nx_web_http_client_response_byte_expect(client_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - /* Check the remaining data. */ - if (client_ptr -> nx_web_http_client_chunked_response_remaining_size) - { - if (client_ptr -> nx_web_http_client_response_packet) - { - - /* If received new packet, adjust the prepend pointer of this packet. */ - client_ptr -> nx_web_http_client_response_packet -> nx_packet_prepend_ptr = current_data_ptr; - } - else - { - - /* Copy the remaining data to a new packet. */ - /* Allocate a packet. */ - status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, - &(client_ptr -> nx_web_http_client_response_packet), - 0, wait_option); - if (status) - { - return(status); - } - - /* Copy the remaining data in current packet to the new packet. */ - temp_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); - status = nx_packet_data_append(client_ptr -> nx_web_http_client_response_packet, - current_data_ptr, - temp_size, - client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - if (status) - { - return(status); - } - - /* Check if any remaining data not in current packet. */ - if (client_ptr -> nx_web_http_client_chunked_response_remaining_size > temp_size) - { -#ifndef NX_DISABLE_PACKET_CHAIN - - /* If there are chained packets, append the packets to the new packet. */ - if (current_packet_ptr -> nx_packet_next) - { - client_ptr -> nx_web_http_client_response_packet -> nx_packet_next = current_packet_ptr -> nx_packet_next; - client_ptr -> nx_web_http_client_response_packet -> nx_packet_last = current_packet_ptr -> nx_packet_last; - current_packet_ptr -> nx_packet_next = NX_NULL; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - { - return(NX_INVALID_PACKET); - } - } - } - - /* Update the packet length. */ - client_ptr -> nx_web_http_client_response_packet -> nx_packet_length = client_ptr -> nx_web_http_client_chunked_response_remaining_size; - } - } - else - { - - /* All the remaining data is in this chunk. */ - client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; - length = remaining_size; - } - - /* Set the received bytes. */ - client_ptr -> nx_web_http_client_total_receive_bytes = chunk_size; - client_ptr -> nx_web_http_client_actual_bytes_received = length; - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Set length of the packet chain header. */ - (*packet_pptr) -> nx_packet_length = length; - - /* Find the last packet. */ - while (packet_ptr -> nx_packet_next && - (length > (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr))) - { - length -= (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); - packet_ptr = packet_ptr -> nx_packet_next; - } - - /* Set the last packet. */ - (*packet_pptr) -> nx_packet_last = packet_ptr; - - /* Maybe the '\r\n' is in another packet, release this packet. */ - if (packet_ptr -> nx_packet_next) - { - nx_packet_release(packet_ptr -> nx_packet_next); - packet_ptr -> nx_packet_next = NX_NULL; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set packet length and append pointer. */ - /* If the packet is chained, set the length and append pointer of the last packet. */ - packet_ptr -> nx_packet_length = length; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + length; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_chunked_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP request chunked set */ -/* API call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* chunk_size Size of the chunk */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_chunked_set */ -/* Actual request chunked set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr) -{ -UINT status; - - /* Make sure the client instance makes sense. */ - if ((client_ptr == NX_NULL) || (packet_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Call actual request chunked set function. */ - status = _nx_web_http_client_request_chunked_set(client_ptr, chunk_size, packet_ptr); - - /* Return success to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_chunked_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the chunked information of chunked request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* chunk_size Size of the chunk */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append the packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr) -{ -UINT status; -UINT temp_size, i, j; -CHAR temp_string[10]; -CHAR crlf[2] = {13,10}; - - /* Covert the size to ASCII. */ - temp_size = chunk_size; - i = 0; - - while (temp_size) - { - - for (j = i; j > 0; j--) - { - temp_string[j] = temp_string[j - 1]; - } - - if ((temp_size & 0x0F) < 10) - { - temp_string[0] = (CHAR)((temp_size & 0x0F) + '0'); - } - else - { - temp_string[0] = (CHAR)((temp_size & 0x0F) - 10 + 'a'); - } - temp_size = temp_size >> 4; - i++; - } - - if (i == 0) - { - temp_string[i++] = '0'; - } - - /* Place the chunk size in the packet. */ - status = nx_packet_data_append(packet_ptr, temp_string, i, client_ptr -> nx_web_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - if (status) - { - return(status); - } - - /* Place the CRLF to signal the end of the chunk size. */ - status = nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, NX_WAIT_FOREVER); - if (status) - { - return(status); - } - - /* Set the request chunked flag. */ - client_ptr -> nx_web_http_client_request_chunked = NX_TRUE; - - /* The total bytes need to transfer is chunk size plus chunk header length. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = chunk_size + i + 2; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP request packet send */ -/* API call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to the packet */ -/* more_data If there are more data to send*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_packet_send */ -/* Actual request packet send */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option) -{ -UINT status; - - /* Make sure the client instance makes sense. */ - if ((client_ptr == NX_NULL) || (packet_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Now send the packet to the HTTP server. */ - status = _nx_web_http_client_request_packet_send(client_ptr, packet_ptr, more_data, wait_option); - - /* Return success to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends an HTTP request packet to a remote server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to the packet */ -/* more_data If there are more data to send*/ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_send Send data to server */ -/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option) -{ -UINT status; -CHAR crlf[2] = {13,10}; -UINT length = packet_ptr -> nx_packet_length; - - /* Check the packet length. */ - if (client_ptr -> nx_web_http_client_total_transfer_bytes < (client_ptr -> nx_web_http_client_actual_bytes_transferred + length)) - { - return(NX_INVALID_PACKET); - } - - /* If the request is chunked, add CRLF at the end of the chunk. */ - if (client_ptr -> nx_web_http_client_request_chunked) - { - - if (client_ptr -> nx_web_http_client_total_transfer_bytes == (client_ptr -> nx_web_http_client_actual_bytes_transferred + length)) - { - - /* Place an extra CRLF to signal the end of the chunk. */ - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - - /* If there are no more data to send, append the last chunk. */ - if (!more_data) - { - nx_packet_data_append(packet_ptr, "0\r\n\r\n", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - client_ptr -> nx_web_http_client_request_chunked = NX_FALSE; - } - } - } - - /* Now send the packet to the HTTP server. */ - status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - /* Update the transferred bytes. */ - client_ptr -> nx_web_http_client_actual_bytes_transferred += length; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_start Actual client put start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_web_http_client_put_start(client_ptr, server_ip, server_port, resource, host, - username, password, total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_put_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_start_extended */ -/* Actual client put start call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_put_start_extended(client_ptr, server_ip, server_port, resource, - temp_resource_length, host, temp_host_length, username, - temp_username_length, password, temp_password_length, - total_bytes, wait_option)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Duo Client put start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_start_extended */ -/* Actual client put start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_web_http_client_put_start_extended(client_ptr, server_ip, server_port, resource, - resource_length, host, host_length, username, - username_length, password, password_length, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_put_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to remote server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize PUT request */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option) -{ -UINT status; - - /* Set the port we are connecting to. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_PUT, - resource, - resource_length, - host, - host_length, - total_bytes, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Add approproate headers from input data. */ - _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - /* Enter the PUT state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; - - - return(status); -} - - -#ifdef NX_WEB_HTTPS_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_put_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure PUT request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to PUT */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_client_put_secure_start Actual PUT request processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_web_http_client_put_secure_start(client_ptr, server_ip, server_port, resource, - host, username, password, - total_bytes, tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_put_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. This version of the function also requires */ -/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to PUT */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_secure_start_extended */ -/* Actual PUT request processing */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_put_secure_start_extended(client_ptr, server_ip, server_port, - resource, temp_resource_length, host, - temp_host_length, username, - temp_username_length, password, - temp_password_length, total_bytes, - tls_setup, wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_put_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure PUT request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total number of bytes to PUT */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_secure_start_extended */ -/* Actual PUT request processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_web_http_client_put_secure_start_extended(client_ptr, server_ip, server_port, - resource, resource_length, host, - host_length, username, username_length, - password, password_length, total_bytes, - tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_put_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application PUT request. Transferring the*/ -/* specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. This version of the function also requires */ -/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total number of bytes to PUT */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_secure_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_error_exit Shutdown HTTPS session */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - - /* Use default HTTPS port. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_PUT, - resource, - resource_length, - host, - host_length, - total_bytes, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Add approproate headers from input data. */ - _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - /* Enter the PUT state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; - - return(status); -} - -#endif /* NX_WEB_HTTPS_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_post_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Client POST start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to POST */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_post_start Actual client post start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual PUT start routine. */ - status = _nx_web_http_client_post_start(client_ptr, server_ip, server_port, resource, host, - username, password, total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_post_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application POST request. Transferring */ -/* the specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to POST */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_post_start_extended */ -/* Actual client put start call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_post_start_extended(client_ptr, server_ip, server_port, resource, - temp_resource_length, host, temp_host_length, username, - temp_username_length, password, temp_password_length, - total_bytes, wait_option)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_post_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP Client POST start */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total number of bytes to POST */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_post_start_extended */ -/* Actual client post start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for invalid total bytes. */ - if (total_bytes == 0) - return(NX_SIZE_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual POST start routine. */ - status = _nx_web_http_client_post_start_extended(client_ptr, server_ip, server_port, resource, - resource_length, host, host_length, username, - username_length, password, password_length, - total_bytes, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_post_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application POST request. Transferring */ -/* the specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total bytes to send */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to remote server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize PUT request */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option) -{ -UINT status; - - - /* Set the port we are connecting to. */ - client_ptr -> nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr -> nx_web_http_client_connect_port, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_POST, - resource, - resource_length, - host, - host_length, - total_bytes, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Add approproate headers from input data. */ - _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - /* Enter the POST state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; - - - return(status); -} - - -#ifdef NX_WEB_HTTPS_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_post_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure POST request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to POST */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_client_post_secure_start */ -/* Actual POST processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual POST start routine. */ - status = _nx_web_http_client_post_secure_start(client_ptr, server_ip, server_port, resource, host, - username, password, total_bytes, tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_post_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application POST request. Transferring */ -/* the specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. This version of the function also requires */ -/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* server_port HTTP Server TCP port */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* total_bytes Total number of bytes to POST */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_post_secure_start_extended */ -/* Actual POST request processing*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_post_secure_start_extended(client_ptr, server_ip, server_port, - resource, temp_resource_length, host, - temp_host_length, username, - temp_username_length, password, - temp_password_length, total_bytes, - tls_setup, wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_post_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure POST request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total number of bytes to POST */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_post_secure_start_extended */ -/* Actual POST request processing*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual POST start routine. */ - status = _nx_web_http_client_post_secure_start_extended(client_ptr, server_ip, server_port, - resource, resource_length, host, - host_length, username, username_length, - password, password_length, total_bytes, - tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_post_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application POST request. Transferring */ -/* the specified resource (URL) is started by this routine. The */ -/* application must call put packet one or more times to transfer */ -/* the resource contents. This version of the function also requires */ -/* a TLS setup callback as the data is sent over TLS-secured HTTPS. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* total_bytes Total number of bytes to POST */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_secure_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* _nx_web_http_client_error_exit Close HTTPS session */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - - /* Use default HTTPS port. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_POST, - resource, - resource_length, - host, - host_length, - total_bytes, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Add approproate headers from input data. */ - _nx_web_http_client_content_type_header_add(client_ptr, resource, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = total_bytes; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - /* Enter the POST state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; - - return(status); -} - -#endif /* NX_WEB_HTTPS_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_head_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to start a HEAD request.*/ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_start Actual HEAD request call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, CHAR *host, CHAR *username, CHAR *password, - ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual HEAD start routine. */ - status = _nx_web_http_client_head_start(client_ptr, server_ip, server_port, resource, - host, username, password, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_head_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application HEAD request. HEAD is */ -/* identical to GET for the HTTP client, so the server response is */ -/* processed by calling nx_web_http_client_response_body_get. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_start_extended */ -/* Actual HEAD request call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_head_start_extended(client_ptr, server_ip, server_port, resource, - temp_resource_length, host, temp_host_length, username, - temp_username_length, password, temp_password_length, - wait_option)); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_head_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to start a HEAD request.*/ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_start_extended */ -/* Actual HEAD request call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual HEAD start routine. */ - status = _nx_web_http_client_head_start_extended(client_ptr, server_ip, server_port, resource, - resource_length, host, host_length, username, - username_length, password, password_length, - wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_head_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application HEAD request. HEAD is */ -/* identical to GET for the HTTP client, so the server response is */ -/* processed by calling nx_web_http_client_response_body_get. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to remote server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HEAD request */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ -UINT status; - - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_HEAD, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the HEAD state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; - - return(status); -} - -#ifdef NX_WEB_HTTPS_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_head_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure HEAD request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_secure_start */ -/* Actual HEAD request processing*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual HEAD start routine. */ - status = _nx_web_http_client_head_secure_start(client_ptr, server_ip, server_port, resource, - host, username, password, tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_head_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application HEAD request. The HTTP */ -/* header for the specified resource (URL) is requested from the HTTP */ -/* Server at the specified IP address and port. This version of the */ -/* function also requires a TLS setup callback as the request is sent */ -/* over TLS-secured HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_secure_start_extended */ -/* Actual HEAD request processing*/ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_head_secure_start_extended(client_ptr, server_ip, server_port, - resource, temp_resource_length, host, - temp_host_length, username, - temp_username_length, password, - temp_password_length, tls_setup, - wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_head_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure HEAD request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_head_secure_start_extended */ -/* Actual HEAD request processing*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual HEAD start routine. */ - status = _nx_web_http_client_head_secure_start_extended(client_ptr, server_ip, server_port, - resource, resource_length, host, - host_length, username, username_length, - password, password_length, - tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_head_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application HEAD request. The HTTP */ -/* header for the specified resource (URL) is requested from the HTTP */ -/* Server at the specified IP address and port. This version of the */ -/* function also requires a TLS setup callback as the request is sent */ -/* over TLS-secured HTTPS. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_secure_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ - -UINT status; - - /* Use default HTTPS port. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_HEAD, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the HEAD state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; - - return(status); -} - -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_delete_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to start a DELETE */ -/* request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_start Actual DELETE request call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, CHAR *host, CHAR *username, CHAR *password, - ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DELETE start routine. */ - status = _nx_web_http_client_delete_start(client_ptr, server_ip, server_port, resource, - host, username, password, wait_option); - - /* Return completion status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_delete_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application DELETE request. DELETE only */ -/* receives a simple response which can be processed with */ -/* nx_web_http_client_response_body_get. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_start_extended */ -/* Actual DELETE request call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_delete_start_extended(client_ptr, server_ip, server_port, resource, - temp_resource_length, host, temp_host_length, username, - temp_username_length, password, temp_password_length, - wait_option)); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_delete_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to start a DELETE */ -/* request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_start Actual DELETE request call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ - -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || (host == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DELETE start routine. */ - status = _nx_web_http_client_delete_start_extended(client_ptr, server_ip, server_port, resource, - resource_length, host, host_length, username, - username_length, password, password_length, - wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_delete_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application DELETE request. DELETE only */ -/* receives a simple response which can be processed with */ -/* nx_web_http_client_response_body_get. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to remote server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize DELETE request */ -/* _nx_web_http_client_content_type_header_add */ -/* Add content type header */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* _nx_web_http_client_error_exit Shutdown HTTP(S) connection */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option) -{ - -UINT status; - - client_ptr -> nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, client_ptr -> nx_web_http_client_connect_port, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_DELETE, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the DELETE state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; - - return(status); -} - -#ifdef NX_WEB_HTTPS_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_delete_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure DELETE request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_secure_start */ -/* Actual DELETE request call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DELETE start routine. */ - status = _nx_web_http_client_delete_secure_start(client_ptr, server_ip, server_port, resource, - host, username, password, tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_delete_secure_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application DELETE request. DELETE only */ -/* receives a simple response which can be processed with */ -/* nx_web_http_client_response_body_get. This version of the function */ -/* also requires a TLS setup callback as the request is sent over */ -/* TLS-secured HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip HTTP Server IP address */ -/* resource Pointer to resource (URL) */ -/* host Pointer to Host */ -/* username Pointer to username */ -/* password Pointer to password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_secure_start_extended */ -/* Actual DELETE processing */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_delete_secure_start_extended(client_ptr, server_ip, server_port, - resource, temp_resource_length, host, - temp_host_length, username, - temp_username_length, password, - temp_password_length, tls_setup, - wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_delete_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS secure DELETE request */ -/* processing call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_delete_secure_start_extended */ -/* Actual DELETE processing */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (resource == NX_NULL) || !server_ip || !tls_setup || (host == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual DELETE start routine. */ - status = _nx_web_http_client_delete_secure_start_extended(client_ptr, server_ip, server_port, - resource, resource_length, host, - host_length, username, username_length, - password, password_length, - tls_setup, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_delete_secure_start_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes an application DELETE request. DELETE only */ -/* receives a simple response which can be processed with */ -/* nx_web_http_client_response_body_get. This version of the function */ -/* also requires a TLS setup callback as the request is sent over */ -/* TLS-secured HTTPS. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip IP duo address of HTTP Server */ -/* resource Pointer to resource (URL) */ -/* resource_length String length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* username Pointer to username */ -/* username_length Length of username */ -/* password Pointer to password */ -/* password_length Length of password */ -/* tls_setup TLS setup callback function */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_secure_connect Connect to HTTPS server */ -/* _nx_web_http_client_request_initialize_extended */ -/* Initialize HTTP request */ -/* _nx_web_http_client_request_send Send HTTP request to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, - UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ - -UINT status; - - /* Use default HTTPS port. */ - client_ptr->nx_web_http_client_connect_port = server_port; - - /* Connect to the server. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, client_ptr->nx_web_http_client_connect_port, tls_setup, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Initialize HTTP request. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, - NX_WEB_HTTP_METHOD_DELETE, - resource, - resource_length, - host, - host_length, - 0, - NX_FALSE, /* If true, input_size is ignored. */ - username, - username_length, - password, - password_length, - wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Send the HTTP request we just built. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Check status. */ - if (status != NX_SUCCESS) - { - return(status); - } - - /* Enter the DELETE state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; - - return(status); -} - -#endif - - - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_put_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP client put packet call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Resource data packet pointer */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_put_packet Actual client put packet call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; -NXD_ADDRESS *server_ip; -UINT header_size; - - - /* Check for invalid input pointers. */ - if ((client_ptr == NX_NULL) || (client_ptr -> nx_web_http_client_id != NX_WEB_HTTP_CLIENT_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Get worker variables for use. */ - server_ip = &(client_ptr -> nx_web_http_client_server_address); - -#ifndef NX_DISABLE_IPV4 - if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) - { - header_size = NX_IPv4_TCP_PACKET; - } - else -#endif /* !NX_DISABLE_IPV4 */ - -#ifdef FEATURE_NX_IPV6 - if (server_ip -> nxd_ip_version == NX_IP_VERSION_V6) - { - header_size = NX_IPv6_TCP_PACKET; - } - else -#endif /* FEATURE_NX_IPV6 */ - { - return(NX_NOT_CONNECTED); - } - - /* Ensure there is enough room for the TCP packet header. */ - if ((UINT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < header_size) - { - - /* Return an invalid packet error. */ - return(NX_INVALID_PACKET); - } - - /* Call actual PUT data routine. */ - status = _nx_web_http_client_put_packet(client_ptr, packet_ptr, wait_option); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_put_packet PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes a packet of resource data associated with */ -/* the previous PUT request. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Resource data packet pointer */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_receive Check for server response */ -/* nx_packet_release Release the packet */ -/* _nx_web_http_client_error_exit Shutdown connection */ -/* _nx_web_http_client_send Send data to server */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -NX_PACKET *response_packet_ptr; -CHAR *buffer_ptr; -UINT length; -UINT status; - - - /* First, check and see if the client instance is still in the PUT state. */ - if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_PUT && - client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_POST) - { - - /* Client not ready, return error. */ - return(NX_WEB_HTTP_NOT_READY); - } - - /* Next, check and see if there is a response from the Server. */ - status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, NX_NO_WAIT); - - /* Check for an early response from the Server. */ - if (status == NX_SUCCESS) - { - - /* This is an error condition since the Server should not respond until the PUT is complete. */ - - /* Setup pointer to server response. */ - buffer_ptr = (CHAR *) response_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if it is an authentication error. */ - if (((buffer_ptr + 11) < (CHAR *)response_packet_ptr -> nx_packet_append_ptr) && - (buffer_ptr[9] == '4') && (buffer_ptr[10] == '0') && (buffer_ptr[11] == '1')) - { - - /* Inform caller of an authentication error. */ - status = NX_WEB_HTTP_AUTHENTICATION_ERROR; - } - else - { - - /* Inform caller of general Server failure. */ - status = NX_WEB_HTTP_INCOMPLETE_PUT_ERROR; - } - - /* Release the packet. */ - nx_packet_release(response_packet_ptr); - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return to the READY state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - - /* Return error to caller. */ - return(status); - } - - /* Otherwise, determine if the packet length fits in the available bytes to send. */ - if (packet_ptr -> nx_packet_length > - (client_ptr -> nx_web_http_client_total_transfer_bytes - client_ptr -> nx_web_http_client_actual_bytes_transferred)) - { - - /* Request doesn't fit into the remaining transfer window. */ - return(NX_WEB_HTTP_BAD_PACKET_LENGTH); - } - - /* Remember the packet length. */ - length = packet_ptr -> nx_packet_length; - - /* Now send the packet out. */ - status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return to the READY state. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; - - /* Return an error. */ - return(status); - } - - /* Otherwise, update the actual bytes transferred. */ - client_ptr -> nx_web_http_client_actual_bytes_transferred = client_ptr -> nx_web_http_client_actual_bytes_transferred + length; - - /* Return status to caller. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_put_start Start the PUT process */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_type_get(CHAR *name, CHAR *http_type_string) -{ - -UINT i; - - - /* First find the end of the string. */ - i = 0; - while (name[i] != (CHAR) NX_NULL) - { - i++; - } - - /* Now look backwards to find the last period that signals the - file extension. */ - while ((i) && (name[i] != '.')) - { - i--; - } - - /* Position forward again, past the period. */ - i++; - - /* Now see what HTTP file type to return. */ - - /* Check for .txt file extension. */ - if (((name[i] == 't') || (name[i] == 'T')) && - ((name[i+1] == 'x') || (name[i+1] == 'X')) && - ((name[i+2] == 't') || (name[i+2] == 'T'))) - { - - /* Yes, we have a plain text file. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'p'; - http_type_string[6] = 'l'; - http_type_string[7] = 'a'; - http_type_string[8] = 'i'; - http_type_string[9] = 'n'; - - /* Return the size of the HTTP ASCII type string. */ - return(10); - } - - /* Check for .htm[l] file extension. */ - else if (((name[i] == 'h') || (name[i] == 'H')) && - ((name[i+1] == 't') || (name[i+1] == 'T')) && - ((name[i+2] == 'm') || (name[i+2] == 'M'))) - { - - /* Yes, we have an HTML text file. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'h'; - http_type_string[6] = 't'; - http_type_string[7] = 'm'; - http_type_string[8] = 'l'; - - /* Return the size of the HTTP ASCII type string. */ - return(9); - } - - /* Check for .gif file extension. */ - else if (((name[i] == 'g') || (name[i] == 'G')) && - ((name[i+1] == 'i') || (name[i+1] == 'I')) && - ((name[i+2] == 'f') || (name[i+2] == 'F'))) - { - - /* Yes, we have a GIF image file. */ - http_type_string[0] = 'i'; - http_type_string[1] = 'm'; - http_type_string[2] = 'a'; - http_type_string[3] = 'g'; - http_type_string[4] = 'e'; - http_type_string[5] = '/'; - http_type_string[6] = 'g'; - http_type_string[7] = 'i'; - http_type_string[8] = 'f'; - - /* Return the size of the HTTP ASCII type string. */ - return(9); - } - - /* Check for .xbm file extension. */ - else if (((name[i] == 'x') || (name[i] == 'X')) && - ((name[i+1] == 'b') || (name[i+1] == 'B')) && - ((name[i+2] == 'm') || (name[i+2] == 'M'))) - { - - /* Yes, we have a x-xbitmap image file. */ - http_type_string[0] = 'i'; - http_type_string[1] = 'm'; - http_type_string[2] = 'a'; - http_type_string[3] = 'g'; - http_type_string[4] = 'e'; - http_type_string[5] = '/'; - http_type_string[6] = 'x'; - http_type_string[7] = '-'; - http_type_string[8] = 'x'; - http_type_string[9] = 'b'; - http_type_string[10] = 'i'; - http_type_string[11] = 't'; - http_type_string[12] = 'm'; - http_type_string[13] = 'a'; - http_type_string[14] = 'p'; - - /* Return the size of the HTTP ASCII type string. */ - return(15); - } - - /* Default to plain text. */ - else - { - - /* Default to plain text. */ - http_type_string[0] = 't'; - http_type_string[1] = 'e'; - http_type_string[2] = 'x'; - http_type_string[3] = 't'; - http_type_string[4] = '/'; - http_type_string[5] = 'p'; - http_type_string[6] = 'l'; - http_type_string[7] = 'a'; - http_type_string[8] = 'i'; - http_type_string[9] = 'n'; - - /* Return the size of the HTTP ASCII type string. */ - return(10); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the content length of the supplied HTTP */ -/* response packet. If the packet is no content or the packet is */ -/* invalid, a zero is returned. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* */ -/* OUTPUT */ -/* */ -/* client_ptr HTTP client control block */ -/* length Length of content */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_get_start Start the GET operation */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_content_length_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ - -UINT length; -CHAR *buffer_ptr; -UINT found = NX_FALSE; - - - NX_PARAMETER_NOT_USED(client_ptr); - - /* Default the content length to an invalid value. */ - length = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *)packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Content-length:" token first. */ - while ((buffer_ptr+14) < (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - - /* Check for the Content-length token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && - ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && - ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && - ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && - (*(buffer_ptr+7) == '-') && - ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && - ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && - ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && - ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && - ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && - ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && - (*(buffer_ptr+14) == ':')) - { - - /* Yes, found content-length token. */ - found = NX_TRUE; - - /* Move past the Content-Length: field. Exit the loop. */ - buffer_ptr += 15; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Check if found the content-length token. */ - if (found != NX_TRUE) - { - - /* No, return an invalid length indicating a bad HTTP packet. */ - return(length); - } - - /* Now skip over white space. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - buffer_ptr++; - } - - /* Now convert the length into a numeric value. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - { - - /* Update the content length. */ - length = length * 10; - length = length + (((UINT) (*buffer_ptr)) - 0x30); - - /* Move the buffer pointer forward. */ - buffer_ptr++; - } - - /* Determine if the content length was picked up properly. */ - if ((buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || - ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR)13))) - { - - /* Error, set the length to zero. */ - length = 0; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_memicmp PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares two pieces of memory case insensitive. */ -/* */ -/* INPUT */ -/* */ -/* src Pointer to source */ -/* src_length Length of source */ -/* dest Pointer to destination */ -/* dest_length Length of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_process_header_fields */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) -{ -UCHAR ch; - - /* Compare the length. */ - if(src_length != dest_length) - return NX_WEB_HTTP_FAILED; - - while(src_length) - { - - /* Is src lowercase? */ - if((*src >= 'a') && (*src <= 'z')) - ch = (UCHAR)(*src - 'a' + 'A'); - - /* Is src uppercase? */ - else if((*src >= 'A') && (*src <= 'Z')) - ch = (UCHAR)(*src - 'A' + 'a'); - else - ch = *src; - - /* Compare case insensitive. */ - if((*src != *dest) && (ch != *dest)) - return NX_WEB_HTTP_FAILED; - - /* Pickup next character. */ - src_length--; - src++; - dest++; - } - - return NX_SUCCESS; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_process_header_fields PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the HTTP headers received from the remote */ -/* server. It also calculates the byte offset to the start of the */ -/* HTTP response content area. This area immediately follows the HTTP */ -/* response header (which ends with a blank line). */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to request packet */ -/* */ -/* OUTPUT */ -/* */ -/* Byte Offset (0 implies no content) */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_memicmp Compile two strings */ -/* [nx_web_http_client_response_callback] */ -/* Application header callback */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_get_start Start GET processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_process_header_fields(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr) -{ - -UINT offset; -CHAR *buffer_ptr; -CHAR *field_name; -UINT field_name_length; -CHAR *field_value; -UINT field_value_length; -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE -UINT version = 0; -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - - /* Default the content offset to zero. */ - offset = 0; - client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - if ((buffer_ptr + 7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) - { - version = (UCHAR)((buffer_ptr[5] - '0') << 4) | (UCHAR)(buffer_ptr[7] - '0'); - } - - /* Is a valid HTTP version found? */ - if(version == 0) - { - client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; - return 0; - } - - /* Initialize the keepalive flag. */ - if(version > 0x10) - client_ptr -> nx_web_http_client_keep_alive = NX_TRUE; - else - client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* Skip over the first HTTP line (e.g. HTTP/1.1 200 OK). */ - while(((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13) && (*(buffer_ptr + 1) != (CHAR) 10)) - { - buffer_ptr++; - offset++; - } - - /* Skip over the CR,LF. */ - buffer_ptr += 2; - offset += 2; - - /* Loop until we find the "cr,lf,cr,lf" token. */ - while (((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the token. This signals a blank line, which also - specifies the start of the content. */ - if ((*buffer_ptr == (CHAR) 13) && - (*(buffer_ptr+1) == (CHAR) 10)) - { - - /* Adjust the offset. */ - offset = offset + 2; - break; - } - - - /* We haven't seen the so we are still processing header data. - * Extract the field name and it's value. - */ - field_name = buffer_ptr; - field_name_length = 0; - - /* Look for the ':' that separates the field name from its value. */ - while(*buffer_ptr != ':') - { - buffer_ptr++; - field_name_length++; - } - offset += field_name_length; - - /* Skip ':'. */ - buffer_ptr++; - offset++; - - /* Now skip over white space. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - buffer_ptr++; - offset++; - } - - /* Now get the field value. */ - field_value = buffer_ptr; - field_value_length = 0; - - /* Loop until we see a . */ - while(((buffer_ptr+1) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13) && (*(buffer_ptr+1) != (CHAR) 10)) - { - buffer_ptr++; - field_value_length++; - } - offset += field_value_length; - - /* Skip over the CR,LF. */ - buffer_ptr += 2; - offset += 2; - - /* Check if the response packet is chunked. */ - if (_nx_web_http_client_memicmp((UCHAR *)field_name, field_name_length, (UCHAR *)"Transfer-Encoding", 17) == 0) - { - if (_nx_web_http_client_memicmp((UCHAR *)field_value, field_value_length, (UCHAR *)"chunked", 7) == 0) - { - client_ptr -> nx_web_http_client_response_chunked = NX_TRUE; - } - } - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - - /* If the "connection" field exist, and the value is "keep-alive", set the keep-alive flag to TRUE. */ - if (_nx_web_http_client_memicmp((UCHAR *)"connection", 10, (UCHAR *)field_name, field_name_length) == NX_SUCCESS) - { - if (_nx_web_http_client_memicmp((UCHAR *)"keep-alive", 10, (UCHAR *)field_value, field_value_length) == NX_SUCCESS) - { - client_ptr -> nx_web_http_client_keep_alive = NX_TRUE; - } - else if (_nx_web_http_client_memicmp((UCHAR *)"close", 5, (UCHAR *)field_value, field_value_length) == NX_SUCCESS) - { - client_ptr -> nx_web_http_client_keep_alive = NX_FALSE; - } - } -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* Invoke the header callback if present. */ - /* If it was set, invoke the application response callback. */ - if(client_ptr -> nx_web_http_client_response_callback) - { - client_ptr -> nx_web_http_client_response_callback(client_ptr, field_name, field_name_length, field_value, field_value_length); - } - } - - /* Not find the "cr,lf,cr,lf" token. */ - if (((buffer_ptr+1) >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr == (CHAR) 0)) - { - offset = 0; - } - - /* Return the offset to the caller. */ - return(offset); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* string Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_get_start Start GET processing */ -/* _nx_web_http_client_put_start Start PUT processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_number_convert(UINT number, CHAR *string) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Default string to return '0'. */ - string[0] = '0'; - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while ((size < 10) && (number)) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string[j] = string[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - string[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - } - - /* Make the string NULL terminated. */ - string[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_base64_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the input string into a base64 */ -/* representation. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* length Length of name */ -/* base64name Encoded base64 name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_get_start Start GET processing */ -/* _nx_web_http_client_put_start Start PUT processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name) -{ - -UINT pad; -UINT i, j; -UINT step; - - - /* Adjust the length to represent the base64 name. */ - length = ((length * 8) / 6); - - /* Default padding to none. */ - pad = 0; - - /* Determine if an extra conversion is needed. */ - if ((length * 6) % 24) - { - - /* Some padding is needed. */ - - /* Calculate the number of pad characters. */ - pad = (length * 6) % 24; - pad = (24 - pad) / 6; - pad = pad - 1; - - /* Adjust the length to pickup the character fraction. */ - length++; - } - - /* Setup index into the base64name. */ - j = 0; - - /* Compute the base64name. */ - step = 0; - i = 0; - while (j < length) - { - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first 6 bits of name character for index. */ - base64name[j++] = _nx_web_http_client_base64_array[((UINT) name[i]) >> 2]; - step++; - } - else if (step == 1) - { - - /* Use last 2 bits of name character and first 4 bits of next name character for index. */ - base64name[j++] = _nx_web_http_client_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; - i++; - step++; - } - else if (step == 2) - { - - /* Use last 4 bits of name character and first 2 bits of next name character for index. */ - base64name[j++] = _nx_web_http_client_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; - i++; - step++; - } - else /* Step 3 */ - { - - /* Use last 6 bits of name character for index. */ - base64name[j++] = _nx_web_http_client_base64_array[(((UINT) name[i]) & 0x3F)]; - i++; - step = 0; - } - } - - /* Determine if the index needs to be advanced. */ - if (step != 3) - i++; - - /* Now add the PAD characters. */ - while ((pad--) && (j < NX_WEB_HTTP_MAX_STRING)) - { - - /* Pad base64name with '=' characters. */ - base64name[j++] = '='; - } - - /* Put a NULL character in. */ - base64name[j] = NX_NULL; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_https_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to connect the HTTP */ -/* client to a remote HTTP server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip Address of remote server */ -/* server_port HTTPS port on remote server */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Actual HTTP connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option) - -{ -UINT status; - - /* Check pointers. */ - if(client_ptr == NX_NULL || server_ip == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call actual function. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, server_port, wait_option); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_https_client_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a HTTP client on the specified IP. The TCP */ -/* socket is left open following this call, allowing multiple */ -/* operations (e.g. GET, PUT, etc.) on this client instance before */ -/* closing the HTTP connection. */ -/* */ -/* Note that multiple operations implies that the HTTP keepalive */ -/* header is present and supported by the remote host. Performing a */ -/* single operation and then disconnecting the socket is equivalent to */ -/* a standard non-keepalive HTTP session. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip Address of remote server */ -/* server_port HTTPS port on remote server */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_cleanup Rest the state */ -/* nx_tcp_client_socket_bind Bind TCP client socket */ -/* nxd_tcp_client_socket_connect Connect to remote server */ -/* nx_tcp_client_socket_unbind Unbind socket on error */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option) - -{ - -UINT status; - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - - /* If keep-alive is true, the client is already connected to the server. */ - if (client_ptr -> nx_web_http_client_keep_alive) - { - - /* Clean up and reset the state. */ - _nx_web_http_client_cleanup(client_ptr); - - if (nx_tcp_socket_state_wait(&(client_ptr -> nx_web_http_client_socket), NX_TCP_ESTABLISHED, 0) == NX_SUCCESS) - { - - /* No need to reconnect. */ - return(NX_SUCCESS); - } - else - { - - /* Server disconnected the connection, need to reconnect. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - } - } -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* Determine if the client is in a ready state. */ - if (client_ptr -> nx_web_http_client_state != NX_WEB_HTTP_CLIENT_STATE_READY) - { - - /* Reset the state. */ - _nx_web_http_client_cleanup(client_ptr); - } - - /* Attempt to bind the client socket. */ - status = nx_tcp_client_socket_bind(&(client_ptr -> nx_web_http_client_socket), NX_ANY_PORT, wait_option); - - /* Check status of the bind. */ - if (status != NX_SUCCESS) - { - - /* Error binding to a port, return to caller. */ - return(status); - } - - client_ptr -> nx_web_http_client_connect_port = server_port; - - /* Connect to the HTTPS server with TCP. */ - status = nxd_tcp_client_socket_connect(&(client_ptr -> nx_web_http_client_socket), server_ip, - client_ptr -> nx_web_http_client_connect_port, wait_option); - - /* Check for connection status. */ - if (status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); - return(status); - } - - /* At this point, the TCP socket to the remote HTTP server is connected. */ -#ifdef FEATURE_NX_IPV6 - COPY_NXD_ADDRESS(server_ip, &(client_ptr -> nx_web_http_client_server_address)); -#else - client_ptr -> nx_web_http_client_server_address.nxd_ip_version = NX_IP_VERSION_V4; - client_ptr -> nx_web_http_client_server_address.nxd_ip_address.v4 = server_ip -> nxd_ip_address.v4; -#endif - - return(NX_SUCCESS); -} - -#ifdef NX_WEB_HTTPS_ENABLE - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_https_client_secure_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the secure HTTPS connect call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip Address of remote server */ -/* server_port HTTPS port on remote server */ -/* tls_setup User-supplied callback */ -/* function to set up TLS */ -/* parameters. */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_https_client_secure_connect Actual secure connect call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - - - /* Check pointers. */ - if(client_ptr == NX_NULL || server_ip == NX_NULL || tls_setup == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call actual function. */ - status = _nx_web_http_client_secure_connect(client_ptr, server_ip, server_port, tls_setup, wait_option); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_https_client_secure_connect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function connects a HTTPS client on the specified IP. The TLS */ -/* session in the NX_WEB_HTTP_CLIENT structure is initialized using */ -/* application-supplied callback. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* server_ip Address of remote server */ -/* server_port HTTPS port on remote server */ -/* tls_setup User-supplied callback */ -/* function to set up TLS */ -/* parameters. */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_connect Connect to server with TCP */ -/* _nx_secure_tls_session_start Connect to server with TLS */ -/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option) -{ -UINT status; - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - - /* If keep-alive is true, the client is already connected to the server. */ - if (client_ptr -> nx_web_http_client_keep_alive && - (nx_tcp_socket_state_wait(&(client_ptr -> nx_web_http_client_socket), NX_TCP_ESTABLISHED, 0) == NX_SUCCESS)) - { - - /* Reset the state. */ - _nx_web_http_client_cleanup(client_ptr); - return(NX_SUCCESS); - } -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* We have an HTTPS client, mark it as such. */ - client_ptr -> nx_web_http_client_is_https = NX_TRUE; - - /* Attempt to connect to the HTTPS server using just TCP - we need to establish the TCP socket - before we attempt to perform a TLS handshake for HTTPS. */ - status = _nx_web_http_client_connect(client_ptr, server_ip, server_port, wait_option); - - if(status != NX_SUCCESS) - { - return(status); - } - - /* Call the TLS setup callback to initialize TLS configuration. */ - status = (*tls_setup)(client_ptr, &(client_ptr->nx_web_http_client_tls_session)); - - if(status != NX_SUCCESS) - { - - /* Error, unbind the port and return an error. */ - _nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), wait_option); - _nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); - return(status); - } - - /* Start TLS session after connecting TCP socket. */ - status = _nx_secure_tls_session_start(&(client_ptr -> nx_web_http_client_tls_session), &(client_ptr -> nx_web_http_client_socket), wait_option); - - if (status != NX_SUCCESS) - { - /* Error, unbind the port and return an error. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - return(status); - } - - /* At this point we have a connection setup with an HTTPS server! */ - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -#endif /* NX_WEB_HTTPS_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP request initialize call.*/ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* method HTTP request type (e.g. GET) */ -/* resource HTTP resource (e.g. URL) */ -/* host Pointer to Host */ -/* input_size Size of input for PUT/POST */ -/* transfer_encoding_chunked Chunked encoding flag */ -/* username Username for server access */ -/* password Password for server access */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_initialize */ -/* Actual request create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, /* GET, PUT, DELETE, POST, HEAD */ - CHAR *resource, - CHAR *host, - UINT input_size, /* Used by PUT and POST */ - UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ - CHAR *username, - CHAR *password, - UINT wait_option) -{ -UINT status; - - /* Check pointers. We need a control block and a resource but - username and password can be NULL. */ - if(client_ptr == NX_NULL || resource == NX_NULL || host == NX_NULL) - { - return(NX_PTR_ERROR); - } - - status = NX_SUCCESS; - - /* Check methods. */ - switch(method) - { - case NX_WEB_HTTP_METHOD_POST: - case NX_WEB_HTTP_METHOD_PUT: - /* PUT and POST need an input size. */ - if (!input_size && !transfer_encoding_chunked) - { - status = NX_WEB_HTTP_METHOD_ERROR; - } - break; - case NX_WEB_HTTP_METHOD_GET: - case NX_WEB_HTTP_METHOD_DELETE: - case NX_WEB_HTTP_METHOD_HEAD: - /* These are good as-is. */ - break; - case NX_WEB_HTTP_METHOD_NONE: - default: - /* Improper or missing method. */ - status = NX_WEB_HTTP_METHOD_ERROR; - } - - /* Check status from method creation. */ - if(status != NX_SUCCESS) - { - return(status); - } - - /* Call actual function. */ - status = _nx_web_http_client_request_initialize(client_ptr, method, resource, host, input_size, - transfer_encoding_chunked, username, password, - wait_option); - - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_initialize PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes an HTTP request using information */ -/* supplied by the caller. When a request is initialized, a packet is */ -/* allocated internally which can then be modified before sending the */ -/* final request to the server. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* method HTTP request type (e.g. GET) */ -/* resource HTTP resource (e.g. URL) */ -/* host Pointer to Host */ -/* input_size Size of input for PUT/POST */ -/* transfer_encoding_chunked Chunked encoding flag */ -/* username Username for server access */ -/* password Password for server access */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_initialize_extended */ -/* Actual request create call */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, /* GET, PUT, DELETE, POST, HEAD */ - CHAR *resource, - CHAR *host, - UINT input_size, /* Used by PUT and POST */ - UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ - CHAR *username, - CHAR *password, - UINT wait_option) -{ -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - return(_nx_web_http_client_request_initialize_extended(client_ptr, method, resource, - temp_resource_length, host, temp_host_length, - input_size, transfer_encoding_chunked, - username, temp_username_length, - password, temp_password_length, - wait_option)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_initialize_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP request initialize call.*/ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* method HTTP request type (e.g. GET) */ -/* resource HTTP resource (e.g. URL) */ -/* resource_length Length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* input_size Size of input for PUT/POST */ -/* transfer_encoding_chunked Chunked encoding flag */ -/* username Username for server access */ -/* username_length Length of username */ -/* password Password for server access */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_initialize_extended */ -/* Actual request create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, /* GET, PUT, DELETE, POST, HEAD */ - CHAR *resource, - UINT resource_length, - CHAR *host, - UINT host_length, - UINT input_size, /* Used by PUT and POST */ - UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ - CHAR *username, - UINT username_length, - CHAR *password, - UINT password_length, - UINT wait_option) -{ -UINT status; - - /* Check pointers. We need a control block and a resource but - username and password can be NULL. */ - if(client_ptr == NX_NULL || resource == NX_NULL || host == NX_NULL) - { - return(NX_PTR_ERROR); - } - - status = NX_SUCCESS; - - /* Check methods. */ - switch(method) - { - case NX_WEB_HTTP_METHOD_POST: - case NX_WEB_HTTP_METHOD_PUT: - /* PUT and POST need an input size. */ - if (!input_size && !transfer_encoding_chunked) - { - status = NX_WEB_HTTP_METHOD_ERROR; - } - break; - case NX_WEB_HTTP_METHOD_GET: - case NX_WEB_HTTP_METHOD_DELETE: - case NX_WEB_HTTP_METHOD_HEAD: - /* These are good as-is. */ - break; - case NX_WEB_HTTP_METHOD_NONE: - default: - /* Improper or missing method. */ - status = NX_WEB_HTTP_METHOD_ERROR; - } - - /* Check status from method creation. */ - if(status != NX_SUCCESS) - { - return(status); - } - - /* Call actual function. */ - status = _nx_web_http_client_request_initialize_extended(client_ptr, method, resource, resource_length, - host, host_length, input_size, - transfer_encoding_chunked, username, - username_length, password, password_length, - wait_option); - - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_initialize_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function initializes an HTTP request using information */ -/* supplied by the caller. When a request is initialized, a packet is */ -/* allocated internally which can then be modified before sending the */ -/* final request to the server. */ -/* */ -/* Note: The strings of resource, host, username and password must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* method HTTP request type (e.g. GET) */ -/* resource HTTP resource (e.g. URL) */ -/* resource_length Length of resource */ -/* host Pointer to Host */ -/* host_length Length of host */ -/* input_size Size of input for PUT/POST */ -/* transfer_encoding_chunked Chunked encoding flag */ -/* username Username for server access */ -/* username_length Length of username */ -/* password Password for server access */ -/* password_length Length of password */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_packet_allocate */ -/* Allocate a request packet */ -/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ -/* nx_packet_data_append Append packet data */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, /* GET, PUT, DELETE, POST, HEAD */ - CHAR *resource, - UINT resource_length, - CHAR *host, - UINT host_length, - UINT input_size, /* Used by PUT and POST */ - UINT transfer_encoding_chunked, /* If true, input_size is ignored. */ - CHAR *username, - UINT username_length, - CHAR *password, - UINT password_length, - UINT wait_option) -{ -UINT status; -NX_PACKET *packet_ptr; -CHAR string1[NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 2]; -CHAR string2[NX_WEB_HTTP_MAX_STRING + 1]; -CHAR crlf[2] = {13,10}; -UINT temp_resource_length; -UINT temp_host_length; -UINT temp_username_length = 0; -UINT temp_password_length = 0; -UINT string1_length; -UINT string2_length; - - /* If there is old request packet, just release it. */ - if (client_ptr -> nx_web_http_client_request_packet_ptr) - { - nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); - client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; - } - - if ((username) && (password)) - { - - /* Check username and password length. */ - if (_nx_utility_string_length_check(username, &temp_username_length, username_length) || - _nx_utility_string_length_check(password, &temp_password_length, password_length)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Validate string length. */ - if ((username_length != temp_username_length) || - (password_length != temp_password_length)) - { - return(NX_WEB_HTTP_ERROR); - } - } - - /* Check resource and host length. */ - if (_nx_utility_string_length_check(resource, &temp_resource_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(host, &temp_host_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Validate string length. */ - if ((resource_length != temp_resource_length) || - (host_length != temp_host_length)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Allocate a packet for the request message. */ - status = _nx_web_http_client_request_packet_allocate(client_ptr, &(client_ptr -> nx_web_http_client_request_packet_ptr), wait_option); - - /* Check allocation status. */ - if (status != NX_SUCCESS) - { - /* Error, unbind the port and return an error. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - return(status); - } - - /* Get a working pointer to our newly-allocated packet. */ - packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; - - /* Determine the requested method. */ - status = NX_SUCCESS; - client_ptr -> nx_web_http_client_method = method; - switch(method) - { - case NX_WEB_HTTP_METHOD_GET: - /* Build the GET request. */ - nx_packet_data_append(packet_ptr, "GET ", 4, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - break; - case NX_WEB_HTTP_METHOD_PUT: - /* Additional information requested, build the POST request. */ - nx_packet_data_append(packet_ptr, "PUT ", 4, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = input_size; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - break; - case NX_WEB_HTTP_METHOD_POST: - /* Additional information requested, build the POST request. */ - nx_packet_data_append(packet_ptr, "POST ", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Store the total number of bytes to send. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = input_size; - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - break; - case NX_WEB_HTTP_METHOD_DELETE: - /* Build the DELETE request. */ - nx_packet_data_append(packet_ptr, "DELETE ", 7, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - break; - case NX_WEB_HTTP_METHOD_HEAD: - /* Build the HEAD request. */ - nx_packet_data_append(packet_ptr, "HEAD ", 5, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - break; - case NX_WEB_HTTP_METHOD_NONE: - default: - status = NX_WEB_HTTP_METHOD_ERROR; - break; - } - - /* Check status from method creation. */ - if(status != NX_SUCCESS) - { - - /* Release the request packet. */ - nx_packet_release(packet_ptr); - client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; - return(status); - } - - /* Determine if the resource needs a leading "/". */ - if (resource[0] != '/') - { - - /* Is this another website e.g. begins with http or https and has a colon? */ - if ( - ((resource[0] == 'h') || (resource[0] == 'H')) && - ((resource[1] == 't') || (resource[1] == 'T')) && - ((resource[2] == 't') || (resource[2] == 'T')) && - ((resource[3] == 'p') || (resource[3] == 'P')) && - ( (resource[4] == ':') || - (((resource[4] == 's') || (resource[4] == 'S')) && (resource[5] == ':'))) - ) - { - - /* Yes, to send this string as is. */ - } - else - { - - /* Local file URI which needs a leading '/' character. */ - nx_packet_data_append(packet_ptr, "/", 1, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - } - } - /* Else URI string refers to root directory file, and has a leading '/' character already. */ - - /* Place the resource in the header. */ - nx_packet_data_append(packet_ptr, resource, resource_length, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Place the HTTP version in the header. */ - nx_packet_data_append(packet_ptr, " HTTP/1.1", 9, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Place the end of line character in the header. */ - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Place the Host in the header. */ - nx_packet_data_append(packet_ptr, "Host: ", 6, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - if (host_length) - { - nx_packet_data_append(packet_ptr, host, host_length, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - } - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Determine if basic authentication is required. */ - if ((username) && (password)) - { - - /* Yes, attempt to build basic authentication. */ - nx_packet_data_append(packet_ptr, "Authorization: Basic ", 21, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - /* Encode and append the "name:password" into next. */ - - /* Place the name and password in a single string. */ - - /* Copy the name into the merged string. */ - memcpy(string1, username, username_length); - - /* Insert the colon. */ - string1[username_length] = ':'; - - /* Copy the password into the merged string. */ - memcpy(&string1[username_length + 1], password, password_length); - - /* Make combined string NULL terminated. */ - string1[username_length + password_length + 1] = NX_NULL; - - /* Now encode the username:password string. */ - _nx_web_http_client_base64_encode(string1, username_length + password_length + 1, string2); - - /* Check string length. */ - _nx_utility_string_length_check(string2, &string2_length, NX_WEB_HTTP_MAX_STRING); - nx_packet_data_append(packet_ptr, string2, string2_length, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - } - - /* Check to see if a Content-Length field is needed. */ - if ((input_size) && (!transfer_encoding_chunked)) - { - - /* Now build the content-length entry. */ - nx_packet_data_append(packet_ptr, "Content-Length: ", 16, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - string1_length = _nx_web_http_client_number_convert(input_size, string1); - nx_packet_data_append(packet_ptr, string1, string1_length, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - } - - if (transfer_encoding_chunked) - { - - /* Place the Transfer Encoding in the header. */ - nx_packet_data_append(packet_ptr, "Transfer-Encoding: chunked", 26, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - } - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_header_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors when calling the custom header */ -/* addition routine. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* field_name HTTP header field name */ -/* name_length Length of field name string */ -/* field_value Value of header field */ -/* value_length Length of value string */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_request_header_add */ -/* Actual header add call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, - CHAR *field_value, UINT value_length, UINT wait_option) -{ -UINT status; - - /* Check pointers. */ - if(client_ptr == NX_NULL || field_name == NX_NULL || field_value == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call the actual function. */ - status = _nx_web_http_client_request_header_add(client_ptr, field_name, name_length, - field_value, value_length, wait_option); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_header_add PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function adds a custom header to an HTTP(S) request that was */ -/* previously initialized with nx_web_http_client_request_initialize. */ -/* The field name and value are placed directly into the HTTP header */ -/* so it is up to the caller to assure that they are valid values. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* field_name HTTP header field name */ -/* name_length Length of field name string */ -/* field_value Value of header field */ -/* value_length Length of value string */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append data to request packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, - CHAR *field_value, UINT value_length, UINT wait_option) -{ -NX_PACKET *packet_ptr; -UINT status; -CHAR crlf[2] = {13,10}; - - - /* Make sure a request packet was allocated. */ - if(client_ptr -> nx_web_http_client_request_packet_ptr == NX_NULL) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Get a working pointer to our newly-allocated packet. */ - packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; - - - /* Add custom header fields to request packet. */ - status = nx_packet_data_append(packet_ptr, field_name, name_length, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - if(status != NX_SUCCESS) - { - return(status); - } - - status = nx_packet_data_append(packet_ptr, ": ", 2, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - if(status != NX_SUCCESS) - { - return(status); - } - - status = nx_packet_data_append(packet_ptr, field_value, value_length, client_ptr -> nx_web_http_client_packet_pool_ptr, - wait_option); - - if(status != NX_SUCCESS) - { - return(status); - } - - status = nx_packet_data_append(packet_ptr, crlf, 2, client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP request send API call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_client_request_send Actual request send call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option) -{ -UINT status; - - /* Make sure the client instance makes sense. */ - if(client_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Now send the packet to the HTTP server. */ - status = _nx_web_http_client_request_send(client_ptr, wait_option); - - /* Return success to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends an HTTP request to a remote server. The request */ -/* being sent must have been initialized previously with a call to */ -/* nx_web_http_client_request_initialize. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append packet data */ -/* nx_packet_release release packet */ -/* _nx_web_http_client_error_exit Cleanup and shut down HTTPS */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option) -{ -UINT status; -NX_PACKET *packet_ptr; -CHAR crlf[2] = {13,10}; - - - /* Make sure a request packet was allocated. */ - if(client_ptr -> nx_web_http_client_request_packet_ptr == NX_NULL) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Get a pointer to our current request packet. */ - packet_ptr = client_ptr -> nx_web_http_client_request_packet_ptr; - - /* Clear the request packet pointer. */ - client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; - - /* Place an extra cr/lf to signal the end of the HTTP header. */ - nx_packet_data_append(packet_ptr, crlf, 2, - client_ptr -> nx_web_http_client_packet_pool_ptr, wait_option); - - /* Now send the packet to the HTTP server. */ - status = _nx_web_http_client_send(client_ptr, packet_ptr, wait_option); - - /* Determine if the send was successful. */ - if (status != NX_SUCCESS) - { - - /* No, send was not successful. */ - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Disconnect and unbind the socket. */ - _nx_web_http_client_error_exit(client_ptr, wait_option); - - /* Return an error. */ - return(status); - } - - /* Set the appropriate state. */ - switch(client_ptr -> nx_web_http_client_method) - { - case NX_WEB_HTTP_METHOD_GET: - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_GET; - break; - case NX_WEB_HTTP_METHOD_PUT: - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_PUT; - break; - case NX_WEB_HTTP_METHOD_POST: - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_POST; - break; - case NX_WEB_HTTP_METHOD_DELETE: - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_DELETE; - break; - case NX_WEB_HTTP_METHOD_HEAD: - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_HEAD; - break; - case NX_WEB_HTTP_METHOD_NONE: - default: - status = NX_WEB_HTTP_METHOD_ERROR; - break; - } - - - /* Return success to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_request_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to allocate packets for */ -/* an HTTP(S) client session, as used for PUT and POST operations. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to allocated packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_client_request_packet_allocate */ -/* Actual packet allocation call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, - UINT wait_option) -{ -UINT status; - - /* Check our pointers. */ - if(client_ptr == NX_NULL || packet_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call the actual function. */ - status = _nx_web_http_client_request_packet_allocate(client_ptr, packet_ptr, wait_option); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_request_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a packet for Client HTTP(S) requests so */ -/* that clients needing to send large amounts of data (such as for */ -/* multi-part file upload) can allocated the needed packets and send */ -/* them with nx_web_http_client_request_packet_send. Note that the */ -/* appropriate headers must have been sent in the initial request. */ -/* Headers can be added to the HTTP request with */ -/* _nx_web_http_client_request_header_add. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to allocated packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_packet_allocate Allocate a TLS packet */ -/* nx_packet_allocate Allocate a TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, UINT wait_option) -{ -UINT status; -NXD_ADDRESS *server_ip; - - /* Get worker variables for use. */ - server_ip = &(client_ptr->nx_web_http_client_server_address); - -#ifdef NX_WEB_HTTPS_ENABLE - /* Allocate a packet for the GET (or POST) message. */ - if(client_ptr->nx_web_http_client_is_https) - { - status = nx_secure_tls_packet_allocate(&(client_ptr->nx_web_http_client_tls_session), client_ptr -> nx_web_http_client_packet_pool_ptr, - packet_ptr, wait_option); - } - else -#endif - if (server_ip -> nxd_ip_version == NX_IP_VERSION_V4) - { - status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, - packet_ptr, - NX_IPv4_TCP_PACKET, wait_option); - } - else - { - - status = nx_packet_allocate(client_ptr -> nx_web_http_client_packet_pool_ptr, - packet_ptr, - NX_IPv6_TCP_PACKET, wait_option); - } - - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_client_response_header_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the set response callback */ -/* routine, */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* callback_function Pointer to callback routine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_response_header_callback_set */ -/* Actual set routine */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, - VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, - CHAR *field_name, - UINT field_name_length, - CHAR *field_value, - UINT field_value_length)) -{ -UINT status; - - - /* Check for NULL pointers. */ - if(client_ptr == NX_NULL || callback_function == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Invoke the real function. */ - status = _nx_web_http_client_response_header_callback_set(client_ptr, callback_function); - - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_response_header_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets a callback routine to be invoked when the HTTP */ -/* client receives a response from the remote server. The callback */ -/* allows the application to process the HTTP headers beyond the */ -/* normal processing done by the NetX Web HTTP library. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* callback_function Pointer to callback routine */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, - VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, - CHAR *field_name, - UINT field_name_length, - CHAR *field_value, - UINT field_value_length)) -{ - - /* Assign the function pointer to the HTTP client. */ - client_ptr -> nx_web_http_client_response_callback = callback_function; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends data to the remote server using either the TCP */ -/* socket for plain HTTP or the TLS session for HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to packet to send. */ -/* wait_option Indicates behavior if packet */ -/* cannot be sent. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_send Send data using TLS session */ -/* nx_secure_tcp_socket_send Send data using TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_client_put_packet */ -/* _nx_web_http_client_request_send */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; - -#ifdef NX_WEB_HTTPS_ENABLE - /* End TLS session if using HTTPS. */ - if(client_ptr -> nx_web_http_client_is_https) - { - status = nx_secure_tls_session_send(&(client_ptr -> nx_web_http_client_tls_session), packet_ptr, wait_option); - } - else -#endif - { - status = nx_tcp_socket_send(&(client_ptr -> nx_web_http_client_socket), packet_ptr, wait_option); - } - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_client_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives data from the remote server using either the */ -/* TCP socket for plain HTTP or the TLS session for HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to packet to send. */ -/* wait_option Indicates behavior if packet */ -/* cannot be received */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_receive Receive data using TLS */ -/* nx_secure_tcp_socket_receive Receive data using TCP */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_client_receive(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; - -#ifdef NX_WEB_HTTPS_ENABLE - /* End TLS session if using HTTPS. */ - if(client_ptr -> nx_web_http_client_is_https) - { - status = nx_secure_tls_session_receive(&(client_ptr -> nx_web_http_client_tls_session), packet_ptr, wait_option); - } - else -#endif - { - status = nx_tcp_socket_receive(&(client_ptr -> nx_web_http_client_socket), packet_ptr, wait_option); - } - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_https_client_error_exit PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used whenever there is an error in the HTTP client */ -/* and the port needs to be unbound. If the client is using TLS for */ -/* HTTPS, then it also needs to end the TLS session. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* error_number Error status in caller */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_client_socket_unbind Unbind TCP port */ -/* nx_secure_tls_session_delete Delete TLS session */ -/* nx_secure_tls_session_end End TLS session */ -/* nx_tcp_socket_disconnect Close TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_client_error_exit(NX_WEB_HTTP_CLIENT *client_ptr, UINT wait_option) -{ -#ifdef NX_WEB_HTTPS_ENABLE - /* End TLS session if using HTTPS. */ - if(client_ptr -> nx_web_http_client_is_https) - { - nx_secure_tls_session_end(&(client_ptr -> nx_web_http_client_tls_session), NX_WAIT_FOREVER); - nx_secure_tls_session_delete(&(client_ptr -> nx_web_http_client_tls_session)); - } -#endif - - nx_tcp_socket_disconnect(&(client_ptr -> nx_web_http_client_socket), wait_option); - nx_tcp_client_socket_unbind(&(client_ptr -> nx_web_http_client_socket)); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_https_client_cleanup PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used to clean up the temporary variables and reset */ -/* the state. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* client_ptr Pointer to HTTP client */ -/* error_number Error status in caller */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_client_receive Receive a packet from server */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_client_cleanup(NX_WEB_HTTP_CLIENT *client_ptr) -{ -UINT status; -NX_PACKET *response_packet_ptr; - - /* Receive the early response from server. */ - while(1) - { - status = _nx_web_http_client_receive(client_ptr, &response_packet_ptr, NX_NO_WAIT); - - if (status) - { - break; - } - else - { - nx_packet_release(response_packet_ptr); - } - } - - /* Clean up the temporary variables. */ - client_ptr -> nx_web_http_client_total_transfer_bytes = 0; - - client_ptr -> nx_web_http_client_actual_bytes_transferred = 0; - - client_ptr -> nx_web_http_client_total_receive_bytes = 0; - - client_ptr -> nx_web_http_client_actual_bytes_received = 0; - - client_ptr -> nx_web_http_client_response_header_received = NX_FALSE; - - /* Release the request packet. */ - if (client_ptr -> nx_web_http_client_request_packet_ptr) - { - nx_packet_release(client_ptr -> nx_web_http_client_request_packet_ptr); - client_ptr -> nx_web_http_client_request_packet_ptr = NX_NULL; - } - - client_ptr -> nx_web_http_client_request_chunked = NX_FALSE; - - client_ptr -> nx_web_http_client_response_chunked = NX_FALSE; - - client_ptr -> nx_web_http_client_chunked_response_remaining_size = 0; - - /* Release the response packet. */ - if (client_ptr -> nx_web_http_client_response_packet) - { - nx_packet_release(client_ptr -> nx_web_http_client_response_packet); - client_ptr -> nx_web_http_client_response_packet = NX_NULL; - } - - /* Reset the state to ready. */ - client_ptr -> nx_web_http_client_state = NX_WEB_HTTP_CLIENT_STATE_READY; -} - diff --git a/protocol_handlers/web/nx_web_http_client.h b/protocol_handlers/web/nx_web_http_client.h deleted file mode 100644 index 1194f928..00000000 --- a/protocol_handlers/web/nx_web_http_client.h +++ /dev/null @@ -1,655 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Web Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_web_http_client.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Web Hypertext Transfer Protocol (HTTP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_WEB_HTTP_CLIENT_H -#define NX_WEB_HTTP_CLIENT_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -#include "nx_api.h" - -/* Include common HTTP definitions. */ -#include "nx_web_http_common.h" - -/* Define the HTTP ID. */ -#define NX_WEB_HTTP_CLIENT_ID 0x48545450UL - -#ifndef NX_WEB_HTTP_CLIENT_TIMEOUT -#define NX_WEB_HTTP_CLIENT_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE -#define NX_WEB_HTTP_CLIENT_MIN_PACKET_SIZE 600 -#endif - -/* Define HTTP Client states. */ - -#define NX_WEB_HTTP_CLIENT_STATE_READY 1 -#define NX_WEB_HTTP_CLIENT_STATE_GET 2 -#define NX_WEB_HTTP_CLIENT_STATE_PUT 3 -#define NX_WEB_HTTP_CLIENT_STATE_POST 4 -#define NX_WEB_HTTP_CLIENT_STATE_HEAD 5 -#define NX_WEB_HTTP_CLIENT_STATE_DELETE 6 - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - -/* Include the MD5 digest header file. */ - -#include "nx_md5.h" - -#endif - - -#ifdef NX_WEB_HTTPS_ENABLE -#include "nx_secure_tls_api.h" -#endif - -/* Define the */ -typedef struct NX_WEB_HTTP_CLIENT_STATUS_MAP_STRUCT -{ - CHAR *nx_web_http_client_status_string; /* String of status */ - UINT nx_web_http_client_status_code; /* Status code */ -} NX_WEB_HTTP_CLIENT_STATUS_MAP; - -/* Define the HTTP Client data structure. */ - -typedef struct NX_WEB_HTTP_CLIENT_STRUCT -{ - ULONG nx_web_http_client_id; /* HTTP Server ID */ - CHAR *nx_web_http_client_name; /* Name of this HTTP Client */ - UINT nx_web_http_client_state; /* Current state of HTTP Client */ - UINT nx_web_http_client_connect_port; /* Client port to connect to the server */ - NX_IP *nx_web_http_client_ip_ptr; /* Pointer to associated IP structure */ - NX_PACKET_POOL *nx_web_http_client_packet_pool_ptr; /* Pointer to HTTP Client packet pool */ - ULONG nx_web_http_client_total_transfer_bytes; /* Total number of bytes to transfer */ - ULONG nx_web_http_client_actual_bytes_transferred; /* Number of bytes actually transferred */ - ULONG nx_web_http_client_total_receive_bytes; /* Total number of bytes to receive */ - ULONG nx_web_http_client_actual_bytes_received; /* Number of bytes actually received */ - NX_TCP_SOCKET nx_web_http_client_socket; /* HTTP Client TCP socket */ - NXD_ADDRESS nx_web_http_client_server_address; /* IP address of remote server */ - NX_PACKET *nx_web_http_client_request_packet_ptr; /* Pointer to current request packet */ - UINT nx_web_http_client_method; /* Current method (e.g. GET, PUT) */ -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - UCHAR nx_web_http_client_keep_alive; /* Flag of keep alive */ -#else - UCHAR nx_web_http_client_reserved; /* Reserved */ -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - UCHAR nx_web_http_client_response_header_received; /* Flag of response header received */ - UCHAR nx_web_http_client_request_chunked; /* Flag for chunked request */ - UCHAR nx_web_http_client_response_chunked; /* Flag for chunked response */ - UINT nx_web_http_client_chunked_response_remaining_size; /* Remaining size of the response */ - NX_PACKET *nx_web_http_client_response_packet; /* Pointer to the received response */ - /* Pointer to application callback invoked for each field in the response header. */ - VOID (*nx_web_http_client_response_callback)(struct NX_WEB_HTTP_CLIENT_STRUCT *client_ptr, - CHAR *field_name, UINT field_name_length, - CHAR *field_value, UINT field_value_length); -#ifdef NX_WEB_HTTPS_ENABLE - UINT nx_web_http_client_is_https; /* If using TLS for HTTPS, set to true. */ - NX_SECURE_TLS_SESSION nx_web_http_client_tls_session; /* TLS session for HTTPS. */ -#endif -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - NX_MD5 nx_web_http_client_md5data; /* HTTP Client MD5 work area */ -#endif -} NX_WEB_HTTP_CLIENT; - - - -#ifndef NX_WEB_HTTP_CLIENT_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_web_http_client_create _nx_web_http_client_create -#define nx_web_http_client_delete _nx_web_http_client_delete -#define nx_web_http_client_get_start _nx_web_http_client_get_start -#define nx_web_http_client_get_start_extended _nx_web_http_client_get_start_extended -#define nx_web_http_client_put_start _nx_web_http_client_put_start -#define nx_web_http_client_put_start_extended _nx_web_http_client_put_start_extended -#define nx_web_http_client_post_start _nx_web_http_client_post_start -#define nx_web_http_client_post_start_extended _nx_web_http_client_post_start_extended -#define nx_web_http_client_head_start _nx_web_http_client_head_start -#define nx_web_http_client_head_start_extended _nx_web_http_client_head_start_extended -#define nx_web_http_client_delete_start _nx_web_http_client_delete_start -#define nx_web_http_client_delete_start_extended _nx_web_http_client_delete_start_extended -#define nx_web_http_client_get_secure_start _nx_web_http_client_get_secure_start -#define nx_web_http_client_get_secure_start_extended _nx_web_http_client_get_secure_start_extended -#define nx_web_http_client_put_secure_start _nx_web_http_client_put_secure_start -#define nx_web_http_client_put_secure_start_extended _nx_web_http_client_put_secure_start_extended -#define nx_web_http_client_post_secure_start _nx_web_http_client_post_secure_start -#define nx_web_http_client_post_secure_start_extended _nx_web_http_client_post_secure_start_extended -#define nx_web_http_client_head_secure_start _nx_web_http_client_head_secure_start -#define nx_web_http_client_head_secure_start_extended _nx_web_http_client_head_secure_start_extended -#define nx_web_http_client_delete_secure_start _nx_web_http_client_delete_secure_start -#define nx_web_http_client_delete_secure_start_extended _nx_web_http_client_delete_secure_start_extended -#define nx_web_http_client_response_body_get _nx_web_http_client_response_body_get -#define nx_web_http_client_put_packet _nx_web_http_client_put_packet -#define nx_web_http_client_response_header_callback_set _nx_web_http_client_response_header_callback_set -#define nx_web_http_client_request_initialize _nx_web_http_client_request_initialize -#define nx_web_http_client_request_initialize_extended _nx_web_http_client_request_initialize_extended -#define nx_web_http_client_request_send _nx_web_http_client_request_send -#define nx_web_http_client_request_header_add _nx_web_http_client_request_header_add -#define nx_web_http_client_connect _nx_web_http_client_connect -#define nx_web_http_client_secure_connect _nx_web_http_client_secure_connect -#define nx_web_http_client_request_packet_allocate _nx_web_http_client_request_packet_allocate -#define nx_web_http_client_request_packet_send _nx_web_http_client_request_packet_send -#define nx_web_http_client_request_chunked_set _nx_web_http_client_request_chunked_set - -#else - -/* Services with error checking. */ - -#define nx_web_http_client_create(p,n,i,pp,w) _nxe_web_http_client_create(p,n,i,pp,w, sizeof(NX_WEB_HTTP_CLIENT)) -#define nx_web_http_client_delete _nxe_web_http_client_delete -#define nx_web_http_client_get_start _nxe_web_http_client_get_start -#define nx_web_http_client_get_start_extended _nxe_web_http_client_get_start_extended -#define nx_web_http_client_put_start _nxe_web_http_client_put_start -#define nx_web_http_client_put_start_extended _nxe_web_http_client_put_start_extended -#define nx_web_http_client_post_start _nxe_web_http_client_post_start -#define nx_web_http_client_post_start_extended _nx_web_http_client_post_start_extended -#define nx_web_http_client_head_start _nxe_web_http_client_head_start -#define nx_web_http_client_head_start_extended _nxe_web_http_client_head_start_extended -#define nx_web_http_client_delete_start _nxe_web_http_client_delete_start -#define nx_web_http_client_delete_start_extended _nxe_web_http_client_delete_start_extended -#define nx_web_http_client_get_secure_start _nxe_web_http_client_get_secure_start -#define nx_web_http_client_get_secure_start_extended _nxe_web_http_client_get_secure_start_extended -#define nx_web_http_client_put_secure_start _nxe_web_http_client_put_secure_start -#define nx_web_http_client_put_secure_start_extended _nxe_web_http_client_put_secure_start_extended -#define nx_web_http_client_post_secure_start _nxe_web_http_client_post_secure_start -#define nx_web_http_client_post_secure_start_extended _nxe_web_http_client_post_secure_start_extended -#define nx_web_http_client_head_secure_start _nxe_web_http_client_head_secure_start -#define nx_web_http_client_head_secure_start_extended _nxe_web_http_client_head_secure_start_extended -#define nx_web_http_client_delete_secure_start _nxe_web_http_client_delete_secure_start -#define nx_web_http_client_delete_secure_start_extended _nxe_web_http_client_delete_secure_start_extended -#define nx_web_http_client_response_body_get _nxe_web_http_client_response_body_get -#define nx_web_http_client_put_packet _nxe_web_http_client_put_packet -#define nx_web_http_client_response_header_callback_set _nxe_web_http_client_response_header_callback_set -#define nx_web_http_client_request_initialize _nxe_web_http_client_request_initialize -#define nx_web_http_client_request_initialize_extended _nxe_web_http_client_request_initialize_extended -#define nx_web_http_client_request_send _nxe_web_http_client_request_send -#define nx_web_http_client_request_header_add _nxe_web_http_client_request_header_add -#define nx_web_http_client_connect _nxe_web_http_client_connect -#define nx_web_http_client_secure_connect _nxe_web_http_client_secure_connect -#define nx_web_http_client_request_packet_allocate _nxe_web_http_client_request_packet_allocate -#define nx_web_http_client_request_packet_send _nxe_web_http_client_request_packet_send -#define nx_web_http_client_request_chunked_set _nxe_web_http_client_request_chunked_set - -#endif /* NX_DISABLE_ERROR_CHECKING */ - -/* Define the prototypes accessible to the application software. */ - - -#ifdef NX_DISABLE_ERROR_CHECKING -UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); -#else -UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); -#endif /* NX_DISABLE_ERROR_CHECKING */ - - -UINT nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); -UINT nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, ULONG wait_option); -UINT nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); -UINT nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG wait_option); - -UINT nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, - VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, - CHAR *field_name, - UINT field_name_length, - CHAR *field_value, - UINT field_value_length)); - -UINT nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); - -UINT nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - CHAR *host, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - CHAR *password, - UINT wait_option); - -UINT nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - UINT resource_length, - CHAR *host, - UINT host_length, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - UINT username_length, - CHAR *password, - UINT password_length, - UINT wait_option); - -UINT nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, - UINT wait_option); - -UINT nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, - CHAR *field_value, UINT value_length, UINT wait_option); - -UINT nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); - -UINT nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); - -UINT nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); - -#ifdef NX_WEB_HTTPS_ENABLE - -UINT nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); - -UINT nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); - -#endif -#else - -/* HTTP source code is being compiled, do not perform any API mapping. */ - -UINT _nxe_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size, UINT http_client_size); -UINT _nx_web_http_client_create(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr, ULONG window_size); -UINT _nxe_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); -UINT _nx_web_http_client_delete(NX_WEB_HTTP_CLIENT *client_ptr); -UINT _nxe_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_web_http_client_response_body_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nxe_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_web_http_client_put_packet(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nxe_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_web_http_client_get_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxe_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); -UINT _nx_web_http_client_get_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); -UINT _nxe_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nx_web_http_client_put_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nxe_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option); -UINT _nx_web_http_client_put_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option); -UINT _nxe_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nx_web_http_client_post_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, ULONG wait_option); -UINT _nxe_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option); -UINT _nx_web_http_client_post_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG total_bytes, - ULONG wait_option); -UINT _nxe_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_web_http_client_head_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxe_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); -UINT _nx_web_http_client_head_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); -UINT _nxe_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nx_web_http_client_delete_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, CHAR *host, CHAR *username, CHAR *password, ULONG wait_option); -UINT _nxe_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); -UINT _nx_web_http_client_delete_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, - UINT server_port, CHAR *resource, UINT resource_length, - CHAR *host, UINT host_length, CHAR *username, - UINT username_length, CHAR *password, - UINT password_length, ULONG wait_option); - - -UINT _nxe_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, - VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, - CHAR *field_name, - UINT field_name_length, - CHAR *field_value, - UINT field_value_length)); -UINT _nx_web_http_client_response_header_callback_set(NX_WEB_HTTP_CLIENT *client_ptr, - VOID (*callback_function)(NX_WEB_HTTP_CLIENT *client_ptr, - CHAR *field_name, - UINT field_name_length, - CHAR *field_value, - UINT field_value_length)); -UINT _nx_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); -UINT _nxe_web_http_client_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, ULONG wait_option); -UINT _nx_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - CHAR *host, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - CHAR *password, - UINT wait_option); -UINT _nxe_web_http_client_request_initialize(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - CHAR *host, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - CHAR *password, - UINT wait_option); -UINT _nx_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - UINT resource_length, - CHAR *host, - UINT host_length, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - UINT username_length, - CHAR *password, - UINT password_length, - UINT wait_option); -UINT _nxe_web_http_client_request_initialize_extended(NX_WEB_HTTP_CLIENT *client_ptr, - UINT method, - CHAR *resource, - UINT resource_length, - CHAR *host, - UINT host_length, - UINT input_size, - UINT transfer_encoding_chunked, - CHAR *username, - UINT username_length, - CHAR *password, - UINT password_length, - UINT wait_option); - - -UINT _nx_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); -UINT _nxe_web_http_client_request_send(NX_WEB_HTTP_CLIENT *client_ptr, ULONG wait_option); -UINT _nx_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, - UINT wait_option); -UINT _nxe_web_http_client_request_packet_allocate(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, - UINT wait_option); - -UINT _nx_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, - CHAR *field_value, UINT value_length, UINT wait_option); -UINT _nxe_web_http_client_request_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *field_name, UINT name_length, - CHAR *field_value, UINT value_length, UINT wait_option); - -UINT _nx_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); -UINT _nxe_web_http_client_request_packet_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT more_data, ULONG wait_option); - -UINT _nx_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); -UINT _nxe_web_http_client_request_chunked_set(NX_WEB_HTTP_CLIENT *client_ptr, UINT chunk_size, NX_PACKET *packet_ptr); - -#ifdef NX_WEB_HTTPS_ENABLE -UINT _nx_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_secure_connect(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_get_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_get_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_put_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_put_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_post_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_post_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, ULONG total_bytes, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); - -UINT _nxe_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_head_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_head_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_delete_secure_start(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, CHAR *resource, - CHAR *host, CHAR *username, CHAR *password, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nxe_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); -UINT _nx_web_http_client_delete_secure_start_extended(NX_WEB_HTTP_CLIENT *client_ptr, NXD_ADDRESS *server_ip, UINT server_port, - CHAR *resource, UINT resource_length, CHAR *host, UINT host_length, - CHAR *username, UINT username_length, CHAR *password, UINT password_length, - UINT (*tls_setup)(NX_WEB_HTTP_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *), - ULONG wait_option); - - - -#endif - -/* Define internal HTTP functions. */ - -UINT _nx_web_http_client_type_get(CHAR *name, CHAR *http_type_string); -UINT _nx_web_http_client_content_length_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); -UINT _nx_web_http_client_process_header_fields(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr); -UINT _nx_web_http_client_number_convert(UINT number, CHAR *string); -VOID _nx_web_http_client_base64_encode(CHAR *name, UINT length, CHAR *base64name); -UINT _nx_web_http_client_content_type_header_add(NX_WEB_HTTP_CLIENT *client_ptr, CHAR *resource, ULONG wait_option); -UINT _nx_web_http_client_content_length_header_add(NX_WEB_HTTP_CLIENT *client_ptr, ULONG total_bytes, ULONG wait_option); -VOID _nx_web_http_client_error_exit(NX_WEB_HTTP_CLIENT *client_ptr, UINT wait_option); -UINT _nx_web_http_client_receive(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_web_http_client_send(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -UINT _nx_web_http_client_get_server_response(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -VOID _nx_web_http_client_cleanup(NX_WEB_HTTP_CLIENT *client_ptr); -UINT _nx_web_http_client_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); -UINT _nx_web_http_client_response_read(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR *data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_client_response_byte_expect(NX_WEB_HTTP_CLIENT *client_ptr, UCHAR data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_client_chunked_size_get(NX_WEB_HTTP_CLIENT *client_ptr, UINT *chunk_size, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_client_response_chunked_get(NX_WEB_HTTP_CLIENT *client_ptr, NX_PACKET **packet_pptr, ULONG wait_option); - -#endif /* NX_WEB_HTTP_CLIENT_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_WEB_HTTP_CLIENT_H */ diff --git a/protocol_handlers/web/nx_web_http_common.h b/protocol_handlers/web/nx_web_http_common.h deleted file mode 100644 index 81ae4e4a..00000000 --- a/protocol_handlers/web/nx_web_http_common.h +++ /dev/null @@ -1,245 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_web_http_common.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Web Hypertext Transfer Protocol (HTTP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. If HTTPS is being used */ -/* then nx_secure_tls_api.h must also be included. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NX_WEB_HTTP_COMMON_H -#define NX_WEB_HTTP_COMMON_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* Define the HTTP version. */ -#define NX_WEB_HTTP_VERSION "HTTP/1.1" - -/* Define HTTP TCP socket create options. */ - -#ifndef NX_WEB_HTTP_TYPE_OF_SERVICE -#define NX_WEB_HTTP_TYPE_OF_SERVICE NX_IP_NORMAL -#endif - -#ifndef NX_WEB_HTTP_FRAGMENT_OPTION -#define NX_WEB_HTTP_FRAGMENT_OPTION NX_DONT_FRAGMENT -#endif - -#ifndef NX_WEB_HTTP_TIME_TO_LIVE -#define NX_WEB_HTTP_TIME_TO_LIVE 0x80 -#endif - -#ifndef NX_WEB_HTTP_MAX_RESOURCE -#define NX_WEB_HTTP_MAX_RESOURCE 40 -#endif - -#ifndef NX_WEB_HTTP_MAX_NAME -#define NX_WEB_HTTP_MAX_NAME 20 -#endif - -#ifndef NX_WEB_HTTP_MAX_PASSWORD -#define NX_WEB_HTTP_MAX_PASSWORD 20 -#endif - -/* To enabled HTTPS, define this symbol -#define NX_WEB_HTTPS_ENABLE -*/ - -/* To enable MD5 digest authentication, define this symbol -#define NX_WEB_HTTP_DIGEST_ENABLE -*/ - -#ifndef NX_PHYSICAL_TRAILER -#define NX_PHYSICAL_TRAILER 4 -#endif - -/* NX_WEB_HTTP_MAX_STRING is base64 of "name:password" and plus 1 if an extra conversion is needed. */ -#define NX_WEB_HTTP_MAX_STRING ((NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 1 ) * 4 / 3 + 1) - -#define NX_WEB_HTTP_MAX_BINARY_MD5 16 -#define NX_WEB_HTTP_MAX_ASCII_MD5 32 - - -/* Define return code constants. */ -#define NX_WEB_HTTP_ERROR 0x30000 /* HTTP internal error */ -#define NX_WEB_HTTP_TIMEOUT 0x30001 /* HTTP timeout occurred */ -#define NX_WEB_HTTP_FAILED 0x30002 /* HTTP error */ -#define NX_WEB_HTTP_DONT_AUTHENTICATE 0x30003 /* HTTP authentication not needed */ -#define NX_WEB_HTTP_BASIC_AUTHENTICATE 0x30004 /* HTTP basic authentication requested */ -#define NX_WEB_HTTP_DIGEST_AUTHENTICATE 0x30005 /* HTTP digest authentication requested */ -#define NX_WEB_HTTP_NOT_FOUND 0x30006 /* HTTP request not found */ -#define NX_WEB_HTTP_DATA_END 0x30007 /* HTTP end of content area */ -#define NX_WEB_HTTP_CALLBACK_COMPLETED 0x30008 /* HTTP user callback completed the processing */ -#define NX_WEB_HTTP_POOL_ERROR 0x30009 /* HTTP supplied pool payload is too small */ -#define NX_WEB_HTTP_NOT_READY 0x3000A /* HTTP client not ready for operation */ -#define NX_WEB_HTTP_GET_DONE 0x3000C /* HTTP client get is complete */ -#define NX_WEB_HTTP_BAD_PACKET_LENGTH 0x3000D /* Invalid packet received - length incorrect */ -#define NX_WEB_HTTP_REQUEST_UNSUCCESSFUL_CODE 0x3000E /* Received an error code instead of 2xx from server */ -#define NX_WEB_HTTP_INCOMPLETE_PUT_ERROR 0x3000F /* Server responds before PUT is complete */ -#define NX_WEB_HTTP_PASSWORD_TOO_LONG 0x30011 /* Password exceeded expected length */ -#define NX_WEB_HTTP_USERNAME_TOO_LONG 0x30012 /* Username exceeded expected length */ -#define NX_WEB_HTTP_NO_QUERY_PARSED 0x30013 /* Server unable to find query in client request */ -#define NX_WEB_HTTP_METHOD_ERROR 0x30014 /* Client method (e.g. GET, POST) was missing required information. */ -#define NX_WEB_HTTP_IMPROPERLY_TERMINATED_PARAM 0x30015 /* Client request parameter not properly terminated */ -#define NX_WEB_HTTP_BOUNDARY_ALREADY_FOUND 0x30016 /* Boundary is already found. */ -#define NX_WEB_HTTP_MISSING_CONTENT_LENGTH 0x30017 /* The Content-Length header was not found. */ -#define NX_WEB_HTTP_EXTENSION_NOT_FOUND 0x30018 /* A searched-for HTTP type extension was not found. */ -#define NX_WEB_HTTP_EXTENSION_MIME_DEFAULT 0x30019 /* No matching extension found, return default. */ -#define NX_WEB_HTTP_STATUS_CODE_CONTINUE 0x3001A /* "100 Continue" */ -#define NX_WEB_HTTP_STATUS_CODE_SWITCHING_PROTOCOLS 0x3001B /* "101 Switching Protocols" */ -#define NX_WEB_HTTP_STATUS_CODE_CREATED 0x3001C /* "201 Created" */ -#define NX_WEB_HTTP_STATUS_CODE_ACCEPTED 0x3001D /* "202 Accepted" */ -#define NX_WEB_HTTP_STATUS_CODE_NON_AUTH_INFO 0x3001E /* "203 Non-Authoritative Information" */ -#define NX_WEB_HTTP_STATUS_CODE_NO_CONTENT 0x3001F /* "204 No Content" */ -#define NX_WEB_HTTP_STATUS_CODE_RESET_CONTENT 0x30020 /* "205 Reset Content" */ -#define NX_WEB_HTTP_STATUS_CODE_PARTIAL_CONTENT 0x30021 /* "206 Partial Content" */ -#define NX_WEB_HTTP_STATUS_CODE_MULTIPLE_CHOICES 0x30022 /* "300 Multiple Choices" */ -#define NX_WEB_HTTP_STATUS_CODE_MOVED_PERMANETLY 0x30023 /* "301 Moved Permanently" */ -#define NX_WEB_HTTP_STATUS_CODE_FOUND 0x30024 /* "302 Found" */ -#define NX_WEB_HTTP_STATUS_CODE_SEE_OTHER 0x30025 /* "303 See Other" */ -#define NX_WEB_HTTP_STATUS_CODE_NOT_MODIFIED 0x30026 /* "304 Not Modified" */ -#define NX_WEB_HTTP_STATUS_CODE_USE_PROXY 0x30027 /* "305 Use Proxy" */ -#define NX_WEB_HTTP_STATUS_CODE_TEMPORARY_REDIRECT 0x30028 /* "307 Temporary Redirect" */ -#define NX_WEB_HTTP_STATUS_CODE_BAD_REQUEST 0x30029 /* "400 Bad Request" */ -#define NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED 0x3002A /* "401 Unauthorized" */ -#define NX_WEB_HTTP_STATUS_CODE_PAYMENT_REQUIRED 0x3002B /* "402 Payment Required" */ -#define NX_WEB_HTTP_STATUS_CODE_FORBIDDEN 0x3002C /* "403 Forbidden" */ -#define NX_WEB_HTTP_STATUS_CODE_NOT_FOUND 0x3002D /* "404 Not Found" */ -#define NX_WEB_HTTP_STATUS_CODE_METHOD_NOT_ALLOWED 0x3002E /* "405 Method Not Allowed" */ -#define NX_WEB_HTTP_STATUS_CODE_NOT_ACCEPTABLE 0x3002F /* "406 Not Acceptable" */ -#define NX_WEB_HTTP_STATUS_CODE_PROXY_AUTH_REQUIRED 0x30030 /* "407 Proxy Authentication Required" */ -#define NX_WEB_HTTP_STATUS_CODE_REQUEST_TIMEOUT 0x30031 /* "408 Request Time-out" */ -#define NX_WEB_HTTP_STATUS_CODE_CONFLICT 0x30032 /* "409 Conflict" */ -#define NX_WEB_HTTP_STATUS_CODE_GONE 0x30033 /* "410 Gone" */ -#define NX_WEB_HTTP_STATUS_CODE_LENGTH_REQUIRED 0x30034 /* "411 Length Required" */ -#define NX_WEB_HTTP_STATUS_CODE_PRECONDITION_FAILED 0x30035 /* "412 Precondition Failed" */ -#define NX_WEB_HTTP_STATUS_CODE_ENTITY_TOO_LARGE 0x30036 /* "413 Request Entity Too Large" */ -#define NX_WEB_HTTP_STATUS_CODE_URL_TOO_LARGE 0x30037 /* "414 Request-URL Too Large" */ -#define NX_WEB_HTTP_STATUS_CODE_UNSUPPORTED_MEDIA 0x30038 /* "415 Unsupported Media Type" */ -#define NX_WEB_HTTP_STATUS_CODE_RANGE_NOT_SATISFY 0x30039 /* "416 Requested range not satisfiable" */ -#define NX_WEB_HTTP_STATUS_CODE_EXPECTATION_FAILED 0x3003A /* "417 Expectation Failed" */ -#define NX_WEB_HTTP_STATUS_CODE_INTERNAL_ERROR 0x3003B /* "500 Internal Server Error" */ -#define NX_WEB_HTTP_STATUS_CODE_NOT_IMPLEMENTED 0x3003C /* "501 Not Implemented" */ -#define NX_WEB_HTTP_STATUS_CODE_BAD_GATEWAY 0x3003D /* "502 Bad Gateway" */ -#define NX_WEB_HTTP_STATUS_CODE_SERVICE_UNAVAILABLE 0x3003E /* "503 Service Unavailable" */ -#define NX_WEB_HTTP_STATUS_CODE_GATEWAY_TIMEOUT 0x3003F /* "504 Gateway Time-out" */ -#define NX_WEB_HTTP_STATUS_CODE_VERSION_ERROR 0x30040 /* "505 HTTP Version not supported" */ -#define NX_WEB_HTTP_AUTHENTICATION_ERROR NX_WEB_HTTP_STATUS_CODE_UNAUTHORIZED /* HTTP client authentication failed */ - -/* Define the HTTP Server TCP port number */ - -#define NX_WEB_HTTP_SERVER_PORT 80 /* Port for HTTP server */ -#define NX_WEB_HTTPS_SERVER_PORT 443 /* Port for HTTPS server. */ - -/* Define constants for the various HTTP methods supported. */ -#define NX_WEB_HTTP_METHOD_NONE 0x0 -#define NX_WEB_HTTP_METHOD_GET 0x1 -#define NX_WEB_HTTP_METHOD_PUT 0x2 -#define NX_WEB_HTTP_METHOD_POST 0x3 -#define NX_WEB_HTTP_METHOD_DELETE 0x4 -#define NX_WEB_HTTP_METHOD_HEAD 0x5 - -/* Define status codes. */ -#define NX_WEB_HTTP_STATUS_CONTINUE "100 Continue" -#define NX_WEB_HTTP_STATUS_SWITCHING_PROTOCOLS "101 Switching Protocols" -#define NX_WEB_HTTP_STATUS_OK "200 OK" -#define NX_WEB_HTTP_STATUS_CREATED "201 Created" -#define NX_WEB_HTTP_STATUS_ACCEPTED "202 Accepted" -#define NX_WEB_HTTP_STATUS_NON_AUTH_INFO "203 Non-Authoritative Information" -#define NX_WEB_HTTP_STATUS_NO_CONTENT "204 No Content" -#define NX_WEB_HTTP_STATUS_RESET_CONTENT "205 Reset Content" -#define NX_WEB_HTTP_STATUS_PARTIAL_CONTENT "206 Partial Content" -#define NX_WEB_HTTP_STATUS_MULTIPLE_CHOICES "300 Multiple Choices" -#define NX_WEB_HTTP_STATUS_MOVED_PERMANETLY "301 Moved Permanently" -#define NX_WEB_HTTP_STATUS_FOUND "302 Found" -#define NX_WEB_HTTP_STATUS_SEE_OTHER "303 See Other" -#define NX_WEB_HTTP_STATUS_NOT_MODIFIED "304 Not Modified" -#define NX_WEB_HTTP_STATUS_USE_PROXY "305 Use Proxy" -#define NX_WEB_HTTP_STATUS_TEMPORARY_REDIRECT "307 Temporary Redirect" -#define NX_WEB_HTTP_STATUS_BAD_REQUEST "400 Bad Request" -#define NX_WEB_HTTP_STATUS_UNAUTHORIZED "401 Unauthorized" -#define NX_WEB_HTTP_STATUS_PAYMENT_REQUIRED "402 Payment Required" -#define NX_WEB_HTTP_STATUS_FORBIDDEN "403 Forbidden" -#define NX_WEB_HTTP_STATUS_NOT_FOUND "404 Not Found" -#define NX_WEB_HTTP_STATUS_METHOD_NOT_ALLOWED "405 Method Not Allowed" -#define NX_WEB_HTTP_STATUS_NOT_ACCEPTABLE "406 Not Acceptable" -#define NX_WEB_HTTP_STATUS_PROXY_AUTH_REQUIRED "407 Proxy Authentication Required" -#define NX_WEB_HTTP_STATUS_REQUEST_TIMEOUT "408 Request Time-out" -#define NX_WEB_HTTP_STATUS_CONFLICT "409 Conflict" -#define NX_WEB_HTTP_STATUS_GONE "410 Gone" -#define NX_WEB_HTTP_STATUS_LENGTH_REQUIRED "411 Length Required" -#define NX_WEB_HTTP_STATUS_PRECONDITION_FAILED "412 Precondition Failed" -#define NX_WEB_HTTP_STATUS_ENTITY_TOO_LARGE "413 Request Entity Too Large" -#define NX_WEB_HTTP_STATUS_URL_TOO_LARGE "414 Request-URL Too Large" -#define NX_WEB_HTTP_STATUS_UNSUPPORTED_MEDIA "415 Unsupported Media Type" -#define NX_WEB_HTTP_STATUS_RANGE_NOT_SATISFY "416 Requested range not satisfiable" -#define NX_WEB_HTTP_STATUS_EXPECTATION_FAILED "417 Expectation Failed" -#define NX_WEB_HTTP_STATUS_INTERNAL_ERROR "500 Internal Server Error" -#define NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED "501 Not Implemented" -#define NX_WEB_HTTP_STATUS_BAD_GATEWAY "502 Bad Gateway" -#define NX_WEB_HTTP_STATUS_SERVICE_UNAVAILABLE "503 Service Unavailable" -#define NX_WEB_HTTP_STATUS_GATEWAY_TIMEOUT "504 Gateway Time-out" -#define NX_WEB_HTTP_STATUS_VERSION_ERROR "505 HTTP Version not supported" - - -/* Define the max length of header field. */ - -#ifndef NX_WEB_HTTP_MAX_HEADER_FIELD -#define NX_WEB_HTTP_MAX_HEADER_FIELD 256 -#endif - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NX_WEB_HTTP_COMMON_H */ diff --git a/protocol_handlers/web/nx_web_http_server.c b/protocol_handlers/web/nx_web_http_server.c deleted file mode 100644 index f0d77229..00000000 --- a/protocol_handlers/web/nx_web_http_server.c +++ /dev/null @@ -1,11103 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Web Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - -#define NX_WEB_HTTP_SERVER_SOURCE_CODE - - -/* Force error checking to be disabled in this module */ - -#ifndef NX_DISABLE_ERROR_CHECKING -#define NX_DISABLE_ERROR_CHECKING -#endif - -/* Include necessary system files. */ - -#include "nx_api.h" -#include "nx_ip.h" -#include "nx_web_http_server.h" - -#include "stdio.h" -#include "string.h" -#ifdef NX_WEB_HTTP_DIGEST_ENABLE -#include "nx_md5.h" -#endif - -#if defined(NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH) && !defined(NX_WEB_HTTP_KEEPALIVE_DISABLE) -#error "Content length needed when keepalive is enabled" -#endif /* NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH */ - -/* Define the Base64 array that is used to build username and passwords for Basic authentication. Indexing - into this array yields the base64 representation of the 6bit number. */ - -CHAR _nx_web_http_server_base64_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE -/* Define the default nonce, used only for MD5 authentication. For security reasons, this ASCII value should - change over time. */ - -CHAR _nx_web_http_server_nonce[] = "a4b8c8d7e0f6a7b2c3d2e4f5a4b7c5d2e7f"; -#endif - -/* Define date strings. */ -const CHAR _nx_web_http_server_weekday[][3] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -const CHAR _nx_web_http_server_month[][3] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -/* Define basic MIME maps. */ -static NX_WEB_HTTP_SERVER_MIME_MAP _nx_web_http_server_mime_maps[] = -{ - {"html", "text/html"}, - {"htm", "text/html"}, - {"txt", "text/plain"}, - {"gif", "image/gif"}, - {"jpg", "image/jpeg"}, - {"ico", "image/x-icon"}, -}; - - -/* Create two arrays to hold encoded and decoded username/password data. */ -static CHAR authorization_request[NX_WEB_HTTP_MAX_STRING + 1]; -static CHAR authorization_decoded[NX_WEB_HTTP_MAX_NAME + NX_WEB_HTTP_MAX_PASSWORD + 2]; - -/* Bring in externs for caller checking code. */ - -NX_CALLER_CHECKING_EXTERNS - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_content_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP content get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_content_get Actual server content get call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server content get function. */ - status = _nx_web_http_server_content_get(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_content_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the user's specified portion of the HTTP */ -/* content. Content is typically included in POST and PUT requests */ -/* from the client. This routine is designed to be called from the */ -/* application's request notify callback. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_content_get_extended */ -/* Get content data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ -UINT status; - - /* Get content data. */ - status = _nx_web_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_packet_content_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP packet content find */ -/* call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to pointer to the */ -/* packet that contains the */ -/* HTTP header */ -/* content_length Pointer to content length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_packet_content_find */ -/* Actual server packet content */ -/* find call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) -{ - - - /* Check for invalid packet pointer. */ - if((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (*packet_ptr == NX_NULL) || (content_length == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server content length get function. */ - return(_nx_web_http_server_packet_content_find(server_ptr, packet_ptr, content_length)); - -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_packet_content_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds the content length specified in the HTTP */ -/* header, and move the nx_packet_prepend_ptr to the beginning of */ -/* the content. If the beginning of the content is not in the packet, */ -/* this function attempts to read the HTTP server socket for the */ -/* next packet. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to pointer to the */ -/* packet that contains the */ -/* HTTP header */ -/* content_length Pointer to content length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_content_length_get */ -/* Get content length */ -/* _nx_web_http_server_packet_get Receive another packet */ -/* _nx_web_http_server_calculate_content_offset */ -/* Pickup content offset */ -/* nx_packet_allocate Allocate a new packet */ -/* nx_packet_release Release the packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length) -{ - -ULONG get_offset; -UINT status; -ULONG length = 0; -UINT packet_chunked; -NX_PACKET *header_packet_ptr; -NX_PACKET *new_packet_ptr; -ULONG temp_offset; - - /* Check if the packet is chunked. */ - packet_chunked = _nx_web_http_server_chunked_check(*packet_ptr); - - /* If the packet isn't chunked. */ - if (!packet_chunked) - { - - /* Get the content length header information. */ - status = _nx_web_http_server_content_length_get(*packet_ptr, &length); - - if (status != NX_SUCCESS) - { - return(status); - } - } - - /* Get the content offset. */ - get_offset = (ULONG)_nx_web_http_server_calculate_content_offset(*packet_ptr); - - /* Check packet length. */ - if((*packet_ptr) -> nx_packet_length == get_offset) - { - - /* If the packet doesn't contain any content, need to receive a new packet. */ - - /* If the received request packet is chunked. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* Initialize the request packet pointer and remaining size for processing chunked packet. */ - server_ptr -> nx_web_http_server_request_packet = NX_NULL; - server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; - } - - /* Make the receive call to obtain the next packet. */ - status = _nx_web_http_server_packet_get(server_ptr, packet_ptr); - - if(status != NX_SUCCESS) - { - return(NX_WEB_HTTP_TIMEOUT); - } - - } - else - { - - /* Separate the HTTP header and content. Copy the content to a new packet. */ - - /* Remember the packet pointer and content offset. */ - header_packet_ptr = *packet_ptr; - temp_offset = get_offset; - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* If the packet is chained, loop to find the end of the HTTP header. */ - while ((*packet_ptr) && (temp_offset > (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr))) - { - temp_offset -= (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr); - (*packet_ptr) = (*packet_ptr) -> nx_packet_next; - } - - /* If this packet contain no content, set next packet as the first packet of the content. */ - if (temp_offset == (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr)) - { - new_packet_ptr = (*packet_ptr) -> nx_packet_next; - } - else - { -#endif - - /* Allocate a new packet to store content. */ - status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, - &new_packet_ptr, 0, NX_WAIT_FOREVER); - if(status) - { - return(status); - } - - /* Copy the content part to the new packet. */ - nx_packet_data_append(new_packet_ptr, - (*packet_ptr) -> nx_packet_prepend_ptr + temp_offset, - (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr) - temp_offset, - server_ptr -> nx_web_http_server_packet_pool_ptr, - NX_WAIT_FOREVER); - - /* Update the append pointer of the header part. */ - (*packet_ptr) -> nx_packet_append_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + temp_offset; - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* Set the next packet of the content packet. */ - new_packet_ptr -> nx_packet_next = (*packet_ptr) -> nx_packet_next; - } - - /* Set the last packet of the content and header packet. */ - new_packet_ptr -> nx_packet_last = header_packet_ptr -> nx_packet_last; - header_packet_ptr -> nx_packet_last = (*packet_ptr); - (*packet_ptr) -> nx_packet_next = NX_NULL; -#endif - - /* Update the length of the header and content packet. */ - new_packet_ptr -> nx_packet_length = header_packet_ptr -> nx_packet_length - get_offset; - header_packet_ptr -> nx_packet_length = get_offset; - - /* Return the content packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* If the packet is chunked, set for processing chunked packet. */ - server_ptr -> nx_web_http_server_request_packet = new_packet_ptr; - server_ptr -> nx_web_http_server_chunked_request_remaining_size = new_packet_ptr -> nx_packet_length; - - /* Get the processed chunked packet. Set this packet as the returned packet. */ - status = _nx_web_http_server_packet_get(server_ptr, packet_ptr); - if (status) - { - return(status); - } - } - else - { - - /* Set the returned packet. */ - *packet_ptr = new_packet_ptr; - } - } - - /* Determine if there is content in this HTTP request. */ - if(content_length) - { - - if (packet_chunked) - { - - /* If the packet is chunked, set content length as packet length. */ - *content_length = (*packet_ptr) -> nx_packet_length; - } - else - { - - /* Set the content length as the length in HTTP header. */ - *content_length = length; - } - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_packet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server packet get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to the packet to */ -/* be returned. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_packet_get Actual server packet get call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ - - - /* Check for invalid packet pointer. */ - if((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server packet get function. */ - return(_nx_web_http_server_packet_get(server_ptr, packet_ptr)); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_packet_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function obtains the next packet from the HTTP server socket. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to the packet to */ -/* be returned. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_request_chunked_get */ -/* Get chunked request packet */ -/* _nx_web_http_server_receive Receive another packet */ -/* nx_packet_release Packet release */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ -NX_PACKET *new_packet_ptr; -UINT status; - - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* If the request packet is chunked, remove the chunk header and get the packet which contain the chunk data. */ - status = _nx_web_http_server_request_chunked_get(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); - } - else - { - - /* Receive another packet from client. */ - status = _nx_web_http_server_receive(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); - } - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* Reset the chunked info. */ - nx_packet_release(server_ptr -> nx_web_http_server_request_packet); - server_ptr -> nx_web_http_server_request_packet = NX_NULL; - server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; - server_ptr -> nx_web_http_server_request_chunked = NX_FALSE; - return(status); - } - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - *packet_ptr = new_packet_ptr; - - return(NX_SUCCESS); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_content_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP extended get content */ -/* service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_content_get_extended */ -/* Actual extended get content */ -/* get service */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_ptr == NX_NULL) || (destination_ptr == NX_NULL) || (actual_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server content get function. */ - status = _nx_web_http_server_content_get_extended(server_ptr, packet_ptr, byte_offset, destination_ptr, destination_size, actual_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_content_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the user's specified portion of the HTTP */ -/* content. Content is typically included in POST and PUT requests */ -/* from the client. This routine is designed to be called from the */ -/* application's request notify callback. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to HTTP request packet*/ -/* byte_offset Byte offset into content */ -/* destination_ptr Pointer to content destination*/ -/* destination_size Maximum size of destination */ -/* actual_size Actual amount of content */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_chunked_check Check if the packet is chunked*/ -/* _nx_web_http_server_packet_get Receive another packet */ -/* _nx_web_http_server_content_length_get */ -/* Get content length with error */ -/* status returned separately */ -/* content length value. */ -/* _nx_web_http_server_calculate_content_offset */ -/* Pickup content offset */ -/* _nx_web_http_server_packet_content_find */ -/* Get the content packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size) -{ - -ULONG content_length; -ULONG offset; -UINT status; -UINT remaining_bytes; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN -NX_PACKET *header_packet_ptr = NX_NULL; -#endif - - /* Default the actual size to zero. */ - *actual_size = 0; - - if (_nx_web_http_server_chunked_check(packet_ptr) == NX_FALSE) - { - - /* Determine if there is content in this HTTP request. */ - status = _nx_web_http_server_content_length_get(packet_ptr, &content_length); - - if (status != NX_SUCCESS) - { - return status; - } - - /* Make sure the content length is at least greater than the byte offset supplied. */ - if (content_length <= byte_offset) - { - - /* No more data in this buffer. */ - return(NX_WEB_HTTP_DATA_END); - } - - /* Determine if the destination size is greater than the content length. */ - if (destination_size > content_length) - { - - /* Yes, make the destination size equal to the content length. */ - destination_size = content_length; - } - - /* Add the byte offset with content offset. */ - byte_offset += ((ULONG) _nx_web_http_server_calculate_content_offset(packet_ptr)); - } - else - { -#ifdef NX_DISABLE_PACKET_CHAIN - - NX_PARAMETER_NOT_USED(server_ptr); - - return NX_WEB_HTTP_ERROR; -#else - - /* If never processed the chunked packet, need to separate the HTTP header and content. */ - if (!server_ptr -> nx_web_http_server_expect_receive_bytes) - { - - /* Remember the header packet. */ - header_packet_ptr = packet_ptr; - - /* Separate the HTTP header and get the first content packet. */ - status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); - if (status) - { - return(status); - } - } - else - { - - /* If the HTTP header and content is already separated, process this packet as normal packet. */ - byte_offset += ((ULONG) _nx_web_http_server_calculate_content_offset(packet_ptr)); - } -#endif - } - - /* Determine if we need to read one or more additional packets. */ - while (byte_offset >= packet_ptr -> nx_packet_length) - { - -#ifdef NX_DISABLE_PACKET_CHAIN - NX_PARAMETER_NOT_USED(server_ptr); - - return NX_WEB_HTTP_ERROR; -#else - /* Read another packet because the offset reaches past the current packet - length. */ - status = _nx_web_http_server_packet_get(server_ptr, &new_packet_ptr); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - /* Otherwise, we have a new packet to append to the head packet. */ - - /* Determine if the current packet is already chained. */ - if (packet_ptr -> nx_packet_next) - { - - /* Yes, link the current last packet to the new packet. */ - (packet_ptr -> nx_packet_last) -> nx_packet_next = new_packet_ptr; - } - else - { - - /* Otherwise, this is our first chained packet. Link to the head. */ - packet_ptr -> nx_packet_next = new_packet_ptr; - } - - /* Is the new packet chained? */ - if (new_packet_ptr -> nx_packet_next) - { - - /* Yes, there is a last packet pointer. Point to this from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr -> nx_packet_last; - } - else - { - - /* No, there isn't a last packet pointer. Point to new packet from the head packet. */ - packet_ptr -> nx_packet_last = new_packet_ptr; - } - - /* Update the packet length. */ - packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + new_packet_ptr -> nx_packet_length; -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - -#ifndef NX_DISABLE_PACKET_CHAIN - if (header_packet_ptr) - { - - /* Append the content packet to the header packet. */ - if (header_packet_ptr -> nx_packet_next) - { - (header_packet_ptr -> nx_packet_last) -> nx_packet_next = packet_ptr; - } - else - { - header_packet_ptr -> nx_packet_next = packet_ptr; - } - - /* Update the last packet. */ - if (packet_ptr -> nx_packet_next) - { - header_packet_ptr -> nx_packet_last = packet_ptr -> nx_packet_last; - } - else - { - header_packet_ptr -> nx_packet_last = packet_ptr; - } - - /* Update the packet length. */ - header_packet_ptr -> nx_packet_length = header_packet_ptr -> nx_packet_length + packet_ptr -> nx_packet_length; - } -#endif - - /* Default the buffer pointer to NULL. */ - buffer_ptr = NX_NULL; - - /* Now find the packet that contains the offset. */ - offset = 0; - new_packet_ptr = packet_ptr; - do - { - - /* Determine if the get request falls into this packet. */ - if (byte_offset < (offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr))) - { - - /* Yes, the get offset is in this packet. */ - - /* Setup the starting byte pointer. */ - buffer_ptr = ((CHAR *) new_packet_ptr -> nx_packet_prepend_ptr) + (byte_offset - offset); - break; - } - - /* Otherwise update the offset. */ - offset = offset + (ULONG)(new_packet_ptr -> nx_packet_append_ptr - new_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - new_packet_ptr = NX_NULL; -#else - /* Move to next packet in the chain. */ - new_packet_ptr = new_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while (new_packet_ptr); - - /* Determine if an error occurred in the search. */ - if ((buffer_ptr == (CHAR *) NX_NULL) || (new_packet_ptr == NX_NULL)) - return(NX_WEB_HTTP_ERROR); - - /* Now determine if the maximum buffer size has to be adjusted. */ - if (destination_size > (UINT) (packet_ptr -> nx_packet_length - byte_offset)) - { - - /* Adjust the destination size downward. */ - destination_size = (UINT) (packet_ptr -> nx_packet_length - byte_offset); - } - - /* Initialize the remaining bytes. */ - remaining_bytes = destination_size; - - /* Otherwise copy the bytes from the offset to the end of the packet pointer. */ - while (remaining_bytes--) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - - /* If the packet is chained, copy the data in the chain. */ - if (buffer_ptr == (CHAR *)new_packet_ptr -> nx_packet_append_ptr) - { - new_packet_ptr = new_packet_ptr -> nx_packet_next; - buffer_ptr = (CHAR *)new_packet_ptr -> nx_packet_prepend_ptr; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Copy a byte to the destination. */ - *destination_ptr++ = *buffer_ptr++; - } - - /* Successful completion. */ - *actual_size = destination_size; - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP content length service. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP packet */ -/* content_length Pointer for returning content */ -/* length value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_content_length_get */ -/* Actual get content length call*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *content_length) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (content_length == NX_NULL)) - return(NX_PTR_ERROR); - - /* Call actual server content length get function. */ - status = _nx_web_http_server_content_length_get(packet_ptr, content_length); - - /* Return completion status. */ - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_content_length_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function find a valid content length field and returns a */ -/* successful completion status (NX_SUCCESS) if so. Otherwise it */ -/* it returns an error status. A valid content length value is */ -/* zero or more and matches the size of the message body. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* content_length Pointer to a valid Content */ -/* Length value */ -/* */ -/* OUTPUT */ -/* */ -/* NX_SUCCESS Content length extracted */ -/* status Invalid content length */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Threads */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length) -{ - -CHAR *buffer_ptr; - - - /* Default the content length to no data. */ - *length = 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Content-length: " token first. */ - while (((buffer_ptr+17) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Content-length token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'o') || (*(buffer_ptr+1) == 'O')) && - ((*(buffer_ptr+2) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+3) == 't') || (*(buffer_ptr+3) == 'T')) && - ((*(buffer_ptr+4) == 'e') || (*(buffer_ptr+4) == 'E')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+5) == 'N')) && - ((*(buffer_ptr+6) == 't') || (*(buffer_ptr+6) == 'T')) && - (*(buffer_ptr+7) == '-') && - ((*(buffer_ptr+8) == 'l') || (*(buffer_ptr+8) == 'L')) && - ((*(buffer_ptr+9) == 'e') || (*(buffer_ptr+9) == 'E')) && - ((*(buffer_ptr+10) == 'n') || (*(buffer_ptr+10) == 'N')) && - ((*(buffer_ptr+11) == 'g') || (*(buffer_ptr+11) == 'G')) && - ((*(buffer_ptr+12) == 't') || (*(buffer_ptr+12) == 'T')) && - ((*(buffer_ptr+13) == 'h') || (*(buffer_ptr+13) == 'H')) && - (*(buffer_ptr+14) == ':') && - (*(buffer_ptr+15) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 16; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now convert the length into a numeric value. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - { - - /* Update the content length. */ - *length = *length * 10; - *length = *length + (((UINT) (*buffer_ptr)) - 0x30); - - /* Move the buffer pointer forward. */ - buffer_ptr++; - } - - /* Determine if the content length was picked up properly. */ - if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || - ((*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13))) - { - - /* Error, set the length to zero. */ - return NX_WEB_HTTP_INCOMPLETE_PUT_ERROR; - } - - /* Return successful completion status to the caller. */ - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server create call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* http_server_name Name of HTTP server */ -/* server_port Port to use for HTTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* authentication_check Pointer to application's */ -/* authentication checking */ -/* request_notify Pointer to application's */ -/* request notify service */ -/* http_server_size Size of HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_create Actual server create call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size) -{ - -NX_PACKET *packet_ptr; -UINT status; - - - /* Check for invalid input pointers. */ - if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || - (http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id == NX_WEB_HTTP_SERVER_ID) || - (stack_ptr == NX_NULL) || (pool_ptr == NX_NULL) || - (http_server_size != sizeof(NX_WEB_HTTP_SERVER))) - return(NX_PTR_ERROR); - - /* Pickup a packet from the supplied packet pool. */ - packet_ptr = pool_ptr -> nx_packet_pool_available_list; - - /* Determine if the packet payload is equal to or greater than the maximum HTTP header supported. */ - if (((packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_data_start) - NX_PHYSICAL_TRAILER) - < NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE) - return(NX_WEB_HTTP_POOL_ERROR); - - /* Call actual server create function. */ - status = _nx_web_http_server_create(http_server_ptr, http_server_name, ip_ptr, server_port, media_ptr, stack_ptr, stack_size, pool_ptr, - authentication_check, request_notify); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_create PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function creates a HTTP server on the specified IP. In doing */ -/* so this function creates an TCP socket for subsequent HTTP */ -/* transfers and a thread for the HTTP server. */ -/* */ -/* Note: The string resource in callback functions authentication_check*/ -/* and request_notify is built by internal logic and always */ -/* NULL-terminated. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* http_server_name Name of HTTP server */ -/* server_port Port for HTTP server */ -/* ip_ptr Pointer to IP instance */ -/* media_ptr Pointer to media structure */ -/* stack_ptr Server thread's stack pointer */ -/* stack_size Server thread's stack size */ -/* pool_ptr Pointer to packet pool */ -/* authentication_check Pointer to application's */ -/* authentication checking */ -/* request_notify Pointer to application's */ -/* request notify service */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_create Create HTTP server socket */ -/* nx_tcp_socket_delete Delete the HTTP server socket */ -/* tx_thread_create Create the HTTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, - CHAR *http_server_name, NX_IP *ip_ptr, - UINT server_port, FX_MEDIA *media_ptr, - VOID *stack_ptr, ULONG stack_size, - NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, - UINT request_type, CHAR *resource, - CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, - CHAR *resource, NX_PACKET *packet_ptr)) -{ - -UINT status; - - - /* Clear the HTTP server structure. */ - memset((void *) http_server_ptr, 0, sizeof(NX_WEB_HTTP_SERVER)); - - /* Create the Server's TCP socket. */ - status = nx_tcpserver_create(ip_ptr, &http_server_ptr -> nx_web_http_server_tcpserver, http_server_name, - NX_WEB_HTTP_TYPE_OF_SERVICE, NX_WEB_HTTP_FRAGMENT_OPTION, NX_WEB_HTTP_TIME_TO_LIVE, - NX_WEB_HTTP_SERVER_WINDOW_SIZE, NX_NULL, - _nx_web_http_server_receive_data, _nx_web_http_server_connection_end, - _nx_web_http_server_connection_timeout, NX_WEB_HTTP_SERVER_TIMEOUT / NX_IP_PERIODIC_RATE, - stack_ptr, stack_size, http_server_ptr -> nx_web_http_server_session_buffer, - NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE, NX_WEB_HTTP_SERVER_PRIORITY, NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, return error code. */ - return(status); - } - - /* Store server ptr. */ - http_server_ptr -> nx_web_http_server_tcpserver.nx_tcpserver_reserved = (ULONG)http_server_ptr; - - /* Save the Server name. */ - http_server_ptr -> nx_web_http_server_name = http_server_name; - - /* Save the IP pointer address. */ - http_server_ptr -> nx_web_http_server_ip_ptr = ip_ptr; - - /* Save the packet pool pointer. */ - http_server_ptr -> nx_web_http_server_packet_pool_ptr = pool_ptr; - - /* Save the media pointer address. */ - http_server_ptr -> nx_web_http_server_media_ptr = media_ptr; - - /* Save the user-supplied routines, if specified. */ - http_server_ptr -> nx_web_http_server_authentication_check = authentication_check; - http_server_ptr -> nx_web_http_server_request_notify = request_notify; - - /* Set the server ID to indicate the HTTP server is ready. */ - http_server_ptr -> nx_web_http_server_id = NX_WEB_HTTP_SERVER_ID; - - /* Set the port to the default HTTP listening port (80). */ - http_server_ptr -> nx_web_http_server_listen_port = server_port; - - /* Return successful completion. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server delete call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_delete Actual server delete call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server delete function. */ - status = _nx_web_http_server_delete(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_delete PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function deletes a previously created HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_socket_delete Delete the HTTP server socket */ -/* nx_tcp_socket_disconnect Disconnect HTTP server socket */ -/* nx_tcp_socket_unaccept Unaccept HTTP server connect */ -/* nx_tcp_socket_unlisten Unlisten on the HTTP port */ -/* tx_thread_delete Delete the HTTP server thread */ -/* tx_thread_suspend Suspend the HTTP server thread*/ -/* tx_thread_terminate Terminate the HTTP server */ -/* thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr) -{ -UINT status; -NX_TCPSERVER *tcpserver_ptr = &(http_server_ptr -> nx_web_http_server_tcpserver); - - -#ifdef NX_WEB_HTTPS_ENABLE -UINT i; - - /* Stop TLS session if using HTTPS. */ - if(http_server_ptr -> nx_web_http_is_https_server) - { - for(i = 0; i < tcpserver_ptr -> nx_tcpserver_sessions_count; i++) - { - nx_secure_tls_session_end(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session), NX_WAIT_FOREVER); - nx_secure_tls_session_delete(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session)); - } - } - -#endif - - /* Delete the TCP server. */ - status = nx_tcpserver_delete(tcpserver_ptr); - - /* Clear the server ID to indicate the HTTP server is no longer ready. */ - http_server_ptr -> nx_web_http_server_id = 0; - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_param_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP parameter get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* param_number Parameter number (start at 0) */ -/* param_ptr Pointer to destination */ -/* max_param_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_param_get Actual server parameter get */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (param_ptr == NX_NULL) || (param_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server parameter get function. */ - status = _nx_web_http_server_param_get(packet_ptr, param_number, param_ptr, param_size, max_param_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_param_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the requested parameter specified in the URL */ -/* requested by the client. If the specified parameter is not present, */ -/* a not found error is returned to the caller. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* param_number Parameter number (start at 0) */ -/* param_ptr Pointer to destination */ -/* max_param_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size) -{ - -UINT i; -UINT current_param; -CHAR *buffer_ptr; - - - /* Set the destination string to NULL. */ - param_ptr[0] = (CHAR) NX_NULL; - *param_size = 0; - - /* Set current parameter to 0. */ - current_param = 0; - - /* Setup a pointer to the HTTP buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Position to the start of the URL. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Move the buffer pointer. */ - buffer_ptr++; - } - - /* Not find URL. */ - if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) - { - return(NX_WEB_HTTP_NOT_FOUND); - } - - /* Loop through the buffer to search for the specified parameter. */ - do - { - - /* Determine if the character is a semicolon, indicating a parameter - is present. */ - if (*buffer_ptr == ';') - { - - /* Yes, a parameter is present. */ - - /* Move the buffer pointer forward. */ - buffer_ptr++; - - /* Is this the parameter requested? */ - if (current_param == param_number) - { - - - /* Yes, we have found the parameter. */ - for (i = 0; i < max_param_size; i++) - { - - /* Check if reach the end of the packet data. */ - if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - return(NX_WEB_HTTP_NOT_FOUND); - } - - /* Check for end of parameter. */ - if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || - (*buffer_ptr == '&') || (*buffer_ptr == ' ') || - (*buffer_ptr == (CHAR) 13)) - { - - /* Yes, we are finished and need to get out of the loop. */ - break; - } - - /* Otherwise, store the character in the destination. */ - param_ptr[i] = *buffer_ptr++; - } - - /* NULL terminate the parameter. */ - if (i < max_param_size) - { - param_ptr[i] = (CHAR) NX_NULL; - } - - /* Return to caller. */ - if (param_ptr[i] == (CHAR) NX_NULL) - { - *param_size = i; - return(NX_SUCCESS); - } - else - { - return(NX_WEB_HTTP_IMPROPERLY_TERMINATED_PARAM); - } - } - else - { - - /* Increment the current parameter. */ - current_param++; - } - } - else - { - - /* Check for any other character that signals the end of the param list. */ - if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == '&')) - break; - - /* Update the buffer pointer. */ - buffer_ptr++; - } - - } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); - - /* Return a not found error. */ - return(NX_WEB_HTTP_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_query_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP query get call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* query_number Query number (start at 0) */ -/* query_ptr Pointer to destination */ -/* query_size Pointer to data size return */ -/* max_query_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_query_get Actual server query get */ -/* call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((packet_ptr == NX_NULL) || (query_ptr == NX_NULL) || (query_size == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server query get function. */ - status = _nx_web_http_server_query_get(packet_ptr, query_number, query_ptr, query_size, max_query_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_query_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function returns the requested query specified in the URL */ -/* requested by the client. If the specified query is not present, */ -/* a not found error is returned to the caller. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to HTTP request packet*/ -/* query_number Query number (start at 0) */ -/* query_ptr Pointer to destination */ -/* query_size Pointer to data size return */ -/* max_query_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size) -{ - -UINT i; -UINT current_query; -CHAR *buffer_ptr; - - - /* Set the destination string to NULL. */ - query_ptr[0] = (CHAR) NX_NULL; - *query_size = 0; - - /* Set current query number to 0. */ - current_query = 0; - - /* Setup a pointer to the HTTP buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Position to the start of the URL. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Move the buffer pointer. */ - buffer_ptr++; - } - - /* Not find URL. */ - if (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) - { - return(NX_WEB_HTTP_NOT_FOUND); - } - - /* Loop through the buffer to search for the specified query instance. */ - do - { - - /* Determine if the character is a '?' or a '&', indicating a query - is present. */ - if (((*buffer_ptr == '?') && (current_query == 0)) || - ((*buffer_ptr == '&') && (current_query != 0))) - { - - /* Yes, a query is present. */ - - /* Move the buffer pointer forward. */ - buffer_ptr++; - - /* Is this the query requested? */ - if (current_query == query_number) - { - - - /* Yes, we have found the query. */ - for (i = 0; i < max_query_size; i++) - { - - /* Check if reach the end of the packet data. */ - if (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - return(NX_WEB_HTTP_NOT_FOUND); - } - - /* Check for end of query. */ - if ((*buffer_ptr == ';') || (*buffer_ptr == '?') || - (*buffer_ptr == '&') || (*buffer_ptr == ' ') || - (*buffer_ptr == (CHAR) 13)) - { - - /* Yes, we are finished and need to get out of the loop. */ - break; - } - - /* Otherwise, store the character in the destination. */ - query_ptr[i] = *buffer_ptr++; - } - - /* NULL terminate the query. */ - query_ptr[i] = (CHAR) NX_NULL; - - /* Return to caller. */ - if (i) - { - *query_size = i; - return(NX_SUCCESS); - } - else - { - return(NX_WEB_HTTP_NO_QUERY_PARSED); - } - } - else - { - - /* Increment the current query. */ - current_query++; - } - } - else - { - - /* Check for any other character that signals the end of the query list. */ - if ((*buffer_ptr == '?') || (*buffer_ptr == ' ') || (*buffer_ptr == ';')) - break; - - /* Update the buffer pointer. */ - buffer_ptr++; - } - - } while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 13)); - - /* Return a not found error. */ - return(NX_WEB_HTTP_NOT_FOUND); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server start call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_start Actual server start call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Call actual server start function. */ - status = _nx_web_http_server_start(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_start PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function starts a previously created HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcp_server_socket_listen Start listening on HTTP port */ -/* tx_thread_resume Resume the HTTP server thread */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr) -{ - -UINT status; -UINT port; - - port = http_server_ptr -> nx_web_http_server_listen_port; - - /* Start listening on the HTTP server port. */ - status = nx_tcpserver_start(&http_server_ptr -> nx_web_http_server_tcpserver, port, NX_WEB_HTTP_SERVER_MAX_PENDING); - - /* Determine if the listen was unsuccessful. */ - if (status != NX_SUCCESS) - { - /* Just return an HTTP error. */ - return(status); - } - - /* Return successful completion. */ - return(NX_SUCCESS); -} - -#ifdef NX_WEB_HTTPS_ENABLE - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_secure_configure PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTPS configuration call. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* crypto_table TLS cryptographic routines */ -/* metadata_buffer Cryptographic metadata buffer */ -/* metadata_size Size of metadata buffer */ -/* packet_buffer TLS packet buffer */ -/* packet_size Size of packet buffer */ -/* identity_certificate TLS server certificate */ -/* trusted_certificates TLS trusted certificates */ -/* trusted_certs_num Number of trusted certs */ -/* remote_certificates Remote certificates array */ -/* remote_certs_num Number of remote certificates */ -/* remote_certificate_buffer Buffer for remote certs */ -/* remote_cert_buffer_size Size of remote cert buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_secure_configure Actual server configure call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, - UCHAR* packet_buffer, UINT packet_buffer_size, - NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], - UINT trusted_certs_num, - NX_SECURE_X509_CERT *remote_certificates[], - UINT remote_certs_num, - UCHAR *remote_certificate_buffer, - UINT remote_cert_buffer_size) -{ - -UINT status; - - - /* Check for invalid input pointers. Note that the remote certificates array and buffer - * may be NX_NULL for the HTTPS server since remote certificates are optional for TLS Server.*/ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - crypto_table == NX_NULL || metadata_buffer == NX_NULL || packet_buffer == NX_NULL || - identity_certificate == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call actual server start function. */ - status = _nx_web_http_server_secure_configure(http_server_ptr, crypto_table, metadata_buffer, metadata_size, - packet_buffer, packet_buffer_size, identity_certificate, - trusted_certificates, trusted_certs_num, - remote_certificates, remote_certs_num, remote_certificate_buffer, - remote_cert_buffer_size); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_secure_configure PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function configures a previously created NetX Web HTTP server */ -/* instance to use TLS for secure HTTPS communications. The parameters */ -/* are used to configure all the possible TLS sessions with identical */ -/* state so that each incoming HTTPS client experiences consistent */ -/* behavior. The number of TLS sessions is controlled using the macro */ -/* NX_WEB_HTTP_SERVER_SESSION_MAX. */ -/* */ -/* The cryptographic routine table (ciphersuite table) is shared */ -/* between all TLS sessions as it just contains function pointers. */ -/* */ -/* The metadata buffer and packet reassembly buffer are divided */ -/* equally between all TLS sessions. If the buffer size is not evenly */ -/* divisible by the number of sessions the remainder will be unused. */ -/* */ -/* The passed-in identity certificate is used by all sessions. During */ -/* TLS operation the server identity certificate is only read from so */ -/* copies are not needed for each session. */ -/* */ -/* The trusted certificates are added to the trusted store for each */ -/* TLS session in the server. This is used for client certificate */ -/* verification which is enabled if remote certificates are provided. */ -/* */ -/* The remote certificate array and buffer is shared by default */ -/* between all TLS sessions. This does mean that some sessions may */ -/* block during certificate validation. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* crypto_table TLS cryptographic routines */ -/* metadata_buffer Cryptographic metadata buffer */ -/* metadata_size Size of metadata buffer */ -/* packet_buffer TLS packet buffer */ -/* packet_size Size of packet buffer */ -/* identity_certificate TLS server certificate */ -/* trusted_certificates TLS trusted certificates */ -/* trusted_certs_num Number of trusted certs */ -/* remote_certificates Remote certificates array */ -/* remote_certs_num Number of remote certificates */ -/* remote_certificate_buffer Buffer for remote certs */ -/* remote_cert_buffer_size Size of remote cert buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcpserver_tls_setup Socket server TLS configure */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, - UCHAR* packet_buffer, UINT packet_buffer_size, - NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], - UINT trusted_certs_num, - NX_SECURE_X509_CERT *remote_certificates[], - UINT remote_certs_num, - UCHAR *remote_certificate_buffer, - UINT remote_cert_buffer_size) -{ - -UINT status; - - /* This is a secure HTTP server, so set HTTPS flag. */ - http_server_ptr -> nx_web_http_is_https_server = NX_TRUE; - - /* Configure TLS for the socket server. */ - status = nx_tcpserver_tls_setup(&http_server_ptr->nx_web_http_server_tcpserver, - crypto_table, metadata_buffer, metadata_size, - packet_buffer, packet_buffer_size, identity_certificate, - trusted_certificates, trusted_certs_num, - remote_certificates, remote_certs_num, - remote_certificate_buffer,remote_cert_buffer_size); - - /* Return result of TLS setup. */ - return(status); -} - -#endif /* NX_WEB_HTTPS_ENABLE */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP server stop call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_stop Actual server stop call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr) -{ - -UINT status; - - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (http_server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call actual server stop function. */ - status = _nx_web_http_server_stop(http_server_ptr); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_stop PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function stops a previously started HTTP server on the */ -/* specified IP. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_tcpserver_stop Suspend the HTTP server thread*/ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr) -{ -UINT status; -NX_TCPSERVER *tcpserver_ptr = &(http_server_ptr -> nx_web_http_server_tcpserver); - -#ifdef NX_WEB_HTTPS_ENABLE -UINT i; - - /* Stop TLS session if using HTTPS. */ - if(http_server_ptr -> nx_web_http_is_https_server) - { - for(i = 0; i < tcpserver_ptr -> nx_tcpserver_sessions_count; i++) - { - nx_secure_tls_session_end(&(tcpserver_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session), NX_WAIT_FOREVER); - } - } -#endif - - /* Suspend the HTTP server thread. */ - status = nx_tcpserver_stop(tcpserver_ptr); - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_data_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the data send call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* data_ptr Pointer to data to send */ -/* data_length Length of data to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_callback_data_send */ -/* Actual function call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) -{ -UINT status; - - /* Check pointers. */ - if(server_ptr == NX_NULL || data_ptr == NX_NULL || server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) - { - return(NX_PTR_ERROR); - } - - /* Actual function call. */ - status = _nx_web_http_server_callback_data_send(server_ptr, data_ptr, data_length); - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_data_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends data to the client from the application */ -/* callback function. This is typically done to satisfy a GET or */ -/* POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* data_ptr Pointer to data to send */ -/* data_length Length of data to send */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_response_packet_allocate */ -/* Allocate a resonse packet */ -/* nx_packet_data_append Append data to packet */ -/* nx_tcp_socket_send Send TCP data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length) -{ - -NX_PACKET *new_packet_ptr; -UINT status; - - - /* Allocate a new packet for data. */ - status = _nx_web_http_server_response_packet_allocate(server_ptr, &new_packet_ptr, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Error, return to caller. */ - return(NX_WEB_HTTP_ERROR); - } - - /* Now append the data to the packet. */ - status = nx_packet_data_append(new_packet_ptr, data_ptr, data_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Release the initial packet. */ - nx_packet_release(new_packet_ptr); - - /* Error, return to caller. */ - return(status); - } - - /* Send the data back to the client. */ - status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Determine if this is successful. */ - if (status != NX_SUCCESS) - { - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - } - - /* Return completion status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the response send call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* status_code Status-code and reason-phrase */ -/* information Pointer to HTTP info string */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_server_callback_response_send */ -/* Actual function call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info) -{ -UINT status; - - if(server_ptr == NX_NULL || status_code == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Actual function call. */ - status = _nx_web_http_server_callback_response_send(server_ptr, status_code, information, additional_info); - - /* Return successful completion. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the completion response to the client from the */ -/* application callback function. This is typically done to satisfy a */ -/* GET or POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* status_code Status-code and reason-phrase */ -/* information Pointer to HTTP info string */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_response_send Send HTTP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info) -{ - -UINT status_code_length = 0; -UINT information_length = 0; -UINT additional_info_length = 0; -UINT status; - - - /* Check length of header, information and additional information. */ - if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || - (information && _nx_utility_string_length_check(information, &information_length, NX_MAX_STRING_LENGTH)) || - (additional_info && _nx_utility_string_length_check(additional_info, &additional_info_length, NX_MAX_STRING_LENGTH))) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - status = _nx_web_http_server_response_send(server_ptr, status_code, status_code_length, information, - information_length, additional_info, additional_info_length); - - /* Return status. */ - return(status); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_response_send_extended */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the response send call. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* information Pointer to HTTP info string */ -/* information_length Length of information */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* additional_information_length Length of additional */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_server_callback_response_send_extended */ -/* Actual function call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_info, - UINT additional_information_length) -{ -UINT status; - - if(server_ptr == NX_NULL || status_code == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Actual function call. */ - status = _nx_web_http_server_callback_response_send_extended(server_ptr, status_code, status_code_length, - information, information_length, - additional_info, additional_information_length); - - /* Return successful completion. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_response_send_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the completion response to the client from the */ -/* application callback function. This is typically done to satisfy a */ -/* GET or POST request that is processed completely by the application */ -/* callback function. */ -/* */ -/* Note: The strings of status_code, information and */ -/* additional_information must be NULL-terminated and length of each */ -/* string matches the length specified in the argument list. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* information Pointer to HTTP info string */ -/* information_length Length of information */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* additional_information_length Length of additional */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_response_send Send HTTP response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_info, - UINT additional_info_length) -{ -UINT temp_status_code_length = 0; -UINT temp_information_length = 0; -UINT temp_additional_info_length = 0; - - /* Check length of status_code, information and additional information. */ - if (_nx_utility_string_length_check(status_code, &temp_status_code_length, NX_MAX_STRING_LENGTH) || - (information && _nx_utility_string_length_check(information, &temp_information_length, NX_MAX_STRING_LENGTH)) || - (additional_info && _nx_utility_string_length_check(additional_info, &temp_additional_info_length, NX_MAX_STRING_LENGTH))) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Validate string length. */ - if ((temp_status_code_length != status_code_length) || - (information && (temp_information_length != information_length)) || - (additional_info && (temp_additional_info_length != additional_info_length))) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - return(_nx_web_http_server_response_send(server_ptr, status_code, status_code_length, information, - information_length, additional_info, additional_info_length)); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_connection_end PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is an internal callback used by the TCP server when a */ -/* TCP connection is ready to close. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tcpserver_ptr Pointer to TCP server */ -/* session_ptr Pointer to TCP session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_connection_disconnect */ -/* Disconnect TCP or TLS */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_connection_end(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) -{ -NX_WEB_HTTP_SERVER *server_ptr; - - - /* Get the HTTP server pointer. */ - server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; - - /* Disconnect the TCP server (and end TLS if used). */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_connection_timeout PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is an internal callback used by the TCP server when a */ -/* TCP connection times out. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* tcpserver_ptr Pointer to TCP server */ -/* session_ptr Pointer to TCP session */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_connection_disconnect */ -/* Disconnect TCP or TLS */ -/* */ -/* CALLED BY */ -/* */ -/* NetX Duo */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_connection_timeout(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) -{ -NX_WEB_HTTP_SERVER *server_ptr; - - - /* Get the HTTP server pointer. */ - server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; - - /* Disconnect the TCP server (and end TLS if used). */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_connection_present PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is the callback function executed whenever a client */ -/* connection appears on the HTTP Server port. It is responsible for */ -/* waking up the HTTP Server thread. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* socket_ptr Pointer to HTTP Server socket */ -/* port HTTP Server port */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_get_client_request */ -/* Get request from client */ -/* _nx_web_http_server_connection_disconnect */ -/* Disconnect connection */ -/* _nx_web_http_server_get_client_keepalive */ -/* Get keepalive flag */ -/* _nx_web_http_server_chunked_check Check if the packet is chunked*/ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* _nx_web_http_server_delete_process Process DELETE request */ -/* _nx_web_http_server_response_packet_allocate */ -/* Allocate a response packet */ -/* */ -/* CALLED BY */ -/* */ -/* NetX */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_receive_data(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr) -{ - -NX_WEB_HTTP_SERVER *server_ptr; -NX_PACKET *packet_ptr; -UCHAR *buffer_ptr; -UINT status; -NX_PACKET *response_pkt; - - - /* Set the HTTP server pointer. */ - server_ptr = (NX_WEB_HTTP_SERVER *) tcpserver_ptr -> nx_tcpserver_reserved; - - /* Store the current session. */ - server_ptr -> nx_web_http_server_current_session_ptr = session_ptr; - - /* Get the complete HTTP client request. */ - status = _nx_web_http_server_get_client_request(server_ptr, &packet_ptr); - - /* Check if the HTTP request is valid. */ - if (status == NX_SUCCESS) - { - if (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr < 7) - { - nx_packet_release(packet_ptr); - status = NX_WEB_HTTP_ERROR; - } - } - - /* Determine if it was successful. */ - if (status != NX_SUCCESS) - { - - if(status != NX_NO_PACKET) - { - - /* Increment the number of invalid HTTP requests. */ - server_ptr -> nx_web_http_server_invalid_http_headers++; - } - - /* Disconnect from the current connection. */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); - - /* Return. */ - return; - } - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - /* Check whether keepalive is necessary. */ - _nx_web_http_server_get_client_keepalive(server_ptr, packet_ptr); -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* Check if the packet is chunked. */ - server_ptr -> nx_web_http_server_request_chunked = (UCHAR)_nx_web_http_server_chunked_check(packet_ptr); - server_ptr -> nx_web_http_server_expect_receive_bytes = 0; - server_ptr -> nx_web_http_server_actual_bytes_received = 0; - - /* Otherwise, we have received an HTTP client request successfully. */ - - /* Setup a pointer to packet buffer area. */ - buffer_ptr = packet_ptr -> nx_packet_prepend_ptr; - - /* Determine what type of request is present. */ - - /* Check for a GET request. */ - if ((buffer_ptr[0] == 'G') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) - { - - /* We have a HTTP GET request to get a resource from this HTTP Server. */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_GET_REQUEST; - - /* Increment the number of GET requests. */ - server_ptr -> nx_web_http_server_get_requests++; - - /* Process the GET request. */ - _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_GET_REQUEST, packet_ptr); - } - - /* Check for a PUT request. */ - else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'U') && (buffer_ptr[2] == 'T') && (buffer_ptr[3] == ' ')) - { - - /* We have a HTTP PUT request to store a resource on this HTTP Server. */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_PUT_REQUEST; - - /* Increment the number of PUT requests. */ - server_ptr -> nx_web_http_server_put_requests++; - - /* Process the PUT request. */ - _nx_web_http_server_put_process(server_ptr, packet_ptr); - } - - /* Check for a DELETE request. */ - else if ((buffer_ptr[0] == 'D') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'L') && (buffer_ptr[3] == 'E') && - (buffer_ptr[4] == 'T') && (buffer_ptr[5] == 'E') && (buffer_ptr[6] == ' ')) - { - - /* We have a HTTP DELETE request to delete a resource from this HTTP Server. */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_DELETE_REQUEST; - - /* Increment the number of DELETE requests. */ - server_ptr -> nx_web_http_server_delete_requests++; - - /* Process the Delete request. */ - _nx_web_http_server_delete_process(server_ptr, packet_ptr); - } - - /* Check for a POST request. */ - else if ((buffer_ptr[0] == 'P') && (buffer_ptr[1] == 'O') && (buffer_ptr[2] == 'S') && - (buffer_ptr[3] == 'T') && (buffer_ptr[4] == ' ')) - { - - /* We have a HTTP POST request to send data to this HTTP Server for processing. Note that the POST - request is nearly identical to the GET request, except the parameter/query data is found in the - content rather than as part of the URL (resource). */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_POST_REQUEST; - - /* Increment the number of POST requests. */ - server_ptr -> nx_web_http_server_post_requests++; - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - - /* Reset last received multipart packet. */ - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = NX_NULL; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - - /* Process the POST request. */ - _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_POST_REQUEST, packet_ptr); - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - /* Restore the packet to release. */ - if (server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet) - packet_ptr = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - } - - /* Check for a HEAD request. */ - else if ((buffer_ptr[0] == 'H') && (buffer_ptr[1] == 'E') && (buffer_ptr[2] == 'A') && - (buffer_ptr[3] == 'D') && (buffer_ptr[4] == ' ')) - { - - /* We have a HTTP HEAD request to get a resource header from this HTTP Server. Note that the HEAD - request is nearly identical to the GET request, except the requested content is not returned to - the client. */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_HEAD_REQUEST; - - /* Increment the number of HEAD requests. */ - server_ptr -> nx_web_http_server_head_requests++; - - /* Process the HEAD request. */ - _nx_web_http_server_get_process(server_ptr, NX_WEB_HTTP_SERVER_HEAD_REQUEST, packet_ptr); - } - - /* Unhandled request. */ - else - { - - /* We have an unhandled HTTP request. */ - server_ptr -> nx_web_http_server_request_type = NX_WEB_HTTP_SERVER_UNKNOWN_REQUEST; - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED, - sizeof(NX_WEB_HTTP_STATUS_NOT_IMPLEMENTED) - 1, - "NetX HTTP Request Not Implemented", - sizeof("NetX HTTP Request Not Implemented") - 1, NX_NULL, 0); - - /* Increment the number of unhandled requests. */ - server_ptr -> nx_web_http_server_unknown_requests++; - } - - /* Release the packet. */ - nx_packet_release(packet_ptr); - - /* Release the unprocessed packet. */ - if (server_ptr -> nx_web_http_server_request_packet) - { - nx_packet_release(server_ptr -> nx_web_http_server_request_packet); - server_ptr -> nx_web_http_server_request_packet = NX_NULL; - } - - /* If there are no more data to send, append the last chunk. */ - if (server_ptr -> nx_web_http_server_response_chunked) - { - - /* Allocate a packet to send the chunk end. */ - status = _nx_web_http_server_response_packet_allocate(server_ptr, &response_pkt, NX_WAIT_FOREVER); - if (status) - { - - /* Disconnect from the current connection. */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); - return; - } - - nx_packet_data_append(response_pkt, "0\r\n\r\n", 5, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Send internal. */ - status = _nx_web_http_server_send(server_ptr, response_pkt, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - if (status) - { - - /* Disconnect from the current connection. */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); - - nx_packet_release(response_pkt); - return; - } - - server_ptr -> nx_web_http_server_response_chunked = NX_FALSE; - } - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - if(server_ptr -> nx_web_http_server_keepalive == NX_FALSE) - { -#endif - /* Disconnect from the current connection. */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - } -#endif - - return; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_get_client_request PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the complete HTTP client request in a single*/ -/* packet. Doing this makes the other parsing and searching */ -/* routines simple. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Destination for request */ -/* packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_copy Copy packet */ -/* nx_packet_data_append Move data into packet */ -/* nx_packet_release Release packet */ -/* nx_tcp_socket_receive Receive an HTTP request packet*/ -/* */ -/* CALLED BY */ -/* _nx_web_http_server_receive_data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_get_client_request(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr) -{ - -NX_PACKET *head_packet_ptr; -NX_PACKET *new_packet_ptr; -CHAR *buffer_ptr; -UINT status; -NX_PACKET *work_ptr; -UINT crlf_found = 0; -NX_PACKET *tmp_ptr; - - - /* Default the return packet pointer to NULL. */ - *packet_ptr = NX_NULL; - - /* Wait for a request on the HTTP TCP well known port 80, or if encryption is enabled 443. */ - status = _nx_web_http_server_receive(server_ptr, &head_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* At this point, the server has a connection with an HTTP Client */ - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Return an error condition. */ - return(status); - } - - /* Setup pointer to start of buffer. */ - buffer_ptr = (CHAR *) head_packet_ptr -> nx_packet_prepend_ptr; - - /* Determine if the packet is an HTTP request. */ - if ((buffer_ptr[0] != 'G') && (buffer_ptr[0] != 'g') && (buffer_ptr[0] != 'P') && (buffer_ptr[0] != 'p') && - (buffer_ptr[0] != 'D') && (buffer_ptr[0] != 'd') && (buffer_ptr[0] != 'H') && (buffer_ptr[0] != 'h') && - (buffer_ptr[0] != 'T') && (buffer_ptr[0] != 't')) - { - - /* Invalid first packet for HTTP request. */ - - /* Release the packet. */ - nx_packet_release(head_packet_ptr); - - /* Return an error. */ - return(NX_WEB_HTTP_ERROR); - } - - crlf_found = 0; - work_ptr = head_packet_ptr; - - /* Build a pointer to the buffer area. */ - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - - do - { - - /* See if there is a blank line present in the buffer. */ - /* Search the buffer for a cr/lf pair. */ - while (buffer_ptr < (CHAR *) work_ptr -> nx_packet_append_ptr) - { - if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) - { - - /* Found CR. */ - crlf_found++; - } - else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) - { - - /* Found LF. */ - crlf_found++; - } - else - { - - /* Reset the CRLF marker. */ - crlf_found = 0; - } - - if (crlf_found == 4) - { - - /* Yes, we have found the end of the HTTP request header. */ - - /* Set the return packet pointer. */ - *packet_ptr = head_packet_ptr; - - /* Return a successful completion. */ - return(NX_SUCCESS); - } - - /* Move the buffer pointer up. */ - buffer_ptr++; - } - - /* Determine if the packet has already overflowed into another packet. */ - -#ifndef NX_DISABLE_PACKET_CHAIN - - if (work_ptr -> nx_packet_next != NX_NULL) - { - /* Get the next packet in the chain. */ - work_ptr = work_ptr -> nx_packet_next; - buffer_ptr = (CHAR *) work_ptr -> nx_packet_prepend_ptr; - } - else - -#endif - { - /* Receive another packet from the HTTP server port. */ - status = _nx_web_http_server_receive(server_ptr, &new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Release the current head packet. */ - nx_packet_release(head_packet_ptr); - - /* Return an error condition. */ - return(status); - } - - /* Successfully received another packet. Its contents now need to be placed in the head packet. */ - tmp_ptr = new_packet_ptr; -#ifndef NX_DISABLE_PACKET_CHAIN - while (tmp_ptr) - { -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Copy the contents of the current packet into the head packet. */ - status = nx_packet_data_append(head_packet_ptr, (VOID *) tmp_ptr -> nx_packet_prepend_ptr, - (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr), - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WEB_HTTP_SERVER_TIMEOUT); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Yes, an error is present. */ - - /* Release both packets. */ - nx_packet_release(head_packet_ptr); - nx_packet_release(new_packet_ptr); - - /* Return an error condition. */ - return(status); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - tmp_ptr = tmp_ptr -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Release the new packet. */ - nx_packet_release(new_packet_ptr); - } - - } while (status == NX_SUCCESS); - - /* Release the packet. */ - nx_packet_release(head_packet_ptr); - - return NX_WEB_HTTP_ERROR; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_get_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the GET, POST, and HEAD HTTP client */ -/* requests. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* request_type Type of request (GET, POST, */ -/* or HEAD) */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_basic_authenticate */ -/* Process basic authentication */ -/* _nx_web_http_server_digest_authenticate */ -/* Process digest authentication */ -/* _nx_web_http_server_calculate_content_offset */ -/* Retrieve content offset */ -/* _nx_web_http_server_content_length_get */ -/* Retrieve content length */ -/* _nx_web_http_server_response_send Send response back to client */ -/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ -/* _nx_web_http_server_type_get_extended Derive file type */ -/* _nx_web_http_server_packet_get Receive another packet */ -/* _nx_web_http_server_field_value_get Get field value */ -/* nx_tcp_socket_transmit_configure Configure the server socket */ -/* fx_directory_information_get Get length of resource file */ -/* fx_file_close Close resource file */ -/* fx_file_open Open resource file */ -/* fx_file_read Read data from resource file */ -/* _nx_web_http_server_reponse_packet_allocate */ -/* Allocate a response packet */ -/* nx_packet_release Release packet */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_receive_data HTTP receive processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_get_process(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr) -{ - -ULONG length = 0; -UINT file_type_length; -UINT status; -NX_PACKET *new_packet_ptr; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -ULONG temp; -CHAR temp_string[30]; -UINT auth_request_present = NX_FALSE; -NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; -UINT offset = 0; -UINT resource_length; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if a POST is present. */ - if (request_type == NX_WEB_HTTP_SERVER_POST_REQUEST) - { - - if (!server_ptr -> nx_web_http_server_request_chunked) - { - - /* It is. Check for a valid content-length field. */ - status = _nx_web_http_server_content_length_get(packet_ptr, &length); - - /* Check for errors. */ - if ( status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Length", - sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - } - - /* Check for an invalid content offset . */ - offset = _nx_web_http_server_calculate_content_offset(packet_ptr); - if (offset == 0) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Offset", - sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - /* Cleanup the multipart field. */ - memset(&server_ptr -> nx_web_http_server_multipart, 0, sizeof(NX_WEB_HTTP_SERVER_MULTIPART)); -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_web_http_server_authentication_check || - server_ptr -> nx_web_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || - (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#endif - - /* Determine if the authentication failed. */ - if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes it did. Inform the HTTP server application about the failed authentication. */ - if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) - { - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, request_type); - } - } - - return; - } - } - - /* Check whether a full response is necessary. */ - if((server_ptr -> nx_web_http_server_cache_info_get) && - (server_ptr -> nx_web_http_server_request_type == NX_WEB_HTTP_SERVER_GET_REQUEST)) - { - - /* Searching for "If-Modified-Since" header. */ - if(_nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"if-modified-since", 17, (UCHAR *)temp_string, sizeof(temp_string)) == NX_SUCCESS) - { - UINT max_age; - NX_WEB_HTTP_SERVER_DATE date; - CHAR date_string[30]; - - /* Get last modified date of this resource. */ - if(server_ptr -> nx_web_http_server_cache_info_get(server_ptr -> nx_web_http_server_request_resource, &max_age, &date) == NX_TRUE) - { - - /* Convert date to string, the return length is always 29. */ - temp = _nx_web_http_server_date_to_string(&date, date_string); - date_string[temp] = 0; - - /* Check the last modified date with if-modified-since. */ - if(memcmp(temp_string, date_string, temp + 1) == 0) - { - - /* Send not modified. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_MODIFIED, - sizeof(NX_WEB_HTTP_STATUS_NOT_MODIFIED) - 1, - NX_NULL, 0, NX_NULL, 0); - - /* Return to caller. */ - return; - } - } - } - } - - /* Setup the server socket with a specific packet transmit retry logic. */ - nx_tcp_socket_transmit_configure(socket_ptr, - NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH, - NX_WEB_HTTP_SERVER_RETRY_SECONDS*NX_IP_PERIODIC_RATE, - NX_WEB_HTTP_SERVER_RETRY_MAX, - NX_WEB_HTTP_SERVER_RETRY_SHIFT); - - /* At this point, either there isn't any required authentication for this resource or the authentication is - complete. */ - - /* If the HTTP server receives an empty POST request (no message body, content length = 0, it is the - responsibility of the request notify callback to send a response (if any) to the HTTP Client. - The HTTP server will process the request no further. */ - - /* Determine if a user supplied get function has been specified. */ - if (server_ptr -> nx_web_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the get request. */ - status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, request_type, server_ptr -> nx_web_http_server_request_resource, packet_ptr); - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - /* Release the packet that is not processed by callback function. */ - if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_next_packet) - nx_packet_release(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_next_packet); -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - - /* Determine if the user supplied routine is requesting the get should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) - { - - /* User callback routine already sent success response back to HTTP Client. */ - return; - } - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", - sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Yes, error was detected. Abort the remainder of the get processing. */ - return; - } - } - - /* If it's POST request, process the message body. */ - if (request_type == NX_WEB_HTTP_SERVER_POST_REQUEST) - { - - /* Was there a message body in the request? */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* Find the first chunk of the content. */ - status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); - if (status) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - nx_packet_release(packet_ptr); - } - else - { - if (length == 0) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - length -= (ULONG)(packet_ptr -> nx_packet_length - offset); - } - - /* If necessary, receive more packets from the TCP socket. */ - while (length || server_ptr -> nx_web_http_server_request_chunked) - { - - /* Wait for more packets. */ - status = _nx_web_http_server_packet_get(server_ptr, &new_packet_ptr); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - if (status == NX_WEB_HTTP_GET_DONE) - { - break; - } - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Receive Timeout", - sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - if (!server_ptr -> nx_web_http_server_request_chunked) - { - length -= new_packet_ptr -> nx_packet_length; - } - - nx_packet_release(new_packet_ptr); - } - } - - - /* Get the length of request resource. */ - if (_nx_utility_string_length_check(server_ptr -> nx_web_http_server_request_resource, &resource_length, - sizeof(server_ptr -> nx_web_http_server_request_resource) - 1)) - { - return; - } - - /* Open the specified file for reading. */ - status = fx_file_open(server_ptr -> nx_web_http_server_media_ptr, &(server_ptr -> nx_web_http_server_file), server_ptr -> nx_web_http_server_request_resource, FX_OPEN_FOR_READ); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_NOT_FOUND, - sizeof(NX_WEB_HTTP_STATUS_NOT_FOUND) - 1, - "NetX HTTP Server unable to find file: ", - sizeof("NetX HTTP Server unable to find file: ") - 1, - server_ptr -> nx_web_http_server_request_resource, - resource_length); - - /* Error, return to caller. */ - return; - } - - /* Calculate the size of the file. */ - length = 0; - fx_directory_information_get(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource, FX_NULL, - &length, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL, FX_NULL); - - /* Derive the file type. We use whatever value is returned since if there is no - match this function will return a default value. */ - _nx_web_http_server_type_get_extended(server_ptr, server_ptr -> nx_web_http_server_request_resource, resource_length, temp_string, sizeof(temp_string), &file_type_length); - - temp = file_type_length; - temp_string[temp] = 0; - - /* Now build a response header. */ - status = _nx_web_http_server_generate_response_header(server_ptr, &new_packet_ptr, NX_WEB_HTTP_STATUS_OK, - sizeof(NX_WEB_HTTP_STATUS_OK) - 1, length, temp_string, - file_type_length, NX_NULL, 0); - if(status) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", - sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Close the file. */ - fx_file_close(&(server_ptr -> nx_web_http_server_file)); - - /* Error, return to caller. */ - return; - } - - /* Check to see if only a response is required. */ - if ((!length) || (request_type == NX_WEB_HTTP_SERVER_HEAD_REQUEST)) - { - - /* Yes, only a response is required... send it! */ - status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Determine if this is successful. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Force zero length. */ - length = 0; - } - } - - /* Get length of packet */ - temp = new_packet_ptr -> nx_packet_length; - - /* Now, loop to send the data contents. If the request type is "HEAD", skip this loop to output the - file contents. */ - while ((length) && (request_type != NX_WEB_HTTP_SERVER_HEAD_REQUEST)) - { - - /* Determine if we need to allocate a new packet for data. */ - if (!temp) - { - - /* Yes, allocate a new packet. */ - status = _nx_web_http_server_response_packet_allocate(server_ptr, &new_packet_ptr, NX_WAIT_FOREVER); - - /* Determine if an error is present. */ - if (status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Error, return to caller. */ - break; - } - } - - /* Calculate the maximum length. */ - temp = ((ULONG) (new_packet_ptr -> nx_packet_data_end - new_packet_ptr -> nx_packet_append_ptr)) - NX_PHYSICAL_TRAILER; - - /* Determine if this exceeds the MSS of the peer. */ - if (temp > socket_ptr -> nx_tcp_socket_connect_mss) - { - - /* Yes, reduce the maximum size to the mss size. */ - temp = socket_ptr -> nx_tcp_socket_connect_mss; - } - - /* Read data from the file. */ - status = fx_file_read(&(server_ptr -> nx_web_http_server_file), new_packet_ptr -> nx_packet_append_ptr, - temp, &temp); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Error, return. */ - break; - } - - /* Update the packet information with the data read. */ - new_packet_ptr -> nx_packet_length = new_packet_ptr -> nx_packet_length + temp; - new_packet_ptr -> nx_packet_append_ptr = new_packet_ptr -> nx_packet_append_ptr + temp; - - /* Send the packet out. */ - status = _nx_web_http_server_send(server_ptr, new_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for success. */ - if (status != NX_SUCCESS) - { - - /* Release the packet. */ - nx_packet_release(new_packet_ptr); - - /* Return to caller. */ - break; - } - - /* Increment the bytes sent count. */ - server_ptr -> nx_web_http_server_total_bytes_sent = server_ptr -> nx_web_http_server_total_bytes_sent + temp; - - /* Adjust the file length based on what we have sent. */ - length = length - temp; - - /* Indicate new packet needed */ - temp = 0; - } - - /* Close the file. */ - fx_file_close(&(server_ptr -> nx_web_http_server_file)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_put_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the PUT HTTP client requests. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_basic_authenticate */ -/* Process basic authentication */ -/* _nx_web_http_server_digest_authenticate */ -/* Process digest authentication */ -/* _nx_web_http_server_calculate_content_offset */ -/* Retrieve content offset */ -/* _nx_web_http_server_content_length_get */ -/* Retrieve content length */ -/* _nx_web_http_server_response_send Send response back to client */ -/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ -/* _nx_web_http_server_packet_get Receive another packet */ -/* fx_file_close Close resource file */ -/* fx_file_create Create resource file */ -/* fx_file_open Open resource file */ -/* fx_file_write Write data to resource file */ -/* nx_packet_release Release packet */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_content_get Content get processing */ -/* _nx_web_http_server_get_process GET request processing */ -/* _nx_web_http_server_put_process PUT request processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_put_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -ULONG length = 0; -UINT offset; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -NX_PACKET *data_packet_ptr; -NX_PACKET *next_packet_ptr; -UINT auth_request_present = NX_FALSE; -NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", - sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - if (!server_ptr -> nx_web_http_server_request_chunked) - { - - /* Calculate the content length from the request. */ - status = _nx_web_http_server_content_length_get(packet_ptr, &length); - - /* Determine if the content length is valid. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Length", - sizeof("NetX HTTP Invalid Content Length") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - } - - /* Calculate the offset to the content (the two Cr LF tokens) in the request. */ - offset = _nx_web_http_server_calculate_content_offset(packet_ptr); - - /* Determine if the offset to the content is valid. */ - if (offset == 0) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP Invalid Content Offset", - sizeof("NetX HTTP Invalid Content Offset") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_web_http_server_authentication_check || - server_ptr -> nx_web_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || - (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#endif - - /* Determine if the authentication is currently in progress. */ - if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ - if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) - { - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, NX_WEB_HTTP_SERVER_PUT_REQUEST); - } - } - - return; - } - } - - /* At this point, either there isn't any required authentication for this resource or the authentication is - complete. */ - - /* If the request is empty (content-length = 0) the request notify callback is where a response is generated - to return to the Client. NetX HTTP Server will not process an empty request further. */ - - /* Determine if a user supplied get function has been specified. */ - if (server_ptr -> nx_web_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the put request. */ - status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, NX_WEB_HTTP_SERVER_PUT_REQUEST, server_ptr -> nx_web_http_server_request_resource, packet_ptr); - - /* Determine if the user supplied routine is requesting the put should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) - { - - /* Send success response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_OK, - sizeof(NX_WEB_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); - return; - } - - /* No, an error was detected. Abort the remainder of the get processing. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", - sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - return; - } - } - - /* Was there a message body in the request? */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* Find the first chunk of the content. */ - status = _nx_web_http_server_packet_content_find(server_ptr, &packet_ptr, NX_NULL); - if (status) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - offset = 0; - length = packet_ptr -> nx_packet_length; - } - else if (length == 0) - { - - /* No. Regardless if a reply was sent via the request notify callback, we are done with this packet. */ - return; - } - - /* Otherwise, everything is okay... complete the request. */ - - /* Create the specified file. */ - status = fx_file_create(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource); - - - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Create Failed", - sizeof("NetX HTTP File Create Failed") - 1, NX_NULL, 0); - - /* Release first chunked packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - nx_packet_release(packet_ptr); - } - - /* Error, return to caller. */ - return; - } - - /* Open the specified file for writing. */ - status = fx_file_open(server_ptr -> nx_web_http_server_media_ptr, &(server_ptr -> nx_web_http_server_file), server_ptr -> nx_web_http_server_request_resource, FX_OPEN_FOR_WRITE); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Open Failed", - sizeof("NetX HTTP File Open Failed") - 1, NX_NULL, 0); - - /* Release first chunked packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - nx_packet_release(packet_ptr); - } - - /* Error, return to caller. */ - return; - } - - /* Determine if there is any content in the first packet. */ - if ((UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) > offset) - { - - /* Write the content found in this packet. */ - status = fx_file_write(&(server_ptr -> nx_web_http_server_file), (packet_ptr -> nx_packet_prepend_ptr + offset), - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", - sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Release first chunked packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - nx_packet_release(packet_ptr); - } - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); - - /* Increment the bytes received count. */ - server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + - ((ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) - offset); - } - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Loop to write chained packets out to the file. */ - next_packet_ptr = packet_ptr -> nx_packet_next; - while ((length) && (next_packet_ptr)) - { - - /* Write the content of the next packet. */ - status = fx_file_write(&(server_ptr -> nx_web_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", - sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Release first chunked packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - nx_packet_release(packet_ptr); - } - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Increment the bytes received count. */ - server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Move to the next pointer. */ - next_packet_ptr = next_packet_ptr -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Release first chunked packet. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - nx_packet_release(packet_ptr); - } - - /* If necessary, receive more packets from the TCP socket to complete the write request. */ - while (length || server_ptr -> nx_web_http_server_request_chunked) - { - - /* Wait for a request. */ - status = _nx_web_http_server_packet_get(server_ptr, &data_packet_ptr); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - if (status == NX_WEB_HTTP_GET_DONE) - { - break; - } - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Receive Timeout", - sizeof("NetX HTTP Receive Timeout") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - if (server_ptr -> nx_web_http_server_request_chunked) - { - length = data_packet_ptr -> nx_packet_length; - } - - /* Loop to write the packet chain out to the file. */ - next_packet_ptr = data_packet_ptr; - do - { - - /* Write the content of this packet. */ - status = fx_file_write(&(server_ptr -> nx_web_http_server_file), next_packet_ptr -> nx_packet_prepend_ptr, - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr)); - - /* Check the status. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Write Failed", - sizeof("NetX HTTP File Write Failed") - 1, NX_NULL, 0); - - /* Release the previous data packet. */ - nx_packet_release(data_packet_ptr); - - /* Error, return to caller. */ - return; - } - - /* Update the length. */ - length = length - (UINT)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - - /* Increment the bytes received count. */ - server_ptr -> nx_web_http_server_total_bytes_received = server_ptr -> nx_web_http_server_total_bytes_received + - (ULONG)(next_packet_ptr -> nx_packet_append_ptr - next_packet_ptr -> nx_packet_prepend_ptr); - -#ifdef NX_DISABLE_PACKET_CHAIN - next_packet_ptr = NX_NULL; -#else - /* Move to the next pointer. */ - next_packet_ptr = next_packet_ptr -> nx_packet_next; -#endif /* NX_DISABLE_PACKET_CHAIN */ - - } while ((length) && (next_packet_ptr)); - - /* Release the previous data packet. */ - nx_packet_release(data_packet_ptr); - } - - /* Success, at this point close the file and prepare a successful response for the client. */ - fx_file_close(&(server_ptr -> nx_web_http_server_file)); - - - /* Now build a response header. */ - status = _nx_web_http_server_generate_response_header(server_ptr, &data_packet_ptr, NX_WEB_HTTP_STATUS_OK, - sizeof(NX_WEB_HTTP_STATUS_OK) - 1, 0, - NX_NULL, 0, NX_NULL, 0); - if (status == NX_SUCCESS) - { - - /* Send the response back to the client. */ - status = _nx_web_http_server_send(server_ptr, data_packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(data_packet_ptr); - } - } - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_delete_process PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function processes the DELETE HTTP client requests. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_basic_authenticate */ -/* Process basic authentication */ -/* _nx_web_http_server_digest_authenticate */ -/* Process digest authentication */ -/* _nx_web_http_server_response_send Send response back to client */ -/* _nx_web_http_server_retrieve_resource Retrieve resource from request*/ -/* fx_file_delete Delete resource file */ -/* nx_packet_release Release packet */ -/* _nx_web_http_server_send Send packet to client */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_receive_data HTTP Server receive processing*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_delete_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - -UINT status; -CHAR *name_ptr; -CHAR *password_ptr; -CHAR *realm_ptr; -NX_PACKET *response_ptr; -UINT auth_request_present = NX_FALSE; -NX_TCP_SOCKET *socket_ptr = &server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket; -UINT name_length = 0; -UINT password_length = 0; -UINT realm_length = 0; -UINT temp_name_length = 0; -UINT temp_password_length = 0; -UINT temp_realm_length = 0; - - - /* Pickup the URL (resource) from the request. */ - status = _nx_web_http_server_retrieve_resource(server_ptr, packet_ptr, server_ptr -> nx_web_http_server_request_resource, NX_WEB_HTTP_MAX_RESOURCE + 1); - - /* Determine if the resource was extracted successfully. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_BAD_REQUEST, - sizeof(NX_WEB_HTTP_STATUS_BAD_REQUEST) - 1, - "NetX HTTP URL Bad", - sizeof("NetX HTTP URL Bad") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Determine if the application has specified an authentication function for this server. */ - if (server_ptr -> nx_web_http_server_authentication_check || - server_ptr -> nx_web_http_server_authentication_check_extended) - { - - /* Determine if authentication is required for the specified resource. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended) - { - status = (server_ptr -> nx_web_http_server_authentication_check_extended)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &name_length, &password_ptr, &password_length, &realm_ptr, &realm_length); - } - else - { - status = (server_ptr -> nx_web_http_server_authentication_check)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, - &name_ptr, &password_ptr, &realm_ptr); - } - - if ((status == NX_WEB_HTTP_BASIC_AUTHENTICATE) || - (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE)) - { - - /* Check name, password and realm string. */ - if (_nx_utility_string_length_check(name_ptr, &temp_name_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password_ptr, &temp_password_length, NX_WEB_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm_ptr, &temp_realm_length, NX_MAX_STRING_LENGTH)) - { - - /* Error, return to caller. */ - return; - } - - /* Validate string length. */ - if (server_ptr -> nx_web_http_server_authentication_check_extended && - ((realm_length != temp_realm_length) || - (name_length != temp_name_length) || - (password_length != temp_password_length))) - { - return; - } - } - - /* Determine what kind - if any - authentication is requested for this resource. */ - if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) - { - - /* Process basic authentication request. */ - status = _nx_web_http_server_basic_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - else if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) - { - - /* Process digest authentication request. */ - status = _nx_web_http_server_digest_authenticate(server_ptr, packet_ptr, name_ptr, password_ptr, realm_ptr, &auth_request_present); - } -#endif - - /* Determine if the authentication is currently in progress. */ - if ((status != NX_WEB_HTTP_DONT_AUTHENTICATE) && (status != NX_SUCCESS)) - { - - /* Yes, authentication is in progress. The HTTP 401 has already been sent. */ - if (server_ptr -> nx_web_http_server_invalid_username_password_callback && auth_request_present) - { - NXD_ADDRESS client_nxd_address; - ULONG client_port; - - /* Get the IP address of the client: */ - status = nxd_tcp_socket_peer_info_get(socket_ptr, &client_nxd_address , &client_port); - - if (status == NX_SUCCESS) - { - /* Send this information to the host application. */ - (server_ptr -> nx_web_http_server_invalid_username_password_callback)(server_ptr -> nx_web_http_server_request_resource, &client_nxd_address, NX_WEB_HTTP_SERVER_DELETE_REQUEST); - } - } - - return; - } - } - - /* Determine if a user supplied notify function has been specified. */ - if (server_ptr -> nx_web_http_server_request_notify) - { - - /* Call the user supplied function to notify the user of the delete request. */ - status = (server_ptr -> nx_web_http_server_request_notify)(server_ptr, NX_WEB_HTTP_SERVER_DELETE_REQUEST, server_ptr -> nx_web_http_server_request_resource, packet_ptr); - - /* Determine if the user supplied routine is requesting the delete should be aborted. */ - if (status != NX_SUCCESS) - { - - /* Determine if the user callback routine successfully completed the request processing. */ - if (status == NX_WEB_HTTP_CALLBACK_COMPLETED) - { - - /* Send success response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_OK, - sizeof(NX_WEB_HTTP_STATUS_OK) - 1, NX_NULL, 0, NX_NULL, 0); - return; - } - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP Request Aborted", - sizeof("NetX HTTP Request Aborted") - 1, NX_NULL, 0); - - /* Yes, error was detected. Abort the remainder of the delete processing. */ - return; - } - } - - /* Otherwise, everything is okay... complete the request. */ - - /* Delete the specified file. */ - status = fx_file_delete(server_ptr -> nx_web_http_server_media_ptr, server_ptr -> nx_web_http_server_request_resource); - - /* Check for error condition. */ - if (status != NX_SUCCESS) - { - - /* Send response back to HTTP Client. */ - _nx_web_http_server_response_send(server_ptr, NX_WEB_HTTP_STATUS_INTERNAL_ERROR, - sizeof(NX_WEB_HTTP_STATUS_INTERNAL_ERROR) - 1, - "NetX HTTP File Delete Failed", - sizeof("NetX HTTP File Delete Failed") - 1, NX_NULL, 0); - - /* Error, return to caller. */ - return; - } - - /* Now build a response header. */ - status = _nx_web_http_server_generate_response_header(server_ptr, &response_ptr, NX_WEB_HTTP_STATUS_OK, - sizeof(NX_WEB_HTTP_STATUS_OK) - 1, 0, NX_NULL, 0, NX_NULL, 0); - if (status == NX_SUCCESS) - { - - /* Send the response back to the client. */ - status = _nx_web_http_server_send(server_ptr, response_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(response_ptr); - } - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_invalid_userpassword_notify_set */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for service to set invalid */ -/* username password callback function. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* invalid_username_password_callback Pointer to application's */ -/* invalid username password */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) -{ - -UINT status; - - - if ((http_server_ptr == NX_NULL) || (invalid_username_password_callback == NX_NULL)) - { - return NX_PTR_ERROR; - } - - status = _nx_web_http_server_invalid_userpassword_notify_set(http_server_ptr, invalid_username_password_callback); - - return status; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_invalid_userpassword_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets invalid username password callback function */ -/* */ -/* Note: The string resource in callback function */ -/* invalid_username_password_callback is built by internal logic and */ -/* always NULL-terminated. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* invalid_username_password_callback Pointer to application's */ -/* invalid username password */ -/* callback function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)) -{ - - http_server_ptr -> nx_web_http_server_invalid_username_password_callback = invalid_username_password_callback; - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_response_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends the specified Server response to the requesting */ -/* HTTP client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* information Pointer to HTTP info string */ -/* information_length Length of information */ -/* additional_information Pointer to additional HTTP */ -/* information */ -/* additional_information_length Length of additional */ -/* information */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_generate_response_header */ -/* Generate response header */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* _nx_web_http_server_send Send HTTP Server response */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_receive HTTP receive processing */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* _nx_web_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_information, - UINT additional_information_length) -{ - -UINT status; -UINT length; -NX_PACKET *packet_ptr; - - /* Determine if there is additional information. */ - if(information) - { - - /* Calculate the size of the information field. */ - length = information_length; - - /* Determine if there is additional information. */ - if (additional_information) - { - - /* Update the length with it as well. */ - length = length + additional_information_length; - } - } - else - length = 0; - - /* Generate response header. */ - status = _nx_web_http_server_generate_response_header(server_ptr, &packet_ptr, status_code, - status_code_length, length, NX_NULL, 0, NX_NULL, 0); - - /* Determine if an error occurred. */ - if (status != NX_SUCCESS) - { - - /* Just return. */ - return(status); - } - - /* Determine if there is additional information. */ - if (information) - { - - /* Place the first informational field. */ - status = nx_packet_data_append(packet_ptr, information, information_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* If there is additional information, place it in the buffer as well. */ - if (additional_information) - { - - /* Now, place the additional informational field. */ - status += nx_packet_data_append(packet_ptr, additional_information, additional_information_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet and return. */ - nx_packet_release(packet_ptr); - return(status); - } - - /* Send the response back to the client. */ - status = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_basic_authenticate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for basic (name & password) authentication. */ -/* If found and correct, it returns a success. Otherwise, it returns */ -/* an authentication request to the requesting client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* name_ptr Pointer to name string */ -/* password_ptr Pointer to password string */ -/* realm_ptr Pointer to realm string */ -/* auth_request_present Indicate if authentication */ -/* must be performed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_retrieve_basic_authorization */ -/* Pickup authorization */ -/* _nx_web_http_base64_decode Decode authorization */ -/* _nx_web_http_server_response_packet_allocate */ -/* Allocate a response packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* _nx_web_http_server_send Send HTTP Server response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* _nx_web_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_basic_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present) -{ - -UINT i, j; -UINT status, status1; -CHAR quote[2] = {0x22, 0}; -CHAR crlf[2] = {13,10}; -UINT match; -UINT realm_length; -UINT length; - - /* Default to no authentication request detected. */ - *auth_request_present = NX_FALSE; - - /* Default the status to authenticate. */ - status = NX_WEB_HTTP_BASIC_AUTHENTICATE; - - memset(&authorization_request[0], 0, sizeof(authorization_request)); - - memset(&authorization_decoded[0], 0, sizeof(authorization_decoded)); - - /* Is the authorization request present? */ - length = _nx_web_http_server_retrieve_basic_authorization(packet_ptr, authorization_request); - if (length) - { - - /* Yes, an authorization request is present. */ - *auth_request_present = NX_TRUE; - - /* Convert the request from Base64 representation to ASCII. */ - _nx_web_http_base64_decode(authorization_request, length, authorization_decoded); - - /* See if it is valid. */ - - /* Compare the name. */ - i = 0; - match = NX_TRUE; - while (name_ptr[i] && (i < sizeof(authorization_decoded))) - { - - /* Is there a mismatch? */ - if (name_ptr[i] != authorization_decoded[i]) - { - - /* Name mismatch. Continue to avoid timing attack. */ - match = NX_FALSE; - } - - /* Move to next character. */ - i++; - } - - /* Determine if everything matches. */ - if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == ':')) - { - - /* Move the authorization index past the semicolon. */ - i++; - - /* Now compare the passwords. */ - j = 0; - match = NX_TRUE; - while (password_ptr[j] && (i < sizeof(authorization_decoded))) - { - - /* Is there a mismatch? */ - if (password_ptr[j] != authorization_decoded[i]) - { - - /* Password mismatch. Continue to avoid timing attack. */ - match = NX_FALSE; - } - - /* Move to next character. */ - i++; - j++; - } - - /* Determine if we have a match. */ - if (match && (i < sizeof(authorization_decoded)) && (authorization_decoded[i] == (CHAR) NX_NULL)) - { - - /* Yes, we have successful authorization!! */ - status = NX_SUCCESS; - } - } - } - - /* Determine if we need to send back an unauthorized request. */ - if (status == NX_WEB_HTTP_BASIC_AUTHENTICATE) - { - - /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ - - if (_nx_utility_string_length_check(realm_ptr, &realm_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Allocate a packet for sending the response back. */ - status1 = _nx_web_http_server_response_packet_allocate(server_ptr, &packet_ptr, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if (status1 != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Just return. */ - return(status1); - } - - /* Insert the response header. */ - nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, NX_WEB_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_WEB_HTTP_STATUS_UNAUTHORIZED) - 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the type of authentication requested. */ - nx_packet_data_append(packet_ptr, "WWW-Authenticate: Basic realm=", 30, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the realm string into the buffer. */ - nx_packet_data_append(packet_ptr, realm_ptr, realm_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place another into the buffer to signal end of FULL HTTP response. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Send the response back to the client. */ - status1 = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status1) - { - - /* Return the internal NetX error. */ - status = status1; - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Return the result of the authentication request. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_retrieve_basic_authorization PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves basic authentication information from the */ -/* HTTP request packet. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Request packet pointer */ -/* authorization_request_ptr Pointer to destination for */ -/* authorization string */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_basic_authenticate */ -/* Basic authenticate processing */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr) -{ - -UINT length; -UINT found; -CHAR *buffer_ptr; - - - /* Set the found flag to false. */ - found = NX_FALSE; - - /* Default the authorization request to zero. */ - length = 0; - - /* Set the authorization request string to NULL. */ - authorization_request_ptr[0] = NX_NULL; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - - /* Find the "Authorization: " token first. */ - while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Authorization: token. */ - if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && - ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && - ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && - ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && - ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && - ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && - ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && - ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && - ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && - ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && - ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && - ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && - (*(buffer_ptr+13) == ':') && - (*(buffer_ptr+14) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 15; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now check for the "Basic " token. */ - while (((buffer_ptr+6) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Basic token. */ - if (((*buffer_ptr == 'b') || (*buffer_ptr == 'B')) && - ((*(buffer_ptr+1) == 'a') || (*(buffer_ptr+1) == 'A')) && - ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+3) == 'i') || (*(buffer_ptr+3) == 'I')) && - ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+4) == 'C')) && - (*(buffer_ptr+5) == ' ')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 6; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the authorization string. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_STRING)) - { - - /* Copy a character of the authorization string into the destination. */ - authorization_request_ptr[length] = *buffer_ptr++; - length++; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_retrieve_resource PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the resource (URL) portion of the request */ -/* and places it in the destination. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* destination Destination for resource */ -/* max_size Maximum size of destination */ -/* */ -/* OUTPUT */ -/* */ -/* Status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* _nx_web_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_retrieve_resource(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *destination, UINT max_size) -{ - -UINT i; -CHAR *buffer_ptr; - -#ifndef NX_WEB_HTTPS_ENABLE - NX_PARAMETER_NOT_USED(server_ptr); -#endif /* NX_WEB_HTTPS_ENABLE */ - - /* Set the destination to NULL. */ - destination[0] = (CHAR) 0; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the first space which is the start position of URI. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ')) - { - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Check for an error condition. */ - if (*buffer_ptr != ' ') - return(NX_WEB_HTTP_ERROR); - - buffer_ptr++; - -#ifdef NX_WEB_HTTPS_ENABLE - - if (server_ptr -> nx_web_http_is_https_server) - { - if ((buffer_ptr + 8 < (CHAR *)packet_ptr->nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Check whether it is an absoluteURI*/ - if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && - ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && - ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 2) == 'T')) && - ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 3) == 'P')) && - ((*(buffer_ptr + 4) == 's') || (*(buffer_ptr + 4) == 'S')) && - (*(buffer_ptr + 5) == ':') && - (*(buffer_ptr + 6) == '/') && - (*(buffer_ptr + 7) == '/')) - { - - /* Yes it is. Find the absolute path. */ - buffer_ptr += 8; - - /* Find the first slash character. The first slash marks the beginning of the URL. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR)0) && (*buffer_ptr != '/')) - { - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - } - } - - } - else -#endif - { - if ((buffer_ptr + 7 < (CHAR *)packet_ptr->nx_packet_append_ptr) && (*buffer_ptr != '/')) - { - - /* Check whether it is an absoluteURI*/ - if (((*buffer_ptr == 'h') || (*buffer_ptr == 'H')) && - ((*(buffer_ptr + 1) == 't') || (*(buffer_ptr + 1) == 'T')) && - ((*(buffer_ptr + 2) == 't') || (*(buffer_ptr + 2) == 'T')) && - ((*(buffer_ptr + 3) == 'p') || (*(buffer_ptr + 3) == 'P')) && - (*(buffer_ptr + 4) == ':') && - (*(buffer_ptr + 5) == '/') && - (*(buffer_ptr + 6) == '/')) - { - - /* Yes it is. Find the absolute path. */ - buffer_ptr += 7; - - /* Find the first slash character. The first slash marks the beginning of the URL. */ - while ((buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR)0) && (*buffer_ptr != '/')) - { - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - } - } - } - - /* Check for an error condition. */ - if ((buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != '/')) - return(NX_WEB_HTTP_ERROR); - - /* Copy the rest of the resource to the destination. Space, semicolon, and question mark characters signal the - end of the resource. */ - i = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ' ') && (*buffer_ptr != ';') && (*buffer_ptr != '?') && (i < (max_size-1))) - { - - /* Check escape characters. */ - if(*buffer_ptr == '%') - { - - /* It is an escape character. */ - if((buffer_ptr + 2) < (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - - /* Convert the HEX number. */ - buffer_ptr++; - if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - destination[i] = (CHAR)(*buffer_ptr - '0'); - else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) - destination[i] = (CHAR)(*buffer_ptr - 'a' + 10); - else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) - destination[i] = (CHAR)(*buffer_ptr - 'A' + 10); - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_WEB_HTTP_ERROR); - } - destination[i] = (CHAR)(destination[i] << 4); - - /* Convert the HEX number. */ - buffer_ptr++; - if((*buffer_ptr >= '0') && (*buffer_ptr <= '9')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - '0')); - else if((*buffer_ptr >= 'a') && (*buffer_ptr <= 'f')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'a' + 10)); - else if((*buffer_ptr >= 'A') && (*buffer_ptr <= 'F')) - destination[i] = (CHAR)(destination[i] + (*buffer_ptr - 'A' + 10)); - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_WEB_HTTP_ERROR); - } - - /* Move to the next byte. */ - i++; - buffer_ptr++; - } - else - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_WEB_HTTP_ERROR); - } - } - else - { - - /* Copy the URL name into the destination. */ - destination[i++] = *buffer_ptr++; - } - } - - /* Determine if the resource was retrieved. */ - if ((destination[0] == (CHAR) 0) || (buffer_ptr >= (CHAR *)packet_ptr -> nx_packet_append_ptr) || ((*buffer_ptr != ' ') && (*buffer_ptr != '?') && (*buffer_ptr != ';'))) - { - - /* Error picking up the resource. */ - destination[0] = (CHAR) 0; - return(NX_WEB_HTTP_ERROR); - } - - /* Everything is okay, place a NULL at the end of the resource. */ - destination[i] = (CHAR) 0; - - /* Return success. */ - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_calculate_content_offset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function calculates the byte offset to the start of the */ -/* HTTP request content area. This area immediately follows the HTTP */ -/* request header (which ends with a blank line). */ -/* */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to request packet */ -/* */ -/* OUTPUT */ -/* */ -/* Byte Offset (0 implies no content) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_content_get Application content get */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_calculate_content_offset(NX_PACKET *packet_ptr) -{ - -UINT offset; -CHAR *buffer_ptr; -UINT crlf_found = 0; - - - /* Default the content offset to zero. */ - offset = 0; - - /* Find the "cr,lf,cr,lf" token. */ -#ifndef NX_DISABLE_PACKET_CHAIN - while(packet_ptr) - { -#endif - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - while(buffer_ptr < (CHAR *)packet_ptr -> nx_packet_append_ptr) - { - if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13)) - { - - /* Found CR. */ - crlf_found++; - } - else if ((crlf_found & 1) && (*buffer_ptr == (CHAR)10)) - { - - /* Found LF. */ - crlf_found++; - } - else - { - - /* Reset the CRLF marker. */ - crlf_found = 0; - } - - offset++; - buffer_ptr++; - - if (crlf_found == 4) - { - - /* Return the offset to the caller. */ - return(offset); - } - } - -#ifndef NX_DISABLE_PACKET_CHAIN - packet_ptr = packet_ptr -> nx_packet_next; - } -#endif - - /* Not found the "cr,lf,cr,lf". */ - return(0); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_number_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a number into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* number Unsigned integer number */ -/* string Destination string */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* (0 implies an error) */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_response_send Send response to client */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_number_convert(UINT number, CHAR *string) -{ - -UINT j; -UINT digit; -UINT size; - - - /* Initialize counters. */ - size = 0; - - /* Loop to convert the number to ASCII. */ - while (size < 10) - { - - /* Shift the current digits over one. */ - for (j = size; j != 0; j--) - { - - /* Move each digit over one place. */ - string[j] = string[j-1]; - } - - /* Compute the next decimal digit. */ - digit = number % 10; - - /* Update the input number. */ - number = number / 10; - - /* Store the new digit in ASCII form. */ - string[0] = (CHAR) (digit + 0x30); - - /* Increment the size. */ - size++; - - /* Determine if the number is now zero. */ - if (number == 0) - break; - } - - /* Make the string NULL terminated. */ - string[size] = (CHAR) NX_NULL; - - /* Determine if there is an overflow error. */ - if (number) - { - - /* Error, return bad values to user. */ - size = 0; - string[0] = '0'; - } - - /* Return size to caller. */ - return(size); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for deriving the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* string_size Return HTTP type string size */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_type_get */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (name == NX_NULL) || (http_type_string == NX_NULL) || (string_size == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - status = _nx_web_http_server_type_get(server_ptr, name, http_type_string, string_size); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_type_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* http_type_string Destination HTTP type string */ -/* string_size Return HTTP type string size */ -/* */ -/* OUTPUT */ -/* */ -/* Size Number of bytes in string */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_memicmp */ -/* _nx_utility_string_length_check */ -/* memcpy */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_type_get_extended Get MIME type */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size) -{ -UINT temp_name_length; - - /* Check name length. */ - if (_nx_utility_string_length_check(name, &temp_name_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Call actual service type get function. */ - return(_nx_web_http_server_type_get_extended(server_ptr, name, temp_name_length, - http_type_string, NX_MAX_STRING_LENGTH + 1, - string_size)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_type_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for deriving the type of the resource. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* name_length Length of name string */ -/* http_type_string Destination HTTP type string */ -/* http_type_string_max_size Size of the destination string*/ -/* string_size Return HTTP type string size */ -/* */ -/* OUTPUT */ -/* */ -/* Status Web HTTP status code */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_type_get_extended Get MIME type */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, - CHAR *http_type_string, UINT http_type_string_max_size, - UINT *string_size) -{ -UINT status; - - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (name == NX_NULL) || (http_type_string == NX_NULL) || (string_size == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - status = _nx_web_http_server_type_get_extended(server_ptr, name, name_length, http_type_string, - http_type_string_max_size, string_size); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_type_get_extended PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function derives the type of the resource. */ -/* */ -/* Note: The string of name must be NULL-terminated and length of each */ -/* string matches the length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* name Name string */ -/* name_length Length of name string */ -/* http_type_string Destination HTTP type string */ -/* http_type_string_max_size Size of the destination string*/ -/* string_size Return HTTP type string size */ -/* */ -/* OUTPUT */ -/* */ -/* Status Web HTTP status code */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_memicmp Compare ignore case */ -/* _nx_utility_string_length_check String length check */ -/* memcpy Copy memory data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process Process GET request */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, - CHAR *http_type_string, UINT http_type_string_max_size, - UINT *string_size) -{ - -UINT i; -CHAR *ch; -UINT ext_length; -UINT map_ext_length; -UINT map_type_length; -UINT temp_name_length; - - /* Check name length. */ - if (_nx_utility_string_length_check(name, &temp_name_length, name_length)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Validate string length. */ - if (name_length != temp_name_length) - { - return(NX_WEB_HTTP_ERROR); - } - - /* First find the end of the string. */ - ch = name + name_length; - - /* Now look backwards to find the last period that signals the - file extension. */ - ext_length = 0; - while ((ch >= name) && (*ch != '.') &&(*ch != '/')) - { - ch--; - ext_length++; - } - - if(*ch != '.') - { - - /* No extension is found. Return the default mime type. */ - if(http_type_string_max_size < (sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME))) - { - /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into - the caller-supplied http_type_string. */ - return (NX_WEB_HTTP_ERROR); - } - - - /* No extension is found. Return the default mime type. */ - memcpy(http_type_string, NX_WEB_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME)); - *string_size = sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME) - 1; - return(NX_WEB_HTTP_EXTENSION_MIME_DEFAULT); - } - - /* Position forward again, past the period. */ - ch++; - ext_length--; - - /* Now see what HTTP file type to return. */ - /* Search user defined MIME maps first. */ - if(server_ptr -> nx_web_http_server_mime_maps_additional && - (server_ptr -> nx_web_http_server_mime_maps_additional_num > 0)) - { - for(i = 0; i < server_ptr -> nx_web_http_server_mime_maps_additional_num; i++) - { - - /* Check map extension and type length. */ - if (_nx_utility_string_length_check(server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_extension, - &map_ext_length, ext_length) || - _nx_utility_string_length_check(server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_type, - &map_type_length, http_type_string_max_size - 1)) - { - continue; - } - - if(_nx_web_http_server_memicmp((UCHAR *)ch, ext_length, - (UCHAR *)server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_extension, - map_ext_length) == NX_SUCCESS) - { - - /* Find the extension. Return the mapped MIME type. */ - memcpy(http_type_string, server_ptr -> nx_web_http_server_mime_maps_additional[i].nx_web_http_server_mime_map_type, map_type_length + 1); - *string_size = map_type_length; - return(NX_SUCCESS); - } - } - } - - /* Search default MIME maps. */ - for(i = 0; i < sizeof(_nx_web_http_server_mime_maps) / sizeof(NX_WEB_HTTP_SERVER_MIME_MAP); i++) - { - - /* Check map extension and type length. */ - if (_nx_utility_string_length_check(_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_extension, - &map_ext_length, ext_length) || - _nx_utility_string_length_check(_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_type, - &map_type_length, http_type_string_max_size - 1)) - { - continue; - } - - if(_nx_web_http_server_memicmp((UCHAR *)ch, ext_length, - (UCHAR *)_nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_extension, - map_ext_length) == NX_SUCCESS) - { - - /* Find the extension. Return the mapped MIME type. */ - memcpy(http_type_string, _nx_web_http_server_mime_maps[i].nx_web_http_server_mime_map_type, map_type_length + 1); - *string_size = map_type_length; - return(NX_SUCCESS); - } - } - - /* No extension matches. Return the default mime type. */ - - if(http_type_string_max_size < (sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME))) - { - /* NX_HTTP_SERVER_DEFAULT_MIME does not fit into - the caller-supplied http_type_string. */ - return (NX_WEB_HTTP_ERROR); - } - - memcpy(http_type_string, NX_WEB_HTTP_SERVER_DEFAULT_MIME, sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME)); - *string_size = sizeof(NX_WEB_HTTP_SERVER_DEFAULT_MIME) - 1; - return(NX_WEB_HTTP_EXTENSION_MIME_DEFAULT); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_base64_encode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function encodes the input string into a base64 */ -/* representation. */ -/* */ -/* INPUT */ -/* */ -/* name Name string */ -/* name Length of name */ -/* base64name Encoded base64 name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* None */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_base64_encode(CHAR *name, UINT length, CHAR *base64name) -{ - -UINT pad; -UINT i, j; -UINT step; - - - /* Adjust the length to represent the base64 name. */ - length = ((length * 8) / 6); - - /* Default padding to none. */ - pad = 0; - - /* Determine if an extra conversion is needed. */ - if ((length * 6) % 24) - { - - /* Some padding is needed. */ - - /* Calculate the number of pad characters. */ - pad = (length * 6) % 24; - pad = (24 - pad) / 6; - pad = pad - 1; - - /* Adjust the length to pickup the character fraction. */ - length++; - } - - /* Setup index into the base64name. */ - j = 0; - - /* Compute the base64name. */ - step = 0; - i = 0; - while (j < length) - { - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first 6 bits of name character for index. */ - base64name[j++] = _nx_web_http_server_base64_array[((UINT) name[i]) >> 2]; - step++; - } - else if (step == 1) - { - - /* Use last 2 bits of name character and first 4 bits of next name character for index. */ - base64name[j++] = _nx_web_http_server_base64_array[((((UINT) name[i]) & 0x3) << 4) | (((UINT) name[i+1]) >> 4)]; - i++; - step++; - } - else if (step == 2) - { - - /* Use last 4 bits of name character and first 2 bits of next name character for index. */ - base64name[j++] = _nx_web_http_server_base64_array[((((UINT) name[i]) & 0xF) << 2) | (((UINT) name[i+1]) >> 6)]; - i++; - step++; - } - else /* Step 3 */ - { - - /* Use last 6 bits of name character for index. */ - base64name[j++] = _nx_web_http_server_base64_array[(((UINT) name[i]) & 0x3F)]; - i++; - step = 0; - } - } - - /* Determine if the index needs to be advanced. */ - if (step != 3) - i++; - - /* Now add the PAD characters. */ - while ((pad--) && (j < NX_WEB_HTTP_MAX_STRING)) - { - - /* Pad base64name with '=' characters. */ - base64name[j++] = '='; - } - - /* Put a NULL character in. */ - base64name[j] = NX_NULL; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_base64_decode PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function decodes the input base64 ASCII string and converts */ -/* it into a standard ASCII representation. */ -/* */ -/* INPUT */ -/* */ -/* base64name Encoded base64 name string */ -/* length Length of encoded base64 name */ -/* name Name string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_basic_authenticate */ -/* Basic authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_base64_decode(CHAR *base64name, UINT length, CHAR *name) -{ - -UINT i, j; -UINT value1, value2; -UINT step; - - - /* Adjust the length to represent the ASCII name. */ - length = ((length * 6) / 8); - - /* Setup index into the ASCII name. */ - j = 0; - - /* Compute the ASCII name. */ - step = 0; - i = 0; - while ((j < length) && (base64name[i]) && (base64name[i] != '=')) - { - - /* Derive values of the Base64 name. */ - if ((base64name[i] >= 'A') && (base64name[i] <= 'Z')) - value1 = (UINT) (base64name[i] - 'A'); - else if ((base64name[i] >= 'a') && (base64name[i] <= 'z')) - value1 = (UINT) (base64name[i] - 'a') + 26; - else if ((base64name[i] >= '0') && (base64name[i] <= '9')) - value1 = (UINT) (base64name[i] - '0') + 52; - else if (base64name[i] == '+') - value1 = 62; - else if (base64name[i] == '/') - value1 = 63; - else - value1 = 0; - - /* Derive value for the next character. */ - if ((base64name[i+1] >= 'A') && (base64name[i+1] <= 'Z')) - value2 = (UINT) (base64name[i+1] - 'A'); - else if ((base64name[i+1] >= 'a') && (base64name[i+1] <= 'z')) - value2 = (UINT) (base64name[i+1] - 'a') + 26; - else if ((base64name[i+1] >= '0') && (base64name[i+1] <= '9')) - value2 = (UINT) (base64name[i+1] - '0') + 52; - else if (base64name[i+1] == '+') - value2 = 62; - else if (base64name[i+1] == '/') - value2 = 63; - else - value2 = 0; - - /* Determine which step we are in. */ - if (step == 0) - { - - /* Use first value and first 2 bits of second value. */ - name[j++] = (CHAR) (((value1 & 0x3f) << 2) | ((value2 >> 4) & 3)); - i++; - step++; - } - else if (step == 1) - { - - /* Use last 4 bits of first value and first 4 bits of next value. */ - name[j++] = (CHAR) (((value1 & 0xF) << 4) | (value2 >> 2)); - i++; - step++; - } - else if (step == 2) - { - - /* Use first 2 bits and following 6 bits of next value. */ - name[j++] = (CHAR) (((value1 & 3) << 6) | (value2 & 0x3f)); - i++; - i++; - step = 0; - } - } - - /* Put a NULL character in. */ - name[j] = NX_NULL; -} - - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_digest_authenticate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for digest (MD5 only) authentication. */ -/* If the digest is correct, it returns a success. Otherwise, it */ -/* returns an authentication request to the requesting client. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* packet_ptr Request packet pointer */ -/* name_ptr Pointer to name string */ -/* password_ptr Pointer to password string */ -/* realm_ptr Pointer to realm string */ -/* auth_request_present Indicate if authentication */ -/* must be performed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_retrieve_digest_authorization */ -/* Pickup authorization */ -/* _nx_web_http_server_digest_response_calculate */ -/* Calculate the digest */ -/* _nx_web_http_server_response_packet_allocate */ -/* Allocate a response packet */ -/* nx_packet_data_append Append information to response*/ -/* nx_packet_release Release packet */ -/* _nx_web_http_server_send Send HTTP Server response */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process Process GET request */ -/* _nx_web_http_server_put_process Process PUT request */ -/* _nx_web_http_server_delete_process Process DELETE request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_digest_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present) -{ - -CHAR authorization_response[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; -CHAR calculated_response[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; -CHAR authorization_uri[NX_WEB_HTTP_MAX_RESOURCE + 1]; -CHAR method[8]; -CHAR quote[2] = {0x22, 0}; -CHAR *buffer_ptr; -UINT i; -UINT status, status1, callback_status; -CHAR crlf[2] = {13,10}; -CHAR authorization_nc[NX_WEB_HTTP_MAX_RESOURCE + 1]; -CHAR authorization_cnonce[NX_WEB_HTTP_MAX_RESOURCE + 1]; -UINT realm_length; - - /* Default to no authentication request detected. */ - *auth_request_present = NX_FALSE; - - /* Default the status to authenticate. */ - status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; - - /* Is the authorization request present? */ - if (_nx_web_http_server_retrieve_digest_authorization(packet_ptr, authorization_response, authorization_uri, authorization_nc, authorization_cnonce)) - { - - /* Yes, an authorization request is present. */ - *auth_request_present = NX_TRUE; - - /* Pickup method from the packet. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - i = 0; - while (((buffer_ptr + i) < (CHAR *)packet_ptr -> nx_packet_append_ptr) && (buffer_ptr[i] != ' ') && (i < (sizeof(method) - 1))) - { - - /* Copy bytes of method. */ - method[i] = buffer_ptr[i]; - i++; - } - - /* Null terminate method. */ - method[i] = (CHAR) NX_NULL; - - /* If the digest authenticate callback function is set, invoke the callback function. */ - if(server_ptr -> nx_web_http_server_digest_authenticate_callback) - { - callback_status = (server_ptr -> nx_web_http_server_digest_authenticate_callback)(server_ptr, name_ptr, realm_ptr, password_ptr, method, authorization_uri, authorization_nc, authorization_cnonce); - } - else - { - - /* If the digest authenticate callback is not set, assume it is success, for backward - compatibility reasons. */ - callback_status = NX_SUCCESS; - } - - /* Calculate what the MD5 should be. */ - _nx_web_http_server_digest_response_calculate(server_ptr, name_ptr, realm_ptr, password_ptr, _nx_web_http_server_nonce, method, authorization_uri, authorization_nc, authorization_cnonce, calculated_response); - - /* Determine if the calculated response is the same as the received response. */ - i = 0; - status = NX_SUCCESS; - while (i < NX_WEB_HTTP_MAX_ASCII_MD5 + 1) - { - /* Is there a mismatch? */ - if (calculated_response[i] != authorization_response[i]) - { - - /* Authorization mismatch. Continue to avoid timing attack. */ - status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; - } - - /* Otherwise, look at next character. */ - i++; - } - /* If digest authenticate callback function returns non-success value, the request is - considered unauthenticated. */ - if(callback_status != NX_SUCCESS) - status = NX_WEB_HTTP_DIGEST_AUTHENTICATE; - } - - /* Determine if we need to send back an unauthorized request. */ - if (status == NX_WEB_HTTP_DIGEST_AUTHENTICATE) - { - - /* We need authorization so build the HTTP 401 Unauthorized message to send to the server. */ - - /* Check string length. */ - if (_nx_utility_string_length_check(realm_ptr, &realm_length, NX_MAX_STRING_LENGTH)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Allocate a packet for sending the response back. */ - status1 = _nx_web_http_server_response_packet_allocate(server_ptr, &packet_ptr, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if (status1 != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Return the internal NetX error. */ - return(status1); - } - - /* Insert the response header. */ - nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - nx_packet_data_append(packet_ptr, NX_WEB_HTTP_STATUS_UNAUTHORIZED, sizeof(NX_WEB_HTTP_STATUS_UNAUTHORIZED) - 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the type of authentication requested. */ - nx_packet_data_append(packet_ptr, "WWW-Authenticate: Digest realm=", 31, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the realm string into the buffer. */ - nx_packet_data_append(packet_ptr, realm_ptr, realm_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place a comma into the buffer. */ - nx_packet_data_append(packet_ptr, ",", 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the algorithm into the buffer. */ - nx_packet_data_append(packet_ptr, " algorithm=", 11, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the md5 tag into the buffer. */ - nx_packet_data_append(packet_ptr, "md5", 3, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place a comma into the buffer. */ - nx_packet_data_append(packet_ptr, ",", 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the nonce into the buffer. */ - nx_packet_data_append(packet_ptr, " nonce=", 7, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the nonce string into the buffer. */ - nx_packet_data_append(packet_ptr, _nx_web_http_server_nonce, sizeof(_nx_web_http_server_nonce) - 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert the double quote. */ - nx_packet_data_append(packet_ptr, quote, 1, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the qop="auth" parameter string into the buffer. */ - nx_packet_data_append(packet_ptr, ", qop=\"auth\"", 12, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place another into the buffer to signal end of FULL HTTP response. */ - nx_packet_data_append(packet_ptr, crlf, 2, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Send the response back to the client. */ - status1 = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - - /* Check for an error. */ - if (status1) - { - - /* Set the internal NetX error as the status return. */ - status = status1; - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - } - - /* Return the result of the authentication request. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_digest_response_calculate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function computes the MD5 digest based on the supplied input */ -/* parameters. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr HTTP Server pointer */ -/* username Username string */ -/* realm Realm string */ -/* password Password string */ -/* nonce Authentication nonce string */ -/* method Request method string */ -/* uri Resource request string */ -/* nc Nonce count string */ -/* cnonce Client nonce string */ -/* result Computed digest string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_hex_ascii_convert Convert hex to ASCII */ -/* _nx_md5_initialize Initialize MD5 algorithm */ -/* _nx_md5_update Update MD5 digest */ -/* _nx_md5_digest_calculate Complete the MD5 algorithm */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_digest_authenticate */ -/* Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_digest_response_calculate(NX_WEB_HTTP_SERVER *server_ptr, CHAR *username, CHAR *realm, CHAR *password, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result) -{ - -CHAR md5_binary[NX_WEB_HTTP_MAX_BINARY_MD5]; -CHAR ha1_string[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; -CHAR ha2_string[NX_WEB_HTTP_MAX_ASCII_MD5 + 1]; -UINT username_length; -UINT password_length; -UINT realm_length; -UINT method_length; -UINT uri_length; -UINT nonce_length; -UINT nc_length; -UINT cnonce_length; - - /* Check string length. */ - if (_nx_utility_string_length_check(username, &username_length, NX_WEB_HTTP_MAX_NAME) || - _nx_utility_string_length_check(password, &password_length, NX_WEB_HTTP_MAX_PASSWORD) || - _nx_utility_string_length_check(realm, &realm_length, NX_MAX_STRING_LENGTH) || - _nx_utility_string_length_check(method, &method_length, 7) || - _nx_utility_string_length_check(uri, &uri_length, NX_WEB_HTTP_MAX_RESOURCE) || - _nx_utility_string_length_check(nonce, &nonce_length, sizeof(_nx_web_http_server_nonce) - 1) || - _nx_utility_string_length_check(nc, &nc_length, NX_WEB_HTTP_MAX_RESOURCE) || - _nx_utility_string_length_check(cnonce, &cnonce_length, NX_WEB_HTTP_MAX_RESOURCE)) - { - return; - } - - - /* Calculate the H(A1) portion of the digest. */ - _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) username, username_length); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) realm, realm_length); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) password, password_length); - _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); - - /* Convert this H(A1) portion to ASCII Hex representation. */ - _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, ha1_string); - - /* Make the H(A2) portion of the digest. */ - _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) method, method_length); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) uri, uri_length); - _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); - - /* Convert this H(A2) portion to ASCII Hex representation. */ - _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, ha2_string); - - /* Now make the final MD5 digest. */ - _nx_md5_initialize(&(server_ptr -> nx_web_http_server_md5data)); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ha1_string, sizeof(ha1_string) - 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) nonce, nonce_length); - - /* Start of Internet Explorer bug work-around. */ - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) nc, nc_length); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) cnonce, cnonce_length); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":auth", 5); - /* End of Internet Explorer bug work-around. */ - - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ":", 1); - _nx_md5_update(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) ha2_string, sizeof(ha2_string) - 1); - _nx_md5_digest_calculate(&(server_ptr -> nx_web_http_server_md5data), (unsigned char *) md5_binary); - - /* Finally, convert the response back to an ASCII string and place in - the destination. */ - _nx_web_http_server_hex_ascii_convert(md5_binary, NX_WEB_HTTP_MAX_BINARY_MD5, result); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_retrieve_digest_authorization PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function retrieves the MD5 digest parameters from the */ -/* supplied request packet. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Request packet pointer */ -/* response Digest response pointer */ -/* uri URI from response pointer */ -/* nc Nonce count string */ -/* cnonce Client nonce string */ -/* */ -/* OUTPUT */ -/* */ -/* length Length of response (should be */ -/* 32). A value of 0 indicates */ -/* an error is present */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_digest_authenticate */ -/* Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce) -{ - -UINT length; -UINT found; -CHAR *buffer_ptr; -CHAR *saved_buffer_ptr; - - - /* Set the found flag to false. */ - found = NX_FALSE; - - /* Default the authorization request to zero. */ - length = 0; - - /* Set the response and uri strings to NULL. */ - response[0] = NX_NULL; - uri[0] = NX_NULL; - - /* Internet Explorer bug work-around. */ - nc[0] = NX_NULL; - cnonce[0] = NX_NULL; - - /* Setup pointer to buffer. */ - buffer_ptr = (CHAR *) packet_ptr -> nx_packet_prepend_ptr; - - /* Find the "Authorization: " token first. */ - while (((buffer_ptr+15) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Authorization: token. */ - if (((*buffer_ptr == 'a') || (*buffer_ptr == 'A')) && - ((*(buffer_ptr+1) == 'u') || (*(buffer_ptr+1) == 'U')) && - ((*(buffer_ptr+2) == 't') || (*(buffer_ptr+2) == 'T')) && - ((*(buffer_ptr+3) == 'h') || (*(buffer_ptr+3) == 'H')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+4) == 'O')) && - ((*(buffer_ptr+5) == 'r') || (*(buffer_ptr+5) == 'R')) && - ((*(buffer_ptr+6) == 'i') || (*(buffer_ptr+6) == 'I')) && - ((*(buffer_ptr+7) == 'z') || (*(buffer_ptr+7) == 'Z')) && - ((*(buffer_ptr+8) == 'a') || (*(buffer_ptr+8) == 'A')) && - ((*(buffer_ptr+9) == 't') || (*(buffer_ptr+9) == 'T')) && - ((*(buffer_ptr+10) == 'i') || (*(buffer_ptr+10) == 'I')) && - ((*(buffer_ptr+11) == 'o') || (*(buffer_ptr+11) == 'O')) && - ((*(buffer_ptr+12) == 'n') || (*(buffer_ptr+12) == 'N')) && - (*(buffer_ptr+13) == ':') && - (*(buffer_ptr+14) == ' ')) - { - - /* Move the pointer up to the length token. */ - buffer_ptr = buffer_ptr + 15; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the first token was found. */ - if (!found) - { - - /* No, authorization is not present. Return a zero length. */ - return(length); - } - - /* Set the found flag back to false. */ - found = NX_FALSE; - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now check for the "Digest " token. */ - while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the Digest token. */ - if (((*buffer_ptr == 'd') || (*buffer_ptr == 'D')) && - ((*(buffer_ptr+1) == 'i') || (*(buffer_ptr+1) == 'I')) && - ((*(buffer_ptr+2) == 'g') || (*(buffer_ptr+2) == 'G')) && - ((*(buffer_ptr+3) == 'e') || (*(buffer_ptr+3) == 'E')) && - ((*(buffer_ptr+4) == 's') || (*(buffer_ptr+4) == 'S')) && - ((*(buffer_ptr+5) == 't') || (*(buffer_ptr+5) == 'T')) && - (*(buffer_ptr+6) == ' ')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 7; - - /* Set the found flag. */ - found = NX_TRUE; - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Determine if the second token was found. */ - if (!found) - { - - /* No, digest is not present. Return a zero length. */ - return(length); - } - - /* Now remove any extra blanks. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' ')) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Start of Internet Explorer bug work-around (Parses nc and cnonce parameters). */ - - /* Save current buffer pointer, so each parameter search always starts from here. */ - saved_buffer_ptr = buffer_ptr; - - /* Now look for the nc in the digest response. */ - while (((buffer_ptr+3) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the nc token. */ - if (((*buffer_ptr == 'n') || (*buffer_ptr == 'N')) && - ((*(buffer_ptr+1) == 'c') || (*(buffer_ptr+1) == 'C')) && - (*(buffer_ptr+2) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 3; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes (should be no starting quote). */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the nc string (should be 8 hex characters; should not be quoted). */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote or comma is present (should be no ending quote). */ - if ((*buffer_ptr == (CHAR) 0x22) || (*buffer_ptr == ',')) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - nc[length++] = *buffer_ptr++; - } - - /* Null terminate the NC. */ - nc[length] = (CHAR) NX_NULL; - - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the cnonce in the digest response. */ - while (((buffer_ptr+7) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'c') || (*buffer_ptr == 'C')) && - ((*(buffer_ptr+1) == 'n') || (*(buffer_ptr+1) == 'N')) && - ((*(buffer_ptr+2) == 'o') || (*(buffer_ptr+2) == 'O')) && - ((*(buffer_ptr+3) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+4) == 'c') || (*(buffer_ptr+2) == 'C')) && - ((*(buffer_ptr+5) == 'e') || (*(buffer_ptr+2) == 'E')) && - (*(buffer_ptr+6) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 7; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the cnonce string. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - cnonce[length++] = *buffer_ptr++; - } - - /* Null terminate the CNONCE. */ - cnonce[length] = (CHAR) NX_NULL; - - /* End of Internet Explorer bug work-around. */ - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the uri in the digest response. */ - while (((buffer_ptr+4) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'u') || (*buffer_ptr == 'U')) && - ((*(buffer_ptr+1) == 'r') || (*(buffer_ptr+1) == 'R')) && - ((*(buffer_ptr+2) == 'i') || (*(buffer_ptr+2) == 'I')) && - (*(buffer_ptr+3) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 4; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and quotes. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Now pickup the uri string. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (length < NX_WEB_HTTP_MAX_RESOURCE)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the authorization string into the destination. */ - uri[length++] = *buffer_ptr++; - } - - /* Null terminate the URI. */ - uri[length] = (CHAR) NX_NULL; - - /* Get saved buffer pointer. */ - buffer_ptr = saved_buffer_ptr; - - /* Now look for the digest response. */ - while (((buffer_ptr+9) < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0)) - { - - /* Check for the uri token. */ - if (((*buffer_ptr == 'r') || (*buffer_ptr == 'R')) && - ((*(buffer_ptr+1) == 'e') || (*(buffer_ptr+1) == 'E')) && - ((*(buffer_ptr+2) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+3) == 'p') || (*(buffer_ptr+2) == 'P')) && - ((*(buffer_ptr+4) == 'o') || (*(buffer_ptr+2) == 'O')) && - ((*(buffer_ptr+5) == 'n') || (*(buffer_ptr+2) == 'N')) && - ((*(buffer_ptr+6) == 's') || (*(buffer_ptr+2) == 'S')) && - ((*(buffer_ptr+7) == 'e') || (*(buffer_ptr+2) == 'E')) && - (*(buffer_ptr+8) == '=')) - { - - /* Move the pointer up to the actual authorization string. */ - buffer_ptr = buffer_ptr + 9; - - break; - } - - /* Move the pointer up to the next character. */ - buffer_ptr++; - } - - /* Now remove any extra blanks and leading quote. */ - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && ((*buffer_ptr == ' ') || (*buffer_ptr == (CHAR) 0x22))) - { - - /* Move the pointer up one character. */ - buffer_ptr++; - } - - /* Finally, pickup the response. */ - length = 0; - while ((buffer_ptr < (CHAR *) packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != (CHAR) 0) && (*buffer_ptr != ' ') && (*buffer_ptr != (CHAR) 13) && (*buffer_ptr != (CHAR) 0x3A) && (length < NX_WEB_HTTP_MAX_ASCII_MD5)) - { - - /* Determine if the ending quote is present. */ - if (*buffer_ptr == (CHAR) 0x22) - { - - break; - } - - /* Copy a character of the response string into the destination. */ - response[length++] = *buffer_ptr++; - } - - /* Null terminate response. */ - response[length] = (CHAR) NX_NULL; - - /* Check for an error. */ - if ((length != 32) || (buffer_ptr >= (CHAR *) packet_ptr -> nx_packet_append_ptr) || (*buffer_ptr != (CHAR) 0x22)) - { - - /* Error, clear the length and the response string. */ - length = 0; - response[0] = (CHAR) NX_NULL; - } - - /* Return the length to the caller. */ - return(length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_hex_ascii_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts hexadecimal characters into an ASCII string. */ -/* */ -/* INPUT */ -/* */ -/* source Source hex string */ -/* source_length Length of source string */ -/* destination Pointer to destination string */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_digest_response_calculate */ -/* Digest authentication */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination) -{ - -UINT i,j; -CHAR digit; - - - /* Setup destination index. */ - j = 0; - - /* Loop to process the entire source string. */ - for (i = 0; i < source_length; i++) - { - - /* Pickup the first nibble. */ - digit = (source[i] >> 4) & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - - /* Pickup the second nibble. */ - digit = source[i] & 0xF; - - /* Convert to ASCII and store. */ - if (digit <= 9) - destination[j++] = (CHAR)(digit + '0'); - else - destination[j++] = (CHAR)(digit + 'a' - 10); - } - - /* Finally, place a NULL in the destination string. */ - destination[j] = (CHAR) NX_NULL; -} -#endif - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_get_entity_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for getting the entity header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* entity_header_buffer Buffer to get entity header */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_get_entity_header */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) -{ - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (entity_header_buffer == NX_NULL)) - return NX_PTR_ERROR; - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_web_http_server_get_entity_header(server_ptr, packet_pptr, entity_header_buffer, buffer_size); -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(entity_header_buffer); - NX_PARAMETER_NOT_USED(buffer_size); - - return NX_WEB_HTTP_ERROR; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_get_entity_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the entity header and skip header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* entity_header_buffer Buffer to get entity header */ -/* buffer_size Size of buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_field_value_get */ -/* _nx_web_http_server_memicmp */ -/* _nx_web_http_server_boundary_find */ -/* nx_packet_release */ -/* nx_tcp_socket_receive */ -/* _nx_utility_string_length_check */ -/* memmove */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size) -{ - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE -NX_WEB_HTTP_SERVER_MULTIPART *multipart_ptr; -UINT status; -UINT offset; -NX_PACKET *available_packet; -UINT crlf_match_count = 0; -UINT end_boundary_count = 2; -UINT skip_count = 2; -UCHAR *ch; -UINT index; - - /* Get multipart context. */ - multipart_ptr = &server_ptr -> nx_web_http_server_multipart; - - /* Is the multipart context initialized? */ - if(multipart_ptr -> nx_web_http_server_multipart_boundary[0] == 0) - { - ULONG field_length; - UINT quotation_index; - UINT i; - - /* No, it is not initialized. */ - - /* Get content type. */ - status = _nx_web_http_server_field_value_get(*packet_pptr, (UCHAR *)"content-type", 12, - multipart_ptr -> nx_web_http_server_multipart_boundary, NX_WEB_HTTP_MAX_HEADER_FIELD + 1); - if(status) - return status; - - /* Is the content type "multipart"? */ - /* Check the length. The length of "multipart/" is 10. */ - if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_web_http_server_multipart_boundary, (UINT *)&field_length, NX_WEB_HTTP_MAX_HEADER_FIELD)) - return NX_WEB_HTTP_ERROR; - if(field_length < 10) - return NX_WEB_HTTP_NOT_FOUND; - - /* Check the data. */ - if(_nx_web_http_server_memicmp(multipart_ptr -> nx_web_http_server_multipart_boundary, 10, - (UCHAR *)"multipart/", 10) != NX_SUCCESS) - return NX_WEB_HTTP_NOT_FOUND; - - /* Find the boundary. The length of "boundary=" is 9. */ - index = 0; - while((index + 9) < field_length) - { - if(_nx_web_http_server_memicmp(&multipart_ptr -> nx_web_http_server_multipart_boundary[index], 9, - (UCHAR *)"boundary=", 9) == NX_SUCCESS) - { - - break; - } - - /* Move the pointer up to the next character. */ - index++; - } - - /* Move the pointer up to the boundary value. */ - index += 9; - - /* Is boundary string found? */ - if((field_length - index) <= 1) - { - - /* Boundary not found or no boundary value. */ - return NX_WEB_HTTP_NOT_FOUND; - } - - /* Boundary is started with "CRLF--". */ - multipart_ptr -> nx_web_http_server_multipart_boundary[0] = 13; - multipart_ptr -> nx_web_http_server_multipart_boundary[1] = 10; - multipart_ptr -> nx_web_http_server_multipart_boundary[2] = '-'; - multipart_ptr -> nx_web_http_server_multipart_boundary[3] = '-'; - - /* Remove quotation. */ - if(multipart_ptr -> nx_web_http_server_multipart_boundary[index] == '"') - { - - /* Find the right quotation. */ - index++; - for(quotation_index = field_length; quotation_index > index; quotation_index--) - { - if(multipart_ptr -> nx_web_http_server_multipart_boundary[quotation_index] == '"') - break; - } - - /* Is the right quotation found? */ - if(quotation_index > index) - multipart_ptr -> nx_web_http_server_multipart_boundary[quotation_index] = 0; - else - { - - /* Boundary not valid. */ - return NX_WEB_HTTP_NOT_FOUND; - } - - /* Leave boundary string only. */ - memmove(&multipart_ptr -> nx_web_http_server_multipart_boundary[4], - &multipart_ptr -> nx_web_http_server_multipart_boundary[index], - quotation_index - index + 1); - } - else - { - - /* Directly copy boundary string to the head field. */ - i = 4; - index -= 4; - do - { - multipart_ptr -> nx_web_http_server_multipart_boundary[i] = multipart_ptr -> nx_web_http_server_multipart_boundary[index + i]; - i++; - }while((multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] != 0) && - (multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] != ' ')); - - /* Set the terminal character. */ - multipart_ptr -> nx_web_http_server_multipart_boundary[i - 1] = 0; - } - } - - /* If the received request is chunked. */ - if (server_ptr -> nx_web_http_server_request_chunked) - { - - /* If never processed the chunked packet, need to separate the HTTP header and content. */ - if (!server_ptr -> nx_web_http_server_expect_receive_bytes) - { - - available_packet = *packet_pptr; - - /* Separate the HTTP header and get the first content packet. */ - status = _nx_web_http_server_packet_content_find(server_ptr, &available_packet, NX_NULL); - if (status) - { - return(status); - } - - /* Append '\r\n' to the start of the packet. */ - available_packet -> nx_packet_prepend_ptr -= 2; - available_packet -> nx_packet_prepend_ptr[0] = 13; - available_packet -> nx_packet_prepend_ptr[1] = 10; - - /* Update packet length. */ - available_packet -> nx_packet_length += 2; - - /* Store the packet. */ - nx_packet_release(*packet_pptr); - *packet_pptr = available_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; - - /* Reset the offset. */ - multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; - } - } - - /* Find the boundary. */ - while(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_FALSE) - { - if(_nx_web_http_server_boundary_find(server_ptr, packet_pptr) != NX_SUCCESS) - break; - } - - /* Whether the boundary is found? */ - if(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_FALSE) - return NX_WEB_HTTP_NOT_FOUND; - - /* Update the packet and offset. */ - _nx_web_http_server_boundary_find(server_ptr, packet_pptr); - - /* Get offset of available data in the packet. */ - offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; - - /* Skip data that are not header. */ - available_packet = *packet_pptr; - - if(offset >= available_packet -> nx_packet_length) - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* All data has been processed. Get a new packet. */ - if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; - } -#ifndef NX_DISABLE_PACKET_CHAIN - else - { - while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) - { - offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); - - /* Get next packet. */ - available_packet = available_packet -> nx_packet_next; - } - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Get entity header. */ - ch = available_packet -> nx_packet_prepend_ptr + offset; - index = 0; - while((entity_header_buffer == NX_NULL) || (index < buffer_size)) - { - - /* Calculate valid CRLF. */ - if((*ch == 13) && ((crlf_match_count & 1) == 0)) - crlf_match_count++; - else if((*ch == 10) && ((crlf_match_count & 1) == 1)) - crlf_match_count++; - else if(*ch == '-') - { - - /* Check whether the last boundary is found. */ - if(end_boundary_count < 3) - end_boundary_count--; - - if(end_boundary_count == 0) - break; - } - else - { - end_boundary_count = 0xFF; - crlf_match_count = 0; - } - - /* Copy data to buffer. */ - if(skip_count >0) - skip_count--; - else - { - if(entity_header_buffer) - entity_header_buffer[index] = *ch; - index++; - } - multipart_ptr -> nx_web_http_server_multipart_available_offset++; - - /* Check whether two CRLFs are found. */ - if(crlf_match_count == 4) - break; - - /* Get next character. */ - if((ch + 1) >= available_packet -> nx_packet_append_ptr) - { - - /* ch points to the end of this packet. */ -#ifndef NX_DISABLE_PACKET_CHAIN - if(available_packet -> nx_packet_next) - { - - /* Copy data from next packet. */ - available_packet = available_packet -> nx_packet_next; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* Get a new packet and copy data from it. */ - status = _nx_web_http_server_packet_get(server_ptr, &available_packet); - - /* Check the return status. */ - if (status != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; - - /* Reset the offset. */ - multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; - } - - ch = available_packet -> nx_packet_prepend_ptr; - } - else - ch++; - - } - - /* Check whether two CRLFs are found. */ - if(crlf_match_count == 4) - { - - /* Set terminal 0. */ - if(entity_header_buffer) - entity_header_buffer[index - 4] = 0; - return NX_SUCCESS; - } - else - return NX_WEB_HTTP_NOT_FOUND; -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(entity_header_buffer); - NX_PARAMETER_NOT_USED(buffer_size); - - return NX_WEB_HTTP_ERROR; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_get_entity_content PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for getting the entity content. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* available_offset Return the offset */ -/* available_length Return the length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_get_entity_content */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) -{ - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (available_offset == NX_NULL) || (available_length == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check whether boundary is found. */ - if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_boundary[0] == 0) - return(NX_WEB_HTTP_ERROR); - - return _nx_web_http_server_get_entity_content(server_ptr, packet_pptr, available_offset, available_length); -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(available_offset); - NX_PARAMETER_NOT_USED(available_length); - - return NX_WEB_HTTP_ERROR; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_get_entity_content PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the entity content. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* available_offset Return the offset */ -/* available_length Return the length */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_boundary_find */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length) -{ - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE -UINT status; - - /* Whether the boundary is found? */ - if(server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_boundary_find == NX_TRUE) - return NX_WEB_HTTP_BOUNDARY_ALREADY_FOUND; - - status = _nx_web_http_server_boundary_find(server_ptr, packet_pptr); - if(status) - return status; - - /* Set the offset and length. */ - *available_offset = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_available_offset; - *available_length = server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_available_length; - - return NX_SUCCESS; -#else - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(packet_pptr); - NX_PARAMETER_NOT_USED(available_offset); - NX_PARAMETER_NOT_USED(available_length); - - return NX_WEB_HTTP_ERROR; -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ -} - - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_boundary_find PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function finds boundary in packet even if it is chained. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_release */ -/* nx_tcp_socket_receive */ -/* _nx_web_http_server_match_string */ -/* _nx_utility_string_length_check */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_entity_header */ -/* _nx_web_http_server_get_entity_content */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_boundary_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr) -{ - -NX_WEB_HTTP_SERVER_MULTIPART *multipart_ptr; -NX_PACKET *available_packet; -UINT offset; -ULONG match_count = 0; -UCHAR *match_end_ptr; -UINT boundary_length; - - /* Get multipart context. */ - multipart_ptr = &server_ptr -> nx_web_http_server_multipart; - - /* Is boundary already found? */ - if(multipart_ptr -> nx_web_http_server_multipart_boundary_find == NX_TRUE) - { - - /* Yes. Update the packet and offset. */ - if(multipart_ptr -> nx_web_http_server_multipart_next_packet != NX_NULL) - { - nx_packet_release(*packet_pptr); - *packet_pptr = multipart_ptr -> nx_web_http_server_multipart_next_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = multipart_ptr -> nx_web_http_server_multipart_next_packet; - } - - multipart_ptr -> nx_web_http_server_multipart_available_offset = multipart_ptr -> nx_web_http_server_multipart_next_available_offset; - - /* Reset next packet and available offset. */ - multipart_ptr -> nx_web_http_server_multipart_next_packet = NX_NULL; - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; - - /* Reset boundary find. */ - multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_FALSE; - - return NX_SUCCESS; - } - - /* Is the boundary in the next packet? */ - if(multipart_ptr -> nx_web_http_server_multipart_next_packet) - { - - /* Yes, we're done with this packet. */ - nx_packet_release(*packet_pptr); - - /* Update the packet and multipart offset. */ - *packet_pptr = multipart_ptr -> nx_web_http_server_multipart_next_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = multipart_ptr -> nx_web_http_server_multipart_next_packet; - multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; - } - else if(multipart_ptr -> nx_web_http_server_multipart_next_available_offset) - { - - /* Find boundary in this packet. */ - /* Update the offset. */ - multipart_ptr -> nx_web_http_server_multipart_available_offset = multipart_ptr -> nx_web_http_server_multipart_next_available_offset; - } - else - { - - /* Find boundary from this packet. */ - /* Initialize the offset. */ - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; - } - - /* Reset next packet. */ - multipart_ptr -> nx_web_http_server_multipart_next_packet = NX_NULL; - - /* Reset boundary find. */ - multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_FALSE; - - - /* Get offset of available data in the packet. */ - offset = multipart_ptr -> nx_web_http_server_multipart_available_offset; - - /* Skip data that are not header. */ - available_packet = *packet_pptr; - - if(offset >= available_packet -> nx_packet_length) - { - - /* Release the packet that has been processed. */ - nx_packet_release(*packet_pptr); - - /* All data has been processed. Get a new packet. */ - if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - /* Store the packet. */ - *packet_pptr = available_packet; - server_ptr -> nx_web_http_server_multipart.nx_web_http_server_multipart_last_packet = available_packet; - - /* Reset the offset. */ - multipart_ptr -> nx_web_http_server_multipart_available_offset = 0; - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; - offset = 0; - } - else - { -#ifndef NX_DISABLE_PACKET_CHAIN - while((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) <= offset) - { - offset -= (UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr); - - /* Get next packet. */ - available_packet = available_packet -> nx_packet_next; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Check boundary length. */ - if (_nx_utility_string_length_check((CHAR *)multipart_ptr -> nx_web_http_server_multipart_boundary, &boundary_length, NX_WEB_HTTP_MAX_HEADER_FIELD)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Look for the boundary string in the (next) packet. */ - while(_nx_web_http_server_match_string(available_packet -> nx_packet_prepend_ptr + offset, - available_packet -> nx_packet_append_ptr, - multipart_ptr -> nx_web_http_server_multipart_boundary, - boundary_length, - &match_count, &match_end_ptr) != NX_SUCCESS) - { - - /* Match string in the next packet. */ -#ifndef NX_DISABLE_PACKET_CHAIN - if(available_packet -> nx_packet_next) - { - multipart_ptr -> nx_web_http_server_multipart_next_available_offset += (UINT)((UINT)(available_packet -> nx_packet_append_ptr - available_packet -> nx_packet_prepend_ptr) - offset); - available_packet = available_packet -> nx_packet_next; - offset = 0; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - break; - } - - /* Is boundary matched? */ - if(match_end_ptr) - { - - /* Yes. Found a match. */ - multipart_ptr -> nx_web_http_server_multipart_next_available_offset += (UINT)((UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) - offset); - multipart_ptr -> nx_web_http_server_multipart_available_length = multipart_ptr -> nx_web_http_server_multipart_next_available_offset - multipart_ptr -> nx_web_http_server_multipart_available_offset - match_count; - multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_TRUE; - - } - else if(match_count) - { - - /* Set the available length to all remaining data. */ - multipart_ptr -> nx_web_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_web_http_server_multipart_available_offset; - - /* Partial match. Get another packet. */ - if(_nx_web_http_server_packet_get(server_ptr, &available_packet) != NX_SUCCESS) - { - - /* Error, return to caller. */ - return(NX_WEB_HTTP_TIMEOUT); - } - - /* Match the boundary again. */ - if(_nx_web_http_server_match_string(available_packet -> nx_packet_prepend_ptr, - available_packet -> nx_packet_append_ptr, - multipart_ptr -> nx_web_http_server_multipart_boundary, - boundary_length, - &match_count, &match_end_ptr) == NX_SUCCESS) - { - - /* Yes. Find a match. */ - if((ULONG)(match_end_ptr - available_packet -> nx_packet_prepend_ptr) < match_count) - { - - /* The boundary is between two packets. */ - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = (UINT)(match_end_ptr - available_packet -> nx_packet_prepend_ptr); - multipart_ptr -> nx_web_http_server_multipart_available_length -= boundary_length - multipart_ptr -> nx_web_http_server_multipart_next_available_offset; - multipart_ptr -> nx_web_http_server_multipart_boundary_find = NX_TRUE; - } - else - { - - /* The boundary is in the next packet. */ - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; - } - } - else - { - - /* The boundary is not found. */ - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = 0; - } - - /* Store the packet. */ - multipart_ptr -> nx_web_http_server_multipart_next_packet = available_packet; - - } - else - { - - /* Set the available length to all remaining data. */ - multipart_ptr -> nx_web_http_server_multipart_available_length = (*packet_pptr) -> nx_packet_length - multipart_ptr -> nx_web_http_server_multipart_available_offset; - multipart_ptr -> nx_web_http_server_multipart_next_available_offset = (*packet_pptr) -> nx_packet_length; - } - - return NX_SUCCESS; -} -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_match_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares a target string in specified memory area. */ -/* */ -/* INPUT */ -/* */ -/* src_start Pointer to start of source */ -/* src_end Pointer to end of source */ -/* target Pointer to target */ -/* target_length Length to target */ -/* match_count Return the match count */ -/* match_end_ptr Return the end match position */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* memcmp Compare memory data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_boundary_find */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr) -{ - -UCHAR *ch; -ULONG pre_match = *match_count; -ULONG remain_match; - - /* Initialize. */ - *match_end_ptr = NX_NULL; - - /* Process part match. */ - while(pre_match) - { - - /* Compare pre-match. */ - if(memcmp(target, target + (*match_count - pre_match), pre_match) == 0) - { - - /* Calculate the remain match. */ - remain_match = target_length - pre_match; - - /* The pre-match is the same. */ - if((ULONG)(src_end - src_start) < remain_match) - remain_match = (ULONG)(src_end - src_start); - - if(memcmp(target + pre_match, src_start, remain_match) == 0) - { - - /* Remain part matches. */ - *match_count = pre_match + remain_match; - - if(*match_count < target_length) - { - - /* Part match. */ - return NX_WEB_HTTP_NOT_FOUND; - } - - /* Full match. */ - *match_end_ptr = src_start + remain_match; - return NX_SUCCESS; - } - } - - pre_match--; - } - - ch = src_start; - - /* Perform full match. */ - *match_count = target_length; - while(ch + *match_count <= src_end) - { - if(memcmp(ch, target, *match_count) == 0) - { - - /* Find a match. */ - *match_end_ptr = ch + *match_count; - return NX_SUCCESS; - } - - ch++; - } - - /* Perform part match. */ - for(*match_count = target_length - 1; *match_count > 0; *match_count = *match_count - 1) - { - if(ch + *match_count <= src_end) - { - if(memcmp(ch, target, *match_count) == 0) - { - - /* Find a match. */ - return NX_WEB_HTTP_NOT_FOUND; - } - - ch++; - } - } - - return NX_WEB_HTTP_NOT_FOUND; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_field_value_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets field value by field name from HTTP header. */ -/* */ -/* INPUT */ -/* */ -/* packet_ptr Pointer to packet */ -/* field_name Name of field in header */ -/* name_length Length of name field */ -/* field_value Return of field value */ -/* field_value_size Size of field value */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_memicmp Compare ignore case */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process */ -/* _nx_web_http_server_get_entity_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size) -{ - -UCHAR *ch; -UINT index; - - - /* Initialize. */ - ch = packet_ptr -> nx_packet_prepend_ptr; - - /* Loop to find field name. */ - while(ch + name_length < packet_ptr -> nx_packet_append_ptr) - { - if(_nx_web_http_server_memicmp(ch, name_length, field_name, name_length) == NX_SUCCESS) - { - - /* Field name found. */ - break; - } - - /* Move the pointer up to the next character. */ - ch++; - } - - /* Skip field name and ':'. */ - ch += name_length + 1; - - /* Is field name found? */ - if(ch >= packet_ptr -> nx_packet_append_ptr) - return NX_WEB_HTTP_NOT_FOUND; - - /* Skip white spaces. */ - while(*ch == ' ') - { - if(ch >= packet_ptr -> nx_packet_append_ptr) - return NX_WEB_HTTP_NOT_FOUND; - - /* Get next character. */ - ch++; - } - - /* Copy field value. */ - index = 0; - while(index < field_value_size) - { - - /* Whether the end of line CRLF is not found? */ - if(ch + 2 > packet_ptr -> nx_packet_append_ptr) - return NX_WEB_HTTP_NOT_FOUND; - - /* Compare CRLF. */ - if((*ch == 13) && (*(ch + 1) == 10)) - break; - - /* Copy data. */ - field_value[index++] = *ch++; - } - - /* Buffer overflow? */ - if(index == field_value_size) - return NX_WEB_HTTP_NOT_FOUND; - - /* Trim white spaces. */ - while((index > 0) && (field_value[index - 1] == ' ')) - index--; - - /* Append terminal 0. */ - field_value[index] = 0; - - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_memicmp PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function compares two pieces of memory case insensitive. */ -/* */ -/* INPUT */ -/* */ -/* src Pointer to source */ -/* src_length Length of source */ -/* dest Pointer to destination */ -/* dest_length Length of destination */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_entity_header */ -/* _nx_web_http_server_field_value_get */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length) -{ -UCHAR ch; - - /* Compare the length. */ - if(src_length != dest_length) - return NX_WEB_HTTP_FAILED; - - while(src_length) - { - - /* Is src lowercase? */ - if((*src >= 'a') && (*src <= 'z')) - ch = (UCHAR)(*src - 'a' + 'A'); - - /* Is src uppercase? */ - else if((*src >= 'A') && (*src <= 'Z')) - ch = (UCHAR)(*src - 'A' + 'a'); - else - ch = *src; - - /* Compare case insensitive. */ - if((*src != *dest) && (ch != *dest)) - return NX_WEB_HTTP_FAILED; - - /* Pickup next character. */ - src_length--; - src++; - dest++; - } - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_generate_response_header PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function generates HTTP response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_response_packet_allocate */ -/* Allocate response packet */ -/* nx_packet_data_append Append packet data */ -/* memcmp Compare string */ -/* _nx_web_http_server_number_convert Convert number to ASCII */ -/* _nx_web_http_server_date_to_string Convert data to string */ -/* nx_packet_release Release packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process */ -/* _nx_web_http_server_put_process */ -/* _nx_web_http_server_delete_process */ -/* _nx_web_http_server_response_send */ -/* _nx_web_http_server_callback_generate_response_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT status_code_length, - UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, - UINT additional_header_length) -{ - -UINT status; -UINT temp; -CHAR temp_string[30]; -CHAR crlf[2] = {13,10}; -NX_PACKET *packet_ptr; -CHAR status_code_ok; -CHAR status_code_not_modified; - - - /* Allocate a packet for sending the response back. */ - status = _nx_web_http_server_response_packet_allocate(server_ptr, packet_pptr, NX_WAIT_FOREVER); - - /* Determine if an error occurred in the packet allocation. */ - if(status != NX_SUCCESS) - { - - /* Indicate an allocation error occurred. */ - server_ptr -> nx_web_http_server_allocation_errors++; - - /* Just return. */ - return status; - } - else - packet_ptr = *packet_pptr; - - /* Check status code. */ - if(memcmp(status_code, NX_WEB_HTTP_STATUS_OK, sizeof(NX_WEB_HTTP_STATUS_OK)) == 0) - status_code_ok = NX_TRUE; - else - status_code_ok = NX_FALSE; - - if(memcmp(status_code, NX_WEB_HTTP_STATUS_NOT_MODIFIED, sizeof(NX_WEB_HTTP_STATUS_NOT_MODIFIED)) == 0) - status_code_not_modified = NX_TRUE; - else - status_code_not_modified = NX_FALSE; - - /* Insert the status line. */ - /* Place HTTP-Version. */ - status = nx_packet_data_append(packet_ptr, NX_WEB_HTTP_VERSION, sizeof(NX_WEB_HTTP_VERSION) - 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert space. */ - status += nx_packet_data_append(packet_ptr, " ", 1, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - status += nx_packet_data_append(packet_ptr, status_code, status_code_length, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Determine if there is content_type. */ - if(content_type) - { - - /* Insert the content type. */ - status += nx_packet_data_append(packet_ptr, "Content-Type: ", 14, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - status += nx_packet_data_append(packet_ptr, content_type, content_type_length, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - -#ifndef NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH - /* Determine if there is content_length. */ - if(content_length || (status_code_not_modified == NX_TRUE)) - { -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - - /* Place the "Connection" field in the header. */ - if(server_ptr -> nx_web_http_server_keepalive == NX_TRUE) - { - - /* Keepalive. */ - status += nx_packet_data_append(packet_ptr, "Connection: keep-alive", 22, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - else -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - { - - /* Close. */ - status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if(content_length) - { - - /* Convert the content_length to ASCII representation. */ - temp = _nx_web_http_server_number_convert(content_length, temp_string); - - /* Place the "Content-Length" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Content-Length: ", 16, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - status += nx_packet_data_append(packet_ptr, temp_string, temp, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - } - else -#endif /* NX_WEB_HTTP_SERVER_OMIT_CONTENT_LENGTH */ - { - - /* Place the "Connection" field in the header. */ - - /* Force close the connection since there's no content-length. */ - status += nx_packet_data_append(packet_ptr, "Connection: Close", 17, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - server_ptr -> nx_web_http_server_keepalive = NX_FALSE; -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Insert Date header if callback function is set. */ - if(server_ptr -> nx_web_http_server_gmt_get) - { - NX_WEB_HTTP_SERVER_DATE date; - - /* Get current date. */ - server_ptr -> nx_web_http_server_gmt_get(&date); - - /* Convert date to string. */ - temp = _nx_web_http_server_date_to_string(&date, temp_string); - - /* Place the "Date" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Date: ", 6, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert date. */ - status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Set Cache Control if callback function is set. */ - if((server_ptr -> nx_web_http_server_cache_info_get) && - ((status_code_ok == NX_TRUE) || (status_code_not_modified == NX_TRUE)) && - (server_ptr -> nx_web_http_server_request_type == NX_WEB_HTTP_SERVER_GET_REQUEST)) - { - UINT max_age; - - /* Get cache infomation. */ - if(server_ptr -> nx_web_http_server_cache_info_get(server_ptr -> nx_web_http_server_request_resource, &max_age, &date) == NX_TRUE) - { - - /* Place "Cache-control" header. */ - status += nx_packet_data_append(packet_ptr, "Cache-Control: max-age=", 23, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Convert the max-age to ASCII representation. */ - temp = _nx_web_http_server_number_convert(max_age, temp_string); - status += nx_packet_data_append(packet_ptr, temp_string, temp, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if(status_code_ok == NX_TRUE) - { - - /* Convert date to string. */ - temp = _nx_web_http_server_date_to_string(&date, temp_string); - - /* Place the "Last-Modified" field in the header. */ - status += nx_packet_data_append(packet_ptr, "Last-Modified: ", 15, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Insert date. */ - status += nx_packet_data_append(packet_ptr, temp_string, temp, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - } - } - } - - /* Insert additional header. */ - if(additional_header) - { - status += nx_packet_data_append(packet_ptr, additional_header, additional_header_length, - server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Place the into the buffer. */ - status += nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - - if (status != NX_SUCCESS) - { - - /* Just release the packet. */ - nx_packet_release(packet_ptr); - } - - return status; -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_request_read PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the next data in byte. */ -/* */ -/* INPUT */ -/* */ -/* Server_ptr Pointer to HTTP server */ -/* data Returned data */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_receive Receive another packet */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_request_byte_expect */ -/* Checks next byte is expected */ -/* _nx_web_http_server_chunked_size_get Gets chunk size of request */ -/* packet chunk */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_request_read(NX_WEB_HTTP_SERVER *server_ptr, UCHAR *data, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; - - /* If there is no remaining data. */ - while (server_ptr -> nx_web_http_server_chunked_request_remaining_size == 0) - { - - /* Release the previous received packet. */ - if (server_ptr -> nx_web_http_server_request_packet) - { - nx_packet_release(server_ptr -> nx_web_http_server_request_packet); - server_ptr -> nx_web_http_server_request_packet = NX_NULL; - } - - /* Receive another packet. */ - status = _nx_web_http_server_receive(server_ptr, &(server_ptr -> nx_web_http_server_request_packet), wait_option); - if (status) - { - return(status); - } - - /* Update the packet pointer, data pointer and remaining size. */ - (*current_packet_pptr) = server_ptr -> nx_web_http_server_request_packet; - (*current_data_pptr) = server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr; - server_ptr -> nx_web_http_server_chunked_request_remaining_size = server_ptr -> nx_web_http_server_request_packet -> nx_packet_length; - } - - /* Process the packet chain. */ - if ((*current_data_pptr) == (*current_packet_pptr) -> nx_packet_append_ptr) - { -#ifndef NX_DISABLE_PACKET_CHAIN - if ((*current_packet_pptr) -> nx_packet_next == NX_NULL) - { - return(NX_INVALID_PACKET); - } - - (*current_packet_pptr) = (*current_packet_pptr) -> nx_packet_next; - (*current_data_pptr) = (*current_packet_pptr) -> nx_packet_prepend_ptr; - - /* Release the processed packet in the packet chain. */ - if (server_ptr -> nx_web_http_server_request_packet) - { - server_ptr -> nx_web_http_server_request_packet -> nx_packet_next = NX_NULL; - nx_packet_release(server_ptr -> nx_web_http_server_request_packet); - server_ptr -> nx_web_http_server_request_packet = (*current_packet_pptr); - } -#else - return(NX_INVALID_PACKET); -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Set the returned data. */ - *data = *(*current_data_pptr); - - /* Update the data pointer and remaining size. */ - (*current_data_pptr)++; - server_ptr -> nx_web_http_server_chunked_request_remaining_size--; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_request_byte_expect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if next byte is the expected data. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* data Expected data */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Compare result */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_request_read Get next data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_chunked_size_get Gets chunk size of request */ -/* _nx_web_http_server_request_chunked_get */ -/* Get chunk data from request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_request_byte_expect(NX_WEB_HTTP_SERVER *server_ptr, UCHAR data, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; -UCHAR tmp; - - /* Get next data. */ - status = _nx_web_http_server_request_read(server_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); - - if (status) - { - return(status); - } - - /* Return the compare result. */ - if (tmp != data) - { - return(NX_NOT_FOUND); - } - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_chunked_size_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the chunk size of the request packet chunk. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* chunk_size Returned chunk size */ -/* wait_option Suspension option */ -/* current_packet_pptr Pointer to the packet being */ -/* processed */ -/* current_data_ptr Pointer to the data will be */ -/* processed */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_chunked_size_get Get chunk size */ -/* _nx_web_http_server_request_byte_expect */ -/* Check if next byte is expected*/ -/* nx_packet_release Release packet */ -/* nx_packet_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_chunked_size_get(NX_WEB_HTTP_SERVER *server_ptr, UINT *chunk_size, ULONG wait_option, - NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr) -{ -UINT status; -UINT size = 0; -UCHAR tmp; -UINT chunk_extension = 0; - - if (server_ptr -> nx_web_http_server_actual_bytes_received < server_ptr -> nx_web_http_server_expect_receive_bytes) - { - - /* If there are bytes need to receive, set the size need to receive as chunk size. */ - *chunk_size = server_ptr -> nx_web_http_server_expect_receive_bytes - server_ptr -> nx_web_http_server_actual_bytes_received; - } - else - { - - /* Get the chunk size. */ - while (1) - { - - /* Read next byte from request packet. */ - status = _nx_web_http_server_request_read(server_ptr, &tmp, wait_option, current_packet_pptr, current_data_pptr); - if (status) - { - return(status); - } - - /* Skip the chunk extension. */ - if (chunk_extension && (tmp != '\r')) - { - continue; - } - - /* Calculate the size. */ - if ((tmp >= 'a') && (tmp <= 'f')) - { - size = (size << 4) + 10 + (UINT)(tmp - 'a'); - } - else if ((tmp >= 'A') && (tmp <= 'F')) - { - size = (size << 4) + 10 + (UINT)(tmp - 'A'); - } - else if ((tmp >= '0') && (tmp <= '9')) - { - size = (size << 4) + (UINT)(tmp - '0'); - } - else if (tmp == '\r') - { - - /* Find the end of chunk header. */ - break; - } - else if (tmp == ';') - { - - /* Find chunk extension. */ - chunk_extension = 1; - } - else - { - return(NX_NOT_FOUND); - } - } - - /* Expect '\n'. */ - status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, current_packet_pptr, current_data_pptr); - if (status) - { - return(status); - } - - *chunk_size = size; - } - - /* If there is no remaining data, receive another packet. */ - while (server_ptr -> nx_web_http_server_chunked_request_remaining_size == 0) - { - if (server_ptr -> nx_web_http_server_request_packet) - { - nx_packet_release(server_ptr -> nx_web_http_server_request_packet); - } - - status = _nx_web_http_server_receive(server_ptr, &(server_ptr -> nx_web_http_server_request_packet), wait_option); - if (status) - { - return(status); - } - - /* Update the current request packet, data pointer and remaining size. */ - (*current_packet_pptr) = server_ptr -> nx_web_http_server_request_packet; - (*current_data_pptr) = server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr; - server_ptr -> nx_web_http_server_chunked_request_remaining_size = server_ptr -> nx_web_http_server_request_packet -> nx_packet_length; - } - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_request_chunked_get PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function gets the chunk data from chunked request. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to the packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_chunked_size_get Get chunk size */ -/* _nx_web_http_server_request_byte_expect */ -/* Check if next byte is expected*/ -/* nx_packet_allocate Allocate packet */ -/* nx_packet_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_packet_get Get next packet from HTTP */ -/* server socket */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_request_chunked_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG wait_option) -{ -UINT status; -UINT chunk_size = 0, length = 0, temp_size = 0; -UINT remaining_size = 0; -NX_PACKET *packet_ptr; -NX_PACKET *current_packet_ptr = NX_NULL; -UCHAR *current_data_ptr = NX_NULL; - - /* Set pointer for processing packet data. */ - current_packet_ptr = server_ptr -> nx_web_http_server_request_packet; - - if (current_packet_ptr) - { - - /* Set current data pointer. */ - current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; - } - - /* Get chunk size. */ - status = _nx_web_http_server_chunked_size_get(server_ptr, &chunk_size, wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - /* Check if it's the end. */ - if (chunk_size == 0) - { - - /* Read CRLF. */ - status = _nx_web_http_server_request_byte_expect(server_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - *packet_pptr = NX_NULL; - - return(NX_WEB_HTTP_GET_DONE); - } - - /* Set the return packet. */ - *packet_pptr = server_ptr -> nx_web_http_server_request_packet; - server_ptr -> nx_web_http_server_request_packet = NX_NULL; - packet_ptr = *packet_pptr; - packet_ptr -> nx_packet_prepend_ptr = current_data_ptr; - remaining_size = server_ptr -> nx_web_http_server_chunked_request_remaining_size; - - /* Process the chunk data. */ - if (chunk_size <= remaining_size) - { - - /* One or more chunk in the remaining data. */ - temp_size = chunk_size; - - /* Check if the chunk data is all in this packet. */ - while (temp_size > (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr)) - { - -#ifndef NX_DISABLE_PACKET_CHAIN - if (current_packet_ptr -> nx_packet_next == NX_NULL) - { - return(NX_INVALID_PACKET); - } - - temp_size -= (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); - current_packet_ptr = current_packet_ptr -> nx_packet_next; - current_data_ptr = current_packet_ptr -> nx_packet_prepend_ptr; -#else - return(NX_INVALID_PACKET); -#endif /* NX_DISABLE_PACKET_CHAIN */ - } - - /* Skip the chunk data. */ - current_data_ptr += temp_size; - server_ptr -> nx_web_http_server_chunked_request_remaining_size -= chunk_size; - length = chunk_size; - - /* Read CRLF. */ - status = _nx_web_http_server_request_byte_expect(server_ptr, '\r', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - status = _nx_web_http_server_request_byte_expect(server_ptr, '\n', wait_option, ¤t_packet_ptr, ¤t_data_ptr); - if (status) - { - return(status); - } - - /* Check the remaining data. */ - if (server_ptr -> nx_web_http_server_chunked_request_remaining_size) - { - if (server_ptr -> nx_web_http_server_request_packet) - { - - /* If received new packet, adjust the prepend pointer of this packet. */ - server_ptr -> nx_web_http_server_request_packet -> nx_packet_prepend_ptr = current_data_ptr; - } - else - { - - /* Copy the remaining data to a new packet. */ - /* Allocate a packet. */ - status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, - &(server_ptr -> nx_web_http_server_request_packet), - 0, wait_option); - if (status) - { - return(status); - } - - /* Copy the remaining data in current packet to the new packet. */ - temp_size = (UINT)(current_packet_ptr -> nx_packet_append_ptr - current_data_ptr); - status = nx_packet_data_append(server_ptr -> nx_web_http_server_request_packet, - current_data_ptr, - temp_size, - server_ptr -> nx_web_http_server_packet_pool_ptr, - wait_option); - if (status) - { - return(status); - } - - /* Check if any remaining data not in current packet. */ - if (server_ptr -> nx_web_http_server_chunked_request_remaining_size > temp_size) - { -#ifndef NX_DISABLE_PACKET_CHAIN - - /* If there are chained packets, append the packets to the new packet. */ - if (current_packet_ptr -> nx_packet_next) - { - server_ptr -> nx_web_http_server_request_packet -> nx_packet_next = current_packet_ptr -> nx_packet_next; - server_ptr -> nx_web_http_server_request_packet -> nx_packet_last = current_packet_ptr -> nx_packet_last; - current_packet_ptr -> nx_packet_next = NX_NULL; - } - else -#endif /* NX_DISABLE_PACKET_CHAIN */ - { - return(NX_INVALID_PACKET); - } - } - } - - /* Update the packet length. */ - server_ptr -> nx_web_http_server_request_packet -> nx_packet_length = server_ptr -> nx_web_http_server_chunked_request_remaining_size; - } - } - else - { - - /* All the remaining data is in this chunk. */ - server_ptr -> nx_web_http_server_chunked_request_remaining_size = 0; - length = remaining_size; - } - - /* Set the received bytes. */ - server_ptr -> nx_web_http_server_expect_receive_bytes = chunk_size; - server_ptr -> nx_web_http_server_actual_bytes_received = length; - -#ifndef NX_DISABLE_PACKET_CHAIN - /* Set length of the packet chain header. */ - (*packet_pptr) -> nx_packet_length = length; - - /* Find the last packet. */ - while (packet_ptr -> nx_packet_next && - (length > (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr))) - { - length -= (UINT)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); - packet_ptr = packet_ptr -> nx_packet_next; - } - - /* Set the last packet. */ - (*packet_pptr) -> nx_packet_last = packet_ptr; - - /* Maybe the '\r\n' is in another packet, release this packet. */ - if (packet_ptr -> nx_packet_next) - { - nx_packet_release(packet_ptr -> nx_packet_next); - packet_ptr -> nx_packet_next = NX_NULL; - } -#endif /* NX_DISABLE_PACKET_CHAIN */ - - /* Set packet length and append pointer. */ - /* If the packet is chained, set the length and append pointer of the last packet. */ - packet_ptr -> nx_packet_length = length; - packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + length; - - return(NX_SUCCESS); -} - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_response_chunked_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the HTTP response chunked set */ -/* API call. */ -/* */ -/* INPUT */ -/* */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* chunk_size Size of the chunk */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_response_chunked_set */ -/* Actual response chunked set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr) -{ -UINT status; - - /* Make sure the client instance makes sense. */ - if ((server_ptr == NX_NULL) || (packet_ptr == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Call actual response chunked set function. */ - status = _nx_web_http_server_response_chunked_set(server_ptr, chunk_size, packet_ptr); - - /* Return success to the caller. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_response_chunked_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the chunked information of chunked response. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* chunk_size Size of the chunk */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_packet_data_append Append the packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr) -{ -UINT status; -UINT temp_size, i, j; -CHAR temp_string[10]; -CHAR crlf[2] = {13,10}; - - /* Covert the size to ASCII. */ - temp_size = chunk_size; - i = 0; - - while (temp_size) - { - - for (j = i; j > 0; j--) - { - temp_string[j] = temp_string[j - 1]; - } - - if ((temp_size & 0x0F) < 10) - { - temp_string[0] = (CHAR)((temp_size & 0x0F) + '0'); - } - else - { - temp_string[0] = (CHAR)((temp_size & 0x0F) - 10 + 'a'); - } - temp_size = temp_size >> 4; - i++; - } - - if (i == 0) - { - temp_string[i++] = '0'; - } - - /* Place the chunk size in the packet. */ - status = nx_packet_data_append(packet_ptr, temp_string, i, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - if (status) - { - return(status); - } - - /* Place the CRLF to signal the end of the chunk size. */ - status = nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - if (status) - { - return(status); - } - - /* Set the request chunked flag. */ - server_ptr -> nx_web_http_server_response_chunked = NX_TRUE; - - /* The total bytes need to transfer is chunk size plus chunk header length. */ - server_ptr -> nx_web_http_server_expect_transfer_bytes = chunk_size + i + 2; - server_ptr -> nx_web_http_server_actual_bytes_transferred = 0; - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_chunked_check PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks if the packet is chunked. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to the packet */ -/* */ -/* OUTPUT */ -/* */ -/* status The packet is chunked or not */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_field_value_get Get filed value */ -/* _nx_web_http_server_memicmp Compare two strings */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_packet_content_find */ -/* Find content length in the */ -/* HTTP header */ -/* _nx_web_http_server_content_get_extended */ -/* Get user specified portion of */ -/* HTTP header */ -/* _nx_web_http_server_receive_data HTTP Server receive processing*/ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_chunked_check(NX_PACKET *packet_ptr) -{ -UINT status; -CHAR temp_string[20]; -UINT temp_string_length; - - /* Check if the packet is chunked. */ - status = _nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"Transfer-Encoding", 17, (UCHAR *)temp_string, sizeof(temp_string)); - - if ((status == NX_SUCCESS) && - (_nx_utility_string_length_check(temp_string, &temp_string_length, sizeof(temp_string) - 1) == NX_SUCCESS) && - (_nx_web_http_server_memicmp((UCHAR *)temp_string, temp_string_length, (UCHAR *)"chunked", 7) == 0)) - { - return(NX_TRUE); - } - - return(NX_FALSE); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_response_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks for errors in the call to allocate packets for */ -/* an HTTP(S) server session, as used for PUT and POST operations. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP client */ -/* packet_ptr Pointer to allocated packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nxe_web_http_server_response_packet_allocate */ -/* Actual packet allocation call */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, - UINT wait_option) -{ -UINT status; - - /* Check our pointers. */ - if(server_ptr == NX_NULL || packet_ptr == NX_NULL) - { - return(NX_PTR_ERROR); - } - - /* Call the actual function. */ - status = _nx_web_http_server_response_packet_allocate(server_ptr, packet_ptr, wait_option); - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_response_packet_allocate PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function allocates a packet for Server HTTP(S) responses so */ -/* that servers needing to send large amounts of data (such as for */ -/* multi-part file upload) can allocated the needed. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to allocated packet */ -/* wait_option Suspension option */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_packet_allocate Allocate a TLS packet */ -/* nx_packet_allocate Allocate a TCP packet */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, - UINT wait_option) -{ -UINT status; - - /* Allocate a packet. */ -#ifdef NX_WEB_HTTPS_ENABLE - if(server_ptr -> nx_web_http_is_https_server) - { - status = nx_secure_tls_packet_allocate(&(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session), - server_ptr -> nx_web_http_server_packet_pool_ptr, - packet_ptr, wait_option); - } - else -#endif - { - status = nx_packet_allocate(server_ptr -> nx_web_http_server_packet_pool_ptr, - packet_ptr, - NX_TCP_PACKET, wait_option); - } - - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_generate_response_header */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for generating HTTP response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* content_length Length of content */ -/* content_type Type of content */ -/* additional_header Other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_callback_generate_response_header */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (status_code == NX_NULL)) - return(NX_PTR_ERROR); - - return _nx_web_http_server_callback_generate_response_header(server_ptr, packet_pptr, status_code, content_length, content_type, additional_header); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_generate_response_header */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to generate HTTP */ -/* response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* content_length Length of content */ -/* content_type Type of content */ -/* additional_header Other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_generate_response_header */ -/* Generate response header */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header) -{ -UINT status_code_length = 0; -UINT content_type_length = 0; -UINT additional_header_length = 0; - - /* Check status code, content type and additional header length. */ - if (_nx_utility_string_length_check(status_code, &status_code_length, NX_MAX_STRING_LENGTH) || - (content_type && _nx_utility_string_length_check(content_type, &content_type_length, NX_MAX_STRING_LENGTH)) || - (additional_header && _nx_utility_string_length_check(additional_header, &additional_header_length, NX_MAX_STRING_LENGTH))) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - return _nx_web_http_server_generate_response_header(server_ptr, packet_pptr, status_code, - status_code_length, content_length, - content_type, content_type_length, - additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_generate_response_header_extended */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for generating HTTP response header. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_callback_generate_response_header_extended */ -/* Actual generate header */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, - NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, - CHAR *content_type, UINT content_type_length, - CHAR *additional_header, UINT additional_header_length) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || - (packet_pptr == NX_NULL) || (status_code == NX_NULL)) - return(NX_PTR_ERROR); - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - return _nx_web_http_server_callback_generate_response_header_extended(server_ptr, packet_pptr, status_code, - status_code_length, content_length, - content_type, content_type_length, - additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_generate_response_header_extended */ -/* PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to generate HTTP */ -/* response header. */ -/* */ -/* Note: The strings of status_code, content_type and additional_header*/ -/* must be NULL-terminated and length of each string matches the */ -/* length specified in the argument list. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_pptr Pointer to packet */ -/* status_code Status-code and reason-phrase */ -/* status_code_length Length of status-code */ -/* content_length Length of content */ -/* content_type Type of content */ -/* content_type_length Length of content type */ -/* additional_header Other HTTP headers */ -/* additional_header_length Length of other HTTP headers */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_generate_response_header */ -/* Generate response header */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, - NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, - CHAR *content_type, UINT content_type_length, - CHAR *additional_header, UINT additional_header_length) -{ -UINT temp_status_code_length = 0; -UINT temp_content_type_length = 0; -UINT temp_add_header_length = 0; - - /* Check status code, content type and additional header length. */ - if (_nx_utility_string_length_check(status_code, &temp_status_code_length, status_code_length) || - (content_type && _nx_utility_string_length_check(content_type, &temp_content_type_length, content_type_length)) || - (additional_header && _nx_utility_string_length_check(additional_header, &temp_add_header_length, additional_header_length))) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Validate string length. */ - if ((status_code_length != temp_status_code_length) || - (content_type && content_type_length != temp_content_type_length) || - (additional_header && additional_header_length != temp_add_header_length)) - { - return(NX_WEB_HTTP_ERROR); - } - - /* Call the internal HTTP response send function. */ - return _nx_web_http_server_generate_response_header(server_ptr, packet_pptr, status_code, - status_code_length, content_length, - content_type, content_type_length, - additional_header, additional_header_length); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_callback_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for sending a packet. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_callback_packet_send */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (packet_ptr == NX_NULL)) - return(NX_PTR_ERROR); - - return _nx_web_http_server_callback_packet_send(server_ptr, packet_ptr); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_callback_packet_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used in callback function to send a packet. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_send Send packet to client */ -/* nx_packet_data_append Append packet data */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ -UINT status; -CHAR crlf[2] = {13,10}; -UINT length = packet_ptr -> nx_packet_length; - - /* If the request is chunked, add CRLF at the end of the chunk. */ - if (server_ptr -> nx_web_http_server_response_chunked) - { - - /* Check the packet length. */ - if (server_ptr -> nx_web_http_server_expect_transfer_bytes < (server_ptr -> nx_web_http_server_actual_bytes_transferred + length)) - { - return(NX_INVALID_PACKET); - } - - if (server_ptr -> nx_web_http_server_expect_transfer_bytes == (server_ptr -> nx_web_http_server_actual_bytes_transferred + length)) - { - - /* Place an extra CRLF to signal the end of the chunk. */ - nx_packet_data_append(packet_ptr, crlf, 2, server_ptr -> nx_web_http_server_packet_pool_ptr, NX_WAIT_FOREVER); - } - - /* Update the transferred bytes. */ - server_ptr -> nx_web_http_server_actual_bytes_transferred += length; - } - - /* Send internal. */ - status = _nx_web_http_server_send(server_ptr, packet_ptr, NX_WEB_HTTP_SERVER_TIMEOUT_SEND); - if (status) - { - return(status); - } - - return(NX_SUCCESS); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_gmt_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting gmt callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* gmt_get Pointer to application's */ -/* GMT time function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_gmt_callback_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (gmt_get == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_web_http_server_gmt_callback_set(server_ptr, gmt_get); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_gmt_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets gmt callback function. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* gmt_get Pointer to application's */ -/* GMT time function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the function pointer. */ - server_ptr -> nx_web_http_server_gmt_get = gmt_get; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_cache_info_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting cache info callback function.*/ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* cache_info_get Pointer to application's */ -/* cache information function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_cache_info_callback_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (cache_info_get == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_web_http_server_cache_info_callback_set(server_ptr, cache_info_get); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_cache_info_callback_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets cache info callback function. */ -/* */ -/* Note: The string resource in callback functions authentication_check*/ -/* and request_notify is built by internal logic and always */ -/* NULL-terminated. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* cache_info_get Pointer to application's */ -/* cache information function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the function pointer. */ - server_ptr -> nx_web_http_server_cache_info_get = cache_info_get; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_date_to_string PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts from date to string. */ -/* */ -/* INPUT */ -/* */ -/* date Pointer to HTTP date */ -/* string Pointer to output buffer */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_date_convert */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_get_process */ -/* _nx_web_http_server_generate_response_header */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_date_to_string(NX_WEB_HTTP_SERVER_DATE *date, CHAR *string) -{ - -UINT index = 0; - - /* RDC1122-date. */ - /* Append weekday. */ - string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][0]; - string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][1]; - string[index++] = _nx_web_http_server_weekday[date -> nx_web_http_server_weekday][2]; - string[index++] = ','; - string[index++] = ' '; - - /* Convert and append day. */ - _nx_web_http_server_date_convert(date -> nx_web_http_server_day, 2, &string[index]); - index += 2; - string[index++] = ' '; - - /* Append month. */ - string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][0]; - string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][1]; - string[index++] = _nx_web_http_server_month[date -> nx_web_http_server_month][2]; - string[index++] = ' '; - - /* Convert and append year. */ - _nx_web_http_server_date_convert(date -> nx_web_http_server_year, 4, &string[index]); - index += 4; - string[index++] = ' '; - - /* Convert and append hour. */ - _nx_web_http_server_date_convert(date -> nx_web_http_server_hour, 2, &string[index]); - index += 2; - string[index++] = ':'; - - /* Convert and append minute. */ - _nx_web_http_server_date_convert(date -> nx_web_http_server_minute, 2, &string[index]); - index += 2; - string[index++] = ':'; - - /* Convert and append second. */ - _nx_web_http_server_date_convert(date -> nx_web_http_server_second, 2, &string[index]); - index += 2; - string[index++] = ' '; - string[index++] = 'G'; - string[index++] = 'M'; - string[index++] = 'T'; - - return index; -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_date_convert PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function converts a date from number to string. */ -/* */ -/* INPUT */ -/* */ -/* date The number to convert */ -/* count Digital count for string */ -/* string Pointer to output buffer */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_date_to_string */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_date_convert(UINT date, UINT count, CHAR *string) -{ - -UINT digit; - - /* Initialize all 4 bytes to digit 0. */ - *((ULONG*)string) = 0x30303030; - string[count] = 0; - - /* Loop to convert the number to ASCII. */ - while(count > 0) - { - count--; - - /* Compute the next decimal digit. */ - digit = date % 10; - - /* Update the input date. */ - date = date / 10; - - /* Store the new digit in ASCII form. */ - string[count] = (CHAR) (digit + 0x30); - } -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_mime_maps_additional_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks error for setting additional MIME maps. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* mime_maps Pointer MIME map array */ -/* mime_maps_num Number of MIME map array */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_mime_maps_additional_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) -{ - - /* Check for invalid input pointers. */ - if ((server_ptr == NX_NULL) || (server_ptr -> nx_web_http_server_id != NX_WEB_HTTP_SERVER_ID) || (mime_maps == NX_NULL)) - return(NX_PTR_ERROR); - - /* Send internal. */ - return _nx_web_http_server_mime_maps_additional_set(server_ptr, mime_maps, mime_maps_num); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_mime_maps_additional_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets additional MIME maps. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* mime_maps Pointer MIME map array */ -/* mime_maps_num Number of MIME map array */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num) -{ - -TX_INTERRUPT_SAVE_AREA - - /* Lockout interrupts. */ - TX_DISABLE - - /* Set the mime maps. */ - server_ptr -> nx_web_http_server_mime_maps_additional = mime_maps; - server_ptr -> nx_web_http_server_mime_maps_additional_num = mime_maps_num; - - /* Restore interrupts. */ - TX_RESTORE - - return NX_SUCCESS; -} - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_get_client_keepalive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function indicates whether this connection will keep alive. */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet */ -/* */ -/* OUTPUT */ -/* */ -/* None */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_field_value_get Get field value */ -/* _nx_web_http_server_memicmp Compare two strings */ -/* _nx_utility_string_length_check Check string length */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_receive_data */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_get_client_keepalive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr) -{ -UCHAR *ch; -UINT version = 0; -UCHAR connection_value[16]; -UINT connection_value_length; - - - /* Locate to HTTP version. */ - ch = packet_ptr -> nx_packet_prepend_ptr; - while(ch + 11 < packet_ptr -> nx_packet_append_ptr) - { - if((*ch == ' ') && - (*(ch + 1) == 'H') && - (*(ch + 2) == 'T') && - (*(ch + 3) == 'T') && - (*(ch + 4) == 'P') && - (*(ch + 5) == '/')) - { - - /* Find the HTTP version. */ - ch += 6; - if((*ch >= '0') && - (*ch <= '9') && - (*(ch + 1) == '.') && - (*(ch + 2) >= '0') && - (*(ch + 2) <= '9')) - { - - /* Get the version. */ - version = (UCHAR)((*ch - '0') << 4) | (UCHAR)(*(ch + 2) - '0'); - } - - break; - } - else if((*ch == 13) && (*(ch + 1) == 10)) - { - - /* Find the end of line. */ - break; - } - - /* Move to the next byte. */ - ch++; - } - - /* Is a valid HTTP version found? */ - if(version == 0) - { - server_ptr -> nx_web_http_server_keepalive = NX_FALSE; - return; - } - - /* Initialize the keepalive flag. */ - if(version > 0x10) - server_ptr -> nx_web_http_server_keepalive = NX_TRUE; - else - server_ptr -> nx_web_http_server_keepalive = NX_FALSE; - - /* Searching for 'connection' header. */ - if(_nx_web_http_server_field_value_get(packet_ptr, (UCHAR *)"connection", 10, connection_value, sizeof(connection_value)) == NX_SUCCESS) - { - _nx_utility_string_length_check((CHAR *)connection_value, &connection_value_length, sizeof(connection_value) - 1); - - if(_nx_web_http_server_memicmp(connection_value, connection_value_length, (UCHAR *)"keep-alive", 10) == NX_SUCCESS) - server_ptr -> nx_web_http_server_keepalive = NX_TRUE; - else if(_nx_web_http_server_memicmp(connection_value, connection_value_length, (UCHAR *)"close", 5) == NX_SUCCESS) - server_ptr -> nx_web_http_server_keepalive = NX_FALSE; - } -} -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_send PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sends data to the remote host using either the TCP */ -/* socket for plain HTTP or the TLS session for HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet to send. */ -/* wait_option Indicates behavior if packet */ -/* cannot be sent. */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_send Send data using TLS session */ -/* nx_secure_tcp_socket_send Send data using TCP socket */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG wait_option) -{ - -UINT status; -NX_TCP_SOCKET *tcp_socket; -#ifdef NX_WEB_HTTPS_ENABLE -NX_SECURE_TLS_SESSION *tls_session; -#endif - - tcp_socket = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket); - -#ifdef NX_WEB_HTTPS_ENABLE - - tls_session = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session); - - /* End TLS session if using HTTPS. */ - if(server_ptr -> nx_web_http_is_https_server) - { - status = nx_secure_tls_session_send(tls_session, packet_ptr, wait_option); - } - else -#endif - { - status = nx_tcp_socket_send(tcp_socket, packet_ptr, wait_option); - } - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_receive PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function receives data from the remote host using either the */ -/* TCP socket for plain HTTP or the TLS session for HTTPS. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* packet_ptr Pointer to packet to send. */ -/* wait_option Indicates behavior if packet */ -/* cannot be received */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* nx_secure_tls_session_receive Receive data using TLS */ -/* nx_secure_tcp_socket_receive Receive data using TCP */ -/* */ -/* CALLED BY */ -/* */ -/* _nx_web_http_server_packet_get Get next packet from HTTP */ -/* server socket. */ -/* _nx_web_http_server_get_client_request */ -/* Get complete HTTP request */ -/* _nx_web_http_server_request_read Get the next data in byte */ -/* _nx_web_http_server_chunked_size_get Get chunk size of the request */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_receive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG wait_option) -{ - -UINT status; -NX_TCP_SOCKET *tcp_socket; -#ifdef NX_WEB_HTTPS_ENABLE -NX_SECURE_TLS_SESSION *tls_session; -#endif - - tcp_socket = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_socket); - -#ifdef NX_WEB_HTTPS_ENABLE - tls_session = &(server_ptr -> nx_web_http_server_current_session_ptr -> nx_tcp_session_tls_session); - - /* End TLS session if using HTTPS. */ - if(server_ptr -> nx_web_http_is_https_server) - { - status = nx_secure_tls_session_receive(tls_session, packet_ptr, wait_option); - } - else -#endif - { - status = nx_tcp_socket_receive(tcp_socket, packet_ptr, wait_option); - } - - /* Return status. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_connection_reset PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used whenever the HTTP server needs to close the */ -/* network connection and reset to receive new requests. If the server */ -/* is using TLS for HTTPS, then it also ends the TLS session. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* session_ptr Pointer to session */ -/* error_number Error status in caller */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_connection_disconnect */ -/* End TLS session, and calls */ -/* Disconnect and unaccept on the*/ -/* socket */ -/* _nx_tcp_server_socket_relisten Reset socket to accept another*/ -/* connection */ -/* */ -/* CALLED BY */ -/* */ -/* Application code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_connection_reset(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option) -{ -NX_TCP_SOCKET *tcp_socket; - - - tcp_socket = &(session_ptr -> nx_tcp_session_socket); - - /* Disconnect the server connection. */ - _nx_web_http_server_connection_disconnect(server_ptr, session_ptr, wait_option); - - /* Relisten on the HTTP(S) Server port. */ - nx_tcp_server_socket_relisten(server_ptr -> nx_web_http_server_ip_ptr, server_ptr -> nx_web_http_server_listen_port, tcp_socket); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_connection_disconnect PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function is used whenever the HTTP server needs to close the */ -/* network connection completely. If the server is using TLS for HTTPS */ -/* then it also ends the TLS session. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* server_ptr Pointer to HTTP server */ -/* session_ptr Pointer to session */ -/* wait_option Wait option for TCP socket */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_secure_tls_session_end End TLS session */ -/* */ -/* CALLED BY */ -/* */ -/* */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -VOID _nx_web_http_server_connection_disconnect(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option) -{ -NX_TCP_SOCKET *tcp_socket; -#ifdef NX_WEB_HTTPS_ENABLE -NX_SECURE_TLS_SESSION *tls_session; -#endif - -#ifndef NX_WEB_HTTPS_ENABLE - NX_PARAMETER_NOT_USED(server_ptr); - NX_PARAMETER_NOT_USED(wait_option); -#endif /* NX_WEB_HTTPS_ENABLE */ - - tcp_socket = &(session_ptr -> nx_tcp_session_socket); - -#ifdef NX_WEB_HTTPS_ENABLE - - tls_session = &(session_ptr -> nx_tcp_session_tls_session); - - /* End TLS session if using HTTPS. */ - if(server_ptr -> nx_web_http_is_https_server) - { - _nx_secure_tls_session_end(tls_session, wait_option); - } -#endif - - /* Disconnect from the current connection. */ - nx_tcp_socket_disconnect(tcp_socket, NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT); - - /* Unaccept the connection. */ - nx_tcp_server_socket_unaccept(tcp_socket); - -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_digest_authenticate_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function performs error checking for service to set digest */ -/* authenticate callback function. */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* digest_authenticate_callback Pointer to application's */ -/* digest authenticate callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_web_http_server_digest_authenticate_notify_set */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)) -{ - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (digest_authenticate_callback == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - return(_nx_web_http_server_digest_authenticate_notify_set(http_server_ptr, digest_authenticate_callback)); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_digest_authenticate_notify_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets digest authenticate callback function. */ -/* */ -/* Note: The strings name_ptr, realm_ptr, password_ptr, method, */ -/* authorization_uri, authorization_nc and authorization_cnonce in */ -/* callback function digest_authenticate_callback is built by internal */ -/* logic and always NULL-terminated. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* digest_authenticate_callback Pointer to application's */ -/* digest authenticate callback */ -/* function */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)) -{ - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - http_server_ptr -> nx_web_http_server_digest_authenticate_callback = digest_authenticate_callback; - - return(NX_SUCCESS); -#else - NX_PARAMETER_NOT_USED(http_server_ptr); - NX_PARAMETER_NOT_USED(digest_authenticate_callback); - - return(NX_NOT_SUPPORTED); -#endif -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nxe_web_http_server_authentication_check_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function checks errors for setting authentication checking */ -/* callback function. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* authentication_check_extended Pointer to application's */ -/* authentication checking */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* _nx_http_server_authentication_check_set */ -/* Set authentication callback */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nxe_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) -{ -UINT status; - - /* Check for invalid input pointers. */ - if ((http_server_ptr == NX_NULL) || (authentication_check_extended == NX_NULL)) - { - return(NX_PTR_ERROR); - } - - /* Check for appropriate caller. */ - NX_THREADS_ONLY_CALLER_CHECKING - - /* Call the actual authentication checking set function. */ - status= _nx_web_http_server_authentication_check_set(http_server_ptr, authentication_check_extended); - - /* Return staus. */ - return(status); -} - - -/**************************************************************************/ -/* */ -/* FUNCTION RELEASE */ -/* */ -/* _nx_web_http_server_authentication_check_set PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This function sets the callback function of authentication checking.*/ -/* */ -/* Note: The strings of name, password and realm must be */ -/* NULL-terminated and length of each string matches the length */ -/* specified in the argument list. The string resource in callback */ -/* function authentication_check and request_notify is built by */ -/* internal logic and always NULL-terminated. */ -/* */ -/* */ -/* INPUT */ -/* */ -/* http_server_ptr Pointer to HTTP server */ -/* authentication_check_extended Pointer to application's */ -/* authentication checking */ -/* */ -/* OUTPUT */ -/* */ -/* status Completion status */ -/* */ -/* CALLS */ -/* */ -/* None */ -/* */ -/* CALLED BY */ -/* */ -/* Application Code */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ -UINT _nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)) -{ - - /* Set the extended authentication checking function. */ - http_server_ptr -> nx_web_http_server_authentication_check_extended = authentication_check_extended; - - /* Return success. */ - return(NX_SUCCESS); -} diff --git a/protocol_handlers/web/nx_web_http_server.h b/protocol_handlers/web/nx_web_http_server.h deleted file mode 100644 index eebd1005..00000000 --- a/protocol_handlers/web/nx_web_http_server.h +++ /dev/null @@ -1,674 +0,0 @@ -/**************************************************************************/ -/* */ -/* Copyright (c) Microsoft Corporation. All rights reserved. */ -/* */ -/* This software is licensed under the Microsoft Software License */ -/* Terms for Microsoft Azure RTOS. Full text of the license can be */ -/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ -/* and in the root directory of this software. */ -/* */ -/**************************************************************************/ - - -/**************************************************************************/ -/**************************************************************************/ -/** */ -/** NetX Web Component */ -/** */ -/** Hypertext Transfer Protocol (HTTP) */ -/** Hypertext Transfer Protocol Secure (HTTPS using TLS) */ -/** */ -/**************************************************************************/ -/**************************************************************************/ - - -/**************************************************************************/ -/* */ -/* APPLICATION INTERFACE DEFINITION RELEASE */ -/* */ -/* nx_web_http_server.h PORTABLE C */ -/* 6.0 */ -/* AUTHOR */ -/* */ -/* Yuxin Zhou, Microsoft Corporation */ -/* */ -/* DESCRIPTION */ -/* */ -/* This file defines the NetX Hypertext Transfer Protocol (HTTP) */ -/* component, including all data types and external references. */ -/* It is assumed that nx_api.h and nx_port.h have already been */ -/* included, along with fx_api.h and fx_port.h. */ -/* */ -/* RELEASE HISTORY */ -/* */ -/* DATE NAME DESCRIPTION */ -/* */ -/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ -/* */ -/**************************************************************************/ - -#ifndef NXD_HTTP_SERVER_H -#define NXD_HTTP_SERVER_H - -/* Determine if a C++ compiler is being used. If so, ensure that standard - C is used to process the API information. */ - -#ifdef __cplusplus - -/* Yes, C++ compiler is present. Use standard C. */ -extern "C" { - -#endif - -/* If HTTPS is enabled, make sure TLS is enabled in the TCP server. */ -#ifdef NX_WEB_HTTPS_ENABLE -#ifndef NX_TCPSERVER_ENABLE_TLS -#define NX_TCPSERVER_ENABLE_TLS -#endif -#endif - -#include "nx_api.h" -/* If not using FileX, define this option and define the file writing services - declared in filex_stub.h. */ -/* #define NX_WEB_HTTP_NO_FILEX */ - -#ifndef NX_WEB_HTTP_NO_FILEX -#include "fx_api.h" -#else -#include "filex_stub.h" -#endif - -/* Include common HTTP definitions. */ -#include "nx_web_http_common.h" - -/* Include multiple-socket TCP/TLS support. */ -#include "nx_tcpserver.h" - -/* Define the HTTP Server ID. */ -#define NX_WEB_HTTP_SERVER_ID 0x48545451UL - -/* Enable Digest authentication. -#define NX_WEB_HTTP_DIGEST_ENABLE -*/ - -/* Define HTTP TCP socket create options. */ -#ifndef NX_WEB_HTTP_SERVER_PRIORITY -#define NX_WEB_HTTP_SERVER_PRIORITY 4 -#endif - -#ifndef NX_WEB_HTTP_SERVER_WINDOW_SIZE -#define NX_WEB_HTTP_SERVER_WINDOW_SIZE 8192 -#endif - -#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT -#define NX_WEB_HTTP_SERVER_TIMEOUT_ACCEPT (1 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE -#define NX_WEB_HTTP_SERVER_TIMEOUT_RECEIVE (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_SEND -#define NX_WEB_HTTP_SERVER_TIMEOUT_SEND (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT -#define NX_WEB_HTTP_SERVER_TIMEOUT_DISCONNECT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_SERVER_TIMEOUT -#define NX_WEB_HTTP_SERVER_TIMEOUT (10 * NX_IP_PERIODIC_RATE) -#endif - -#ifndef NX_WEB_HTTP_SERVER_SESSION_MAX -#define NX_WEB_HTTP_SERVER_SESSION_MAX 2 -#endif - -#ifndef NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE -#define NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE (sizeof(NX_TCP_SESSION) * NX_WEB_HTTP_SERVER_SESSION_MAX) -#endif - -#ifndef NX_WEB_HTTP_SERVER_MAX_PENDING -#define NX_WEB_HTTP_SERVER_MAX_PENDING (NX_WEB_HTTP_SERVER_SESSION_MAX << 1) -#endif - -#ifndef NX_WEB_HTTP_SERVER_THREAD_TIME_SLICE -#define NX_WEB_HTTP_SERVER_THREAD_TIME_SLICE 2 -#endif - - -#ifndef NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE -#define NX_WEB_HTTP_SERVER_MIN_PACKET_SIZE 600 -#endif - -/* Define the HTTP server retry parameters. */ - -#ifndef NX_WEB_HTTP_SERVER_RETRY_SECONDS -#define NX_WEB_HTTP_SERVER_RETRY_SECONDS 2 /* 2 second initial timeout */ -#endif - -#ifndef NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH -#define NX_WEB_HTTP_SERVER_TRANSMIT_QUEUE_DEPTH 20 /* Maximum of 20 queued transmit packets */ -#endif - -#ifndef NX_WEB_HTTP_SERVER_RETRY_MAX -#define NX_WEB_HTTP_SERVER_RETRY_MAX 10 /* Maximum of 10 retries per packet */ -#endif - -#ifndef NX_WEB_HTTP_SERVER_RETRY_SHIFT -#define NX_WEB_HTTP_SERVER_RETRY_SHIFT 1 /* Every retry is twice as long */ -#endif - -/* Define HTTP Server request types. */ - -#define NX_WEB_HTTP_SERVER_UNKNOWN_REQUEST 0 -#define NX_WEB_HTTP_SERVER_GET_REQUEST 1 -#define NX_WEB_HTTP_SERVER_POST_REQUEST 2 -#define NX_WEB_HTTP_SERVER_HEAD_REQUEST 3 -#define NX_WEB_HTTP_SERVER_PUT_REQUEST 4 -#define NX_WEB_HTTP_SERVER_DELETE_REQUEST 5 - - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - -/* Include the MD5 digest header file. */ - -#include "nx_md5.h" - -#endif - -#ifdef NX_WEB_HTTPS_ENABLE -/* Include TLS for HTTPS support. */ -#include "nx_secure_tls_api.h" -#endif - -/* Define default MIME type. */ -/* Page 14, Section 5.2, RFC 2045 */ -#define NX_WEB_HTTP_SERVER_DEFAULT_MIME "text/plain" - - -/* Define the MIME map structure. */ - -typedef struct NX_WEB_HTTP_SERVER_MIME_MAP_STRUCT -{ - CHAR *nx_web_http_server_mime_map_extension; /* Extension of file */ - CHAR *nx_web_http_server_mime_map_type; /* MIME type of file */ -} NX_WEB_HTTP_SERVER_MIME_MAP; - - -/* Define the date structure. */ - -typedef struct NX_WEB_HTTP_SERVER_DATE_STRUCT -{ - USHORT nx_web_http_server_year; /* Year */ - UCHAR nx_web_http_server_month; /* Month */ - UCHAR nx_web_http_server_day; /* Day */ - UCHAR nx_web_http_server_hour; /* Hour */ - UCHAR nx_web_http_server_minute; /* Minute */ - UCHAR nx_web_http_server_second; /* Second */ - UCHAR nx_web_http_server_weekday; /* Weekday */ -} NX_WEB_HTTP_SERVER_DATE; - -/* Define the multipart context data structure. */ - -typedef struct NX_WEB_HTTP_SERVER_MULTIPART_STRUCT -{ - - /* Boundary string. */ - UCHAR nx_web_http_server_multipart_boundary[NX_WEB_HTTP_MAX_HEADER_FIELD + 1]; - - /* Offset of available data. */ - UINT nx_web_http_server_multipart_available_offset; - - /* Length of available data. */ - UINT nx_web_http_server_multipart_available_length; - - /* Boundary find status. */ - volatile UINT nx_web_http_server_multipart_boundary_find; - - /* The next packet to process. */ - NX_PACKET *nx_web_http_server_multipart_next_packet; - - /* Offset of next available data. */ - UINT nx_web_http_server_multipart_next_available_offset; - - /* The packet returned at last. */ - NX_PACKET *nx_web_http_server_multipart_last_packet; - -} NX_WEB_HTTP_SERVER_MULTIPART; - - -/* Define the HTTP Server data structure. */ - -typedef struct NX_WEB_HTTP_SERVER_STRUCT -{ - ULONG nx_web_http_server_id; /* HTTP Server ID */ - CHAR *nx_web_http_server_name; /* Name of this HTTP Server */ - NX_IP *nx_web_http_server_ip_ptr; /* Pointer to associated IP structure */ - CHAR nx_web_http_server_request_resource[NX_WEB_HTTP_MAX_RESOURCE + 1]; - /* Uniform Resource Locator (URL) */ - NX_PACKET_POOL *nx_web_http_server_packet_pool_ptr; /* Pointer to HTTP Server packet pool */ - FX_MEDIA *nx_web_http_server_media_ptr; /* Pointer to media control block */ - ULONG nx_web_http_server_get_requests; /* Number of get requests */ - ULONG nx_web_http_server_head_requests; /* Number of head requests */ - ULONG nx_web_http_server_put_requests; /* Number of put requests */ - ULONG nx_web_http_server_delete_requests; /* Number of delete requests */ - ULONG nx_web_http_server_post_requests; /* Number of post requests */ - ULONG nx_web_http_server_unknown_requests; /* Number of unknown requests */ - ULONG nx_web_http_server_total_bytes_sent; /* Number of total bytes sent */ - ULONG nx_web_http_server_total_bytes_received; /* Number of total bytes received */ - ULONG nx_web_http_server_allocation_errors; /* Number of allocation errors */ - ULONG nx_web_http_server_invalid_http_headers; /* Number of invalid http headers */ - FX_FILE nx_web_http_server_file; /* HTTP file control block */ - - NX_TCPSERVER nx_web_http_server_tcpserver; /* TCP server with multiple sessions */ - NX_TCP_SESSION *nx_web_http_server_current_session_ptr; /* Current session in process */ - UCHAR nx_web_http_server_session_buffer[NX_WEB_HTTP_SERVER_SESSION_BUFFER_SIZE]; - /* Size of session buffer */ - - NX_TCP_SOCKET nx_web_http_server_socket; /* HTTP Server TCP socket */ - UINT nx_web_http_server_listen_port; /* HTTP(S) listening port. */ -#ifdef NX_WEB_HTTPS_ENABLE - UINT nx_web_http_is_https_server; /* If using TLS for HTTPS, set to true. */ -#endif - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - NX_MD5 nx_web_http_server_md5data; /* HTTP server MD5 work area */ -#endif /* NX_WEB_HTTP_DIGEST_ENABLE */ - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE - NX_WEB_HTTP_SERVER_MULTIPART - nx_web_http_server_multipart; /* HTTP multipart area */ -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - - UINT nx_web_http_server_request_type; /* HTTP request type */ - NX_WEB_HTTP_SERVER_MIME_MAP - *nx_web_http_server_mime_maps_additional; /* Additional HTTP MIME maps */ - UINT nx_web_http_server_mime_maps_additional_num; /* Number of additional HTTP MIME maps */ - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE - UCHAR nx_web_http_server_keepalive; /* HTTP keepalive flag */ - UCHAR nx_web_http_server_reserved; /* Reserved */ -#else - UCHAR nx_web_http_server_reserved[2]; /* Reserved */ -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - - UCHAR nx_web_http_server_response_chunked; /* Flag for chunked response */ - UCHAR nx_web_http_server_request_chunked; /* Flag for chunked request */ - UINT nx_web_http_server_expect_transfer_bytes; /* The bytes expected to transfer */ - UINT nx_web_http_server_actual_bytes_transferred; /* The actual transferred bytes */ - UINT nx_web_http_server_expect_receive_bytes; /* The bytes expected to receive */ - UINT nx_web_http_server_actual_bytes_received; /* The actual received bytes */ - UINT nx_web_http_server_chunked_request_remaining_size; /* Remaining size of the chunked request*/ - NX_PACKET *nx_web_http_server_request_packet; /* Pointer to the received request */ - - /* Define the user supplied routines that are used to inform the application of particular server requests. */ - - UINT (*nx_web_http_server_authentication_check)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm); - UINT (*nx_web_http_server_authentication_check_extended)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length); - UINT (*nx_web_http_server_request_notify)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr); -#ifdef __PRODUCT_NETXDUO__ - UINT (*nx_web_http_server_invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type); -#else - UINT (*nx_web_http_server_invalid_username_password_callback)(CHAR *resource, ULONG client_address, UINT request_type); -#endif - VOID (*nx_web_http_server_gmt_get)(NX_WEB_HTTP_SERVER_DATE *date); - UINT (*nx_web_http_server_cache_info_get)(CHAR *resource, UINT *max_age, NX_WEB_HTTP_SERVER_DATE *last_modified); -#ifdef NX_WEB_HTTP_DIGEST_ENABLE - UINT (*nx_web_http_server_digest_authenticate_callback)(struct NX_WEB_HTTP_SERVER_STRUCT *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce); -#endif -} NX_WEB_HTTP_SERVER; - - -#ifndef NX_WEB_HTTP_SERVER_SOURCE_CODE - -/* Application caller is present, perform API mapping. */ - -/* Determine if error checking is desired. If so, map API functions - to the appropriate error checking front-ends. Otherwise, map API - functions to the core functions that actually perform the work. - Note: error checking is enabled by default. */ - -#ifdef NX_DISABLE_ERROR_CHECKING - -/* Services without error checking. */ - -#define nx_web_http_server_callback_data_send _nx_web_http_server_callback_data_send -#define nx_web_http_server_callback_response_send _nx_web_http_server_callback_response_send -#define nx_web_http_server_callback_response_send_extended _nx_web_http_server_callback_response_send_extended -#define nx_web_http_server_content_get _nx_web_http_server_content_get -#define nx_web_http_server_create _nx_web_http_server_create -#define nx_web_http_server_delete _nx_web_http_server_delete -#define nx_web_http_server_param_get _nx_web_http_server_param_get -#define nx_web_http_server_query_get _nx_web_http_server_query_get -#define nx_web_http_server_start _nx_web_http_server_start -#define nx_web_http_server_secure_configure _nx_web_http_server_secure_configure -#define nx_web_http_server_stop _nx_web_http_server_stop -#define nx_web_http_server_content_get_extended _nx_web_http_server_content_get_extended -#define nx_web_http_server_content_length_get _nx_web_http_server_content_length_get -#define nx_web_http_server_get_entity_header _nx_web_http_server_get_entity_header -#define nx_web_http_server_get_entity_content _nx_web_http_server_get_entity_content -#define nx_web_http_server_callback_generate_response_header _nx_web_http_server_callback_generate_response_header -#define nx_web_http_server_callback_generate_response_header_extended _nx_web_http_server_callback_generate_response_header_extended -#define nx_web_http_server_callback_packet_send _nx_web_http_server_callback_packet_send -#define nx_web_http_server_gmt_callback_set _nx_web_http_server_gmt_callback_set -#define nx_web_http_server_cache_info_callback_set _nx_web_http_server_cache_info_callback_set -#define nx_web_http_server_mime_maps_additional_set _nx_web_http_server_mime_maps_additional_set -#define nx_web_http_server_type_get _nx_web_http_server_type_get -#define nx_web_http_server_type_get_extended _nx_web_http_server_type_get_extended -#define nx_web_http_server_packet_content_find _nx_web_http_server_packet_content_find -#define nx_web_http_server_packet_get _nx_web_http_server_packet_get -#define nx_web_http_server_invalid_userpassword_notify_set _nx_web_http_server_invalid_userpassword_notify_set -#define nx_web_http_server_response_chunked_set _nx_web_http_server_response_chunked_set -#define nx_web_http_server_response_packet_allocate _nx_web_http_server_response_packet_allocate -#define nx_web_http_server_digest_authenticate_notify_set _nx_web_http_server_digest_authenticate_notify_set -#define nx_web_http_server_authentication_check_set _nx_web_http_server_authentication_check_set - -#else - -/* Services with error checking. */ - -#define nx_web_http_server_callback_data_send _nxe_web_http_server_callback_data_send -#define nx_web_http_server_callback_response_send _nxe_web_http_server_callback_response_send -#define nx_web_http_server_callback_response_send_extended _nxe_web_http_server_callback_response_send_extended -#define nx_web_http_server_content_get _nxe_web_http_server_content_get -#define nx_web_http_server_content_length_get _nxe_web_http_server_content_length_get -#define nx_web_http_server_create(p,n,i,pn,m,sp,ss,pp,a,r) _nxe_web_http_server_create(p,n,i,pn,m,sp,ss,pp,a,r,sizeof(NX_WEB_HTTP_SERVER)) -#define nx_web_http_server_delete _nxe_web_http_server_delete -#define nx_web_http_server_param_get _nxe_web_http_server_param_get -#define nx_web_http_server_query_get _nxe_web_http_server_query_get -#define nx_web_http_server_start _nxe_web_http_server_start -#define nx_web_http_server_secure_configure _nxe_web_http_server_secure_configure -#define nx_web_http_server_stop _nxe_web_http_server_stop -#define nx_web_http_server_content_get_extended _nxe_web_http_server_content_get_extended -#define nx_web_http_server_get_entity_header _nxe_web_http_server_get_entity_header -#define nx_web_http_server_get_entity_content _nxe_web_http_server_get_entity_content -#define nx_web_http_server_callback_generate_response_header _nxe_web_http_server_callback_generate_response_header -#define nx_web_http_server_callback_generate_response_header_extended _nxe_web_http_server_callback_generate_response_header_extended -#define nx_web_http_server_callback_packet_send _nxe_web_http_server_callback_packet_send -#define nx_web_http_server_gmt_callback_set _nxe_web_http_server_gmt_callback_set -#define nx_web_http_server_cache_info_callback_set _nxe_web_http_server_cache_info_callback_set -#define nx_web_http_server_mime_maps_additional_set _nxe_web_http_server_mime_maps_additional_set -#define nx_web_http_server_type_get _nxe_web_http_server_type_get -#define nx_web_http_server_type_get_extended _nxe_web_http_server_type_get_extended -#define nx_web_http_server_packet_content_find _nxe_web_http_server_packet_content_find -#define nx_web_http_server_packet_get _nxe_web_http_server_packet_get -#define nx_web_http_server_invalid_userpassword_notify_set _nxe_web_http_server_invalid_userpassword_notify_set -#define nx_web_http_server_response_chunked_set _nxe_web_http_server_response_chunked_set -#define nx_web_http_server_response_packet_allocate _nxe_web_http_server_response_packet_allocate -#define nx_web_http_server_digest_authenticate_notify_set _nxe_web_http_server_digest_authenticate_notify_set -#define nx_web_http_server_authentication_check_set _nxe_web_http_server_authentication_check_set - -#endif - -/* Define the prototypes accessible to the application software. */ - - -UINT nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_info, - UINT additional_info_length); -UINT nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); - -#ifdef NX_DISABLE_ERROR_CHECKING -UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); -#else -UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size); -#endif /* NX_DISABLE_ERROR_CHECKING */ - -UINT nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); -UINT nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); -UINT nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); -#ifdef NX_WEB_HTTPS_ENABLE -UINT nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, - UCHAR* packet_buffer, UINT packet_buffer_size, - NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], - UINT trusted_certs_num, - NX_SECURE_X509_CERT *remote_certificates[], - UINT remote_certs_num, - UCHAR *remote_certificate_buffer, - UINT remote_cert_buffer_size); -#endif /* NX_WEB_HTTPS_ENABLE */ -UINT nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length); -UINT nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, - NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, - CHAR *content_type, UINT content_type_length, - CHAR *additional_header, UINT additional_header_length); -UINT nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)); -UINT nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); -UINT nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); -UINT nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, - CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); - -UINT nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); - -UINT nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); -UINT nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); -UINT nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - - -#else - -/* HTTP source code is being compiled, do not perform any API mapping. */ - -UINT _nx_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT _nx_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT _nx_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_info, - UINT additional_info_length); -UINT _nx_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nx_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr)); -UINT _nx_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT _nx_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); -UINT _nx_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); -UINT _nx_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); -#ifdef NX_WEB_HTTPS_ENABLE -UINT _nx_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, - UCHAR* packet_buffer, UINT packet_buffer_size, - NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], - UINT trusted_certs_num, - NX_SECURE_X509_CERT *remote_certificates[], - UINT remote_certs_num, - UCHAR *remote_certificate_buffer, - UINT remote_cert_buffer_size); -#endif /* NX_WEB_HTTPS_ENABLE */ -UINT _nx_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT _nx_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nx_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *length); -UINT _nx_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT _nx_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT _nx_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT _nx_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, - NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, - CHAR *content_type, UINT content_type_length, - CHAR *additional_header, UINT additional_header_length); -UINT _nx_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nx_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_callback)(NX_WEB_HTTP_SERVER_DATE *)); -UINT _nx_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); -UINT _nx_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT _nx_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); -UINT _nx_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT _nx_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type )); -UINT _nx_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT _nx_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - - -/* Define internal HTTP Server functions. */ - -VOID _nx_web_http_server_connection_present(NX_TCP_SOCKET *socket_ptr, UINT port); -UINT _nx_web_http_server_get_client_request(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -VOID _nx_web_http_server_get_process(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, NX_PACKET *packet_ptr); -VOID _nx_web_http_server_put_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -VOID _nx_web_http_server_delete_process(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nx_web_http_server_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_information, - UINT additional_information_length); -UINT _nx_web_http_server_basic_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present); -UINT _nx_web_http_server_retrieve_basic_authorization(NX_PACKET *packet_ptr, CHAR *authorization_request_ptr); -UINT _nx_web_http_server_retrieve_resource(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *destination, UINT max_size); -UINT _nx_web_http_server_calculate_content_offset(NX_PACKET *packet_ptr); -UINT _nx_web_http_server_number_convert(UINT number, CHAR *string); -UINT _nx_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); -UINT _nx_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, - CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); -VOID _nx_web_http_base64_encode(CHAR *name, UINT length, CHAR *base64name); -VOID _nx_web_http_base64_decode(CHAR *base64name, UINT length, CHAR *name); - -UINT _nx_web_http_server_receive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG wait_option); -UINT _nx_web_http_server_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG wait_option); -VOID _nx_web_http_server_connection_reset(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option); -VOID _nx_web_http_server_connection_disconnect(NX_WEB_HTTP_SERVER *server_ptr, NX_TCP_SESSION *session_ptr, UINT wait_option); - -#ifdef NX_WEB_HTTP_DIGEST_ENABLE -UINT _nx_web_http_server_digest_authenticate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, CHAR *name_ptr, CHAR *password_ptr, CHAR *realm_ptr, UINT *auth_request_present); -VOID _nx_web_http_server_digest_response_calculate(NX_WEB_HTTP_SERVER *server_ptr, CHAR *username, CHAR *realm, CHAR *password, CHAR *nonce, CHAR *method, CHAR *uri, CHAR *nc, CHAR *cnonce, CHAR *result); -UINT _nx_web_http_server_retrieve_digest_authorization(NX_PACKET *packet_ptr, CHAR *response, CHAR *uri, CHAR *nc, CHAR *cnonce); -VOID _nx_web_http_server_hex_ascii_convert(CHAR *source, UINT source_length, CHAR *destination); -#endif - -#ifdef NX_WEB_HTTP_MULTIPART_ENABLE -UINT _nx_web_http_server_boundary_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr); -#endif /* NX_WEB_HTTP_MULTIPART_ENABLE */ - -UINT _nx_web_http_server_match_string(UCHAR *src_start, UCHAR *src_end, UCHAR *target, ULONG target_length, ULONG *match_count, UCHAR **match_end_ptr); -UINT _nx_web_http_server_field_value_get(NX_PACKET *packet_ptr, UCHAR *field_name, ULONG name_length, UCHAR *field_value, ULONG field_value_size); -UINT _nx_web_http_server_memicmp(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length); - -UINT _nx_web_http_server_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT status_code_length, - UINT content_length, CHAR *content_type, - UINT content_type_length, CHAR* additional_header, - UINT additional_header_length); -UINT _nx_web_http_server_date_to_string(NX_WEB_HTTP_SERVER_DATE *date, CHAR *string); -VOID _nx_web_http_server_date_convert(UINT date, UINT count, CHAR *string); - -VOID _nx_web_http_server_receive_data(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); -VOID _nx_web_http_server_connection_end(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); -VOID _nx_web_http_server_connection_timeout(NX_TCPSERVER *tcpserver_ptr, NX_TCP_SESSION *session_ptr); - - -#ifndef NX_WEB_HTTP_KEEPALIVE_DISABLE -VOID _nx_web_http_server_get_client_keepalive(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -#endif /* NX_WEB_HTTP_KEEPALIVE_DISABLE */ - -UINT _nx_web_http_server_chunked_check(NX_PACKET *packet_ptr); -UINT _nx_web_http_server_request_read(NX_WEB_HTTP_SERVER *server_ptr, UCHAR *data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_server_request_byte_expect(NX_WEB_HTTP_SERVER *server_ptr, UCHAR data, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_server_chunked_size_get(NX_WEB_HTTP_SERVER *server_ptr, UINT *chunk_size, ULONG wait_option, NX_PACKET **current_packet_pptr, UCHAR **current_data_pptr); -UINT _nx_web_http_server_request_chunked_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG wait_option); -UINT _nx_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); -UINT _nx_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); -UINT _nxe_web_http_server_response_chunked_set(NX_WEB_HTTP_SERVER *server_ptr, UINT chunk_size, NX_PACKET *packet_ptr); -UINT _nxe_web_http_server_response_packet_allocate(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, UINT wait_option); -UINT _nxe_web_http_server_callback_data_send(NX_WEB_HTTP_SERVER *server_ptr, VOID *data_ptr, ULONG data_length); -UINT _nxe_web_http_server_callback_response_send(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, CHAR *information, CHAR *additional_info); -UINT _nxe_web_http_server_callback_response_send_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *status_code, - UINT status_code_length, CHAR *information, - UINT information_length, CHAR *additional_info, - UINT additional_info_length); -UINT _nxe_web_http_server_content_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nxe_web_http_server_packet_content_find(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr, ULONG *content_length); -UINT _nxe_web_http_server_packet_get(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_ptr); -UINT _nxe_web_http_server_content_get_extended(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr, ULONG byte_offset, - CHAR *destination_ptr, UINT destination_size, UINT *actual_size); -UINT _nxe_web_http_server_content_length_get(NX_PACKET *packet_ptr, ULONG *content_length); -UINT _nxe_web_http_server_create(NX_WEB_HTTP_SERVER *http_server_ptr, CHAR *http_server_name, NX_IP *ip_ptr, UINT server_port, FX_MEDIA *media_ptr, VOID *stack_ptr, ULONG stack_size, NX_PACKET_POOL *pool_ptr, - UINT (*authentication_check)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, CHAR **password, CHAR **realm), - UINT (*request_notify)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr), UINT http_server_size); -UINT _nxe_web_http_server_delete(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT _nxe_web_http_server_param_get(NX_PACKET *packet_ptr, UINT param_number, CHAR *param_ptr, UINT *param_size, UINT max_param_size); -UINT _nxe_web_http_server_query_get(NX_PACKET *packet_ptr, UINT query_number, CHAR *query_ptr, UINT *query_size, UINT max_query_size); -UINT _nxe_web_http_server_start(NX_WEB_HTTP_SERVER *http_server_ptr); -#ifdef NX_WEB_HTTPS_ENABLE -UINT _nxe_web_http_server_secure_configure(NX_WEB_HTTP_SERVER *http_server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table, - VOID *metadata_buffer, ULONG metadata_size, - UCHAR* packet_buffer, UINT packet_buffer_size, - NX_SECURE_X509_CERT *identity_certificate, - NX_SECURE_X509_CERT *trusted_certificates[], - UINT trusted_certs_num, - NX_SECURE_X509_CERT *remote_certificates[], - UINT remote_certs_num, - UCHAR *remote_certificate_buffer, - UINT remote_cert_buffer_size); -#endif /* NX_WEB_HTTPS_ENABLE */ -UINT _nxe_web_http_server_stop(NX_WEB_HTTP_SERVER *http_server_ptr); -UINT _nxe_web_http_server_invalid_userpassword_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*invalid_username_password_callback)(CHAR *resource, NXD_ADDRESS *client_nxd_address, UINT request_type)); -UINT _nxe_web_http_server_type_get(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, CHAR *http_type_string, UINT *string_size); -UINT _nxe_web_http_server_type_get_extended(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name, UINT name_length, - CHAR *http_type_string, UINT http_type_string_max_size, UINT *string_size); -UINT _nxe_web_http_server_get_entity_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, UCHAR *entity_header_buffer, ULONG buffer_size); -UINT _nxe_web_http_server_get_entity_content(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, ULONG *available_offset, ULONG *available_length); -UINT _nxe_web_http_server_callback_generate_response_header(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET **packet_pptr, - CHAR *status_code, UINT content_length, CHAR *content_type, - CHAR* additional_header); -UINT _nxe_web_http_server_callback_generate_response_header_extended(NX_WEB_HTTP_SERVER *server_ptr, - NX_PACKET **packet_pptr, CHAR *status_code, - UINT status_code_length, UINT content_length, - CHAR *content_type, UINT content_type_length, - CHAR *additional_header, UINT additional_header_length); -UINT _nxe_web_http_server_callback_packet_send(NX_WEB_HTTP_SERVER *server_ptr, NX_PACKET *packet_ptr); -UINT _nxe_web_http_server_gmt_callback_set(NX_WEB_HTTP_SERVER *server_ptr, VOID (*gmt_get)(NX_WEB_HTTP_SERVER_DATE *)); -UINT _nxe_web_http_server_cache_info_callback_set(NX_WEB_HTTP_SERVER *server_ptr, UINT (*cache_info_get)(CHAR *, UINT *, NX_WEB_HTTP_SERVER_DATE *)); -UINT _nxe_web_http_server_mime_maps_additional_set(NX_WEB_HTTP_SERVER *server_ptr, NX_WEB_HTTP_SERVER_MIME_MAP *mime_maps, UINT mime_maps_num); -UINT _nxe_web_http_server_digest_authenticate_notify_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*digest_authenticate_callback)(NX_WEB_HTTP_SERVER *server_ptr, CHAR *name_ptr, - CHAR *realm_ptr, CHAR *password_ptr, CHAR *method, - CHAR *authorization_uri, CHAR *authorization_nc, - CHAR *authorization_cnonce)); -UINT _nxe_web_http_server_authentication_check_set(NX_WEB_HTTP_SERVER *http_server_ptr, - UINT (*authentication_check_extended)(NX_WEB_HTTP_SERVER *server_ptr, UINT request_type, CHAR *resource, CHAR **name, UINT *name_length, CHAR **password, UINT *password_length, CHAR **realm, UINT *realm_length)); - -#endif /* NX_WEB_HTTP_SERVER_SOURCE_CODE */ - -/* Determine if a C++ compiler is being used. If so, complete the standard - C conditional started above. */ -#ifdef __cplusplus - } -#endif - -#endif /* NXD_HTTP_SERVER_H */ -- cgit v1.3.1